Merge "AudioTrack JNI function rename"
diff --git a/Android.mk b/Android.mk
index 0865d24..d478a59 100644
--- a/Android.mk
+++ b/Android.mk
@@ -260,6 +260,8 @@
 	media/java/android/media/IAudioService.aidl \
 	media/java/android/media/IAudioFocusDispatcher.aidl \
 	media/java/android/media/IAudioRoutesObserver.aidl \
+	media/java/android/media/IMediaHTTPConnection.aidl \
+	media/java/android/media/IMediaHTTPService.aidl \
 	media/java/android/media/IMediaRouterClient.aidl \
 	media/java/android/media/IMediaRouterService.aidl \
 	media/java/android/media/IMediaScannerListener.aidl \
diff --git a/api/current.txt b/api/current.txt
index 94ffb30..3ebd522 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -543,6 +543,7 @@
     field public static final int fromAlpha = 16843210; // 0x10101ca
     field public static final int fromDegrees = 16843187; // 0x10101b3
     field public static final int fromScene = 16843741; // 0x10103dd
+    field public static final int fromSceneName = 16843774; // 0x10103fe
     field public static final int fromXDelta = 16843206; // 0x10101c6
     field public static final int fromXScale = 16843202; // 0x10101c2
     field public static final int fromYDelta = 16843208; // 0x10101c8
@@ -960,6 +961,7 @@
     field public static final int shadowRadius = 16843108; // 0x1010164
     field public static final int shape = 16843162; // 0x101019a
     field public static final int shareInterpolator = 16843195; // 0x10101bb
+    field public static final int sharedElementName = 16843776; // 0x1010400
     field public static final int sharedUserId = 16842763; // 0x101000b
     field public static final int sharedUserLabel = 16843361; // 0x1010261
     field public static final int shouldDisableView = 16843246; // 0x10101ee
@@ -1142,6 +1144,7 @@
     field public static final int toAlpha = 16843211; // 0x10101cb
     field public static final int toDegrees = 16843188; // 0x10101b4
     field public static final int toScene = 16843742; // 0x10103de
+    field public static final int toSceneName = 16843775; // 0x10103ff
     field public static final int toXDelta = 16843207; // 0x10101c7
     field public static final int toXScale = 16843203; // 0x10101c3
     field public static final int toYDelta = 16843209; // 0x10101c9
@@ -1157,6 +1160,7 @@
     field public static final int transformPivotX = 16843552; // 0x1010320
     field public static final int transformPivotY = 16843553; // 0x1010321
     field public static final int transition = 16843743; // 0x10103df
+    field public static final int transitionGroup = 16843777; // 0x1010401
     field public static final int transitionOrdering = 16843744; // 0x10103e0
     field public static final int translationX = 16843554; // 0x1010322
     field public static final int translationY = 16843555; // 0x1010323
@@ -1514,6 +1518,7 @@
     field public static final int selectAll = 16908319; // 0x102001f
     field public static final int selectTextMode = 16908333; // 0x102002d
     field public static final int selectedIcon = 16908302; // 0x102000e
+    field public static final int shared_element_name = 16908334; // 0x102002e
     field public static final int startSelectingText = 16908328; // 0x1020028
     field public static final int stopSelectingText = 16908329; // 0x1020029
     field public static final int summary = 16908304; // 0x1020010
@@ -3035,6 +3040,7 @@
     method public int getTaskId();
     method public final java.lang.CharSequence getTitle();
     method public final int getTitleColor();
+    method public android.os.Bundle getTransitionArgs();
     method public final int getVolumeControlStream();
     method public android.view.Window getWindow();
     method public android.view.WindowManager getWindowManager();
@@ -3130,6 +3136,7 @@
     method public void setContentView(android.view.View);
     method public void setContentView(android.view.View, android.view.ViewGroup.LayoutParams);
     method public final void setDefaultKeyMode(int);
+    method public void setEarlyBackgroundTransition(boolean);
     method public final void setFeatureDrawable(int, android.graphics.drawable.Drawable);
     method public final void setFeatureDrawableAlpha(int, int);
     method public final void setFeatureDrawableResource(int, int);
@@ -3170,6 +3177,7 @@
     method public boolean startNextMatchingActivity(android.content.Intent);
     method public boolean startNextMatchingActivity(android.content.Intent, android.os.Bundle);
     method public void startSearch(java.lang.String, boolean, android.os.Bundle, boolean);
+    method protected void startSharedElementTransition(android.os.Bundle);
     method public deprecated void stopManagingCursor(android.database.Cursor);
     method public void takeKeyEvents(boolean);
     method public void triggerSearch(java.lang.String, android.os.Bundle);
@@ -3340,6 +3348,7 @@
   public class ActivityOptions {
     method public static android.app.ActivityOptions makeCustomAnimation(android.content.Context, int, int);
     method public static android.app.ActivityOptions makeScaleUpAnimation(android.view.View, int, int, int, int);
+    method public static android.app.ActivityOptions makeSceneTransitionAnimation(android.os.Bundle);
     method public static android.app.ActivityOptions makeThumbnailScaleUpAnimation(android.view.View, android.graphics.Bitmap, int, int);
     method public android.os.Bundle toBundle();
     method public void update(android.app.ActivityOptions);
@@ -3349,8 +3358,11 @@
     ctor public ActivityView(android.content.Context);
     ctor public ActivityView(android.content.Context, android.util.AttributeSet);
     ctor public ActivityView(android.content.Context, android.util.AttributeSet, int);
+    method public boolean isAttachedToDisplay();
     method protected void onLayout(boolean, int, int, int, int);
     method public void startActivity(android.content.Intent);
+    method public void startActivity(android.content.IntentSender);
+    method public void startActivity(android.app.PendingIntent);
   }
 
   public class AlarmManager {
@@ -4219,6 +4231,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
@@ -4304,6 +4317,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);
@@ -4759,6 +4773,7 @@
     method public boolean isActivePasswordSufficient();
     method public boolean isAdminActive(android.content.ComponentName);
     method public boolean isDeviceOwnerApp(java.lang.String);
+    method public boolean isProfileOwnerApp(java.lang.String);
     method public void lockNow();
     method public void removeActiveAdmin(android.content.ComponentName);
     method public boolean resetPassword(java.lang.String, int);
@@ -11259,27 +11274,37 @@
     field public static final android.hardware.camera2.CameraMetadata.Key LENS_INFO_AVAILABLE_FILTER_DENSITIES;
     field public static final android.hardware.camera2.CameraMetadata.Key LENS_INFO_AVAILABLE_FOCAL_LENGTHS;
     field public static final android.hardware.camera2.CameraMetadata.Key LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION;
+    field public static final android.hardware.camera2.CameraMetadata.Key LENS_INFO_FOCUS_DISTANCE_CALIBRATION;
     field public static final android.hardware.camera2.CameraMetadata.Key LENS_INFO_HYPERFOCAL_DISTANCE;
     field public static final android.hardware.camera2.CameraMetadata.Key LENS_INFO_MINIMUM_FOCUS_DISTANCE;
     field public static final android.hardware.camera2.CameraMetadata.Key LENS_INFO_SHADING_MAP_SIZE;
+    field public static final android.hardware.camera2.CameraMetadata.Key REQUEST_AVAILABLE_CAPABILITIES;
+    field public static final android.hardware.camera2.CameraMetadata.Key REQUEST_MAX_NUM_INPUT_STREAMS;
     field public static final android.hardware.camera2.CameraMetadata.Key REQUEST_MAX_NUM_OUTPUT_STREAMS;
     field public static final android.hardware.camera2.CameraMetadata.Key REQUEST_PARTIAL_RESULT_COUNT;
     field public static final android.hardware.camera2.CameraMetadata.Key REQUEST_PIPELINE_MAX_DEPTH;
     field public static final android.hardware.camera2.CameraMetadata.Key SCALER_AVAILABLE_FORMATS;
+    field public static final android.hardware.camera2.CameraMetadata.Key SCALER_AVAILABLE_INPUT_OUTPUT_FORMATS_MAP;
     field public static final android.hardware.camera2.CameraMetadata.Key SCALER_AVAILABLE_JPEG_MIN_DURATIONS;
     field public static final android.hardware.camera2.CameraMetadata.Key SCALER_AVAILABLE_JPEG_SIZES;
     field public static final android.hardware.camera2.CameraMetadata.Key SCALER_AVAILABLE_MAX_DIGITAL_ZOOM;
+    field public static final android.hardware.camera2.CameraMetadata.Key SCALER_AVAILABLE_MIN_FRAME_DURATIONS;
     field public static final android.hardware.camera2.CameraMetadata.Key SCALER_AVAILABLE_PROCESSED_MIN_DURATIONS;
     field public static final android.hardware.camera2.CameraMetadata.Key SCALER_AVAILABLE_PROCESSED_SIZES;
+    field public static final android.hardware.camera2.CameraMetadata.Key SCALER_AVAILABLE_STALL_DURATIONS;
+    field public static final android.hardware.camera2.CameraMetadata.Key SCALER_AVAILABLE_STREAM_CONFIGURATIONS;
     field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_AVAILABLE_TEST_PATTERN_MODES;
     field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_BASE_GAIN_FACTOR;
+    field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_BLACK_LEVEL_PATTERN;
     field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_INFO_ACTIVE_ARRAY_SIZE;
     field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_INFO_EXPOSURE_TIME_RANGE;
     field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_INFO_MAX_FRAME_DURATION;
     field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_INFO_PHYSICAL_SIZE;
+    field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_INFO_PIXEL_ARRAY_SIZE;
     field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_INFO_SENSITIVITY_RANGE;
     field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_MAX_ANALOG_SENSITIVITY;
     field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_ORIENTATION;
+    field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_PROFILE_HUE_SAT_MAP_DIMENSIONS;
     field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES;
     field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_INFO_MAX_FACE_COUNT;
     field public static final android.hardware.camera2.CameraMetadata.Key SYNC_MAX_LATENCY;
@@ -11411,6 +11436,7 @@
     field public static final int CONTROL_EFFECT_MODE_WHITEBOARD = 6; // 0x6
     field public static final int CONTROL_MODE_AUTO = 1; // 0x1
     field public static final int CONTROL_MODE_OFF = 0; // 0x0
+    field public static final int CONTROL_MODE_OFF_KEEP_STATE = 3; // 0x3
     field public static final int CONTROL_MODE_USE_SCENE_MODE = 2; // 0x2
     field public static final int CONTROL_SCENE_MODE_ACTION = 2; // 0x2
     field public static final int CONTROL_SCENE_MODE_BARCODE = 16; // 0x10
@@ -11439,10 +11465,16 @@
     field public static final int FLASH_STATE_FIRED = 3; // 0x3
     field public static final int FLASH_STATE_READY = 2; // 0x2
     field public static final int FLASH_STATE_UNAVAILABLE = 0; // 0x0
+    field public static final int HOT_PIXEL_MODE_FAST = 1; // 0x1
+    field public static final int HOT_PIXEL_MODE_HIGH_QUALITY = 2; // 0x2
+    field public static final int HOT_PIXEL_MODE_OFF = 0; // 0x0
     field public static final int INFO_SUPPORTED_HARDWARE_LEVEL_FULL = 1; // 0x1
     field public static final int INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED = 0; // 0x0
     field public static final int LENS_FACING_BACK = 1; // 0x1
     field public static final int LENS_FACING_FRONT = 0; // 0x0
+    field public static final int LENS_INFO_FOCUS_DISTANCE_CALIBRATION_APPROXIMATE = 1; // 0x1
+    field public static final int LENS_INFO_FOCUS_DISTANCE_CALIBRATION_CALIBRATED = 2; // 0x2
+    field public static final int LENS_INFO_FOCUS_DISTANCE_CALIBRATION_UNCALIBRATED = 0; // 0x0
     field public static final int LENS_OPTICAL_STABILIZATION_MODE_OFF = 0; // 0x0
     field public static final int LENS_OPTICAL_STABILIZATION_MODE_ON = 1; // 0x1
     field public static final int LENS_STATE_MOVING = 1; // 0x1
@@ -11450,6 +11482,11 @@
     field public static final int NOISE_REDUCTION_MODE_FAST = 1; // 0x1
     field public static final int NOISE_REDUCTION_MODE_HIGH_QUALITY = 2; // 0x2
     field public static final int NOISE_REDUCTION_MODE_OFF = 0; // 0x0
+    field public static final int REQUEST_AVAILABLE_CAPABILITIES_DNG = 5; // 0x5
+    field public static final int REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR = 2; // 0x2
+    field public static final int REQUEST_AVAILABLE_CAPABILITIES_ZSL = 4; // 0x4
+    field public static final int SCALER_AVAILABLE_STREAM_CONFIGURATIONS_INPUT = 1; // 0x1
+    field public static final int SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT = 0; // 0x0
     field public static final int SENSOR_TEST_PATTERN_MODE_COLOR_BARS = 2; // 0x2
     field public static final int SENSOR_TEST_PATTERN_MODE_COLOR_BARS_FADE_TO_GRAY = 3; // 0x3
     field public static final int SENSOR_TEST_PATTERN_MODE_CUSTOM1 = 256; // 0x100
@@ -11517,6 +11554,7 @@
     field public static final android.os.Parcelable.Creator CREATOR;
     field public static final android.hardware.camera2.CameraMetadata.Key EDGE_MODE;
     field public static final android.hardware.camera2.CameraMetadata.Key FLASH_MODE;
+    field public static final android.hardware.camera2.CameraMetadata.Key HOT_PIXEL_MODE;
     field public static final android.hardware.camera2.CameraMetadata.Key JPEG_GPS_COORDINATES;
     field public static final android.hardware.camera2.CameraMetadata.Key JPEG_GPS_PROCESSING_METHOD;
     field public static final android.hardware.camera2.CameraMetadata.Key JPEG_GPS_TIMESTAMP;
@@ -11574,6 +11612,8 @@
     field public static final android.hardware.camera2.CameraMetadata.Key EDGE_MODE;
     field public static final android.hardware.camera2.CameraMetadata.Key FLASH_MODE;
     field public static final android.hardware.camera2.CameraMetadata.Key FLASH_STATE;
+    field public static final android.hardware.camera2.CameraMetadata.Key HOT_PIXEL_MAP;
+    field public static final android.hardware.camera2.CameraMetadata.Key HOT_PIXEL_MODE;
     field public static final android.hardware.camera2.CameraMetadata.Key JPEG_GPS_COORDINATES;
     field public static final android.hardware.camera2.CameraMetadata.Key JPEG_GPS_PROCESSING_METHOD;
     field public static final android.hardware.camera2.CameraMetadata.Key JPEG_GPS_TIMESTAMP;
@@ -11592,8 +11632,14 @@
     field public static final android.hardware.camera2.CameraMetadata.Key REQUEST_FRAME_COUNT;
     field public static final android.hardware.camera2.CameraMetadata.Key REQUEST_PIPELINE_DEPTH;
     field public static final android.hardware.camera2.CameraMetadata.Key SCALER_CROP_REGION;
+    field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_CALIBRATION_TRANSFORM;
+    field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_COLOR_TRANSFORM;
     field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_EXPOSURE_TIME;
+    field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_FORWARD_MATRIX;
     field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_FRAME_DURATION;
+    field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_NEUTRAL_COLOR_POINT;
+    field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_PROFILE_HUE_SAT_MAP;
+    field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_PROFILE_TONE_CURVE;
     field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_SENSITIVITY;
     field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_TEMPERATURE;
     field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_TEST_PATTERN_MODE;
@@ -18375,7 +18421,7 @@
 
   public abstract class CountDownTimer {
     ctor public CountDownTimer(long, long);
-    method public final void cancel();
+    method public final synchronized void cancel();
     method public abstract void onFinish();
     method public abstract void onTick(long);
     method public final synchronized android.os.CountDownTimer start();
@@ -26679,6 +26725,7 @@
     method public android.transition.Transition addListener(android.transition.Transition.TransitionListener);
     method public android.transition.Transition addTarget(int);
     method public android.transition.Transition addTarget(android.view.View);
+    method public boolean canRemoveViews();
     method public abstract void captureEndValues(android.transition.TransitionValues);
     method public abstract void captureStartValues(android.transition.TransitionValues);
     method public android.transition.Transition clone();
@@ -28617,6 +28664,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);
@@ -28648,7 +28696,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();
@@ -28743,6 +28791,7 @@
     method public int getScrollBarStyle();
     method public final int getScrollX();
     method public final int getScrollY();
+    method public java.lang.String getSharedElementName();
     method public int getSolidColor();
     method protected int getSuggestedMinimumHeight();
     method protected int getSuggestedMinimumWidth();
@@ -28833,6 +28882,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();
@@ -28899,7 +28949,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);
@@ -28963,6 +29014,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);
@@ -28996,6 +29048,7 @@
     method public void setScrollY(int);
     method public void setScrollbarFadingEnabled(boolean);
     method public void setSelected(boolean);
+    method public void setSharedElementName(java.lang.String);
     method public void setSoundEffectsEnabled(boolean);
     method public void setSystemUiVisibility(int);
     method public void setTag(java.lang.Object);
@@ -29183,6 +29236,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);
@@ -29382,6 +29439,7 @@
     method protected boolean isChildrenDrawingOrderEnabled();
     method protected boolean isChildrenDrawnWithCacheEnabled();
     method public boolean isMotionEventSplittingEnabled();
+    method public boolean isTransitionGroup();
     method public final void layout(int, int, int, int);
     method protected void measureChild(android.view.View, int, int);
     method protected void measureChildWithMargins(android.view.View, int, int, int, int);
@@ -29427,6 +29485,7 @@
     method public void setOnHierarchyChangeListener(android.view.ViewGroup.OnHierarchyChangeListener);
     method public void setPersistentDrawingCache(int);
     method protected void setStaticTransformationsEnabled(boolean);
+    method public void setTransitionGroup(boolean);
     method public boolean shouldDelayChildPressedState();
     method public boolean showContextMenuForChild(android.view.View);
     method public android.view.ActionMode startActionModeForChild(android.view.View, android.view.ActionMode.Callback);
@@ -29721,7 +29780,6 @@
     method public abstract void setTitle(java.lang.CharSequence);
     method public abstract deprecated void setTitleColor(int);
     method public void setTransitionManager(android.transition.TransitionManager);
-    method public void setTransitionOptions(android.os.Bundle);
     method public void setType(int);
     method public void setUiOptions(int);
     method public void setUiOptions(int, int);
@@ -29801,6 +29859,27 @@
     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();
+  }
+
   public abstract interface WindowManager implements android.view.ViewManager {
     method public abstract android.view.Display getDefaultDisplay();
     method public abstract void removeViewImmediate(android.view.View);
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 698f06a..a8716bf 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -18,7 +18,6 @@
 
 import android.annotation.NonNull;
 import android.transition.Scene;
-import android.transition.Transition;
 import android.transition.TransitionManager;
 import android.util.ArrayMap;
 import android.util.SuperNotCalledException;
@@ -771,6 +770,7 @@
 
     private Thread mUiThread;
     final Handler mHandler = new Handler();
+    private ActivityOptions mTransitionActivityOptions;
 
     /** Return the intent that started this activity. */
     public Intent getIntent() {
@@ -3443,38 +3443,16 @@
      *
      * @throws android.content.ActivityNotFoundException
      *
-     * @see #startActivity 
+     * @see #startActivity
      */
     public void startActivityForResult(Intent intent, int requestCode) {
-        final TransitionManager tm = getWindow().getTransitionManager();
-        final Scene currScene = getWindow().getContentScene();
-        final String[] targetSceneNames = currScene != null && tm != null ?
-                tm.getTargetSceneNames(currScene) : null;
-
-        if (targetSceneNames == null || targetSceneNames.length == 0) {
-            startActivityForResult(intent, requestCode, null);
-        } else {
-            // TODO Capture the scene transition args and send along
-            final ActivityOptions opts = ActivityOptions.makeSceneTransitionAnimation(
-                    targetSceneNames, null,
-                    new ActivityOptions.OnSceneTransitionStartedListener() {
-                        @Override public void onSceneTransitionStarted(String destSceneName) {
-                            final Transition t = tm.getNamedTransition(currScene, destSceneName);
-                            // TODO Fill this in to notify the outgoing activity that it should
-                            // treat this as a sync point for the transition - the target
-                            // transition has started.
-                            Log.d(TAG, "Scene transition to scene " + destSceneName +
-                                    " transition " + t);
-                        }
-                    }, mHandler);
-            startActivityForResult(intent, requestCode, opts.toBundle());
-        }
+        startActivityForResult(intent, requestCode, null);
     }
 
     /**
      * Launch an activity for which you would like a result when it finished.
      * When this activity exits, your
-     * onActivityResult() method will be called with the given requestCode. 
+     * onActivityResult() method will be called with the given requestCode.
      * Using a negative requestCode is the same as calling 
      * {@link #startActivity} (the activity is not launched as a sub-activity).
      *
@@ -3487,9 +3465,9 @@
      *
      * <p>As a special case, if you call startActivityForResult() with a requestCode 
      * >= 0 during the initial onCreate(Bundle savedInstanceState)/onResume() of your
-     * activity, then your window will not be displayed until a result is 
-     * returned back from the started activity.  This is to avoid visible 
-     * flickering when redirecting to another activity. 
+     * activity, then your window will not be displayed until a result is
+     * returned back from the started activity.  This is to avoid visible
+     * flickering when redirecting to another activity.
      *
      * <p>This method throws {@link android.content.ActivityNotFoundException}
      * if there was no Activity found to run the given Intent.
@@ -3503,9 +3481,17 @@
      *
      * @throws android.content.ActivityNotFoundException
      *
-     * @see #startActivity 
+     * @see #startActivity
      */
     public void startActivityForResult(Intent intent, int requestCode, @Nullable Bundle options) {
+        TransitionManager tm = getContentTransitionManager();
+        if (tm != null && options != null) {
+            ActivityOptions activityOptions = new ActivityOptions(options);
+            if (activityOptions.getAnimationType() == ActivityOptions.ANIM_SCENE_TRANSITION) {
+                getWindow().startExitTransition(activityOptions);
+                options = activityOptions.toBundle();
+            }
+        }
         if (mParent == null) {
             Instrumentation.ActivityResult ar =
                 mInstrumentation.execStartActivity(
@@ -5313,7 +5299,7 @@
             mWindow.setUiOptions(info.uiOptions);
         }
         mUiThread = Thread.currentThread();
-        
+
         mMainThread = aThread;
         mInstrumentation = instr;
         mToken = token;
@@ -5335,8 +5321,40 @@
             mWindow.setContainer(mParent.getWindow());
         }
         mWindowManager = mWindow.getWindowManager();
-        mWindow.setTransitionOptions(options);
         mCurrentConfig = config;
+        mTransitionActivityOptions = null;
+        Window.SceneTransitionListener sceneTransitionListener = null;
+        if (options != null) {
+            ActivityOptions activityOptions = new ActivityOptions(options);
+            if (activityOptions.getAnimationType() == ActivityOptions.ANIM_SCENE_TRANSITION) {
+                mTransitionActivityOptions = activityOptions;
+                sceneTransitionListener = new Window.SceneTransitionListener() {
+                    @Override
+                    public void enterSharedElement(Bundle transitionArgs) {
+                        startSharedElementTransition(transitionArgs);
+                        mTransitionActivityOptions = null;
+                    }
+
+                    @Override
+                    public void nullPendingTransition() {
+                        overridePendingTransition(0, 0);
+                    }
+
+                    @Override
+                    public void convertFromTranslucent() {
+                        Activity.this.convertFromTranslucent();
+                    }
+
+                    @Override
+                    public void convertToTranslucent() {
+                        Activity.this.convertToTranslucent(null);
+                    }
+                };
+
+            }
+        }
+
+        mWindow.setTransitionOptions(mTransitionActivityOptions, sceneTransitionListener);
     }
 
     /** @hide */
@@ -5350,7 +5368,7 @@
                 com.android.internal.R.styleable.Window_windowNoDisplay, false);
         mFragments.dispatchActivityCreated();
     }
-    
+
     final void performStart() {
         mFragments.noteStateNotSaved();
         mCalled = false;
@@ -5507,7 +5525,7 @@
                     }
                 }
             }
-    
+
             mStopped = true;
         }
         mResumed = false;
@@ -5522,7 +5540,57 @@
             mLoaderManager.doDestroy();
         }
     }
-    
+
+    /**
+     * Gets the entering Activity transition args. Will be null if
+     * {@link android.app.ActivityOptions#makeSceneTransitionAnimation(android.os.Bundle)} was
+     * not used to pass a Bundle to startActivity. The Bundle passed to that method in the
+     * calling Activity is returned here.
+     * <p>After startSharedElementTransition is called, this method will return null.</p>
+     *
+     * @return The Bundle passed into Bundle parameter of
+     *         {@link android.app.ActivityOptions#makeSceneTransitionAnimation(android.os.Bundle)}
+     *         in the calling Activity.
+     */
+    public Bundle getTransitionArgs() {
+        if (mTransitionActivityOptions == null) {
+            return null;
+        }
+        return mTransitionActivityOptions.getSceneTransitionArgs();
+    }
+
+    /**
+     * Override to transfer a shared element from a calling Activity to this Activity.
+     * Shared elements will be made VISIBLE before this call. The Activity is responsible
+     * for transitioning the shared elements from their location to the eventual destination.
+     * The shared element will be laid out a the destination when this method is called.
+     *
+     * @param transitionArgs The same as returned from {@link #getTransitionArgs()}, this should
+     *                       contain information from the calling Activity to tell where the
+     *                       shared element should be placed.
+     */
+    protected void startSharedElementTransition(Bundle transitionArgs) {
+    }
+
+    /**
+     * Controls how the background fade is triggered when there is an entering Activity transition.
+     * If fadeEarly is true, the Window background will fade in as soon as the shared elements are
+     * ready to switch. If fadeEarly is false, the background will fade only after the calling
+     * Activity's exit transition completes. By default, the Window will fade in when the calling
+     * Activity's exit transition completes.
+     *
+     * @param fadeEarly Set to true to fade out the exiting Activity as soon as the shared elements
+     *                  are transferred. Set to false to fade out the exiting Activity as soon as
+     *                  the shared element is transferred.
+     * @see android.app.ActivityOptions#makeSceneTransitionAnimation(android.os.Bundle)
+     */
+    public void setEarlyBackgroundTransition(boolean fadeEarly) {
+        if (mTransitionActivityOptions == null) {
+            return;
+        }
+        mWindow.setEarlyBackgroundTransition(fadeEarly);
+    }
+
     /**
      * @hide
      */
@@ -5530,7 +5598,7 @@
         return mResumed;
     }
 
-    void dispatchActivityResult(String who, int requestCode, 
+    void dispatchActivityResult(String who, int requestCode,
         int resultCode, Intent data) {
         if (false) Log.v(
             TAG, "Dispatching result: who=" + who + ", reqCode=" + requestCode
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index 582ce3c..3f97c40 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -16,16 +16,21 @@
 
 package android.app;
 
+import android.animation.Animator;
 import android.content.Context;
 import android.graphics.Bitmap;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IRemoteCallback;
 import android.os.RemoteException;
-import android.text.TextUtils;
+import android.transition.Transition;
+import android.util.ArrayMap;
 import android.util.Log;
 import android.view.View;
 
+import java.util.ArrayList;
+import java.util.Map;
+
 /**
  * Helper class for building an options Bundle that can be used with
  * {@link android.content.Context#startActivity(android.content.Intent, android.os.Bundle)
@@ -95,34 +100,30 @@
     public static final String KEY_ANIM_START_LISTENER = "android:animStartListener";
 
     /**
-     * A string array of names for the destination scene. This defines an API in the same
-     * way that intent action or extra names do and should follow a similar convention:
-     * "com.example.scene.FOO"
-     *
-     * @hide
-     */
-    public static final String KEY_DEST_SCENE_NAMES = "android:destSceneNames";
-
-    /**
-     * A string indicating the destination scene name that was chosen by the target.
-     * Used by {@link OnSceneTransitionStartedListener}.
-     * @hide
-     */
-    public static final String KEY_DEST_SCENE_NAME_CHOSEN = "android:destSceneNameChosen";
-
-    /**
-     * Callback for when scene transition is started.
-     * @hide
-     */
-    public static final String KEY_SCENE_TRANSITION_START_LISTENER =
-            "android:sceneTransitionStartListener";
-
-    /**
      * Arguments for the scene transition about to begin.
      * @hide
      */
     public static final String KEY_SCENE_TRANSITION_ARGS = "android:sceneTransitionArgs";
 
+    /**
+     * For Activity transitions, the calling Activity's TransitionListener used to
+     * notify the called Activity when the shared element and the exit transitions
+     * complete.
+     */
+    private static final String KEY_TRANSITION_COMPLETE_LISTENER
+            = "android:transitionCompleteListener";
+
+    /**
+     * For Activity transitions, the called Activity's listener to receive calls
+     * when transitions complete.
+     */
+    private static final String KEY_TRANSITION_TARGET_LISTENER = "android:transitionTargetListener";
+
+    /**
+     * The shared element's texture ID (TODO: not used yet).
+     */
+    private static final String KEY_SHARED_ELEMENT_TEXTURE_ID = "android:sharedElementTextureId";
+
     /** @hide */
     public static final int ANIM_NONE = 0;
     /** @hide */
@@ -145,10 +146,9 @@
     private int mStartY;
     private int mStartWidth;
     private int mStartHeight;
-    private String[] mDestSceneNames;
     private Bundle mTransitionArgs;
     private IRemoteCallback mAnimationStartedListener;
-    private IRemoteCallback mSceneTransitionStartedListener;
+    private IRemoteCallback mTransitionCompleteListener;
 
     /**
      * Create an ActivityOptions specifying a custom animation to run when
@@ -215,24 +215,6 @@
         }
     }
 
-    private void setOnSceneTransitionStartedListener(Handler handler,
-            OnSceneTransitionStartedListener listener) {
-        if (listener != null) {
-            final Handler h = handler;
-            final OnSceneTransitionStartedListener l = listener;
-            mSceneTransitionStartedListener = new IRemoteCallback.Stub() {
-                @Override public void sendResult(final Bundle data) throws RemoteException {
-                    h.post(new Runnable() {
-                        public void run() {
-                            l.onSceneTransitionStarted(data != null ?
-                                    data.getString(KEY_DEST_SCENE_NAME_CHOSEN) : null);
-                        }
-                    });
-                }
-            };
-        }
-    }
-
     /**
      * Callback for use with {@link ActivityOptions#makeThumbnailScaleUpAnimation}
      * to find out when the given animation has started running.
@@ -242,13 +224,10 @@
         void onAnimationStarted();
     }
 
-    /**
-     * Callback for use with {@link ActivityOptions#makeSceneTransitionAnimation}
-     * to find out when a transition is about to begin.
-     * @hide
-     */
-    public interface OnSceneTransitionStartedListener {
-        void onSceneTransitionStarted(String destSceneName);
+    /** @hide */
+    public interface ActivityTransitionTarget {
+        void sharedElementTransitionComplete();
+        void exitTransitionComplete();
     }
 
     /**
@@ -369,18 +348,35 @@
     }
 
     /**
-     * Create an ActivityOptions specifying an animation where an activity window is asked
-     * to perform animations within the window content.
+     * Create an ActivityOptions to transition between Activities using cross-Activity animation.
+     * When visual elements are to carry between Activities, args should be used to tell the called
+     * Activity about the location and size.
      *
-     * @hide
+     * TODO: Provide facility to capture layout and bitmap of shared elements.
+     *
+     * <p>When
+     * {@link android.app.Activity#startActivities(android.content.Intent[], android.os.Bundle)}
+     * is used with the {@link #toBundle()} result, the Activity's content scene will automatically
+     * transition out by setting their visibility to {@link View#INVISIBLE}. Shared elements
+     * ({@link android.view.View#setSharedElementName(String)}) are unmodified during the
+     * transition to allow the started Activity to seamlessly take it over. ViewGroups typically
+     * don't transition out, and instead transition out their children unless they have a
+     * background. To modify this behavior, use
+     * {@link android.view.ViewGroup#setTransitionGroup(boolean)}.</p>
+     *
+     * <p>This requires {@link android.view.Window#FEATURE_CONTENT_TRANSITIONS} to be
+     * enabled on the calling Activity to cause an exit transition. The same must be in
+     * the called Activity to get an entering transition.</p>
+     *
+     * @param args Contains information for transferring a view between this Activity and the
+     *             target Activity. Will be used by the called Activity to transition the
+     *             view to its eventual destination
+     * @see android.app.Activity#startSharedElementTransition(android.os.Bundle)
      */
-    public static ActivityOptions makeSceneTransitionAnimation(String[] destSceneNames,
-            Bundle args, OnSceneTransitionStartedListener listener, Handler handler) {
+    public static ActivityOptions makeSceneTransitionAnimation(Bundle args) {
         ActivityOptions opts = new ActivityOptions();
         opts.mAnimationType = ANIM_SCENE_TRANSITION;
-        opts.mDestSceneNames = destSceneNames;
         opts.mTransitionArgs = args;
-        opts.setOnSceneTransitionStartedListener(handler, listener);
         return opts;
     }
 
@@ -416,10 +412,9 @@
                 break;
 
             case ANIM_SCENE_TRANSITION:
-                mDestSceneNames = opts.getStringArray(KEY_DEST_SCENE_NAMES);
                 mTransitionArgs = opts.getBundle(KEY_SCENE_TRANSITION_ARGS);
-                mSceneTransitionStartedListener = IRemoteCallback.Stub.asInterface(
-                        opts.getBinder(KEY_SCENE_TRANSITION_START_LISTENER));
+                mTransitionCompleteListener = IRemoteCallback.Stub.asInterface(
+                        opts.getBinder(KEY_TRANSITION_COMPLETE_LISTENER));
                 break;
         }
     }
@@ -470,11 +465,6 @@
     }
 
     /** @hide */
-    public String[] getDestSceneNames() {
-        return mDestSceneNames;
-    }
-
-    /** @hide */
     public Bundle getSceneTransitionArgs() {
         return mTransitionArgs;
     }
@@ -485,19 +475,33 @@
     }
 
     /** @hide */
-    public void dispatchSceneTransitionStarted(String destScene) {
-        if (mSceneTransitionStartedListener != null) {
-            Bundle data = null;
-            if (!TextUtils.isEmpty(destScene)) {
-                data = new Bundle();
-                data.putString(KEY_DEST_SCENE_NAME_CHOSEN, destScene);
-            }
+    public void dispatchSceneTransitionStarted(final ActivityTransitionTarget target) {
+        boolean listenerSent = false;
+        if (mTransitionCompleteListener != null) {
+            IRemoteCallback callback = new IRemoteCallback.Stub() {
+                @Override
+                public void sendResult(Bundle data) throws RemoteException {
+                    if (data == null) {
+                        target.exitTransitionComplete();
+                    } else {
+                        // TODO: Use texture id
+                        target.sharedElementTransitionComplete();
+                    }
+                }
+            };
+            Bundle bundle = new Bundle();
+            bundle.putBinder(KEY_TRANSITION_TARGET_LISTENER, callback.asBinder());
             try {
-                mSceneTransitionStartedListener.sendResult(data);
+                mTransitionCompleteListener.sendResult(bundle);
+                listenerSent = true;
             } catch (RemoteException e) {
-                Log.e(TAG, "Caught exception dispatching scene transition start", e);
+                Log.w(TAG, "Couldn't retrieve transition notifications", e);
             }
         }
+        if (!listenerSent) {
+            target.sharedElementTransitionComplete();
+            target.exitTransitionComplete();
+        }
     }
 
     /** @hide */
@@ -508,12 +512,6 @@
             } catch (RemoteException e) {
             }
         }
-        if (mSceneTransitionStartedListener != null) {
-            try {
-                mSceneTransitionStartedListener.sendResult(null);
-            } catch (RemoteException e) {
-            }
-        }
     }
 
     /** @hide */
@@ -545,9 +543,8 @@
                     }
                 }
                 mAnimationStartedListener = otherOptions.mAnimationStartedListener;
-                mSceneTransitionStartedListener = null;
+                mTransitionCompleteListener = null;
                 mTransitionArgs = null;
-                mDestSceneNames = null;
                 break;
             case ANIM_SCALE_UP:
                 mAnimationType = otherOptions.mAnimationType;
@@ -562,9 +559,8 @@
                     }
                 }
                 mAnimationStartedListener = null;
-                mSceneTransitionStartedListener = null;
+                mTransitionCompleteListener = null;
                 mTransitionArgs = null;
-                mDestSceneNames = null;
                 break;
             case ANIM_THUMBNAIL_SCALE_UP:
             case ANIM_THUMBNAIL_SCALE_DOWN:
@@ -579,20 +575,12 @@
                     }
                 }
                 mAnimationStartedListener = otherOptions.mAnimationStartedListener;
-                mSceneTransitionStartedListener = null;
+                mTransitionCompleteListener = null;
                 mTransitionArgs = null;
-                mDestSceneNames = null;
                 break;
             case ANIM_SCENE_TRANSITION:
                 mAnimationType = otherOptions.mAnimationType;
-                if (mSceneTransitionStartedListener != null) {
-                    try {
-                        mSceneTransitionStartedListener.sendResult(null);
-                    } catch (RemoteException e) {
-                    }
-                }
-                mSceneTransitionStartedListener = otherOptions.mSceneTransitionStartedListener;
-                mDestSceneNames = otherOptions.mDestSceneNames;
+                mTransitionCompleteListener = otherOptions.mTransitionCompleteListener;
                 mTransitionArgs = otherOptions.mTransitionArgs;
                 mThumbnail = null;
                 mAnimationStartedListener = null;
@@ -639,10 +627,11 @@
                 break;
             case ANIM_SCENE_TRANSITION:
                 b.putInt(KEY_ANIM_TYPE, mAnimationType);
-                b.putStringArray(KEY_DEST_SCENE_NAMES, mDestSceneNames);
                 b.putBundle(KEY_SCENE_TRANSITION_ARGS, mTransitionArgs);
-                b.putBinder(KEY_SCENE_TRANSITION_START_LISTENER, mSceneTransitionStartedListener
-                        != null ? mSceneTransitionStartedListener.asBinder() : null);
+                if (mTransitionCompleteListener != null) {
+                    b.putBinder(KEY_TRANSITION_COMPLETE_LISTENER,
+                            mTransitionCompleteListener.asBinder());
+                }
                 break;
         }
         return b;
@@ -661,4 +650,123 @@
 
         return null;
     }
+
+    /** @hide */
+    public interface SharedElementSource {
+        int getTextureId();
+    }
+
+    /**
+     * In the calling Activity when transitioning out, sets the Transition to listen for
+     * changes.
+     * @hide
+     */
+    public void setExitTransition(Transition transition, SharedElementSource sharedElementSource) {
+        mTransitionCompleteListener = new ExitTransitionListener(transition, sharedElementSource);
+    }
+
+    private static class ExitTransitionListener extends IRemoteCallback.Stub
+            implements Transition.TransitionListener, Animator.AnimatorListener {
+        private ArrayList<Animator> mSharedElementAnimators = new ArrayList<Animator>();
+        private boolean mSharedElementNotified;
+        private Transition mExitTransition;
+        private IRemoteCallback mTransitionCompleteCallback;
+        private boolean mExitComplete;
+        private SharedElementSource mSharedElementSource;
+
+        public ExitTransitionListener(Transition transition, SharedElementSource sharedElementSource) {
+            mSharedElementSource = sharedElementSource;
+            mExitTransition = transition;
+            mExitTransition.addListener(this);
+        }
+
+        @Override
+        public void sendResult(Bundle data) throws RemoteException {
+            if (data != null) {
+                mTransitionCompleteCallback = IRemoteCallback.Stub.asInterface(
+                        data.getBinder(KEY_TRANSITION_TARGET_LISTENER));
+                notifySharedElement();
+                notifyExit();
+            }
+        }
+
+        @Override
+        public void onTransitionStart(Transition transition) {
+            ArrayMap<Animator, Transition.AnimationInfo> runningAnimators
+                    = Transition.getRunningAnimators();
+            for (Map.Entry<Animator, Transition.AnimationInfo> entry : runningAnimators.entrySet()) {
+                if (entry.getValue().view.getSharedElementName() != null) {
+                    mSharedElementAnimators.add(entry.getKey());
+                    entry.getKey().addListener(this);
+                }
+            }
+            notifySharedElement();
+        }
+
+        @Override
+        public void onTransitionEnd(Transition transition) {
+            mExitComplete = true;
+            notifyExit();
+            mExitTransition.removeListener(this);
+        }
+
+        @Override
+        public void onTransitionCancel(Transition transition) {
+            mExitComplete = true;
+            notifyExit();
+            mExitTransition.removeListener(this);
+        }
+
+        @Override
+        public void onTransitionPause(Transition transition) {
+        }
+
+        @Override
+        public void onTransitionResume(Transition transition) {
+        }
+
+        @Override
+        public void onAnimationStart(Animator animation) {
+        }
+
+        @Override
+        public void onAnimationEnd(Animator animation) {
+            mSharedElementAnimators.remove(animation);
+            notifySharedElement();
+        }
+
+        @Override
+        public void onAnimationCancel(Animator animation) {
+            mSharedElementAnimators.remove(animation);
+            notifySharedElement();
+        }
+
+        @Override
+        public void onAnimationRepeat(Animator animation) {
+        }
+
+        private void notifySharedElement() {
+            if (!mSharedElementNotified && mSharedElementAnimators.isEmpty()
+                    && mTransitionCompleteCallback != null) {
+                mSharedElementNotified = true;
+                try {
+                    Bundle bundle = new Bundle();
+                    bundle.putInt(KEY_SHARED_ELEMENT_TEXTURE_ID, mSharedElementSource.getTextureId());
+                    mTransitionCompleteCallback.sendResult(bundle);
+                } catch (RemoteException e) {
+                    Log.w(TAG, "Couldn't notify that the transition ended", e);
+                }
+            }
+        }
+
+        private void notifyExit() {
+            if (mExitComplete && mTransitionCompleteCallback != null) {
+                try {
+                    mTransitionCompleteCallback.sendResult(null);
+                } catch (RemoteException e) {
+                    Log.w(TAG, "Couldn't notify that the transition ended", e);
+                }
+            }
+        }
+    }
 }
diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java
index 25cde8c..8acd19b 100644
--- a/core/java/android/app/ActivityView.java
+++ b/core/java/android/app/ActivityView.java
@@ -18,7 +18,9 @@
 
 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;
@@ -28,6 +30,7 @@
 import android.view.Surface;
 import android.view.TextureView;
 import android.view.TextureView.SurfaceTextureListener;
+import android.view.View;
 import android.view.ViewGroup;
 import android.view.WindowManager;
 
@@ -37,11 +40,14 @@
     private final TextureView mTextureView;
     private IActivityContainer mActivityContainer;
     private Activity mActivity;
-    private boolean mAttached;
     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);
     }
@@ -71,7 +77,7 @@
 
     @Override
     protected void onLayout(boolean changed, int l, int t, int r, int b) {
-        mTextureView.layout(l, t, r, b);
+        mTextureView.layout(0, 0, r - l, b - t);
     }
 
     @Override
@@ -85,66 +91,112 @@
                     + e);
         }
 
-        final SurfaceTexture surfaceTexture = mTextureView.getSurfaceTexture();
-        if (surfaceTexture != null) {
-            attachToSurface(surfaceTexture);
-        }
+        attachToSurfaceWhenReady();
     }
 
     @Override
     protected void onDetachedFromWindow() {
-        detachFromSurface();
+        if (mActivityContainer != null) {
+            detach();
+            mActivityContainer = null;
+        }
     }
 
     @Override
-    public boolean isAttachedToWindow() {
-        return mAttached;
+    protected void onWindowVisibilityChanged(int visibility) {
+        super.onWindowVisibilityChanged(visibility);
+        if (visibility == View.VISIBLE) {
+            attachToSurfaceWhenReady();
+        } else {
+            detach();
+        }
+    }
+
+    public boolean isAttachedToDisplay() {
+        return mSurface != null;
     }
 
     public void startActivity(Intent intent) {
-        if (mActivityContainer != null && mAttached) {
+        if (mSurface != null) {
             try {
                 mActivityContainer.startActivity(intent);
             } catch (RemoteException e) {
                 throw new IllegalStateException("ActivityView: Unable to startActivity. " + e);
             }
+        } else {
+            mQueuedIntent = intent;
+            mQueuedPendingIntent = null;
         }
     }
 
-    /** Call when both mActivityContainer and mTextureView's SurfaceTexture are not null */
-    private void attachToSurface(SurfaceTexture surfaceTexture) {
+    private void startActivityIntentSender(IIntentSender iIntentSender) {
+        try {
+            mActivityContainer.startActivityIntentSender(iIntentSender);
+        } catch (RemoteException e) {
+            throw new IllegalStateException(
+                    "ActivityView: Unable to startActivity from IntentSender. " + e);
+        }
+    }
+
+    public void startActivity(IntentSender intentSender) {
+        final IIntentSender iIntentSender = intentSender.getTarget();
+        if (mSurface != null) {
+            startActivityIntentSender(iIntentSender);
+        } else {
+            mQueuedPendingIntent = iIntentSender;
+            mQueuedIntent = null;
+        }
+    }
+
+    public void startActivity(PendingIntent pendingIntent) {
+        final IIntentSender iIntentSender = pendingIntent.getTarget();
+        if (mSurface != null) {
+            startActivityIntentSender(iIntentSender);
+        } else {
+            mQueuedPendingIntent = iIntentSender;
+            mQueuedIntent = null;
+        }
+    }
+
+    private void attachToSurfaceWhenReady() {
+        final SurfaceTexture surfaceTexture = mTextureView.getSurfaceTexture();
+        if (mActivityContainer == null || surfaceTexture == null || mSurface != null) {
+            // Either not ready to attach, or already attached.
+            return;
+        }
+
         WindowManager wm = (WindowManager)mActivity.getSystemService(Context.WINDOW_SERVICE);
         DisplayMetrics metrics = new DisplayMetrics();
         wm.getDefaultDisplay().getMetrics(metrics);
 
         mSurface = new Surface(surfaceTexture);
         try {
-            mActivityContainer.attachToSurface(mSurface, mWidth, mHeight,
-                    metrics.densityDpi);
+            mActivityContainer.attachToSurface(mSurface, mWidth, mHeight, metrics.densityDpi);
         } catch (RemoteException e) {
-            mActivityContainer = null;
             mSurface.release();
             mSurface = null;
-            mAttached = false;
             throw new IllegalStateException(
                     "ActivityView: Unable to create ActivityContainer. " + e);
         }
-        mAttached = true;
+
+        if (mQueuedIntent != null) {
+            startActivity(mQueuedIntent);
+            mQueuedIntent = null;
+        } else if (mQueuedPendingIntent != null) {
+            startActivityIntentSender(mQueuedPendingIntent);
+            mQueuedPendingIntent = null;
+        }
     }
 
-    private void detachFromSurface() {
-        if (mActivityContainer != null) {
+    private void detach() {
+        if (mSurface != null) {
             try {
                 mActivityContainer.detachFromDisplay();
             } catch (RemoteException e) {
             }
-            mActivityContainer = null;
-        }
-        if (mSurface != null) {
             mSurface.release();
             mSurface = null;
         }
-        mAttached = false;
     }
 
     private class ActivityViewSurfaceTextureListener implements SurfaceTextureListener {
@@ -154,7 +206,7 @@
             mWidth = width;
             mHeight = height;
             if (mActivityContainer != null) {
-                attachToSurface(surfaceTexture);
+                attachToSurfaceWhenReady();
             }
         }
 
@@ -167,7 +219,7 @@
         @Override
         public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
             Log.d(TAG, "onSurfaceTextureDestroyed");
-            detachFromSurface();
+            detach();
             return true;
         }
 
diff --git a/core/java/android/app/IActivityContainer.aidl b/core/java/android/app/IActivityContainer.aidl
index df1cf91..abd296a 100644
--- a/core/java/android/app/IActivityContainer.aidl
+++ b/core/java/android/app/IActivityContainer.aidl
@@ -18,6 +18,7 @@
 
 import android.app.IActivityContainerCallback;
 import android.content.Intent;
+import android.content.IIntentSender;
 import android.os.IBinder;
 import android.view.Surface;
 
@@ -27,5 +28,6 @@
     void attachToSurface(in Surface surface, int width, int height, int density);
     void detachFromDisplay();
     int startActivity(in Intent intent);
+    int startActivityIntentSender(in IIntentSender intentSender);
     int getDisplayId();
 }
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index e2ea763..7926595 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -351,6 +351,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;
 
     /** @hide */
@@ -1598,6 +1605,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
@@ -1996,8 +2014,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/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index ab82531..40bdb73 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -26,6 +26,7 @@
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.os.Handler;
+import android.os.Process;
 import android.os.RemoteCallback;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -1681,4 +1682,88 @@
         }
         return null;
     }
+
+    /**
+     * @hide
+     * Sets the given package as the profile owner of the given user profile. The package must
+     * already be installed and there shouldn't be an existing profile owner registered for this
+     * user. Also, this method must be called before the user has been used for the first time.
+     * @param packageName the package name of the application to be registered as profile owner.
+     * @param ownerName the human readable name of the organisation associated with this DPM.
+     * @return whether the package was successfully registered as the profile owner.
+     * @throws IllegalArgumentException if packageName is null, the package isn't installed, or
+     *         the user has already been set up.
+     */
+    public boolean setProfileOwner(String packageName, String ownerName)
+            throws IllegalArgumentException {
+        if (mService != null) {
+            try {
+                return mService.setProfileOwner(packageName, ownerName,
+                        Process.myUserHandle().getIdentifier());
+            } catch (RemoteException re) {
+                Log.w(TAG, "Failed to set profile owner", re);
+                throw new IllegalArgumentException("Couldn't set profile owner.", re);
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Used to determine if a particular package is registered as the Profile Owner for the
+     * current user. A profile owner is a special device admin that has additional priviledges
+     * within the managed profile.
+     *
+     * @param packageName The package name of the app to compare with the registered profile owner.
+     * @return Whether or not the package is registered as the profile owner.
+     */
+    public boolean isProfileOwnerApp(String packageName) {
+        if (mService != null) {
+            try {
+                String profileOwnerPackage = mService.getProfileOwner(
+                        Process.myUserHandle().getIdentifier());
+                return profileOwnerPackage != null && profileOwnerPackage.equals(packageName);
+            } catch (RemoteException re) {
+                Log.w(TAG, "Failed to check profile owner");
+            }
+        }
+        return false;
+    }
+
+    /**
+     * @hide
+     * @return the packageName of the owner of the given user profile or null if no profile
+     * owner has been set for that user.
+     * @throws IllegalArgumentException if the userId is invalid.
+     */
+    public String getProfileOwner() throws IllegalArgumentException {
+        if (mService != null) {
+            try {
+                return mService.getProfileOwner(Process.myUserHandle().getIdentifier());
+            } catch (RemoteException re) {
+                Log.w(TAG, "Failed to get profile owner");
+                throw new IllegalArgumentException(
+                        "Requested profile owner for invalid userId", re);
+            }
+        }
+        return null;
+    }
+
+    /**
+     * @hide
+     * @return the human readable name of the organisation associated with this DPM or null if
+     *         one is not set.
+     * @throws IllegalArgumentException if the userId is invalid.
+     */
+    public String getProfileOwnerName() throws IllegalArgumentException {
+        if (mService != null) {
+            try {
+                return mService.getProfileOwnerName(Process.myUserHandle().getIdentifier());
+            } catch (RemoteException re) {
+                Log.w(TAG, "Failed to get profile owner");
+                throw new IllegalArgumentException(
+                        "Requested profile owner for invalid userId", re);
+            }
+        }
+        return null;
+    }
 }
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 172c47c..9d189db 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -103,6 +103,10 @@
     String getDeviceOwner();
     String getDeviceOwnerName();
 
+    boolean setProfileOwner(String packageName, String ownerName, int userHandle);
+    String getProfileOwner(int userHandle);
+    String getProfileOwnerName(int userHandle);
+
     boolean installCaCert(in byte[] certBuffer);
     void uninstallCaCert(in byte[] certBuffer);
 }
diff --git a/core/java/android/content/pm/UserInfo.java b/core/java/android/content/pm/UserInfo.java
index 4c87830..aa4a243 100644
--- a/core/java/android/content/pm/UserInfo.java
+++ b/core/java/android/content/pm/UserInfo.java
@@ -63,6 +63,15 @@
      */
     public static final int FLAG_INITIALIZED = 0x00000010;
 
+    /**
+     * Indicates that this user is a profile of another user, for example holding a users
+     * corporate data.
+     */
+    public static final int FLAG_MANAGED_PROFILE = 0x00000020;
+
+
+    public static final int NO_RELATED_GROUP_ID = -1;
+
     public int id;
     public int serialNumber;
     public String name;
@@ -70,6 +79,7 @@
     public int flags;
     public long creationTime;
     public long lastLoggedInTime;
+    public int relatedGroupId;
 
     /** User is only partially created. */
     public boolean partial;
@@ -83,6 +93,7 @@
         this.name = name;
         this.flags = flags;
         this.iconPath = iconPath;
+        this.relatedGroupId = NO_RELATED_GROUP_ID;
     }
 
     public boolean isPrimary() {
@@ -101,6 +112,10 @@
         return (flags & FLAG_RESTRICTED) == FLAG_RESTRICTED;
     }
 
+    public boolean isManagedProfile() {
+        return (flags & FLAG_MANAGED_PROFILE) == FLAG_MANAGED_PROFILE;
+    }
+
     public UserInfo() {
     }
 
@@ -113,6 +128,7 @@
         creationTime = orig.creationTime;
         lastLoggedInTime = orig.lastLoggedInTime;
         partial = orig.partial;
+        relatedGroupId = orig.relatedGroupId;
     }
 
     public UserHandle getUserHandle() {
@@ -137,6 +153,7 @@
         dest.writeLong(creationTime);
         dest.writeLong(lastLoggedInTime);
         dest.writeInt(partial ? 1 : 0);
+        dest.writeInt(relatedGroupId);
     }
 
     public static final Parcelable.Creator<UserInfo> CREATOR
@@ -158,5 +175,6 @@
         creationTime = source.readLong();
         lastLoggedInTime = source.readLong();
         partial = source.readInt() != 0;
+        relatedGroupId = source.readInt();
     }
 }
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index aa96f0e..de00f71 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -1625,10 +1625,7 @@
 
             String locale = null;
             if (mConfiguration.locale != null) {
-                locale = mConfiguration.locale.getLanguage();
-                if (mConfiguration.locale.getCountry() != null) {
-                    locale += "-" + mConfiguration.locale.getCountry();
-                }
+                locale = mConfiguration.locale.toLanguageTag();
             }
             int width, height;
             if (mMetrics.widthPixels >= mMetrics.heightPixels) {
diff --git a/core/java/android/emoji/EmojiFactory.java b/core/java/android/emoji/EmojiFactory.java
index 8fd8695..aba990d 100644
--- a/core/java/android/emoji/EmojiFactory.java
+++ b/core/java/android/emoji/EmojiFactory.java
@@ -54,7 +54,7 @@
     }
     
     // A pointer to native EmojiFactory object.
-    private int mNativeEmojiFactory;
+    private long mNativeEmojiFactory;
     private String mName;
     // Cache.
     private Map<Integer, WeakReference<Bitmap>> mCache;
@@ -68,7 +68,7 @@
      *
      * This can be called from JNI code.
      */
-    private EmojiFactory(int nativeEmojiFactory, String name) {
+    private EmojiFactory(long nativeEmojiFactory, String name) {
         mNativeEmojiFactory = nativeEmojiFactory;
         mName = name;
         mCache = new CustomLinkedHashMap<Integer, WeakReference<Bitmap>>();
@@ -272,18 +272,18 @@
     
     // native methods
     
-    private native void nativeDestructor(int factory);
-    private native Bitmap nativeGetBitmapFromAndroidPua(int nativeEmojiFactory, int AndroidPua);
-    private native int nativeGetAndroidPuaFromVendorSpecificSjis(int nativeEmojiFactory,
+    private native void nativeDestructor(long nativeEmojiFactory);
+    private native Bitmap nativeGetBitmapFromAndroidPua(long nativeEmojiFactory, int AndroidPua);
+    private native int nativeGetAndroidPuaFromVendorSpecificSjis(long nativeEmojiFactory,
             char sjis);
-    private native int nativeGetVendorSpecificSjisFromAndroidPua(int nativeEmojiFactory,
+    private native int nativeGetVendorSpecificSjisFromAndroidPua(long nativeEmojiFactory,
             int pua);
-    private native int nativeGetAndroidPuaFromVendorSpecificPua(int nativeEmojiFactory,
+    private native int nativeGetAndroidPuaFromVendorSpecificPua(long nativeEmojiFactory,
             int vsp);
-    private native int nativeGetVendorSpecificPuaFromAndroidPua(int nativeEmojiFactory,
+    private native int nativeGetVendorSpecificPuaFromAndroidPua(long nativeEmojiFactory,
             int pua);
-    private native int nativeGetMaximumVendorSpecificPua(int nativeEmojiFactory);
-    private native int nativeGetMinimumVendorSpecificPua(int nativeEmojiFactory);
-    private native int nativeGetMaximumAndroidPua(int nativeEmojiFactory);
-    private native int nativeGetMinimumAndroidPua(int nativeEmojiFactory);
+    private native int nativeGetMaximumVendorSpecificPua(long nativeEmojiFactory);
+    private native int nativeGetMinimumVendorSpecificPua(long nativeEmojiFactory);
+    private native int nativeGetMaximumAndroidPua(long nativeEmojiFactory);
+    private native int nativeGetMinimumAndroidPua(long nativeEmojiFactory);
 }
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index bb8b184..f06ffaa 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -167,7 +167,9 @@
     /**
      * <p>Maximum and minimum exposure compensation
      * setting, in counts of
-     * android.control.aeCompensationStepSize</p>
+     * {@link CameraCharacteristics#CONTROL_AE_COMPENSATION_STEP android.control.aeCompensationStep}.</p>
+     *
+     * @see CameraCharacteristics#CONTROL_AE_COMPENSATION_STEP
      */
     public static final Key<int[]> CONTROL_AE_COMPENSATION_RANGE =
             new Key<int[]>("android.control.aeCompensationRange", int[].class);
@@ -284,16 +286,16 @@
      * <li>The sizes will be sorted by increasing pixel area (width x height).
      * If several resolutions have the same area, they will be sorted by increasing width.</li>
      * <li>The aspect ratio of the largest thumbnail size will be same as the
-     * aspect ratio of largest size in {@link CameraCharacteristics#SCALER_AVAILABLE_JPEG_SIZES android.scaler.availableJpegSizes}.
+     * aspect ratio of largest JPEG output size in {@link CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS android.scaler.availableStreamConfigurations}.
      * The largest size is defined as the size that has the largest pixel area
      * in a given size list.</li>
-     * <li>Each size in {@link CameraCharacteristics#SCALER_AVAILABLE_JPEG_SIZES android.scaler.availableJpegSizes} will have at least
+     * <li>Each output JPEG size in {@link CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS android.scaler.availableStreamConfigurations} will have at least
      * one corresponding size that has the same aspect ratio in availableThumbnailSizes,
      * and vice versa.</li>
      * <li>All non (0, 0) sizes will have non-zero widths and heights.</li>
      * </ul>
      *
-     * @see CameraCharacteristics#SCALER_AVAILABLE_JPEG_SIZES
+     * @see CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS
      */
     public static final Key<android.hardware.camera2.Size[]> JPEG_AVAILABLE_THUMBNAIL_SIZES =
             new Key<android.hardware.camera2.Size[]>("android.jpeg.availableThumbnailSizes", android.hardware.camera2.Size[].class);
@@ -348,19 +350,22 @@
             new Key<byte[]>("android.lens.info.availableOpticalStabilization", byte[].class);
 
     /**
-     * <p>Hyperfocal distance for this lens; set to
-     * 0 if fixed focus</p>
-     * <p>The hyperfocal distance is used for the old
-     * API's 'fixed' setting</p>
+     * <p>Optional. Hyperfocal distance for this lens.</p>
+     * <p>If the lens is fixed focus, the camera device will report 0.</p>
+     * <p>If the lens is not fixed focus, the camera device will report this
+     * field when {@link CameraCharacteristics#LENS_INFO_FOCUS_DISTANCE_CALIBRATION android.lens.info.focusDistanceCalibration} is APPROXIMATE or CALIBRATED.</p>
+     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     *
+     * @see CameraCharacteristics#LENS_INFO_FOCUS_DISTANCE_CALIBRATION
      */
     public static final Key<Float> LENS_INFO_HYPERFOCAL_DISTANCE =
             new Key<Float>("android.lens.info.hyperfocalDistance", float.class);
 
     /**
      * <p>Shortest distance from frontmost surface
-     * of the lens that can be focused correctly</p>
+     * of the lens that can be focused correctly.</p>
      * <p>If the lens is fixed-focus, this should be
-     * 0</p>
+     * 0.</p>
      */
     public static final Key<Float> LENS_INFO_MINIMUM_FOCUS_DISTANCE =
             new Key<Float>("android.lens.info.minimumFocusDistance", float.class);
@@ -374,6 +379,24 @@
             new Key<android.hardware.camera2.Size>("android.lens.info.shadingMapSize", android.hardware.camera2.Size.class);
 
     /**
+     * <p>The lens focus distance calibration quality.</p>
+     * <p>The lens focus distance calibration quality determines the reliability of
+     * focus related metadata entries, i.e. {@link CaptureRequest#LENS_FOCUS_DISTANCE android.lens.focusDistance},
+     * {@link CaptureResult#LENS_FOCUS_RANGE android.lens.focusRange}, {@link CameraCharacteristics#LENS_INFO_HYPERFOCAL_DISTANCE android.lens.info.hyperfocalDistance}, and
+     * {@link CameraCharacteristics#LENS_INFO_MINIMUM_FOCUS_DISTANCE android.lens.info.minimumFocusDistance}.</p>
+     *
+     * @see CaptureRequest#LENS_FOCUS_DISTANCE
+     * @see CaptureResult#LENS_FOCUS_RANGE
+     * @see CameraCharacteristics#LENS_INFO_HYPERFOCAL_DISTANCE
+     * @see CameraCharacteristics#LENS_INFO_MINIMUM_FOCUS_DISTANCE
+     * @see #LENS_INFO_FOCUS_DISTANCE_CALIBRATION_UNCALIBRATED
+     * @see #LENS_INFO_FOCUS_DISTANCE_CALIBRATION_APPROXIMATE
+     * @see #LENS_INFO_FOCUS_DISTANCE_CALIBRATION_CALIBRATED
+     */
+    public static final Key<Integer> LENS_INFO_FOCUS_DISTANCE_CALIBRATION =
+            new Key<Integer>("android.lens.info.focusDistanceCalibration", int.class);
+
+    /**
      * <p>Direction the camera faces relative to
      * device screen</p>
      * @see #LENS_FACING_FRONT
@@ -398,16 +421,48 @@
             new Key<Byte>("android.quirks.usePartialResult", byte.class);
 
     /**
-     * <p>How many output streams can be allocated at
-     * the same time for each type of stream</p>
-     * <p>Video snapshot with preview callbacks requires 3
-     * processed streams (preview, record, app callbacks) and
-     * one JPEG stream (snapshot)</p>
+     * <p>The maximum numbers of different types of output streams
+     * that can be configured and used simultaneously by a camera device.</p>
+     * <p>This is a 3 element tuple that contains the max number of output simultaneous
+     * streams for raw sensor, processed (and uncompressed), and JPEG formats respectively.
+     * For example, if max raw sensor format output stream number is 1, max YUV streams
+     * number is 3, and max JPEG stream number is 2, then this tuple should be <code>(1, 3, 2)</code>.</p>
+     * <p>This lists the upper bound of the number of output streams supported by
+     * the camera device. Using more streams simultaneously may require more hardware and
+     * CPU resources that will consume more power. The image format for a output stream can
+     * be any supported format provided by {@link CameraCharacteristics#SCALER_AVAILABLE_FORMATS android.scaler.availableFormats}. The formats
+     * defined in {@link CameraCharacteristics#SCALER_AVAILABLE_FORMATS android.scaler.availableFormats} can be catergorized into the 3 stream types
+     * as below:</p>
+     * <ul>
+     * <li>JPEG-compressed format: BLOB.</li>
+     * <li>Raw formats: RAW_SENSOR and RAW_OPAQUE.</li>
+     * <li>processed, uncompressed formats: YCbCr_420_888, YCrCb_420_SP, YV12.</li>
+     * </ul>
+     *
+     * @see CameraCharacteristics#SCALER_AVAILABLE_FORMATS
      */
     public static final Key<int[]> REQUEST_MAX_NUM_OUTPUT_STREAMS =
             new Key<int[]>("android.request.maxNumOutputStreams", int[].class);
 
     /**
+     * <p>The maximum numbers of any type of input streams
+     * that can be configured and used simultaneously by a camera device.</p>
+     * <p>When set to 0, it means no input stream is supported.</p>
+     * <p>The image format for a input stream can be any supported
+     * format provided by
+     * {@link CameraCharacteristics#SCALER_AVAILABLE_INPUT_OUTPUT_FORMATS_MAP android.scaler.availableInputOutputFormatsMap}. When using an
+     * input stream, there must be at least one output stream
+     * configured to to receive the reprocessed images.</p>
+     * <p>For example, for Zero Shutter Lag (ZSL) still capture use case, the input
+     * stream image format will be RAW_OPAQUE, the associated output stream image format
+     * should be JPEG.</p>
+     *
+     * @see CameraCharacteristics#SCALER_AVAILABLE_INPUT_OUTPUT_FORMATS_MAP
+     */
+    public static final Key<Integer> REQUEST_MAX_NUM_INPUT_STREAMS =
+            new Key<Integer>("android.request.maxNumInputStreams", int.class);
+
+    /**
      * <p>Specifies the number of maximum pipeline stages a frame
      * has to go through from when it's exposed to when it's available
      * to the framework.</p>
@@ -445,8 +500,100 @@
             new Key<Integer>("android.request.partialResultCount", int.class);
 
     /**
+     * <p>List of capabilities that the camera device
+     * advertises as fully supporting.</p>
+     * <p>A capability is a contract that the camera device makes in order
+     * to be able to satisfy one or more use cases.</p>
+     * <p>Listing a capability guarantees that the whole set of features
+     * required to support a common use will all be available.</p>
+     * <p>Using a subset of the functionality provided by an unsupported
+     * capability may be possible on a specific camera device implementation;
+     * to do this query each of android.request.availableRequestKeys,
+     * android.request.availableResultKeys,
+     * android.request.availableCharacteristicsKeys.</p>
+     * <p>XX: Maybe these should go into {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel}
+     * as a table instead?</p>
+     * <p>The following capabilities are guaranteed to be available on
+     * {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel} <code>==</code> FULL devices:</p>
+     * <ul>
+     * <li>MANUAL_SENSOR</li>
+     * <li>ZSL</li>
+     * </ul>
+     * <p>Other capabilities may be available on either FULL or LIMITED
+     * devices, but the app. should query this field to be sure.</p>
+     *
+     * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
+     * @see #REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE
+     * @see #REQUEST_AVAILABLE_CAPABILITIES_OPTIONAL
+     * @see #REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR
+     * @see #REQUEST_AVAILABLE_CAPABILITIES_GCAM
+     * @see #REQUEST_AVAILABLE_CAPABILITIES_ZSL
+     * @see #REQUEST_AVAILABLE_CAPABILITIES_DNG
+     */
+    public static final Key<Integer> REQUEST_AVAILABLE_CAPABILITIES =
+            new Key<Integer>("android.request.availableCapabilities", int.class);
+
+    /**
+     * <p>A list of all keys that the camera device has available
+     * to use with CaptureRequest.</p>
+     * <p>Attempting to set a key into a CaptureRequest that is not
+     * listed here will result in an invalid request and will be rejected
+     * by the camera device.</p>
+     * <p>This field can be used to query the feature set of a camera device
+     * at a more granular level than capabilities. This is especially
+     * important for optional keys that are not listed under any capability
+     * in {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}.</p>
+     * <p>TODO: This should be used by #getAvailableCaptureRequestKeys.</p>
+     *
+     * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
+     * @hide
+     */
+    public static final Key<int[]> REQUEST_AVAILABLE_REQUEST_KEYS =
+            new Key<int[]>("android.request.availableRequestKeys", int[].class);
+
+    /**
+     * <p>A list of all keys that the camera device has available
+     * to use with CaptureResult.</p>
+     * <p>Attempting to get a key from a CaptureResult that is not
+     * listed here will always return a <code>null</code> value. Getting a key from
+     * a CaptureResult that is listed here must never return a <code>null</code>
+     * value.</p>
+     * <p>The following keys may return <code>null</code> unless they are enabled:</p>
+     * <ul>
+     * <li>{@link CaptureResult#STATISTICS_LENS_SHADING_MAP android.statistics.lensShadingMap} (non-null iff {@link CaptureRequest#STATISTICS_LENS_SHADING_MAP_MODE android.statistics.lensShadingMapMode} == ON)</li>
+     * </ul>
+     * <p>(Those sometimes-null keys should nevertheless be listed here
+     * if they are available.)</p>
+     * <p>This field can be used to query the feature set of a camera device
+     * at a more granular level than capabilities. This is especially
+     * important for optional keys that are not listed under any capability
+     * in {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}.</p>
+     * <p>TODO: This should be used by #getAvailableCaptureResultKeys.</p>
+     *
+     * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
+     * @see CaptureResult#STATISTICS_LENS_SHADING_MAP
+     * @see CaptureRequest#STATISTICS_LENS_SHADING_MAP_MODE
+     * @hide
+     */
+    public static final Key<int[]> REQUEST_AVAILABLE_RESULT_KEYS =
+            new Key<int[]>("android.request.availableResultKeys", int[].class);
+
+    /**
+     * <p>A list of all keys that the camera device has available
+     * to use with CameraCharacteristics.</p>
+     * <p>This entry follows the same rules as
+     * android.request.availableResultKeys (except that it applies for
+     * CameraCharacteristics instead of CaptureResult). See above for more
+     * details.</p>
+     * <p>TODO: This should be used by CameraCharacteristics#getKeys.</p>
+     * @hide
+     */
+    public static final Key<int[]> REQUEST_AVAILABLE_CHARACTERISTICS_KEYS =
+            new Key<int[]>("android.request.availableCharacteristicsKeys", int[].class);
+
+    /**
      * <p>The list of image formats that are supported by this
-     * camera device.</p>
+     * camera device for output streams.</p>
      * <p>All camera devices will support JPEG and YUV_420_888 formats.</p>
      * <p>When set to YUV_420_888, application can access the YUV420 data directly.</p>
      */
@@ -521,6 +668,242 @@
             new Key<android.hardware.camera2.Size[]>("android.scaler.availableProcessedSizes", android.hardware.camera2.Size[].class);
 
     /**
+     * <p>The mapping of image formats that are supported by this
+     * camera device for input streams, to their corresponding output formats.</p>
+     * <p>All camera devices with at least 1
+     * {@link CameraCharacteristics#REQUEST_MAX_NUM_INPUT_STREAMS android.request.maxNumInputStreams} will have at least one
+     * available input format.</p>
+     * <p>The camera device will support the following map of formats,
+     * if its dependent capability is supported:</p>
+     * <table>
+     * <thead>
+     * <tr>
+     * <th align="left">Input Format</th>
+     * <th align="left">Output Format</th>
+     * <th align="left">Capability</th>
+     * </tr>
+     * </thead>
+     * <tbody>
+     * <tr>
+     * <td align="left">RAW_OPAQUE</td>
+     * <td align="left">JPEG</td>
+     * <td align="left">ZSL</td>
+     * </tr>
+     * <tr>
+     * <td align="left">RAW_OPAQUE</td>
+     * <td align="left">YUV_420_888</td>
+     * <td align="left">ZSL</td>
+     * </tr>
+     * <tr>
+     * <td align="left">RAW_OPAQUE</td>
+     * <td align="left">RAW16</td>
+     * <td align="left">DNG</td>
+     * </tr>
+     * <tr>
+     * <td align="left">RAW16</td>
+     * <td align="left">YUV_420_888</td>
+     * <td align="left">DNG</td>
+     * </tr>
+     * <tr>
+     * <td align="left">RAW16</td>
+     * <td align="left">JPEG</td>
+     * <td align="left">DNG</td>
+     * </tr>
+     * </tbody>
+     * </table>
+     * <p>For ZSL-capable camera devices, using the RAW_OPAQUE format
+     * as either input or output will never hurt maximum frame rate (i.e.
+     * {@link CameraCharacteristics#SCALER_AVAILABLE_STALL_DURATIONS android.scaler.availableStallDurations} will not have RAW_OPAQUE).</p>
+     * <p>Attempting to configure an input stream with output streams not
+     * listed as available in this map is not valid.</p>
+     * <p>TODO: Add java type mapping for this property.</p>
+     *
+     * @see CameraCharacteristics#REQUEST_MAX_NUM_INPUT_STREAMS
+     * @see CameraCharacteristics#SCALER_AVAILABLE_STALL_DURATIONS
+     */
+    public static final Key<int[]> SCALER_AVAILABLE_INPUT_OUTPUT_FORMATS_MAP =
+            new Key<int[]>("android.scaler.availableInputOutputFormatsMap", int[].class);
+
+    /**
+     * <p>The available stream configurations that this
+     * camera device supports
+     * (i.e. format, width, height, output/input stream).</p>
+     * <p>The configurations are listed as <code>(format, width, height, input?)</code>
+     * tuples.</p>
+     * <p>All camera devices will support sensor maximum resolution (defined by
+     * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}) for the JPEG format.</p>
+     * <p>For a given use case, the actual maximum supported resolution
+     * may be lower than what is listed here, depending on the destination
+     * Surface for the image data. For example, for recording video,
+     * the video encoder chosen may have a maximum size limit (e.g. 1080p)
+     * smaller than what the camera (e.g. maximum resolution is 3264x2448)
+     * can provide.</p>
+     * <p>Please reference the documentation for the image data destination to
+     * check if it limits the maximum size for image data.</p>
+     * <p>Not all output formats may be supported in a configuration with
+     * an input stream of a particular format. For more details, see
+     * {@link CameraCharacteristics#SCALER_AVAILABLE_INPUT_OUTPUT_FORMATS_MAP android.scaler.availableInputOutputFormatsMap}.</p>
+     * <p>The following table describes the minimum required output stream
+     * configurations based on the hardware level
+     * ({@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel}):</p>
+     * <table>
+     * <thead>
+     * <tr>
+     * <th align="center">Format</th>
+     * <th align="center">Size</th>
+     * <th align="center">Hardware Level</th>
+     * <th align="center">Notes</th>
+     * </tr>
+     * </thead>
+     * <tbody>
+     * <tr>
+     * <td align="center">JPEG</td>
+     * <td align="center">{@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}</td>
+     * <td align="center">Any</td>
+     * <td align="center"></td>
+     * </tr>
+     * <tr>
+     * <td align="center">JPEG</td>
+     * <td align="center">1920x1080 (1080p)</td>
+     * <td align="center">Any</td>
+     * <td align="center">if 1080p &lt;= activeArraySize</td>
+     * </tr>
+     * <tr>
+     * <td align="center">JPEG</td>
+     * <td align="center">1280x720 (720)</td>
+     * <td align="center">Any</td>
+     * <td align="center">if 720p &lt;= activeArraySize</td>
+     * </tr>
+     * <tr>
+     * <td align="center">JPEG</td>
+     * <td align="center">640x480 (480p)</td>
+     * <td align="center">Any</td>
+     * <td align="center">if 480p &lt;= activeArraySize</td>
+     * </tr>
+     * <tr>
+     * <td align="center">JPEG</td>
+     * <td align="center">320x240 (240p)</td>
+     * <td align="center">Any</td>
+     * <td align="center">if 240p &lt;= activeArraySize</td>
+     * </tr>
+     * <tr>
+     * <td align="center">YUV_420_888</td>
+     * <td align="center">all output sizes available for JPEG</td>
+     * <td align="center">FULL</td>
+     * <td align="center"></td>
+     * </tr>
+     * <tr>
+     * <td align="center">YUV_420_888</td>
+     * <td align="center">all output sizes available for JPEG, up to the maximum video size</td>
+     * <td align="center">LIMITED</td>
+     * <td align="center"></td>
+     * </tr>
+     * <tr>
+     * <td align="center">IMPLEMENTATION_DEFINED</td>
+     * <td align="center">same as YUV_420_888</td>
+     * <td align="center">Any</td>
+     * <td align="center"></td>
+     * </tr>
+     * </tbody>
+     * </table>
+     * <p>Refer to {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities} for additional
+     * mandatory stream configurations on a per-capability basis.</p>
+     *
+     * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
+     * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
+     * @see CameraCharacteristics#SCALER_AVAILABLE_INPUT_OUTPUT_FORMATS_MAP
+     * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
+     * @see #SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT
+     * @see #SCALER_AVAILABLE_STREAM_CONFIGURATIONS_INPUT
+     */
+    public static final Key<int[]> SCALER_AVAILABLE_STREAM_CONFIGURATIONS =
+            new Key<int[]>("android.scaler.availableStreamConfigurations", int[].class);
+
+    /**
+     * <p>This lists the minimum frame duration for each
+     * format/size combination.</p>
+     * <p>This should correspond to the frame duration when only that
+     * stream is active, with all processing (typically in android.*.mode)
+     * set to either OFF or FAST.</p>
+     * <p>When multiple streams are used in a request, the minimum frame
+     * duration will be max(individual stream min durations).</p>
+     * <p>The minimum frame duration of a stream (of a particular format, size)
+     * is the same regardless of whether the stream is input or output.</p>
+     * <p>See {@link CaptureRequest#SENSOR_FRAME_DURATION android.sensor.frameDuration} and
+     * {@link CameraCharacteristics#SCALER_AVAILABLE_STALL_DURATIONS android.scaler.availableStallDurations} for more details about
+     * calculating the max frame rate.</p>
+     *
+     * @see CameraCharacteristics#SCALER_AVAILABLE_STALL_DURATIONS
+     * @see CaptureRequest#SENSOR_FRAME_DURATION
+     */
+    public static final Key<long[]> SCALER_AVAILABLE_MIN_FRAME_DURATIONS =
+            new Key<long[]>("android.scaler.availableMinFrameDurations", long[].class);
+
+    /**
+     * <p>This lists the maximum stall duration for each
+     * format/size combination.</p>
+     * <p>A stall duration is how much extra time would get added
+     * to the normal minimum frame duration for a repeating request
+     * that has streams with non-zero stall.</p>
+     * <p>For example, consider JPEG captures which have the following
+     * characteristics:</p>
+     * <ul>
+     * <li>JPEG streams act like processed YUV streams in requests for which
+     * they are not included; in requests in which they are directly
+     * referenced, they act as JPEG streams. This is because supporting a
+     * JPEG stream requires the underlying YUV data to always be ready for
+     * use by a JPEG encoder, but the encoder will only be used (and impact
+     * frame duration) on requests that actually reference a JPEG stream.</li>
+     * <li>The JPEG processor can run concurrently to the rest of the camera
+     * pipeline, but cannot process more than 1 capture at a time.</li>
+     * </ul>
+     * <p>In other words, using a repeating YUV request would result
+     * in a steady frame rate (let's say it's 30 FPS). If a single
+     * JPEG request is submitted periodically, the frame rate will stay
+     * at 30 FPS (as long as we wait for the previous JPEG to return each
+     * time). If we try to submit a repeating YUV + JPEG request, then
+     * the frame rate will drop from 30 FPS.</p>
+     * <p>In general, submitting a new request with a non-0 stall time
+     * stream will <em>not</em> cause a frame rate drop unless there are still
+     * outstanding buffers for that stream from previous requests.</p>
+     * <p>Submitting a repeating request with streams (call this <code>S</code>)
+     * is the same as setting the minimum frame duration from
+     * the normal minimum frame duration corresponding to <code>S</code>, added with
+     * the maximum stall duration for <code>S</code>.</p>
+     * <p>If interleaving requests with and without a stall duration,
+     * a request will stall by the maximum of the remaining times
+     * for each can-stall stream with outstanding buffers.</p>
+     * <p>This means that a stalling request will not have an exposure start
+     * until the stall has completed.</p>
+     * <p>This should correspond to the stall duration when only that stream is
+     * active, with all processing (typically in android.*.mode) set to FAST
+     * or OFF. Setting any of the processing modes to HIGH_QUALITY
+     * effectively results in an indeterminate stall duration for all
+     * streams in a request (the regular stall calculation rules are
+     * ignored).</p>
+     * <p>The following formats may always have a stall duration:</p>
+     * <ul>
+     * <li>JPEG</li>
+     * <li>RAW16</li>
+     * </ul>
+     * <p>The following formats will never have a stall duration:</p>
+     * <ul>
+     * <li>YUV_420_888</li>
+     * <li>IMPLEMENTATION_DEFINED</li>
+     * </ul>
+     * <p>All other formats may or may not have an allowed stall duration on
+     * a per-capability basis; refer to {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}
+     * for more details.</p>
+     * <p>See {@link CaptureRequest#SENSOR_FRAME_DURATION android.sensor.frameDuration} for more information about
+     * calculating the max frame rate (absent stalls).</p>
+     *
+     * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
+     * @see CaptureRequest#SENSOR_FRAME_DURATION
+     */
+    public static final Key<long[]> SCALER_AVAILABLE_STALL_DURATIONS =
+            new Key<long[]>("android.scaler.availableStallDurations", long[].class);
+
+    /**
      * <p>Area of raw data which corresponds to only
      * active pixels.</p>
      * <p>It is smaller or equal to
@@ -547,7 +930,7 @@
     /**
      * <p>Maximum possible frame duration (minimum frame
      * rate).</p>
-     * <p>The largest possible android.sensor.frameDuration
+     * <p>The largest possible {@link CaptureRequest#SENSOR_FRAME_DURATION android.sensor.frameDuration}
      * that will be accepted by the camera device. Attempting to use
      * frame durations beyond the maximum will result in the frame duration
      * being clipped to the maximum. See that control
@@ -560,6 +943,7 @@
      *
      * @see CameraCharacteristics#SCALER_AVAILABLE_JPEG_MIN_DURATIONS
      * @see CameraCharacteristics#SCALER_AVAILABLE_PROCESSED_MIN_DURATIONS
+     * @see CaptureRequest#SENSOR_FRAME_DURATION
      */
     public static final Key<Long> SENSOR_INFO_MAX_FRAME_DURATION =
             new Key<Long>("android.sensor.info.maxFrameDuration", long.class);
@@ -573,6 +957,18 @@
             new Key<float[]>("android.sensor.info.physicalSize", float[].class);
 
     /**
+     * <p>Dimensions of full pixel array, possibly
+     * including black calibration pixels.</p>
+     * <p>Maximum output resolution for raw format must
+     * match this in
+     * {@link CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS android.scaler.availableStreamConfigurations}.</p>
+     *
+     * @see CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS
+     */
+    public static final Key<android.hardware.camera2.Size> SENSOR_INFO_PIXEL_ARRAY_SIZE =
+            new Key<android.hardware.camera2.Size>("android.sensor.info.pixelArraySize", android.hardware.camera2.Size.class);
+
+    /**
      * <p>Gain factor from electrons to raw units when
      * ISO=100</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
@@ -586,6 +982,18 @@
             new Key<Rational>("android.sensor.baseGainFactor", Rational.class);
 
     /**
+     * <p>A fixed black level offset for each of the color filter arrangement
+     * (CFA) mosaic channels.</p>
+     * <p>This tag specifies the zero light value for each of the CFA mosaic
+     * channels in the camera sensor.</p>
+     * <p>The values are given in row-column scan order, with the first value
+     * corresponding to the element of the CFA in row=0, column=0.</p>
+     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     */
+    public static final Key<int[]> SENSOR_BLACK_LEVEL_PATTERN =
+            new Key<int[]>("android.sensor.blackLevelPattern", int[].class);
+
+    /**
      * <p>Maximum sensitivity that is implemented
      * purely through analog gain.</p>
      * <p>For {@link CaptureRequest#SENSOR_SENSITIVITY android.sensor.sensitivity} values less than or
@@ -614,9 +1022,25 @@
             new Key<Integer>("android.sensor.orientation", int.class);
 
     /**
-     * <p>Optional. Defaults to [OFF]. Lists the supported test
-     * pattern modes for android.test.patternMode.</p>
+     * <p>The number of input samples for each dimension of
+     * {@link CaptureResult#SENSOR_PROFILE_HUE_SAT_MAP android.sensor.profileHueSatMap}.</p>
+     * <p>The number of input samples for the hue, saturation, and value
+     * dimension of {@link CaptureResult#SENSOR_PROFILE_HUE_SAT_MAP android.sensor.profileHueSatMap}. The order of the
+     * dimensions given is hue, saturation, value; where hue is the 0th
+     * element.</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     *
+     * @see CaptureResult#SENSOR_PROFILE_HUE_SAT_MAP
+     */
+    public static final Key<int[]> SENSOR_PROFILE_HUE_SAT_MAP_DIMENSIONS =
+            new Key<int[]>("android.sensor.profileHueSatMapDimensions", int[].class);
+
+    /**
+     * <p>Optional. Defaults to [OFF]. Lists the supported test
+     * pattern modes for {@link CaptureRequest#SENSOR_TEST_PATTERN_MODE android.sensor.testPatternMode}.</p>
+     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     *
+     * @see CaptureRequest#SENSOR_TEST_PATTERN_MODE
      */
     public static final Key<Byte> SENSOR_AVAILABLE_TEST_PATTERN_MODES =
             new Key<Byte>("android.sensor.availableTestPatternModes", byte.class);
@@ -671,14 +1095,20 @@
             new Key<int[]>("android.led.availableLeds", int[].class);
 
     /**
-     * <p>The camera 3 HAL device can implement one of two possible
-     * operational modes; limited and full. Full support is
-     * expected from new higher-end devices. Limited mode has
-     * hardware requirements roughly in line with those for a
-     * camera HAL device v1 implementation, and is expected from
-     * older or inexpensive devices. Full is a strict superset of
-     * limited, and they share the same essential operational flow.</p>
-     * <p>For full details refer to "S3. Operational Modes" in camera3.h</p>
+     * <p>Generally classifies the overall set of the camera device functionality.</p>
+     * <p>Camera devices will come in two flavors: LIMITED and FULL.</p>
+     * <p>A FULL device has the most support possible and will enable the
+     * widest range of use cases such as:</p>
+     * <ul>
+     * <li>30 FPS at maximum resolution (== sensor resolution)</li>
+     * <li>Per frame control</li>
+     * <li>Manual sensor control</li>
+     * <li>Zero Shutter Lag (ZSL)</li>
+     * </ul>
+     * <p>A LIMITED device may have some or none of the above characteristics.
+     * To find out more refer to {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}.</p>
+     *
+     * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
      * @see #INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED
      * @see #INFO_SUPPORTED_HARDWARE_LEVEL_FULL
      */
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index a1f432d..a581982 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -206,6 +206,45 @@
      *~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~*/
 
     //
+    // Enumeration values for CameraCharacteristics#LENS_INFO_FOCUS_DISTANCE_CALIBRATION
+    //
+
+    /**
+     * <p>The lens focus distance is not accurate, and the units used for
+     * {@link CaptureRequest#LENS_FOCUS_DISTANCE android.lens.focusDistance} do not correspond to any physical units.
+     * Setting the lens to the same focus distance on separate occasions may
+     * result in a different real focus distance, depending on factors such
+     * as the orientation of the device, the age of the focusing mechanism,
+     * and the device temperature. The focus distance value will still be
+     * in the range of <code>[0, {@link CameraCharacteristics#LENS_INFO_MINIMUM_FOCUS_DISTANCE android.lens.info.minimumFocusDistance}]</code>, where 0
+     * represents the farthest focus.</p>
+     *
+     * @see CaptureRequest#LENS_FOCUS_DISTANCE
+     * @see CameraCharacteristics#LENS_INFO_MINIMUM_FOCUS_DISTANCE
+     * @see CameraCharacteristics#LENS_INFO_FOCUS_DISTANCE_CALIBRATION
+     */
+    public static final int LENS_INFO_FOCUS_DISTANCE_CALIBRATION_UNCALIBRATED = 0;
+
+    /**
+     * <p>The lens focus distance is measured in diopters. However, setting the lens
+     * to the same focus distance on separate occasions may result in a
+     * different real focus distance, depending on factors such as the
+     * orientation of the device, the age of the focusing mechanism, and
+     * the device temperature.</p>
+     * @see CameraCharacteristics#LENS_INFO_FOCUS_DISTANCE_CALIBRATION
+     */
+    public static final int LENS_INFO_FOCUS_DISTANCE_CALIBRATION_APPROXIMATE = 1;
+
+    /**
+     * <p>The lens focus distance is measured in diopters. The lens mechanism is
+     * calibrated so that setting the same focus distance is repeatable on
+     * multiple occasions with good accuracy, and the focus distance corresponds
+     * to the real physical distance to the plane of best focus.</p>
+     * @see CameraCharacteristics#LENS_INFO_FOCUS_DISTANCE_CALIBRATION
+     */
+    public static final int LENS_INFO_FOCUS_DISTANCE_CALIBRATION_CALIBRATED = 2;
+
+    //
     // Enumeration values for CameraCharacteristics#LENS_FACING
     //
 
@@ -220,6 +259,172 @@
     public static final int LENS_FACING_BACK = 1;
 
     //
+    // Enumeration values for CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
+    //
+
+    /**
+     * <p>The minimal set of capabilities that every camera
+     * device (regardless of {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel})
+     * will support.</p>
+     * <p>The full set of features supported by this capability makes
+     * the camera2 api backwards compatible with the camera1
+     * (android.hardware.Camera) API.</p>
+     * <p>TODO: @hide this. Doesn't really mean anything except
+     * act as a catch-all for all the 'base' functionality.</p>
+     *
+     * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
+     * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
+     */
+    public static final int REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE = 0;
+
+    /**
+     * <p>This is a catch-all capability to include all other
+     * tags or functionality not encapsulated by one of the other
+     * capabilities.</p>
+     * <p>A typical example is all tags marked 'optional'.</p>
+     * <p>TODO: @hide. We may not need this if we @hide all the optional
+     * tags not belonging to a capability.</p>
+     * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
+     */
+    public static final int REQUEST_AVAILABLE_CAPABILITIES_OPTIONAL = 1;
+
+    /**
+     * <p>The camera device can be manually controlled (3A algorithms such
+     * as auto exposure, and auto focus can be
+     * bypassed), this includes but is not limited to:</p>
+     * <ul>
+     * <li>Manual exposure control<ul>
+     * <li>{@link CaptureRequest#SENSOR_EXPOSURE_TIME android.sensor.exposureTime}</li>
+     * <li>{@link CameraCharacteristics#SENSOR_INFO_EXPOSURE_TIME_RANGE android.sensor.info.exposureTimeRange}</li>
+     * </ul>
+     * </li>
+     * <li>Manual sensitivity control<ul>
+     * <li>{@link CaptureRequest#SENSOR_SENSITIVITY android.sensor.sensitivity}</li>
+     * <li>{@link CameraCharacteristics#SENSOR_INFO_SENSITIVITY_RANGE android.sensor.info.sensitivityRange}</li>
+     * <li>{@link CameraCharacteristics#SENSOR_BASE_GAIN_FACTOR android.sensor.baseGainFactor}</li>
+     * </ul>
+     * </li>
+     * <li>Manual lens control<ul>
+     * <li>android.lens.*</li>
+     * </ul>
+     * </li>
+     * <li>Manual flash control<ul>
+     * <li>android.flash.*</li>
+     * </ul>
+     * </li>
+     * <li>Manual black level locking<ul>
+     * <li>{@link CaptureRequest#BLACK_LEVEL_LOCK android.blackLevel.lock}</li>
+     * </ul>
+     * </li>
+     * </ul>
+     * <p>If any of the above 3A algorithms are enabled, then the camera
+     * device will accurately report the values applied by 3A in the
+     * result.</p>
+     *
+     * @see CaptureRequest#BLACK_LEVEL_LOCK
+     * @see CameraCharacteristics#SENSOR_BASE_GAIN_FACTOR
+     * @see CaptureRequest#SENSOR_EXPOSURE_TIME
+     * @see CameraCharacteristics#SENSOR_INFO_EXPOSURE_TIME_RANGE
+     * @see CameraCharacteristics#SENSOR_INFO_SENSITIVITY_RANGE
+     * @see CaptureRequest#SENSOR_SENSITIVITY
+     * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
+     */
+    public static final int REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR = 2;
+
+    /**
+     * <p>TODO: This should be @hide</p>
+     * <ul>
+     * <li>Manual tonemap control<ul>
+     * <li>{@link CaptureRequest#TONEMAP_CURVE_BLUE android.tonemap.curveBlue}</li>
+     * <li>{@link CaptureRequest#TONEMAP_CURVE_GREEN android.tonemap.curveGreen}</li>
+     * <li>{@link CaptureRequest#TONEMAP_CURVE_RED android.tonemap.curveRed}</li>
+     * <li>{@link CaptureRequest#TONEMAP_MODE android.tonemap.mode}</li>
+     * <li>{@link CameraCharacteristics#TONEMAP_MAX_CURVE_POINTS android.tonemap.maxCurvePoints}</li>
+     * </ul>
+     * </li>
+     * <li>Manual white balance control<ul>
+     * <li>{@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform}</li>
+     * <li>{@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains}</li>
+     * </ul>
+     * </li>
+     * <li>Lens shading map information<ul>
+     * <li>{@link CaptureResult#STATISTICS_LENS_SHADING_MAP android.statistics.lensShadingMap}</li>
+     * <li>{@link CameraCharacteristics#LENS_INFO_SHADING_MAP_SIZE android.lens.info.shadingMapSize}</li>
+     * </ul>
+     * </li>
+     * </ul>
+     * <p>If auto white balance is enabled, then the camera device
+     * will accurately report the values applied by AWB in the result.</p>
+     * <p>The camera device will also support everything in MANUAL_SENSOR
+     * except manual lens control and manual flash control.</p>
+     *
+     * @see CaptureRequest#COLOR_CORRECTION_GAINS
+     * @see CaptureRequest#COLOR_CORRECTION_TRANSFORM
+     * @see CameraCharacteristics#LENS_INFO_SHADING_MAP_SIZE
+     * @see CaptureResult#STATISTICS_LENS_SHADING_MAP
+     * @see CaptureRequest#TONEMAP_CURVE_BLUE
+     * @see CaptureRequest#TONEMAP_CURVE_GREEN
+     * @see CaptureRequest#TONEMAP_CURVE_RED
+     * @see CameraCharacteristics#TONEMAP_MAX_CURVE_POINTS
+     * @see CaptureRequest#TONEMAP_MODE
+     * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
+     */
+    public static final int REQUEST_AVAILABLE_CAPABILITIES_GCAM = 3;
+
+    /**
+     * <p>The camera device supports the Zero Shutter Lag use case.</p>
+     * <ul>
+     * <li>At least one input stream can be used.</li>
+     * <li>RAW_OPAQUE is supported as an output/input format</li>
+     * <li>Using RAW_OPAQUE does not cause a frame rate drop
+     * relative to the sensor's maximum capture rate (at that
+     * resolution).</li>
+     * <li>RAW_OPAQUE will be reprocessable into both YUV_420_888
+     * and JPEG formats.</li>
+     * <li>The maximum available resolution for RAW_OPAQUE streams
+     * (both input/output) will match the maximum available
+     * resolution of JPEG streams.</li>
+     * </ul>
+     * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
+     */
+    public static final int REQUEST_AVAILABLE_CAPABILITIES_ZSL = 4;
+
+    /**
+     * <p>The camera device supports outputting RAW buffers that can be
+     * saved offline into a DNG format. It can reprocess DNG
+     * files (produced from the same camera device) back into YUV.</p>
+     * <ul>
+     * <li>At least one input stream can be used.</li>
+     * <li>RAW16 is supported as output/input format.</li>
+     * <li>RAW16 is reprocessable into both YUV_420_888 and JPEG
+     * formats.</li>
+     * <li>The maximum available resolution for RAW16 streams (both
+     * input/output) will match the value in
+     * {@link CameraCharacteristics#SENSOR_INFO_PIXEL_ARRAY_SIZE android.sensor.info.pixelArraySize}.</li>
+     * <li>All DNG-related optional metadata entries are provided
+     * by the camera device.</li>
+     * </ul>
+     *
+     * @see CameraCharacteristics#SENSOR_INFO_PIXEL_ARRAY_SIZE
+     * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
+     */
+    public static final int REQUEST_AVAILABLE_CAPABILITIES_DNG = 5;
+
+    //
+    // Enumeration values for CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS
+    //
+
+    /**
+     * @see CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS
+     */
+    public static final int SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT = 0;
+
+    /**
+     * @see CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS
+     */
+    public static final int SCALER_AVAILABLE_STREAM_CONFIGURATIONS_INPUT = 1;
+
+    //
     // Enumeration values for CameraCharacteristics#LED_AVAILABLE_LEDS
     //
 
@@ -580,10 +785,11 @@
 
     /**
      * <p>The camera device's auto white balance routine is active;
-     * the application's values for android.colorCorrection.transform
+     * the application's values for {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform}
      * and {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains} are ignored.</p>
      *
      * @see CaptureRequest#COLOR_CORRECTION_GAINS
+     * @see CaptureRequest#COLOR_CORRECTION_TRANSFORM
      * @see CaptureRequest#CONTROL_AWB_MODE
      */
     public static final int CONTROL_AWB_MODE_AUTO = 1;
@@ -802,6 +1008,14 @@
      */
     public static final int CONTROL_MODE_USE_SCENE_MODE = 2;
 
+    /**
+     * <p>Same as OFF mode, except that this capture will not be
+     * used by camera device background auto-exposure, auto-white balance and
+     * auto-focus algorithms to update their statistics.</p>
+     * @see CaptureRequest#CONTROL_MODE
+     */
+    public static final int CONTROL_MODE_OFF_KEEP_STATE = 3;
+
     //
     // Enumeration values for CaptureRequest#CONTROL_SCENE_MODE
     //
@@ -820,10 +1034,11 @@
      * this should still operate correctly (but will not return
      * face detection statistics to the framework).</p>
      * <p>Unlike the other scene modes, {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode},
-     * {@link CaptureRequest#CONTROL_AWB_MODE android.control.awbMode}, and android.control.afMode
+     * {@link CaptureRequest#CONTROL_AWB_MODE android.control.awbMode}, and {@link CaptureRequest#CONTROL_AF_MODE android.control.afMode}
      * remain active when FACE_PRIORITY is set.</p>
      *
      * @see CaptureRequest#CONTROL_AE_MODE
+     * @see CaptureRequest#CONTROL_AF_MODE
      * @see CaptureRequest#CONTROL_AWB_MODE
      * @see CaptureRequest#STATISTICS_FACE_DETECT_MODE
      * @see CaptureRequest#CONTROL_SCENE_MODE
@@ -978,6 +1193,34 @@
     public static final int FLASH_MODE_TORCH = 2;
 
     //
+    // Enumeration values for CaptureRequest#HOT_PIXEL_MODE
+    //
+
+    /**
+     * <p>The frame rate must not be reduced relative to sensor raw output
+     * for this option.</p>
+     * <p>No hot pixel correction is applied.</p>
+     * @see CaptureRequest#HOT_PIXEL_MODE
+     */
+    public static final int HOT_PIXEL_MODE_OFF = 0;
+
+    /**
+     * <p>The frame rate must not be reduced relative to sensor raw output
+     * for this option.</p>
+     * <p>Hot pixel correction is applied.</p>
+     * @see CaptureRequest#HOT_PIXEL_MODE
+     */
+    public static final int HOT_PIXEL_MODE_FAST = 1;
+
+    /**
+     * <p>The frame rate may be reduced relative to sensor raw output
+     * for this option.</p>
+     * <p>A high-quality hot pixel correction is applied.</p>
+     * @see CaptureRequest#HOT_PIXEL_MODE
+     */
+    public static final int HOT_PIXEL_MODE_HIGH_QUALITY = 2;
+
+    //
     // Enumeration values for CaptureRequest#LENS_OPTICAL_STABILIZATION_MODE
     //
 
@@ -1190,7 +1433,7 @@
 
     /**
      * <p>Use the tone mapping curve specified in
-     * android.tonemap.curve.</p>
+     * the android.tonemap.curve* entries.</p>
      * <p>All color enhancement and tonemapping must be disabled, except
      * for applying the tonemapping curve specified by
      * {@link CaptureRequest#TONEMAP_CURVE_RED android.tonemap.curveRed}, {@link CaptureRequest#TONEMAP_CURVE_BLUE android.tonemap.curveBlue}, or
@@ -1403,21 +1646,25 @@
     //
 
     /**
-     * <p>The lens parameters ({@link CaptureRequest#LENS_FOCAL_LENGTH android.lens.focalLength}, android.lens.focusDistance
-     * android.lens.filterDensity and {@link CaptureRequest#LENS_APERTURE android.lens.aperture}) are not changing.</p>
+     * <p>The lens parameters ({@link CaptureRequest#LENS_FOCAL_LENGTH android.lens.focalLength}, {@link CaptureRequest#LENS_FOCUS_DISTANCE android.lens.focusDistance},
+     * {@link CaptureRequest#LENS_FILTER_DENSITY android.lens.filterDensity} and {@link CaptureRequest#LENS_APERTURE android.lens.aperture}) are not changing.</p>
      *
      * @see CaptureRequest#LENS_APERTURE
+     * @see CaptureRequest#LENS_FILTER_DENSITY
      * @see CaptureRequest#LENS_FOCAL_LENGTH
+     * @see CaptureRequest#LENS_FOCUS_DISTANCE
      * @see CaptureResult#LENS_STATE
      */
     public static final int LENS_STATE_STATIONARY = 0;
 
     /**
-     * <p>Any of the lens parameters ({@link CaptureRequest#LENS_FOCAL_LENGTH android.lens.focalLength}, android.lens.focusDistance
-     * android.lens.filterDensity or {@link CaptureRequest#LENS_APERTURE android.lens.aperture}) is changing.</p>
+     * <p>Any of the lens parameters ({@link CaptureRequest#LENS_FOCAL_LENGTH android.lens.focalLength}, {@link CaptureRequest#LENS_FOCUS_DISTANCE android.lens.focusDistance},
+     * {@link CaptureRequest#LENS_FILTER_DENSITY android.lens.filterDensity} or {@link CaptureRequest#LENS_APERTURE android.lens.aperture}) is changing.</p>
      *
      * @see CaptureRequest#LENS_APERTURE
+     * @see CaptureRequest#LENS_FILTER_DENSITY
      * @see CaptureRequest#LENS_FOCAL_LENGTH
+     * @see CaptureRequest#LENS_FOCUS_DISTANCE
      * @see CaptureResult#LENS_STATE
      */
     public static final int LENS_STATE_MOVING = 1;
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 1327ba9..408e532 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -373,13 +373,15 @@
     /**
      * <p>A color transform matrix to use to transform
      * from sensor RGB color space to output linear sRGB color space</p>
-     * <p>This matrix is either set by HAL when the request
+     * <p>This matrix is either set by the camera device when the request
      * {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode} is not TRANSFORM_MATRIX, or
      * directly by the application in the request when the
      * {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode} is TRANSFORM_MATRIX.</p>
-     * <p>In the latter case, the HAL may round the matrix to account
-     * for precision issues; the final rounded matrix should be
-     * reported back in this matrix result metadata.</p>
+     * <p>In the latter case, the camera device may round the matrix to account
+     * for precision issues; the final rounded matrix should be reported back
+     * in this matrix result metadata. The transform should keep the magnitude
+     * of the output color values within <code>[0, 1.0]</code> (assuming input color
+     * values is within the normalized range <code>[0, 1.0]</code>), or clipping may occur.</p>
      *
      * @see CaptureRequest#COLOR_CORRECTION_MODE
      */
@@ -463,10 +465,23 @@
 
     /**
      * <p>Whether AE is currently locked to its latest
-     * calculated values</p>
+     * calculated values.</p>
      * <p>Note that even when AE is locked, the flash may be
-     * fired if the AE mode is ON_AUTO_FLASH / ON_ALWAYS_FLASH /
+     * fired if the {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} is ON_AUTO_FLASH / ON_ALWAYS_FLASH /
      * ON_AUTO_FLASH_REDEYE.</p>
+     * <p>If AE precapture is triggered (see {@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger})
+     * when AE is already locked, the camera device will not change the exposure time
+     * ({@link CaptureRequest#SENSOR_EXPOSURE_TIME android.sensor.exposureTime}) and sensitivity ({@link CaptureRequest#SENSOR_SENSITIVITY android.sensor.sensitivity})
+     * parameters. The flash may be fired if the {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode}
+     * is ON_AUTO_FLASH/ON_AUTO_FLASH_REDEYE and the scene is too dark. If the
+     * {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} is ON_ALWAYS_FLASH, the scene may become overexposed.</p>
+     * <p>See {@link CaptureResult#CONTROL_AE_STATE android.control.aeState} for AE lock related state transition details.</p>
+     *
+     * @see CaptureRequest#CONTROL_AE_MODE
+     * @see CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER
+     * @see CaptureResult#CONTROL_AE_STATE
+     * @see CaptureRequest#SENSOR_EXPOSURE_TIME
+     * @see CaptureRequest#SENSOR_SENSITIVITY
      */
     public static final Key<Boolean> CONTROL_AE_LOCK =
             new Key<Boolean>("android.control.aeLock", boolean.class);
@@ -566,9 +581,10 @@
      * mode it is set to</p>
      * <p>Only effective if {@link CaptureRequest#CONTROL_MODE android.control.mode} = AUTO.</p>
      * <p>If the lens is controlled by the camera device auto-focus algorithm,
-     * the camera device will report the current AF status in android.control.afState
+     * the camera device will report the current AF status in {@link CaptureResult#CONTROL_AF_STATE android.control.afState}
      * in result metadata.</p>
      *
+     * @see CaptureResult#CONTROL_AF_STATE
      * @see CaptureRequest#CONTROL_MODE
      * @see #CONTROL_AF_MODE_OFF
      * @see #CONTROL_AF_MODE_AUTO
@@ -624,10 +640,10 @@
 
     /**
      * <p>Whether AWB is currently locked to its
-     * latest calculated values</p>
+     * latest calculated values.</p>
      * <p>Note that AWB lock is only meaningful for AUTO
      * mode; in other modes, AWB is already fixed to a specific
-     * setting</p>
+     * setting.</p>
      */
     public static final Key<Boolean> CONTROL_AWB_LOCK =
             new Key<Boolean>("android.control.awbLock", boolean.class);
@@ -643,7 +659,7 @@
      * {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode}.</p>
      * <p>When set to the OFF mode, the camera device's auto white balance
      * routine is disabled. The applicantion manually controls the white
-     * balance by {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform}, android.colorCorrection.gains
+     * balance by {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform}, {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains}
      * and {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode}.</p>
      * <p>When set to any other modes, the camera device's auto white balance
      * routine is disabled. The camera device uses each particular illumination
@@ -748,11 +764,17 @@
      * one of the scene mode settings (such as ACTION, SUNSET, or PARTY)
      * as it wishes. The camera device scene mode 3A settings are provided by
      * android.control.sceneModeOverrides.</p>
+     * <p>When set to OFF_KEEP_STATE, it is similar to OFF mode, the only difference
+     * is that this frame will not be used by camera device background 3A statistics
+     * update, as if this frame is never captured. This mode can be used in the scenario
+     * where the application doesn't want a 3A manual control capture to affect
+     * the subsequent auto 3A capture results.</p>
      *
      * @see CaptureRequest#CONTROL_AF_MODE
      * @see #CONTROL_MODE_OFF
      * @see #CONTROL_MODE_AUTO
      * @see #CONTROL_MODE_USE_SCENE_MODE
+     * @see #CONTROL_MODE_OFF_KEEP_STATE
      */
     public static final Key<Integer> CONTROL_MODE =
             new Key<Integer>("android.control.mode", int.class);
@@ -851,6 +873,18 @@
             new Key<Integer>("android.flash.mode", int.class);
 
     /**
+     * <p>Set operational mode for hot pixel correction.</p>
+     * <p>Hotpixel correction interpolates out, or otherwise removes, pixels
+     * that do not accurately encode the incoming light (i.e. pixels that
+     * are stuck at an arbitrary value).</p>
+     * @see #HOT_PIXEL_MODE_OFF
+     * @see #HOT_PIXEL_MODE_FAST
+     * @see #HOT_PIXEL_MODE_HIGH_QUALITY
+     */
+    public static final Key<Integer> HOT_PIXEL_MODE =
+            new Key<Integer>("android.hotPixel.mode", int.class);
+
+    /**
      * <p>GPS coordinates to include in output JPEG
      * EXIF</p>
      */
@@ -911,7 +945,7 @@
      * one of the values listed in {@link CameraCharacteristics#LENS_INFO_AVAILABLE_APERTURES android.lens.info.availableApertures}.</p>
      * <p>When this is supported and {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} is OFF,
      * this can be set along with {@link CaptureRequest#SENSOR_EXPOSURE_TIME android.sensor.exposureTime},
-     * {@link CaptureRequest#SENSOR_SENSITIVITY android.sensor.sensitivity}, and android.sensor.frameDuration
+     * {@link CaptureRequest#SENSOR_SENSITIVITY android.sensor.sensitivity}, and {@link CaptureRequest#SENSOR_FRAME_DURATION android.sensor.frameDuration}
      * to achieve manual exposure control.</p>
      * <p>The requested aperture value may take several frames to reach the
      * requested value; the camera device will report the current (intermediate)
@@ -926,6 +960,7 @@
      * @see CameraCharacteristics#LENS_INFO_AVAILABLE_APERTURES
      * @see CaptureResult#LENS_STATE
      * @see CaptureRequest#SENSOR_EXPOSURE_TIME
+     * @see CaptureRequest#SENSOR_FRAME_DURATION
      * @see CaptureRequest#SENSOR_SENSITIVITY
      */
     public static final Key<Float> LENS_APERTURE =
@@ -1058,9 +1093,11 @@
      * for raw output, where only a few fixed scales may be
      * possible. The width and height of the crop region cannot
      * be set to be smaller than floor( activeArraySize.width /
-     * android.scaler.maxDigitalZoom ) and floor(
-     * activeArraySize.height / android.scaler.maxDigitalZoom),
-     * respectively.</p>
+     * {@link CameraCharacteristics#SCALER_AVAILABLE_MAX_DIGITAL_ZOOM android.scaler.availableMaxDigitalZoom} ) and floor(
+     * activeArraySize.height /
+     * {@link CameraCharacteristics#SCALER_AVAILABLE_MAX_DIGITAL_ZOOM android.scaler.availableMaxDigitalZoom}), respectively.</p>
+     *
+     * @see CameraCharacteristics#SCALER_AVAILABLE_MAX_DIGITAL_ZOOM
      */
     public static final Key<android.graphics.Rect> SCALER_CROP_REGION =
             new Key<android.graphics.Rect>("android.scaler.cropRegion", android.graphics.Rect.class);
@@ -1108,62 +1145,45 @@
      * largest requested stream resolution.</li>
      * <li>Using more than one output stream in a request does not affect the
      * frame duration.</li>
-     * <li>JPEG streams act like processed YUV streams in requests for which
-     * they are not included; in requests in which they are directly
-     * referenced, they act as JPEG streams. This is because supporting a
-     * JPEG stream requires the underlying YUV data to always be ready for
-     * use by a JPEG encoder, but the encoder will only be used (and impact
-     * frame duration) on requests that actually reference a JPEG stream.</li>
-     * <li>The JPEG processor can run concurrently to the rest of the camera
-     * pipeline, but cannot process more than 1 capture at a time.</li>
+     * <li>Certain format-streams may need to do additional background processing
+     * before data is consumed/produced by that stream. These processors
+     * can run concurrently to the rest of the camera pipeline, but
+     * cannot process more than 1 capture at a time.</li>
      * </ul>
      * <p>The necessary information for the application, given the model above,
-     * is provided via the android.scaler.available*MinDurations fields.
+     * is provided via the {@link CameraCharacteristics#SCALER_AVAILABLE_MIN_FRAME_DURATIONS android.scaler.availableMinFrameDurations} field.
      * These are used to determine the maximum frame rate / minimum frame
      * duration that is possible for a given stream configuration.</p>
      * <p>Specifically, the application can use the following rules to
-     * determine the minimum frame duration it can request from the HAL
+     * determine the minimum frame duration it can request from the camera
      * device:</p>
      * <ol>
-     * <li>Given the application's currently configured set of output
-     * streams, <code>S</code>, divide them into three sets: streams in a JPEG format
-     * <code>SJ</code>, streams in a raw sensor format <code>SR</code>, and the rest ('processed')
-     * <code>SP</code>.</li>
-     * <li>For each subset of streams, find the largest resolution (by pixel
-     * count) in the subset. This gives (at most) three resolutions <code>RJ</code>,
-     * <code>RR</code>, and <code>RP</code>.</li>
-     * <li>If <code>RJ</code> is greater than <code>RP</code>, set <code>RP</code> equal to <code>RJ</code>. If there is
-     * no exact match for <code>RP == RJ</code> (in particular there isn't an available
-     * processed resolution at the same size as <code>RJ</code>), then set <code>RP</code> equal
-     * to the smallest processed resolution that is larger than <code>RJ</code>. If
-     * there are no processed resolutions larger than <code>RJ</code>, then set <code>RJ</code> to
-     * the processed resolution closest to <code>RJ</code>.</li>
-     * <li>If <code>RP</code> is greater than <code>RR</code>, set <code>RR</code> equal to <code>RP</code>. If there is
-     * no exact match for <code>RR == RP</code> (in particular there isn't an available
-     * raw resolution at the same size as <code>RP</code>), then set <code>RR</code> equal to
-     * or to the smallest raw resolution that is larger than <code>RP</code>. If
-     * there are no raw resolutions larger than <code>RP</code>, then set <code>RR</code> to
-     * the raw resolution closest to <code>RP</code>.</li>
-     * <li>Look up the matching minimum frame durations in the property lists
-     * {@link CameraCharacteristics#SCALER_AVAILABLE_JPEG_MIN_DURATIONS android.scaler.availableJpegMinDurations},
-     * android.scaler.availableRawMinDurations, and
-     * {@link CameraCharacteristics#SCALER_AVAILABLE_PROCESSED_MIN_DURATIONS android.scaler.availableProcessedMinDurations}.  This gives three
-     * minimum frame durations <code>FJ</code>, <code>FR</code>, and <code>FP</code>.</li>
-     * <li>If a stream of requests do not use a JPEG stream, then the minimum
-     * supported frame duration for each request is <code>max(FR, FP)</code>.</li>
-     * <li>If a stream of requests all use the JPEG stream, then the minimum
-     * supported frame duration for each request is <code>max(FR, FP, FJ)</code>.</li>
-     * <li>If a mix of JPEG-using and non-JPEG-using requests is submitted by
-     * the application, then the HAL will have to delay JPEG-using requests
-     * whenever the JPEG encoder is still busy processing an older capture.
-     * This will happen whenever a JPEG-using request starts capture less
-     * than <code>FJ</code> <em>ns</em> after a previous JPEG-using request. The minimum
-     * supported frame duration will vary between the values calculated in
-     * #6 and #7.</li>
+     * <li>Let the set of currently configured input/output streams
+     * be called <code>S</code>.</li>
+     * <li>Find the minimum frame durations for each stream in <code>S</code>, by
+     * looking it up in {@link CameraCharacteristics#SCALER_AVAILABLE_MIN_FRAME_DURATIONS android.scaler.availableMinFrameDurations} (with
+     * its respective size/format). Let this set of frame durations be called
+     * <code>F</code>.</li>
+     * <li>For any given request <code>R</code>, the minimum frame duration allowed
+     * for <code>R</code> is the maximum out of all values in <code>F</code>. Let the streams
+     * used in <code>R</code> be called <code>S_r</code>.</li>
      * </ol>
+     * <p>If none of the streams in <code>S_r</code> have a stall time (listed in
+     * {@link CameraCharacteristics#SCALER_AVAILABLE_STALL_DURATIONS android.scaler.availableStallDurations}), then the frame duration in
+     * <code>F</code> determines the steady state frame rate that the application will
+     * get if it uses <code>R</code> as a repeating request. Let this special kind
+     * of request be called <code>Rsimple</code>.</p>
+     * <p>A repeating request <code>Rsimple</code> can be <em>occasionally</em> interleaved
+     * by a single capture of a new request <code>Rstall</code> (which has at least
+     * one in-use stream with a non-0 stall time) and if <code>Rstall</code> has the
+     * same minimum frame duration this will not cause a frame rate loss
+     * if all buffers from the previous <code>Rstall</code> have already been
+     * delivered.</p>
+     * <p>For more details about stalling, see
+     * {@link CameraCharacteristics#SCALER_AVAILABLE_STALL_DURATIONS android.scaler.availableStallDurations}.</p>
      *
-     * @see CameraCharacteristics#SCALER_AVAILABLE_JPEG_MIN_DURATIONS
-     * @see CameraCharacteristics#SCALER_AVAILABLE_PROCESSED_MIN_DURATIONS
+     * @see CameraCharacteristics#SCALER_AVAILABLE_MIN_FRAME_DURATIONS
+     * @see CameraCharacteristics#SCALER_AVAILABLE_STALL_DURATIONS
      */
     public static final Key<Long> SENSOR_FRAME_DURATION =
             new Key<Long>("android.sensor.frameDuration", long.class);
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 46d95b1..345b52c 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -126,13 +126,15 @@
     /**
      * <p>A color transform matrix to use to transform
      * from sensor RGB color space to output linear sRGB color space</p>
-     * <p>This matrix is either set by HAL when the request
+     * <p>This matrix is either set by the camera device when the request
      * {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode} is not TRANSFORM_MATRIX, or
      * directly by the application in the request when the
      * {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode} is TRANSFORM_MATRIX.</p>
-     * <p>In the latter case, the HAL may round the matrix to account
-     * for precision issues; the final rounded matrix should be
-     * reported back in this matrix result metadata.</p>
+     * <p>In the latter case, the camera device may round the matrix to account
+     * for precision issues; the final rounded matrix should be reported back
+     * in this matrix result metadata. The transform should keep the magnitude
+     * of the output color values within <code>[0, 1.0]</code> (assuming input color
+     * values is within the normalized range <code>[0, 1.0]</code>), or clipping may occur.</p>
      *
      * @see CaptureRequest#COLOR_CORRECTION_MODE
      */
@@ -389,9 +391,10 @@
      * mode it is set to</p>
      * <p>Only effective if {@link CaptureRequest#CONTROL_MODE android.control.mode} = AUTO.</p>
      * <p>If the lens is controlled by the camera device auto-focus algorithm,
-     * the camera device will report the current AF status in android.control.afState
+     * the camera device will report the current AF status in {@link CaptureResult#CONTROL_AF_STATE android.control.afState}
      * in result metadata.</p>
      *
+     * @see CaptureResult#CONTROL_AF_STATE
      * @see CaptureRequest#CONTROL_MODE
      * @see #CONTROL_AF_MODE_OFF
      * @see #CONTROL_AF_MODE_AUTO
@@ -769,7 +772,7 @@
      * {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode}.</p>
      * <p>When set to the OFF mode, the camera device's auto white balance
      * routine is disabled. The applicantion manually controls the white
-     * balance by {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform}, android.colorCorrection.gains
+     * balance by {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform}, {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains}
      * and {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode}.</p>
      * <p>When set to any other modes, the camera device's auto white balance
      * routine is disabled. The camera device uses each particular illumination
@@ -936,11 +939,17 @@
      * one of the scene mode settings (such as ACTION, SUNSET, or PARTY)
      * as it wishes. The camera device scene mode 3A settings are provided by
      * android.control.sceneModeOverrides.</p>
+     * <p>When set to OFF_KEEP_STATE, it is similar to OFF mode, the only difference
+     * is that this frame will not be used by camera device background 3A statistics
+     * update, as if this frame is never captured. This mode can be used in the scenario
+     * where the application doesn't want a 3A manual control capture to affect
+     * the subsequent auto 3A capture results.</p>
      *
      * @see CaptureRequest#CONTROL_AF_MODE
      * @see #CONTROL_MODE_OFF
      * @see #CONTROL_MODE_AUTO
      * @see #CONTROL_MODE_USE_SCENE_MODE
+     * @see #CONTROL_MODE_OFF_KEEP_STATE
      */
     public static final Key<Integer> CONTROL_MODE =
             new Key<Integer>("android.control.mode", int.class);
@@ -1006,6 +1015,32 @@
             new Key<Integer>("android.flash.state", int.class);
 
     /**
+     * <p>List of <code>(x, y)</code> coordinates of hot/defective pixels on the
+     * sensor, where <code>(x, y)</code> lies between <code>(0, 0)</code>, which is the top-left
+     * of the pixel array, and the width,height of the pixel array given in
+     * {@link CameraCharacteristics#SENSOR_INFO_PIXEL_ARRAY_SIZE android.sensor.info.pixelArraySize}.  This may include hot pixels
+     * that lie outside of the active array bounds given by
+     * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.</p>
+     *
+     * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
+     * @see CameraCharacteristics#SENSOR_INFO_PIXEL_ARRAY_SIZE
+     */
+    public static final Key<int[]> HOT_PIXEL_MAP =
+            new Key<int[]>("android.hotPixel.map", int[].class);
+
+    /**
+     * <p>Set operational mode for hot pixel correction.</p>
+     * <p>Hotpixel correction interpolates out, or otherwise removes, pixels
+     * that do not accurately encode the incoming light (i.e. pixels that
+     * are stuck at an arbitrary value).</p>
+     * @see #HOT_PIXEL_MODE_OFF
+     * @see #HOT_PIXEL_MODE_FAST
+     * @see #HOT_PIXEL_MODE_HIGH_QUALITY
+     */
+    public static final Key<Integer> HOT_PIXEL_MODE =
+            new Key<Integer>("android.hotPixel.mode", int.class);
+
+    /**
      * <p>GPS coordinates to include in output JPEG
      * EXIF</p>
      */
@@ -1066,7 +1101,7 @@
      * one of the values listed in {@link CameraCharacteristics#LENS_INFO_AVAILABLE_APERTURES android.lens.info.availableApertures}.</p>
      * <p>When this is supported and {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} is OFF,
      * this can be set along with {@link CaptureRequest#SENSOR_EXPOSURE_TIME android.sensor.exposureTime},
-     * {@link CaptureRequest#SENSOR_SENSITIVITY android.sensor.sensitivity}, and android.sensor.frameDuration
+     * {@link CaptureRequest#SENSOR_SENSITIVITY android.sensor.sensitivity}, and {@link CaptureRequest#SENSOR_FRAME_DURATION android.sensor.frameDuration}
      * to achieve manual exposure control.</p>
      * <p>The requested aperture value may take several frames to reach the
      * requested value; the camera device will report the current (intermediate)
@@ -1081,6 +1116,7 @@
      * @see CameraCharacteristics#LENS_INFO_AVAILABLE_APERTURES
      * @see CaptureResult#LENS_STATE
      * @see CaptureRequest#SENSOR_EXPOSURE_TIME
+     * @see CaptureRequest#SENSOR_FRAME_DURATION
      * @see CaptureRequest#SENSOR_SENSITIVITY
      */
     public static final Key<Float> LENS_APERTURE =
@@ -1292,9 +1328,11 @@
      * for raw output, where only a few fixed scales may be
      * possible. The width and height of the crop region cannot
      * be set to be smaller than floor( activeArraySize.width /
-     * android.scaler.maxDigitalZoom ) and floor(
-     * activeArraySize.height / android.scaler.maxDigitalZoom),
-     * respectively.</p>
+     * {@link CameraCharacteristics#SCALER_AVAILABLE_MAX_DIGITAL_ZOOM android.scaler.availableMaxDigitalZoom} ) and floor(
+     * activeArraySize.height /
+     * {@link CameraCharacteristics#SCALER_AVAILABLE_MAX_DIGITAL_ZOOM android.scaler.availableMaxDigitalZoom}), respectively.</p>
+     *
+     * @see CameraCharacteristics#SCALER_AVAILABLE_MAX_DIGITAL_ZOOM
      */
     public static final Key<android.graphics.Rect> SCALER_CROP_REGION =
             new Key<android.graphics.Rect>("android.scaler.cropRegion", android.graphics.Rect.class);
@@ -1342,62 +1380,45 @@
      * largest requested stream resolution.</li>
      * <li>Using more than one output stream in a request does not affect the
      * frame duration.</li>
-     * <li>JPEG streams act like processed YUV streams in requests for which
-     * they are not included; in requests in which they are directly
-     * referenced, they act as JPEG streams. This is because supporting a
-     * JPEG stream requires the underlying YUV data to always be ready for
-     * use by a JPEG encoder, but the encoder will only be used (and impact
-     * frame duration) on requests that actually reference a JPEG stream.</li>
-     * <li>The JPEG processor can run concurrently to the rest of the camera
-     * pipeline, but cannot process more than 1 capture at a time.</li>
+     * <li>Certain format-streams may need to do additional background processing
+     * before data is consumed/produced by that stream. These processors
+     * can run concurrently to the rest of the camera pipeline, but
+     * cannot process more than 1 capture at a time.</li>
      * </ul>
      * <p>The necessary information for the application, given the model above,
-     * is provided via the android.scaler.available*MinDurations fields.
+     * is provided via the {@link CameraCharacteristics#SCALER_AVAILABLE_MIN_FRAME_DURATIONS android.scaler.availableMinFrameDurations} field.
      * These are used to determine the maximum frame rate / minimum frame
      * duration that is possible for a given stream configuration.</p>
      * <p>Specifically, the application can use the following rules to
-     * determine the minimum frame duration it can request from the HAL
+     * determine the minimum frame duration it can request from the camera
      * device:</p>
      * <ol>
-     * <li>Given the application's currently configured set of output
-     * streams, <code>S</code>, divide them into three sets: streams in a JPEG format
-     * <code>SJ</code>, streams in a raw sensor format <code>SR</code>, and the rest ('processed')
-     * <code>SP</code>.</li>
-     * <li>For each subset of streams, find the largest resolution (by pixel
-     * count) in the subset. This gives (at most) three resolutions <code>RJ</code>,
-     * <code>RR</code>, and <code>RP</code>.</li>
-     * <li>If <code>RJ</code> is greater than <code>RP</code>, set <code>RP</code> equal to <code>RJ</code>. If there is
-     * no exact match for <code>RP == RJ</code> (in particular there isn't an available
-     * processed resolution at the same size as <code>RJ</code>), then set <code>RP</code> equal
-     * to the smallest processed resolution that is larger than <code>RJ</code>. If
-     * there are no processed resolutions larger than <code>RJ</code>, then set <code>RJ</code> to
-     * the processed resolution closest to <code>RJ</code>.</li>
-     * <li>If <code>RP</code> is greater than <code>RR</code>, set <code>RR</code> equal to <code>RP</code>. If there is
-     * no exact match for <code>RR == RP</code> (in particular there isn't an available
-     * raw resolution at the same size as <code>RP</code>), then set <code>RR</code> equal to
-     * or to the smallest raw resolution that is larger than <code>RP</code>. If
-     * there are no raw resolutions larger than <code>RP</code>, then set <code>RR</code> to
-     * the raw resolution closest to <code>RP</code>.</li>
-     * <li>Look up the matching minimum frame durations in the property lists
-     * {@link CameraCharacteristics#SCALER_AVAILABLE_JPEG_MIN_DURATIONS android.scaler.availableJpegMinDurations},
-     * android.scaler.availableRawMinDurations, and
-     * {@link CameraCharacteristics#SCALER_AVAILABLE_PROCESSED_MIN_DURATIONS android.scaler.availableProcessedMinDurations}.  This gives three
-     * minimum frame durations <code>FJ</code>, <code>FR</code>, and <code>FP</code>.</li>
-     * <li>If a stream of requests do not use a JPEG stream, then the minimum
-     * supported frame duration for each request is <code>max(FR, FP)</code>.</li>
-     * <li>If a stream of requests all use the JPEG stream, then the minimum
-     * supported frame duration for each request is <code>max(FR, FP, FJ)</code>.</li>
-     * <li>If a mix of JPEG-using and non-JPEG-using requests is submitted by
-     * the application, then the HAL will have to delay JPEG-using requests
-     * whenever the JPEG encoder is still busy processing an older capture.
-     * This will happen whenever a JPEG-using request starts capture less
-     * than <code>FJ</code> <em>ns</em> after a previous JPEG-using request. The minimum
-     * supported frame duration will vary between the values calculated in
-     * #6 and #7.</li>
+     * <li>Let the set of currently configured input/output streams
+     * be called <code>S</code>.</li>
+     * <li>Find the minimum frame durations for each stream in <code>S</code>, by
+     * looking it up in {@link CameraCharacteristics#SCALER_AVAILABLE_MIN_FRAME_DURATIONS android.scaler.availableMinFrameDurations} (with
+     * its respective size/format). Let this set of frame durations be called
+     * <code>F</code>.</li>
+     * <li>For any given request <code>R</code>, the minimum frame duration allowed
+     * for <code>R</code> is the maximum out of all values in <code>F</code>. Let the streams
+     * used in <code>R</code> be called <code>S_r</code>.</li>
      * </ol>
+     * <p>If none of the streams in <code>S_r</code> have a stall time (listed in
+     * {@link CameraCharacteristics#SCALER_AVAILABLE_STALL_DURATIONS android.scaler.availableStallDurations}), then the frame duration in
+     * <code>F</code> determines the steady state frame rate that the application will
+     * get if it uses <code>R</code> as a repeating request. Let this special kind
+     * of request be called <code>Rsimple</code>.</p>
+     * <p>A repeating request <code>Rsimple</code> can be <em>occasionally</em> interleaved
+     * by a single capture of a new request <code>Rstall</code> (which has at least
+     * one in-use stream with a non-0 stall time) and if <code>Rstall</code> has the
+     * same minimum frame duration this will not cause a frame rate loss
+     * if all buffers from the previous <code>Rstall</code> have already been
+     * delivered.</p>
+     * <p>For more details about stalling, see
+     * {@link CameraCharacteristics#SCALER_AVAILABLE_STALL_DURATIONS android.scaler.availableStallDurations}.</p>
      *
-     * @see CameraCharacteristics#SCALER_AVAILABLE_JPEG_MIN_DURATIONS
-     * @see CameraCharacteristics#SCALER_AVAILABLE_PROCESSED_MIN_DURATIONS
+     * @see CameraCharacteristics#SCALER_AVAILABLE_MIN_FRAME_DURATIONS
+     * @see CameraCharacteristics#SCALER_AVAILABLE_STALL_DURATIONS
      */
     public static final Key<Long> SENSOR_FRAME_DURATION =
             new Key<Long>("android.sensor.frameDuration", long.class);
@@ -1438,6 +1459,83 @@
             new Key<Float>("android.sensor.temperature", float.class);
 
     /**
+     * <p>A per-device calibration transform matrix to be applied after the
+     * color space transform when rendering the raw image buffer.</p>
+     * <p>This matrix is expressed as a 3x3 matrix in row-major-order, and
+     * contains a per-device calibration transform that maps colors
+     * from reference camera color space (i.e. the "golden module"
+     * colorspace) into this camera device's linear native sensor color
+     * space for the current scene illumination and white balance choice.</p>
+     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     */
+    public static final Key<Rational[]> SENSOR_CALIBRATION_TRANSFORM =
+            new Key<Rational[]>("android.sensor.calibrationTransform", Rational[].class);
+
+    /**
+     * <p>A matrix that transforms color values from CIE XYZ color space to
+     * reference camera color space when rendering the raw image buffer.</p>
+     * <p>This matrix is expressed as a 3x3 matrix in row-major-order, and
+     * contains a color transform matrix that maps colors from the CIE
+     * XYZ color space to the reference camera raw color space (i.e. the
+     * "golden module" colorspace) for the current scene illumination and
+     * white balance choice.</p>
+     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     */
+    public static final Key<Rational[]> SENSOR_COLOR_TRANSFORM =
+            new Key<Rational[]>("android.sensor.colorTransform", Rational[].class);
+
+    /**
+     * <p>A matrix that transforms white balanced camera colors to the CIE XYZ
+     * colorspace with a D50 whitepoint.</p>
+     * <p>This matrix is expressed as a 3x3 matrix in row-major-order, and contains
+     * a color transform matrix that maps a unit vector in the linear native
+     * sensor color space to the D50 whitepoint in CIE XYZ color space.</p>
+     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     */
+    public static final Key<Rational[]> SENSOR_FORWARD_MATRIX =
+            new Key<Rational[]>("android.sensor.forwardMatrix", Rational[].class);
+
+    /**
+     * <p>The estimated white balance at the time of capture.</p>
+     * <p>The estimated white balance encoded as the RGB values of the
+     * perfectly neutral color point in the linear native sensor color space.
+     * The order of the values is R, G, B; where R is in the lowest index.</p>
+     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     */
+    public static final Key<Rational[]> SENSOR_NEUTRAL_COLOR_POINT =
+            new Key<Rational[]>("android.sensor.neutralColorPoint", Rational[].class);
+
+    /**
+     * <p>A mapping containing a hue shift, saturation scale, and value scale
+     * for each pixel.</p>
+     * <p>hue_samples, saturation_samples, and value_samples are given in
+     * {@link CameraCharacteristics#SENSOR_PROFILE_HUE_SAT_MAP_DIMENSIONS android.sensor.profileHueSatMapDimensions}.</p>
+     * <p>Each entry of this map contains three floats corresponding to the
+     * hue shift, saturation scale, and value scale, respectively; where the
+     * hue shift has the lowest index. The map entries are stored in the tag
+     * in nested loop order, with the value divisions in the outer loop, the
+     * hue divisions in the middle loop, and the saturation divisions in the
+     * inner loop. All zero input saturation entries are required to have a
+     * value scale factor of 1.0.</p>
+     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     *
+     * @see CameraCharacteristics#SENSOR_PROFILE_HUE_SAT_MAP_DIMENSIONS
+     */
+    public static final Key<float[]> SENSOR_PROFILE_HUE_SAT_MAP =
+            new Key<float[]>("android.sensor.profileHueSatMap", float[].class);
+
+    /**
+     * <p>A list of x,y samples defining a tone-mapping curve for gamma adjustment.</p>
+     * <p>This tag contains a default tone curve that can be applied while
+     * processing the image as a starting point for user adjustments.
+     * The curve is specified as a list of value pairs in linear gamma.
+     * The curve is interpolated using a cubic spline.</p>
+     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     */
+    public static final Key<float[]> SENSOR_PROFILE_TONE_CURVE =
+            new Key<float[]>("android.sensor.profileToneCurve", float[].class);
+
+    /**
      * <p>When enabled, the sensor sends a test pattern instead of
      * doing a real exposure from the camera.</p>
      * <p>When a test pattern is enabled, all manual sensor controls specified
@@ -1645,7 +1743,7 @@
      * (<code>{@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} == OFF</code> or <code>{@link CaptureRequest#CONTROL_MODE android.control.mode} == OFF</code>),
      * the {@link CaptureRequest#CONTROL_AE_ANTIBANDING_MODE android.control.aeAntibandingMode} doesn't do the antibanding, and the
      * application can ensure it selects exposure times that do not cause banding
-     * issues by looking into this metadata field. See android.control.aeAntibandingMode
+     * issues by looking into this metadata field. See {@link CaptureRequest#CONTROL_AE_ANTIBANDING_MODE android.control.aeAntibandingMode}
      * for more details.</p>
      * <p>Report NONE if there doesn't appear to be flickering illumination.</p>
      *
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 6ac126e..3a35cb9 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -800,6 +800,8 @@
      * Ensure that a network route exists to deliver traffic to the specified
      * host via the specified network interface. An attempt to add a route that
      * already exists is ignored, but treated as successful.
+     * <p>This method requires the caller to hold the permission
+     * {@link android.Manifest.permission#CHANGE_NETWORK_STATE}.
      * @param networkType the type of the network over which traffic to the specified
      * host is to be routed
      * @param hostAddress the IP address of the host to which the route is desired
diff --git a/core/java/android/net/MobileDataStateTracker.java b/core/java/android/net/MobileDataStateTracker.java
index d9c35c0..3c3d8ec 100644
--- a/core/java/android/net/MobileDataStateTracker.java
+++ b/core/java/android/net/MobileDataStateTracker.java
@@ -306,18 +306,18 @@
                     if (VDBG) {
                         Slog.d(TAG, "TelephonyMgr.DataConnectionStateChanged");
                         if (mNetworkInfo != null) {
-                            Slog.d(TAG, "NetworkInfo = " + mNetworkInfo.toString());
-                            Slog.d(TAG, "subType = " + String.valueOf(mNetworkInfo.getSubtype()));
+                            Slog.d(TAG, "NetworkInfo = " + mNetworkInfo);
+                            Slog.d(TAG, "subType = " + mNetworkInfo.getSubtype());
                             Slog.d(TAG, "subType = " + mNetworkInfo.getSubtypeName());
                         }
                         if (mLinkProperties != null) {
-                            Slog.d(TAG, "LinkProperties = " + mLinkProperties.toString());
+                            Slog.d(TAG, "LinkProperties = " + mLinkProperties);
                         } else {
                             Slog.d(TAG, "LinkProperties = " );
                         }
 
                         if (mLinkCapabilities != null) {
-                            Slog.d(TAG, "LinkCapabilities = " + mLinkCapabilities.toString());
+                            Slog.d(TAG, "LinkCapabilities = " + mLinkCapabilities);
                         } else {
                             Slog.d(TAG, "LinkCapabilities = " );
                         }
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 27c0f5d..345ff82 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -507,10 +507,7 @@
         
         public long time;
 
-        // The command codes 0-3 can be written with delta updates; all others require
-        // that a full entry be written.
-        public static final byte CMD_UPDATE = 0;
-        public static final byte CMD_EVENT = 1;
+        public static final byte CMD_UPDATE = 0;        // These can be written as deltas
         public static final byte CMD_NULL = -1;
         public static final byte CMD_START = 4;
         public static final byte CMD_OVERFLOW = 5;
@@ -520,15 +517,8 @@
         /**
          * Return whether the command code is a delta data update.
          */
-        public static boolean isDeltaData(byte cmd) {
-            return cmd >= 0 && cmd <= 3;
-        }
-
-        /**
-         * Return whether the command code is a delta data update.
-         */
         public boolean isDeltaData() {
-            return cmd >= 0 && cmd <= 3;
+            return cmd == CMD_UPDATE;
         }
 
         public byte batteryLevel;
@@ -555,16 +545,16 @@
         // These states always appear directly in the first int token
         // of a delta change; they should be ones that change relatively
         // frequently.
-        public static final int STATE_WAKE_LOCK_FLAG = 1<<30;
-        public static final int STATE_SENSOR_ON_FLAG = 1<<29;
-        public static final int STATE_GPS_ON_FLAG = 1<<28;
-        public static final int STATE_PHONE_SCANNING_FLAG = 1<<27;
-        public static final int STATE_WIFI_RUNNING_FLAG = 1<<26;
-        public static final int STATE_WIFI_FULL_LOCK_FLAG = 1<<25;
-        public static final int STATE_WIFI_SCAN_FLAG = 1<<24;
-        public static final int STATE_WIFI_MULTICAST_ON_FLAG = 1<<23;
+        public static final int STATE_WAKE_LOCK_FLAG = 1<<31;
+        public static final int STATE_SENSOR_ON_FLAG = 1<<30;
+        public static final int STATE_GPS_ON_FLAG = 1<<29;
+        public static final int STATE_WIFI_FULL_LOCK_FLAG = 1<<28;
+        public static final int STATE_WIFI_SCAN_FLAG = 1<<29;
+        public static final int STATE_WIFI_MULTICAST_ON_FLAG = 1<<26;
+        public static final int STATE_WIFI_RUNNING_FLAG = 1<<24;
         // These are on the lower bits used for the command; if they change
         // we need to write another int of data.
+        public static final int STATE_PHONE_SCANNING_FLAG = 1<<23;
         public static final int STATE_AUDIO_ON_FLAG = 1<<22;
         public static final int STATE_VIDEO_ON_FLAG = 1<<21;
         public static final int STATE_SCREEN_ON_FLAG = 1<<20;
@@ -582,9 +572,26 @@
         // The wake lock that was acquired at this point.
         public HistoryTag wakelockTag;
 
-        public static final int EVENT_NONE = 0;
-        public static final int EVENT_PROC_STARTED = 1;
-        public static final int EVENT_PROC_FINISHED = 2;
+        public static final int EVENT_FLAG_START = 0x8000;
+        public static final int EVENT_FLAG_FINISH = 0x4000;
+
+        // No event in this item.
+        public static final int EVENT_NONE = 0x0000;
+        // Event is about a process that is running.
+        public static final int EVENT_PROC = 0x0001;
+        // Event is about an application package that is in the foreground.
+        public static final int EVENT_FOREGROUND = 0x0002;
+        // Event is about an application package that is at the top of the screen.
+        public static final int EVENT_TOP = 0x0003;
+        // Number of event types.
+        public static final int EVENT_COUNT = 0x0004;
+
+        public static final int EVENT_PROC_START = EVENT_PROC | EVENT_FLAG_START;
+        public static final int EVENT_PROC_FINISH = EVENT_PROC | EVENT_FLAG_FINISH;
+        public static final int EVENT_FOREGROUND_START = EVENT_FOREGROUND | EVENT_FLAG_START;
+        public static final int EVENT_FOREGROUND_FINISH = EVENT_FOREGROUND | EVENT_FLAG_FINISH;
+        public static final int EVENT_TOP_START = EVENT_TOP | EVENT_FLAG_START;
+        public static final int EVENT_TOP_FINISH = EVENT_TOP | EVENT_FLAG_FINISH;
 
         // For CMD_EVENT.
         public int eventCode;
@@ -628,7 +635,8 @@
             } else {
                 dest.writeInt(0);
             }
-            if (cmd == CMD_EVENT) {
+            dest.writeInt(eventCode);
+            if (eventCode != EVENT_NONE) {
                 dest.writeInt(eventCode);
                 eventTag.writeToParcel(dest, flags);
             }
@@ -652,13 +660,10 @@
             } else {
                 wakelockTag = null;
             }
-            if (cmd == CMD_EVENT) {
-                eventCode = src.readInt();
+            eventCode = src.readInt();
+            if (eventCode != EVENT_NONE) {
                 eventTag = localEventTag;
                 eventTag.readFromParcel(src);
-            } else {
-                eventCode = EVENT_NONE;
-                eventTag = null;
             }
             numReadInts += (src.dataPosition()-start)/4;
         }
@@ -681,6 +686,16 @@
         public void setTo(HistoryItem o) {
             time = o.time;
             cmd = o.cmd;
+            setToCommon(o);
+        }
+
+        public void setTo(long time, byte cmd, HistoryItem o) {
+            this.time = time;
+            this.cmd = cmd;
+            setToCommon(o);
+        }
+
+        private void setToCommon(HistoryItem o) {
             batteryLevel = o.batteryLevel;
             batteryStatus = o.batteryStatus;
             batteryHealth = o.batteryHealth;
@@ -703,32 +718,6 @@
             }
         }
 
-        public void setTo(long time, byte cmd, int eventCode, int eventUid, String eventName,
-                HistoryItem o) {
-            this.time = time;
-            this.cmd = cmd;
-            this.eventCode = eventCode;
-            if (eventCode != EVENT_NONE) {
-                eventTag = localEventTag;
-                eventTag.setTo(eventName, eventUid);
-            } else {
-                eventTag = null;
-            }
-            batteryLevel = o.batteryLevel;
-            batteryStatus = o.batteryStatus;
-            batteryHealth = o.batteryHealth;
-            batteryPlugType = o.batteryPlugType;
-            batteryTemperature = o.batteryTemperature;
-            batteryVoltage = o.batteryVoltage;
-            states = o.states;
-            if (o.wakelockTag != null) {
-                wakelockTag = localWakelockTag;
-                wakelockTag.setTo(o.wakelockTag);
-            } else {
-                wakelockTag = null;
-            }
-        }
-
         public boolean sameNonEvent(HistoryItem o) {
             return batteryLevel == o.batteryLevel
                     && batteryStatus == o.batteryStatus
@@ -938,36 +927,44 @@
     
     public static final BitDescription[] HISTORY_STATE_DESCRIPTIONS
             = new BitDescription[] {
-        new BitDescription(HistoryItem.STATE_BATTERY_PLUGGED_FLAG, "plugged", "BP"),
-        new BitDescription(HistoryItem.STATE_SCREEN_ON_FLAG, "screen", "S"),
+        new BitDescription(HistoryItem.STATE_WAKE_LOCK_FLAG, "wake_lock", "w"),
+        new BitDescription(HistoryItem.STATE_SENSOR_ON_FLAG, "sensor", "s"),
         new BitDescription(HistoryItem.STATE_GPS_ON_FLAG, "gps", "g"),
-        new BitDescription(HistoryItem.STATE_PHONE_IN_CALL_FLAG, "phone_in_call", "Pcl"),
-        new BitDescription(HistoryItem.STATE_PHONE_SCANNING_FLAG, "phone_scanning", "Psc"),
-        new BitDescription(HistoryItem.STATE_WIFI_ON_FLAG, "wifi", "W"),
-        new BitDescription(HistoryItem.STATE_WIFI_RUNNING_FLAG, "wifi_running", "Wr"),
         new BitDescription(HistoryItem.STATE_WIFI_FULL_LOCK_FLAG, "wifi_full_lock", "Wl"),
         new BitDescription(HistoryItem.STATE_WIFI_SCAN_FLAG, "wifi_scan", "Ws"),
         new BitDescription(HistoryItem.STATE_WIFI_MULTICAST_ON_FLAG, "wifi_multicast", "Wm"),
-        new BitDescription(HistoryItem.STATE_BLUETOOTH_ON_FLAG, "bluetooth", "b"),
+        new BitDescription(HistoryItem.STATE_WIFI_RUNNING_FLAG, "wifi_running", "Wr"),
+        new BitDescription(HistoryItem.STATE_PHONE_SCANNING_FLAG, "phone_scanning", "Psc"),
         new BitDescription(HistoryItem.STATE_AUDIO_ON_FLAG, "audio", "a"),
         new BitDescription(HistoryItem.STATE_VIDEO_ON_FLAG, "video", "v"),
-        new BitDescription(HistoryItem.STATE_WAKE_LOCK_FLAG, "wake_lock", "w"),
-        new BitDescription(HistoryItem.STATE_SENSOR_ON_FLAG, "sensor", "s"),
-        new BitDescription(HistoryItem.STATE_BRIGHTNESS_MASK,
-                HistoryItem.STATE_BRIGHTNESS_SHIFT, "brightness", "Sb",
-                SCREEN_BRIGHTNESS_NAMES, SCREEN_BRIGHTNESS_SHORT_NAMES),
+        new BitDescription(HistoryItem.STATE_SCREEN_ON_FLAG, "screen", "S"),
+        new BitDescription(HistoryItem.STATE_BATTERY_PLUGGED_FLAG, "plugged", "BP"),
+        new BitDescription(HistoryItem.STATE_PHONE_IN_CALL_FLAG, "phone_in_call", "Pcl"),
+        new BitDescription(HistoryItem.STATE_WIFI_ON_FLAG, "wifi", "W"),
+        new BitDescription(HistoryItem.STATE_BLUETOOTH_ON_FLAG, "bluetooth", "b"),
+        new BitDescription(HistoryItem.STATE_DATA_CONNECTION_MASK,
+                HistoryItem.STATE_DATA_CONNECTION_SHIFT, "data_conn", "Pcn",
+                DATA_CONNECTION_NAMES, DATA_CONNECTION_NAMES),
+        new BitDescription(HistoryItem.STATE_PHONE_STATE_MASK,
+                HistoryItem.STATE_PHONE_STATE_SHIFT, "phone_state", "Pst",
+                new String[] {"in", "out", "emergency", "off"},
+                new String[] {"in", "out", "em", "off"}),
         new BitDescription(HistoryItem.STATE_SIGNAL_STRENGTH_MASK,
                 HistoryItem.STATE_SIGNAL_STRENGTH_SHIFT, "signal_strength", "Pss",
                 SignalStrength.SIGNAL_STRENGTH_NAMES, new String[] {
                     "0", "1", "2", "3", "4"
         }),
-        new BitDescription(HistoryItem.STATE_PHONE_STATE_MASK,
-                HistoryItem.STATE_PHONE_STATE_SHIFT, "phone_state", "Pst",
-                new String[] {"in", "out", "emergency", "off"},
-                new String[] {"in", "out", "em", "off"}),
-        new BitDescription(HistoryItem.STATE_DATA_CONNECTION_MASK,
-                HistoryItem.STATE_DATA_CONNECTION_SHIFT, "data_conn", "Pcn",
-                DATA_CONNECTION_NAMES, DATA_CONNECTION_NAMES),
+        new BitDescription(HistoryItem.STATE_BRIGHTNESS_MASK,
+                HistoryItem.STATE_BRIGHTNESS_SHIFT, "brightness", "Sb",
+                SCREEN_BRIGHTNESS_NAMES, SCREEN_BRIGHTNESS_SHORT_NAMES),
+    };
+
+    public static final String[] HISTORY_EVENT_NAMES = new String[] {
+            "null", "proc", "fg", "top"
+    };
+
+    public static final String[] HISTORY_EVENT_CHECKIN_NAMES = new String[] {
+            "Nl", "Pr", "Fg", "Tp"
     };
 
     /**
@@ -2464,7 +2461,8 @@
                     else if (rec.batteryLevel < 100) pw.print("0");
                     pw.print(rec.batteryLevel);
                     pw.print(" ");
-                    if (rec.states < 0x10) pw.print("0000000");
+                    if (rec.states < 0) ;
+                    else if (rec.states < 0x10) pw.print("0000000");
                     else if (rec.states < 0x100) pw.print("000000");
                     else if (rec.states < 0x1000) pw.print("00000");
                     else if (rec.states < 0x10000) pw.print("0000");
@@ -2524,6 +2522,9 @@
                         case BatteryManager.BATTERY_HEALTH_UNSPECIFIED_FAILURE:
                             pw.print(checkin ? "f" : "failure");
                             break;
+                        case BatteryManager.BATTERY_HEALTH_COLD:
+                            pw.print(checkin ? "c" : "cold");
+                            break;
                         default:
                             pw.print(oldHealth);
                             break;
@@ -2563,25 +2564,23 @@
                 printBitDescriptions(pw, oldState, rec.states, rec.wakelockTag,
                         HISTORY_STATE_DESCRIPTIONS, !checkin);
                 if (rec.eventCode != HistoryItem.EVENT_NONE) {
-                    switch (rec.eventCode) {
-                        case HistoryItem.EVENT_PROC_STARTED:
-                            pw.print(checkin ? ",PrSt=" : " procstart=");
-                            break;
-                        case HistoryItem.EVENT_PROC_FINISHED:
-                            pw.print(checkin ? ",PrFn=" : " procfin=");
-                            break;
-                        default:
-                            if (checkin) {
-                                pw.print(",?cmd_");
-                                pw.print(rec.eventCode);
-                                pw.print("=");
-                            } else {
-                                pw.print(" cmd_");
-                                pw.print(rec.eventCode);
-                                pw.print("=");
-                            }
-                            break;
+                    pw.print(checkin ? "," : " ");
+                    if ((rec.eventCode&HistoryItem.EVENT_FLAG_START) != 0) {
+                        pw.print("+");
+                    } else if ((rec.eventCode&HistoryItem.EVENT_FLAG_FINISH) != 0) {
+                        pw.print("-");
                     }
+                    String[] eventNames = checkin ? HISTORY_EVENT_CHECKIN_NAMES
+                            : HISTORY_EVENT_NAMES;
+                    int idx = rec.eventCode & ~(HistoryItem.EVENT_FLAG_START
+                            | HistoryItem.EVENT_FLAG_FINISH);
+                    if (idx >= 0 && idx < eventNames.length) {
+                        pw.print(eventNames[idx]);
+                    } else {
+                        pw.print(checkin ? "Ev" : "event");
+                        pw.print(idx);
+                    }
+                    pw.print("=");
                     if (checkin) {
                         pw.print(rec.eventTag.poolIdx);
                     } else {
diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java
index 15a154a..dc18dee 100644
--- a/core/java/android/os/FileUtils.java
+++ b/core/java/android/os/FileUtils.java
@@ -326,14 +326,15 @@
      *
      * @param minCount Always keep at least this many files.
      * @param minAge Always keep files younger than this age.
+     * @return if any files were deleted.
      */
-    public static void deleteOlderFiles(File dir, int minCount, long minAge) {
+    public static boolean deleteOlderFiles(File dir, int minCount, long minAge) {
         if (minCount < 0 || minAge < 0) {
             throw new IllegalArgumentException("Constraints must be positive or 0");
         }
 
         final File[] files = dir.listFiles();
-        if (files == null) return;
+        if (files == null) return false;
 
         // Sort with newest files first
         Arrays.sort(files, new Comparator<File>() {
@@ -344,16 +345,20 @@
         });
 
         // Keep at least minCount files
+        boolean deleted = false;
         for (int i = minCount; i < files.length; i++) {
             final File file = files[i];
 
             // Keep files newer than minAge
             final long age = System.currentTimeMillis() - file.lastModified();
             if (age > minAge) {
-                Log.d(TAG, "Deleting old file " + file);
-                file.delete();
+                if (file.delete()) {
+                    Log.d(TAG, "Deleted old file " + file);
+                    deleted = true;
+                }
             }
         }
+        return deleted;
     }
 
     /**
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index 3c9d0d9..6e6c06d 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -28,11 +28,13 @@
  */
 interface IUserManager {
     UserInfo createUser(in String name, int flags);
+    UserInfo createRelatedUser(in String name, int flags, int relatedUserId);
     boolean removeUser(int userHandle);
     void setUserName(int userHandle, String name);
     void setUserIcon(int userHandle, in Bitmap icon);
     Bitmap getUserIcon(int userHandle);
     List<UserInfo> getUsers(boolean excludeDying);
+    List<UserInfo> getRelatedUsers(int userHandle);
     UserInfo getUserInfo(int userHandle);
     boolean isRestricted();
     void setGuestEnabled(boolean enable);
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 3a9611e..0439eeb 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -223,6 +223,13 @@
     public static final int ON_AFTER_RELEASE = 0x20000000;
 
     /**
+     * Wake lock flag: This wake lock is not important for logging events.  If a later
+     * wake lock is acquired that is important, it will be considered the one to log.
+     * @hide
+     */
+    public static final int UNIMPORTANT_FOR_LOGGING = 0x40000000;
+
+    /**
      * Flag for {@link WakeLock#release release(int)} to defer releasing a
      * {@link #PROXIMITY_SCREEN_OFF_WAKE_LOCK} wake lock until the proximity sensor returns
      * a negative value.
@@ -634,8 +641,8 @@
      * </p>
      */
     public final class WakeLock {
-        private final int mFlags;
-        private final String mTag;
+        private int mFlags;
+        private String mTag;
         private final String mPackageName;
         private final IBinder mToken;
         private int mCount;
@@ -829,6 +836,17 @@
             }
         }
 
+        /** @hide */
+        public void setTag(String tag) {
+            mTag = tag;
+        }
+
+        /** @hide */
+        public void setUnimportantForLogging(boolean state) {
+            if (state) mFlags |= UNIMPORTANT_FOR_LOGGING;
+            else mFlags &= ~UNIMPORTANT_FOR_LOGGING;
+        }
+
         @Override
         public String toString() {
             synchronized (mToken) {
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 5d087ea..8f6dda1 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -408,6 +408,27 @@
     }
 
     /**
+     * Creates a user with the specified name and options.
+     * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
+     *
+     * @param name the user's name
+     * @param flags flags that identify the type of user and other properties.
+     * @see UserInfo
+     * @param relatedUserId new user will be related to this user id.
+     *
+     * @return the UserInfo object for the created user, or null if the user could not be created.
+     * @hide
+     */
+    public UserInfo createRelatedUser(String name, int flags, int relatedUserId) {
+        try {
+            return mService.createRelatedUser(name, flags, relatedUserId);
+        } catch (RemoteException re) {
+            Log.w(TAG, "Could not create a user", re);
+            return null;
+        }
+    }
+
+    /**
      * Return the number of users currently created on the device.
      */
     public int getUserCount() {
@@ -431,6 +452,22 @@
     }
 
     /**
+     * Returns information for all users related to userId
+     * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
+     * @param userHandle users related to this user id will be returned.
+     * @return the list of related users.
+     * @hide
+     */
+    public List<UserInfo> getRelatedUsers(int userHandle) {
+        try {
+            return mService.getRelatedUsers(userHandle);
+        } catch (RemoteException re) {
+            Log.w(TAG, "Could not get user list", re);
+            return null;
+        }
+    }
+
+    /**
      * Returns information for all users on this device.
      * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
      * @param excludeDying specify if the list should exclude users being removed.
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index b9a898e..9332578 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6057,6 +6057,14 @@
          */
         public static final String WIFI_BOUNCE_DELAY_OVERRIDE_MS = "wifi_bounce_delay_override_ms";
 
+        /**
+         * Defines global runtime overrides to window policy.
+         *
+         * See {@link com.android.internal.policy.impl.PolicyControl} for value format.
+         *
+         * @hide
+         */
+        public static final String POLICY_CONTROL = "policy_control";
 
         /**
          * Settings to backup. This is here so that it's in the same place as the settings
diff --git a/core/java/android/transition/Transition.java b/core/java/android/transition/Transition.java
index da9ba5a..fd3f9b3 100644
--- a/core/java/android/transition/Transition.java
+++ b/core/java/android/transition/Transition.java
@@ -552,7 +552,8 @@
         return false;
     }
 
-    private static ArrayMap<Animator, AnimationInfo> getRunningAnimators() {
+    /** @hide */
+    public static ArrayMap<Animator, AnimationInfo> getRunningAnimators() {
         ArrayMap<Animator, AnimationInfo> runningAnimators = sRunningAnimators.get();
         if (runningAnimators == null) {
             runningAnimators = new ArrayMap<Animator, AnimationInfo>();
@@ -1077,6 +1078,9 @@
         if (view == null) {
             return;
         }
+        if (!isValidTarget(view, view.getId())) {
+            return;
+        }
         boolean isListViewItem = false;
         if (view.getParent() instanceof ListView) {
             isListViewItem = true;
@@ -1467,6 +1471,10 @@
         mCanRemoveViews = canRemoveViews;
     }
 
+    public boolean canRemoveViews() {
+        return mCanRemoveViews;
+    }
+
     @Override
     public String toString() {
         return toString("");
@@ -1629,9 +1637,10 @@
      * animation should be canceled or a new animation noop'd. The structure holds
      * information about the state that an animation is going to, to be compared to
      * end state of a new animation.
+     * @hide
      */
-    private static class AnimationInfo {
-        View view;
+    public static class AnimationInfo {
+        public View view;
         String name;
         TransitionValues values;
 
diff --git a/core/java/android/util/SparseBooleanArray.java b/core/java/android/util/SparseBooleanArray.java
index 905dcb0..f59ef0f6d 100644
--- a/core/java/android/util/SparseBooleanArray.java
+++ b/core/java/android/util/SparseBooleanArray.java
@@ -115,6 +115,13 @@
         }
     }
 
+    /** @hide */
+    public void removeAt(int index) {
+        System.arraycopy(mKeys, index + 1, mKeys, index, mSize - (index + 1));
+        System.arraycopy(mValues, index + 1, mValues, index, mSize - (index + 1));
+        mSize--;
+    }
+
     /**
      * Adds a mapping from the specified key to the specified value,
      * replacing the previous mapping from the specified key if there
@@ -191,6 +198,11 @@
         return mValues[index];
     }
 
+    /** @hide */
+    public void setValueAt(int index, boolean value) {
+        mValues[index] = value;
+    }
+
     /**
      * Returns the index for which {@link #keyAt} would return the
      * specified key, or a negative number if the specified
diff --git a/core/java/android/view/DisplayList.java b/core/java/android/view/DisplayList.java
index 8b63359..9aecbea 100644
--- a/core/java/android/view/DisplayList.java
+++ b/core/java/android/view/DisplayList.java
@@ -431,7 +431,19 @@
     }
 
     /**
-     * Sets the outline, defining the shape that casts a shadow.
+     * Sets whether the display list is a projection receiver - that its parent
+     * DisplayList should draw any descendent DisplayLists with
+     * ProjectBackwards=true directly on top of it. Default value is false.
+     */
+    public void setProjectionReceiver(boolean shouldRecieve) {
+        if (hasNativeDisplayList()) {
+            nSetProjectionReceiver(mFinalizer.mNativeDisplayList, shouldRecieve);
+        }
+    }
+
+    /**
+     * Sets the outline, defining the shape that casts a shadow, and the path to
+     * be clipped if setClipToOutline is set.
      *
      * Deep copies the native path to simplify reference ownership.
      *
@@ -445,6 +457,40 @@
     }
 
     /**
+     * Enables or disables clipping to the outline.
+     *
+     * @param clipToOutline true if clipping to the outline.
+     */
+    public void setClipToOutline(boolean clipToOutline) {
+        if (hasNativeDisplayList()) {
+            nSetClipToOutline(mFinalizer.mNativeDisplayList, clipToOutline);
+        }
+    }
+
+    /**
+     * Set whether the DisplayList should cast a shadow.
+     *
+     * The shape of the shadow casting area is defined by the outline of the display list, if set
+     * and non-empty, otherwise it will be the bounds rect.
+     */
+    public void setCastsShadow(boolean castsShadow) {
+        if (hasNativeDisplayList()) {
+            nSetCastsShadow(mFinalizer.mNativeDisplayList, castsShadow);
+        }
+    }
+
+    /**
+     * Sets whether the DisplayList should be drawn with perspective applied from the global camera.
+     *
+     * If set to true, camera distance will be ignored. Defaults to false.
+     */
+    public void setSharesGlobalCamera(boolean sharesGlobalCamera) {
+        if (hasNativeDisplayList()) {
+            nSetSharesGlobalCamera(mFinalizer.mNativeDisplayList, sharesGlobalCamera);
+        }
+    }
+
+    /**
      * Set the static matrix on the display list. The specified matrix is combined with other
      * transforms (such as {@link #setScaleX(float)}, {@link #setRotation(float)}, etc.)
      *
@@ -1065,8 +1111,12 @@
     private static native void nSetCaching(long displayList, boolean caching);
     private static native void nSetClipToBounds(long displayList, boolean clipToBounds);
     private static native void nSetProjectBackwards(long displayList, boolean shouldProject);
+    private static native void nSetProjectionReceiver(long displayList, boolean shouldRecieve);
     private static native void nSetIsolatedZVolume(long displayList, boolean isolateZVolume);
     private static native void nSetOutline(long displayList, long nativePath);
+    private static native void nSetClipToOutline(long displayList, boolean clipToOutline);
+    private static native void nSetCastsShadow(long displayList, boolean castsShadow);
+    private static native void nSetSharesGlobalCamera(long displayList, boolean sharesGlobalCamera);
     private static native void nSetAlpha(long displayList, float alpha);
     private static native void nSetHasOverlappingRendering(long displayList,
             boolean hasOverlappingRendering);
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index 3384359..2ed0cba 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -31,7 +31,6 @@
 import android.graphics.RectF;
 import android.graphics.Region;
 import android.graphics.Shader;
-import android.graphics.SurfaceTexture;
 import android.graphics.TemporaryBuffer;
 import android.text.GraphicsOperations;
 import android.text.SpannableString;
@@ -46,7 +45,6 @@
     private static final int MODIFIER_NONE = 0;
     private static final int MODIFIER_SHADOW = 1;
     private static final int MODIFIER_SHADER = 2;
-    private static final int MODIFIER_COLOR_FILTER = 4;
 
     private final boolean mOpaque;
     private long mRenderer;
@@ -88,15 +86,6 @@
     GLES20Canvas(boolean translucent) {
         this(false, translucent);
     }
-
-    /**
-     * Creates a canvas to render into an FBO.
-     */
-    GLES20Canvas(long layer, boolean translucent) {
-        mOpaque = !translucent;
-        mRenderer = nCreateLayerRenderer(layer);
-        setupFinalizer();
-    }
     
     protected GLES20Canvas(boolean record, boolean translucent) {
         mOpaque = !translucent;
@@ -123,7 +112,6 @@
     }
 
     private static native long nCreateRenderer();
-    private static native long nCreateLayerRenderer(long layer);
     private static native long nCreateDisplayListRenderer();
     private static native void nResetDisplayListRenderer(long renderer);
     private static native void nDestroyRenderer(long renderer);
@@ -157,12 +145,12 @@
 
     @Override
     void pushLayerUpdate(HardwareLayer layer) {
-        nPushLayerUpdate(mRenderer, ((GLES20RenderLayer) layer).mLayer);
+        nPushLayerUpdate(mRenderer, layer.getLayer());
     }
 
     @Override
     void cancelLayerUpdate(HardwareLayer layer) {
-        nCancelLayerUpdate(mRenderer, ((GLES20RenderLayer) layer).mLayer);
+        nCancelLayerUpdate(mRenderer, layer.getLayer());
     }
 
     @Override
@@ -175,22 +163,7 @@
         nClearLayerUpdates(mRenderer);
     }
 
-    static native long nCreateTextureLayer(boolean opaque, int[] layerInfo);
-    static native long nCreateLayer(int width, int height, boolean isOpaque, int[] layerInfo);
-    static native boolean nResizeLayer(long layerId, int width, int height, int[] layerInfo);
-    static native void nSetOpaqueLayer(long layerId, boolean isOpaque);
-    static native void nSetLayerPaint(long layerId, long nativePaint);
-    static native void nSetLayerColorFilter(long layerId, long nativeColorFilter);
-    static native void nUpdateTextureLayer(long layerId, int width, int height, boolean opaque,
-            SurfaceTexture surface);
-    static native void nClearLayerTexture(long layerId);
-    static native void nSetTextureLayerTransform(long layerId, long matrix);
-    static native void nDestroyLayer(long layerId);
-    static native void nDestroyLayerDeferred(long layerId);
-    static native void nUpdateRenderLayer(long layerId, long renderer, long displayList,
-            int left, int top, int right, int bottom);
     static native boolean nCopyLayer(long layerId, long bitmap);
-
     private static native void nClearLayerUpdates(long renderer);
     private static native void nFlushLayerUpdates(long renderer);
     private static native void nPushLayerUpdate(long renderer, long layer);
@@ -284,18 +257,6 @@
 
     private static native int nGetStencilSize();
 
-    void setCountOverdrawEnabled(boolean enabled) {
-        nSetCountOverdrawEnabled(mRenderer, enabled);
-    }
-
-    static native void nSetCountOverdrawEnabled(long renderer, boolean enabled);
-
-    float getOverdraw() {
-        return nGetOverdraw(mRenderer);
-    }
-
-    static native float nGetOverdraw(long renderer);
-
     ///////////////////////////////////////////////////////////////////////////
     // Functor
     ///////////////////////////////////////////////////////////////////////////
@@ -421,9 +382,7 @@
     
     void drawHardwareLayer(HardwareLayer layer, float x, float y, Paint paint) {
         layer.setLayerPaint(paint);
-
-        final GLES20Layer glLayer = (GLES20Layer) layer;
-        nDrawLayer(mRenderer, glLayer.getLayer(), x, y);
+        nDrawLayer(mRenderer, layer.getLayer(), x, y);
     }
 
     private static native void nDrawLayer(long renderer, long layer, float x, float y);
@@ -639,15 +598,8 @@
             return saveLayer(bounds.left, bounds.top, bounds.right, bounds.bottom, paint, saveFlags);
         }
 
-        int count;
-        int modifier = paint != null ? setupColorFilter(paint) : MODIFIER_NONE;
-        try {
-            final long nativePaint = paint == null ? 0 : paint.mNativePaint;
-            count = nSaveLayer(mRenderer, nativePaint, saveFlags);
-        } finally {
-            if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier);
-        }
-        return count;
+        final long nativePaint = paint == null ? 0 : paint.mNativePaint;
+        return nSaveLayer(mRenderer, nativePaint, saveFlags);
     }
 
     private static native int nSaveLayer(long renderer, long paint, int saveFlags);
@@ -656,15 +608,8 @@
     public int saveLayer(float left, float top, float right, float bottom, Paint paint,
             int saveFlags) {
         if (left < right && top < bottom) {
-            int count;
-            int modifier = paint != null ? setupColorFilter(paint) : MODIFIER_NONE;
-            try {
-                final long nativePaint = paint == null ? 0 : paint.mNativePaint;
-                count = nSaveLayer(mRenderer, left, top, right, bottom, nativePaint, saveFlags);
-            } finally {
-                if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier);
-            }
-            return count;
+            final long nativePaint = paint == null ? 0 : paint.mNativePaint;
+            return nSaveLayer(mRenderer, left, top, right, bottom, nativePaint, saveFlags);
         }
         return save(saveFlags);
     }
@@ -746,7 +691,7 @@
     @Override
     public void drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter,
             Paint paint) {
-        int modifiers = setupModifiers(paint, MODIFIER_COLOR_FILTER | MODIFIER_SHADER);
+        int modifiers = setupModifiers(paint, MODIFIER_SHADER);
         try {
             nDrawArc(mRenderer, oval.left, oval.top, oval.right, oval.bottom,
                     startAngle, sweepAngle, useCenter, paint.mNativePaint);
@@ -769,14 +714,9 @@
         Bitmap bitmap = patch.getBitmap();
         throwIfCannotDraw(bitmap);
         // Shaders are ignored when drawing patches
-        int modifier = paint != null ? setupColorFilter(paint) : MODIFIER_NONE;
-        try {
-            final long nativePaint = paint == null ? 0 : paint.mNativePaint;
-            nDrawPatch(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, patch.mNativeChunk,
-                    dst.left, dst.top, dst.right, dst.bottom, nativePaint);
-        } finally {
-            if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier);
-        }
+        final long nativePaint = paint == null ? 0 : paint.mNativePaint;
+        nDrawPatch(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, patch.mNativeChunk,
+                dst.left, dst.top, dst.right, dst.bottom, nativePaint);
     }
 
     @Override
@@ -784,14 +724,9 @@
         Bitmap bitmap = patch.getBitmap();
         throwIfCannotDraw(bitmap);
         // Shaders are ignored when drawing patches
-        int modifier = paint != null ? setupColorFilter(paint) : MODIFIER_NONE;
-        try {
-            final long nativePaint = paint == null ? 0 : paint.mNativePaint;
-            nDrawPatch(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, patch.mNativeChunk,
-                    dst.left, dst.top, dst.right, dst.bottom, nativePaint);
-        } finally {
-            if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier);
-        }
+        final long nativePaint = paint == null ? 0 : paint.mNativePaint;
+        nDrawPatch(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, patch.mNativeChunk,
+                dst.left, dst.top, dst.right, dst.bottom, nativePaint);
     }
 
     private static native void nDrawPatch(long renderer, long bitmap, byte[] buffer, long chunk,
@@ -912,14 +847,9 @@
         }
 
         // Shaders are ignored when drawing bitmaps
-        int modifier = paint != null ? setupColorFilter(paint) : MODIFIER_NONE;
-        try {
-            final long nativePaint = paint == null ? 0 : paint.mNativePaint;
-            nDrawBitmap(mRenderer, colors, offset, stride, x, y,
-                    width, height, hasAlpha, nativePaint);
-        } finally {
-            if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier);
-        }
+        final long nativePaint = paint == null ? 0 : paint.mNativePaint;
+        nDrawBitmap(mRenderer, colors, offset, stride, x, y,
+                width, height, hasAlpha, nativePaint);
     }
 
     private static native void nDrawBitmap(long renderer, int[] colors, int offset, int stride,
@@ -967,7 +897,7 @@
 
     @Override
     public void drawCircle(float cx, float cy, float radius, Paint paint) {
-        int modifiers = setupModifiers(paint, MODIFIER_COLOR_FILTER | MODIFIER_SHADER);
+        int modifiers = setupModifiers(paint, MODIFIER_SHADER);
         try {
             nDrawCircle(mRenderer, cx, cy, radius, paint.mNativePaint);
         } finally {
@@ -1007,7 +937,7 @@
         if ((offset | count) < 0 || offset + count > pts.length) {
             throw new IllegalArgumentException("The lines array must contain 4 elements per line.");
         }
-        int modifiers = setupModifiers(paint, MODIFIER_COLOR_FILTER | MODIFIER_SHADER);
+        int modifiers = setupModifiers(paint, MODIFIER_SHADER);
         try {
             nDrawLines(mRenderer, pts, offset, count, paint.mNativePaint);
         } finally {
@@ -1025,7 +955,7 @@
 
     @Override
     public void drawOval(RectF oval, Paint paint) {
-        int modifiers = setupModifiers(paint, MODIFIER_COLOR_FILTER | MODIFIER_SHADER);
+        int modifiers = setupModifiers(paint, MODIFIER_SHADER);
         try {
             nDrawOval(mRenderer, oval.left, oval.top, oval.right, oval.bottom, paint.mNativePaint);
         } finally {
@@ -1045,7 +975,7 @@
 
     @Override
     public void drawPath(Path path, Paint paint) {
-        int modifiers = setupModifiers(paint, MODIFIER_COLOR_FILTER | MODIFIER_SHADER);
+        int modifiers = setupModifiers(paint, MODIFIER_SHADER);
         try {
             if (path.isSimplePath) {
                 if (path.rects != null) {
@@ -1063,7 +993,7 @@
     private static native void nDrawRects(long renderer, long region, long paint);
 
     void drawRects(float[] rects, int count, Paint paint) {
-        int modifiers = setupModifiers(paint, MODIFIER_COLOR_FILTER | MODIFIER_SHADER);
+        int modifiers = setupModifiers(paint, MODIFIER_SHADER);
         try {
             nDrawRects(mRenderer, rects, count, paint.mNativePaint);
         } finally {
@@ -1130,7 +1060,7 @@
     public void drawPoints(float[] pts, int offset, int count, Paint paint) {
         if (count < 2) return;
 
-        int modifiers = setupModifiers(paint, MODIFIER_COLOR_FILTER | MODIFIER_SHADER);
+        int modifiers = setupModifiers(paint, MODIFIER_SHADER);
         try {
             nDrawPoints(mRenderer, pts, offset, count, paint.mNativePaint);
         } finally {
@@ -1180,7 +1110,7 @@
     @Override
     public void drawRect(float left, float top, float right, float bottom, Paint paint) {
         if (left == right || top == bottom) return;
-        int modifiers = setupModifiers(paint, MODIFIER_COLOR_FILTER | MODIFIER_SHADER);
+        int modifiers = setupModifiers(paint, MODIFIER_SHADER);
         try {
             nDrawRect(mRenderer, left, top, right, bottom, paint.mNativePaint);
         } finally {
@@ -1208,7 +1138,7 @@
 
     @Override
     public void drawRoundRect(RectF rect, float rx, float ry, Paint paint) {
-        int modifiers = setupModifiers(paint, MODIFIER_COLOR_FILTER | MODIFIER_SHADER);
+        int modifiers = setupModifiers(paint, MODIFIER_SHADER);
         try {
             nDrawRoundRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom,
                     rx, ry, paint.mNativePaint);
@@ -1388,12 +1318,6 @@
 
     private int setupModifiers(Bitmap b, Paint paint) {
         if (b.getConfig() != Bitmap.Config.ALPHA_8) {
-            final ColorFilter filter = paint.getColorFilter();
-            if (filter != null) {
-                nSetupColorFilter(mRenderer, filter.nativeColorFilter);
-                return MODIFIER_COLOR_FILTER;
-            }
-
             return MODIFIER_NONE;
         } else {
             return setupModifiers(paint);
@@ -1415,12 +1339,6 @@
             modifiers |= MODIFIER_SHADER;
         }
 
-        final ColorFilter filter = paint.getColorFilter();
-        if (filter != null) {
-            nSetupColorFilter(mRenderer, filter.nativeColorFilter);
-            modifiers |= MODIFIER_COLOR_FILTER;
-        }
-
         return modifiers;
     }
 
@@ -1439,26 +1357,10 @@
             modifiers |= MODIFIER_SHADER;
         }
 
-        final ColorFilter filter = paint.getColorFilter();
-        if (filter != null && (flags & MODIFIER_COLOR_FILTER) != 0) {
-            nSetupColorFilter(mRenderer, filter.nativeColorFilter);
-            modifiers |= MODIFIER_COLOR_FILTER;
-        }
-
         return modifiers;
     }
 
-    private int setupColorFilter(Paint paint) {
-        final ColorFilter filter = paint.getColorFilter();
-        if (filter != null) {
-            nSetupColorFilter(mRenderer, filter.nativeColorFilter);
-            return MODIFIER_COLOR_FILTER;
-        }
-        return MODIFIER_NONE;
-    }
-
     private static native void nSetupShader(long renderer, long shader);
-    private static native void nSetupColorFilter(long renderer, long colorFilter);
     private static native void nSetupShadow(long renderer, float radius,
             float dx, float dy, int color);
 
diff --git a/core/java/android/view/GLES20Layer.java b/core/java/android/view/GLES20Layer.java
deleted file mode 100644
index 37154eb..0000000
--- a/core/java/android/view/GLES20Layer.java
+++ /dev/null
@@ -1,100 +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 android.view;
-
-import android.graphics.Bitmap;
-import android.graphics.Paint;
-
-/**
- * An OpenGL ES 2.0 implementation of {@link HardwareLayer}.
- */
-abstract class GLES20Layer extends HardwareLayer {
-    long mLayer;
-    Finalizer mFinalizer;
-
-    GLES20Layer() {
-    }
-
-    GLES20Layer(int width, int height, boolean opaque) {
-        super(width, height, opaque);
-    }
-
-    /**
-     * Returns the native layer object used to render this layer.
-     * 
-     * @return A pointer to the native layer object, or 0 if the object is NULL
-     */
-    public long getLayer() {
-        return mLayer;
-    }
-
-    @Override
-    void setLayerPaint(Paint paint) {
-        if (paint != null) {
-            GLES20Canvas.nSetLayerPaint(mLayer, paint.mNativePaint);
-            GLES20Canvas.nSetLayerColorFilter(mLayer, paint.getColorFilter() != null ?
-                    paint.getColorFilter().nativeColorFilter : 0);
-        }
-    }
-
-    @Override
-    public boolean copyInto(Bitmap bitmap) {
-        return GLES20Canvas.nCopyLayer(mLayer, bitmap.mNativeBitmap);
-    }
-
-    @Override
-    public void destroy() {
-        if (mDisplayList != null) {
-            mDisplayList.reset();
-        }
-        if (mFinalizer != null) {
-            mFinalizer.destroy();
-            mFinalizer = null;
-        }
-        mLayer = 0;
-    }
-
-    @Override
-    void clearStorage() {
-        if (mLayer != 0) GLES20Canvas.nClearLayerTexture(mLayer);
-    }
-
-    static class Finalizer {
-        private long mLayerId;
-
-        public Finalizer(long layerId) {
-            mLayerId = layerId;
-        }
-
-        @Override
-        protected void finalize() throws Throwable {
-            try {
-                if (mLayerId != 0) {
-                    GLES20Canvas.nDestroyLayerDeferred(mLayerId);
-                }
-            } finally {
-                super.finalize();
-            }
-        }
-
-        void destroy() {
-            GLES20Canvas.nDestroyLayer(mLayerId);
-            mLayerId = 0;
-        }
-    }
-}
diff --git a/core/java/android/view/GLES20RenderLayer.java b/core/java/android/view/GLES20RenderLayer.java
deleted file mode 100644
index 8c97867..0000000
--- a/core/java/android/view/GLES20RenderLayer.java
+++ /dev/null
@@ -1,130 +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 android.view;
-
-import android.graphics.Canvas;
-import android.graphics.Matrix;
-import android.graphics.Rect;
-
-/**
- * An OpenGL ES 2.0 implementation of {@link HardwareLayer}. This
- * implementation can be used a rendering target. It generates a
- * {@link Canvas} that can be used to render into an FBO using OpenGL.
- */
-class GLES20RenderLayer extends GLES20Layer {
-    private int mLayerWidth;
-    private int mLayerHeight;
-
-    private final GLES20Canvas mCanvas;
-
-    GLES20RenderLayer(int width, int height, boolean isOpaque) {
-        super(width, height, isOpaque);
-
-        int[] layerInfo = new int[2];
-        mLayer = GLES20Canvas.nCreateLayer(width, height, isOpaque, layerInfo);
-        if (mLayer != 0) {
-            mLayerWidth = layerInfo[0];
-            mLayerHeight = layerInfo[1];
-
-            mCanvas = new GLES20Canvas(mLayer, !isOpaque);
-            mFinalizer = new Finalizer(mLayer);
-        } else {
-            mCanvas = null;
-            mFinalizer = null;
-        }
-    }
-
-    @Override
-    boolean isValid() {
-        return mLayer != 0 && mLayerWidth > 0 && mLayerHeight > 0;
-    }
-
-    @Override
-    boolean resize(int width, int height) {
-        if (!isValid() || width <= 0 || height <= 0) return false;
-
-        mWidth = width;
-        mHeight = height;
-        
-        if (width != mLayerWidth || height != mLayerHeight) {
-            int[] layerInfo = new int[2];
-
-            if (GLES20Canvas.nResizeLayer(mLayer, width, height, layerInfo)) {
-                mLayerWidth = layerInfo[0];
-                mLayerHeight = layerInfo[1];
-            } else {
-                // Failure: not enough GPU resources for requested size
-                mLayer = 0;
-                mLayerWidth = 0;
-                mLayerHeight = 0;
-            }
-        }
-        return isValid();
-    }
-
-    @Override
-    void setOpaque(boolean isOpaque) {
-        mOpaque = isOpaque;
-        GLES20Canvas.nSetOpaqueLayer(mLayer, isOpaque);
-    }
-
-    @Override
-    HardwareCanvas getCanvas() {
-        return mCanvas;
-    }
-
-    @Override
-    void end(Canvas currentCanvas) {
-        HardwareCanvas canvas = getCanvas();
-        if (canvas != null) {
-            canvas.onPostDraw();
-        }
-        if (currentCanvas instanceof GLES20Canvas) {
-            ((GLES20Canvas) currentCanvas).resume();
-        }
-    }
-
-    @Override
-    HardwareCanvas start(Canvas currentCanvas) {
-        return start(currentCanvas, null);
-    }
-
-    @Override
-    HardwareCanvas start(Canvas currentCanvas, Rect dirty) {
-        if (currentCanvas instanceof GLES20Canvas) {
-            ((GLES20Canvas) currentCanvas).interrupt();
-        }
-        HardwareCanvas canvas = getCanvas();
-        canvas.setViewport(mWidth, mHeight);
-        canvas.onPreDraw(dirty);
-        return canvas;
-    }
-
-    /**
-     * Ignored
-     */
-    @Override
-    void setTransform(Matrix matrix) {
-    }
-
-    @Override
-    void redrawLater(DisplayList displayList, Rect dirtyRect) {
-        GLES20Canvas.nUpdateRenderLayer(mLayer, mCanvas.getRenderer(),
-                displayList.getNativeDisplayList(),
-                dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom);
-    }
-}
diff --git a/core/java/android/view/GLES20TextureLayer.java b/core/java/android/view/GLES20TextureLayer.java
deleted file mode 100644
index bb5a6eb..0000000
--- a/core/java/android/view/GLES20TextureLayer.java
+++ /dev/null
@@ -1,108 +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 android.view;
-
-import android.graphics.Canvas;
-import android.graphics.Matrix;
-import android.graphics.Rect;
-import android.graphics.SurfaceTexture;
-
-/**
- * An OpenGL ES 2.0 implementation of {@link HardwareLayer}. This
- * implementation can be used as a texture. Rendering into this
- * layer is not controlled by a {@link HardwareCanvas}.
- */
-class GLES20TextureLayer extends GLES20Layer {
-    private int mTexture;
-    private SurfaceTexture mSurface;
-
-    GLES20TextureLayer(boolean isOpaque) {
-        int[] layerInfo = new int[2];
-        mLayer = GLES20Canvas.nCreateTextureLayer(isOpaque, layerInfo);
-
-        if (mLayer != 0) {
-            mTexture = layerInfo[0];
-            mFinalizer = new Finalizer(mLayer);
-        } else {
-            mFinalizer = null;
-        }
-    }
-
-    @Override
-    boolean isValid() {
-        return mLayer != 0 && mTexture != 0;
-    }
-
-    @Override
-    boolean resize(int width, int height) {
-        return isValid();
-    }
-
-    @Override
-    HardwareCanvas getCanvas() {
-        return null;
-    }
-
-    @Override
-    HardwareCanvas start(Canvas currentCanvas) {
-        return null;
-    }
-
-    @Override
-    HardwareCanvas start(Canvas currentCanvas, Rect dirty) {
-        return null;
-    }
-
-    @Override
-    void end(Canvas currentCanvas) {
-    }
-
-    SurfaceTexture getSurfaceTexture() {
-        if (mSurface == null) {
-            mSurface = new SurfaceTexture(mTexture);
-        }
-        return mSurface;
-    }
-
-    void setSurfaceTexture(SurfaceTexture surfaceTexture) {
-        if (mSurface != null) {
-            mSurface.release();
-        }
-        mSurface = surfaceTexture;
-        mSurface.attachToGLContext(mTexture);
-    }
-
-    @Override
-    void update(int width, int height, boolean isOpaque) {
-        super.update(width, height, isOpaque);
-        GLES20Canvas.nUpdateTextureLayer(mLayer, width, height, isOpaque, mSurface);
-    }
-
-    @Override
-    void setOpaque(boolean isOpaque) {
-        throw new UnsupportedOperationException("Use update(int, int, boolean) instead");
-    }
-
-    @Override
-    void setTransform(Matrix matrix) {
-        GLES20Canvas.nSetTextureLayerTransform(mLayer, matrix.native_instance);
-    }
-
-    @Override
-    void redrawLater(DisplayList displayList, Rect dirtyRect) {
-    }
-}
diff --git a/core/java/android/view/GLRenderer.java b/core/java/android/view/GLRenderer.java
index 449bad6..40ad72c 100644
--- a/core/java/android/view/GLRenderer.java
+++ b/core/java/android/view/GLRenderer.java
@@ -40,7 +40,7 @@
 import static javax.microedition.khronos.egl.EGL10.EGL_WINDOW_BIT;
 
 import android.content.ComponentCallbacks2;
-import android.graphics.Color;
+import android.graphics.Bitmap;
 import android.graphics.Paint;
 import android.graphics.Rect;
 import android.graphics.SurfaceTexture;
@@ -62,6 +62,8 @@
 import com.google.android.gles_jni.EGLImpl;
 
 import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.concurrent.locks.ReentrantLock;
 
 import javax.microedition.khronos.egl.EGL10;
@@ -109,9 +111,7 @@
 
     private static final String[] OVERDRAW = {
             OVERDRAW_PROPERTY_SHOW,
-            OVERDRAW_PROPERTY_COUNT
     };
-    private static final int OVERDRAW_TYPE_COUNT = 1;
     private static final int GL_VERSION = 2;
 
     static EGL10 sEgl;
@@ -160,8 +160,6 @@
 
     boolean mDebugDirtyRegions;
     int mDebugOverdraw = -1;
-    HardwareLayer mDebugOverdrawLayer;
-    Paint mDebugOverdrawPaint;
 
     final boolean mTranslucent;
 
@@ -181,6 +179,8 @@
     private static EGLSurface sPbuffer;
     private static final Object[] sPbufferLock = new Object[0];
 
+    private List<HardwareLayer> mAttachedLayers = new ArrayList<HardwareLayer>();
+
     private static class GLRendererEglContext extends ManagedEGLContext {
         final Handler mHandler = new Handler();
 
@@ -476,41 +476,40 @@
     }
 
     @Override
-    void cancelLayerUpdate(HardwareLayer layer) {
-        mGlCanvas.cancelLayerUpdate(layer);
-    }
-
-    @Override
     void flushLayerUpdates() {
         mGlCanvas.flushLayerUpdates();
     }
 
     @Override
-    HardwareLayer createHardwareLayer(boolean isOpaque) {
-        return new GLES20TextureLayer(isOpaque);
+    HardwareLayer createTextureLayer() {
+        return HardwareLayer.createTextureLayer(this);
     }
 
     @Override
-    public HardwareLayer createHardwareLayer(int width, int height, boolean isOpaque) {
-        return new GLES20RenderLayer(width, height, isOpaque);
+    public HardwareLayer createDisplayListLayer(int width, int height) {
+        return HardwareLayer.createRenderLayer(this, width, height);
     }
 
-    void countOverdraw(HardwareCanvas canvas) {
-        ((GLES20Canvas) canvas).setCountOverdrawEnabled(true);
+    @Override
+    void onLayerCreated(HardwareLayer hardwareLayer) {
+        mAttachedLayers.add(hardwareLayer);
     }
 
-    float getOverdraw(HardwareCanvas canvas) {
-        return ((GLES20Canvas) canvas).getOverdraw();
+    @Override
+    void onLayerDestroyed(HardwareLayer layer) {
+        mGlCanvas.cancelLayerUpdate(layer);
+        mAttachedLayers.remove(layer);
     }
 
     @Override
     public SurfaceTexture createSurfaceTexture(HardwareLayer layer) {
-        return ((GLES20TextureLayer) layer).getSurfaceTexture();
+        return layer.createSurfaceTexture();
     }
 
     @Override
-    void setSurfaceTexture(HardwareLayer layer, SurfaceTexture surfaceTexture) {
-        ((GLES20TextureLayer) layer).setSurfaceTexture(surfaceTexture);
+    boolean copyLayerInto(HardwareLayer layer, Bitmap bitmap) {
+        layer.flushChanges();
+        return GLES20Canvas.nCopyLayer(layer.getLayer(), bitmap.mNativeBitmap);
     }
 
     @Override
@@ -706,14 +705,6 @@
         if (debugOverdraw != mDebugOverdraw) {
             changed = true;
             mDebugOverdraw = debugOverdraw;
-
-            if (mDebugOverdraw != OVERDRAW_TYPE_COUNT) {
-                if (mDebugOverdrawLayer != null) {
-                    mDebugOverdrawLayer.destroy();
-                    mDebugOverdrawLayer = null;
-                    mDebugOverdrawPaint = null;
-                }
-            }
         }
 
         if (loadProperties()) {
@@ -1147,6 +1138,8 @@
 
                 DisplayList displayList = buildDisplayList(view, canvas);
 
+                flushLayerChanges();
+
                 // buildDisplayList() calls into user code which can cause
                 // an eglMakeCurrent to happen with a different surface/context.
                 // We must therefore check again here.
@@ -1182,7 +1175,6 @@
                     if (mDrawDelta > 0) {
                         mFrameCount++;
 
-                        debugOverdraw(attachInfo, dirty, canvas, displayList);
                         debugDirtyRegions(dirty, canvas);
                         drawProfileData(attachInfo);
                     }
@@ -1201,55 +1193,20 @@
         }
     }
 
-    private void debugOverdraw(View.AttachInfo attachInfo, Rect dirty,
-            HardwareCanvas canvas, DisplayList displayList) {
-
-        if (mDebugOverdraw == OVERDRAW_TYPE_COUNT) {
-            if (mDebugOverdrawLayer == null) {
-                mDebugOverdrawLayer = createHardwareLayer(mWidth, mHeight, true);
-            } else if (mDebugOverdrawLayer.getWidth() != mWidth ||
-                    mDebugOverdrawLayer.getHeight() != mHeight) {
-                mDebugOverdrawLayer.resize(mWidth, mHeight);
+    private void flushLayerChanges() {
+        // Loop through and apply any pending layer changes
+        for (int i = 0; i < mAttachedLayers.size(); i++) {
+            HardwareLayer layer = mAttachedLayers.get(i);
+            layer.flushChanges();
+            if (!layer.isValid()) {
+                // The layer was removed from mAttachedLayers, rewind i by 1
+                // Note that this shouldn't actually happen as View.getHardwareLayer()
+                // is already flushing for error checking reasons
+                i--;
             }
-
-            if (!mDebugOverdrawLayer.isValid()) {
-                mDebugOverdraw = -1;
-                return;
-            }
-
-            HardwareCanvas layerCanvas = mDebugOverdrawLayer.start(canvas, dirty);
-            countOverdraw(layerCanvas);
-            final int restoreCount = layerCanvas.save();
-            layerCanvas.drawDisplayList(displayList, null, DisplayList.FLAG_CLIP_CHILDREN);
-            layerCanvas.restoreToCount(restoreCount);
-            mDebugOverdrawLayer.end(canvas);
-
-            float overdraw = getOverdraw(layerCanvas);
-            DisplayMetrics metrics = attachInfo.mRootView.getResources().getDisplayMetrics();
-
-            drawOverdrawCounter(canvas, overdraw, metrics.density);
         }
     }
 
-    private void drawOverdrawCounter(HardwareCanvas canvas, float overdraw, float density) {
-        final String text = String.format("%.2fx", overdraw);
-        final Paint paint = setupPaint(density);
-        // HSBtoColor will clamp the values in the 0..1 range
-        paint.setColor(Color.HSBtoColor(0.28f - 0.28f * overdraw / 3.5f, 0.8f, 1.0f));
-
-        canvas.drawText(text, density * 4.0f, mHeight - paint.getFontMetrics().bottom, paint);
-    }
-
-    private Paint setupPaint(float density) {
-        if (mDebugOverdrawPaint == null) {
-            mDebugOverdrawPaint = new Paint();
-            mDebugOverdrawPaint.setAntiAlias(true);
-            mDebugOverdrawPaint.setShadowLayer(density * 3.0f, 0.0f, 0.0f, 0xff000000);
-            mDebugOverdrawPaint.setTextSize(density * 20.0f);
-        }
-        return mDebugOverdrawPaint;
-    }
-
     private DisplayList buildDisplayList(View view, HardwareCanvas canvas) {
         if (mDrawDelta <= 0) {
             return view.mDisplayList;
diff --git a/core/java/android/view/HardwareLayer.java b/core/java/android/view/HardwareLayer.java
index 23383d9..9bbcf7c 100644
--- a/core/java/android/view/HardwareLayer.java
+++ b/core/java/android/view/HardwareLayer.java
@@ -17,10 +17,10 @@
 package android.view;
 
 import android.graphics.Bitmap;
-import android.graphics.Canvas;
 import android.graphics.Matrix;
 import android.graphics.Paint;
 import android.graphics.Rect;
+import android.graphics.SurfaceTexture;
 
 /**
  * A hardware layer can be used to render graphics operations into a hardware
@@ -28,38 +28,35 @@
  * would use a Frame Buffer Object (FBO.) The hardware layer can be used as
  * a drawing cache when a complex set of graphics operations needs to be
  * drawn several times.
+ *
+ * @hide
  */
-abstract class HardwareLayer {
-    /**
-     * Indicates an unknown dimension (width or height.)
-     */
-    static final int DIMENSION_UNDEFINED = -1;
-    
-    int mWidth;
-    int mHeight;
-    DisplayList mDisplayList;
+final class HardwareLayer {
+    private static final int LAYER_TYPE_TEXTURE = 1;
+    private static final int LAYER_TYPE_RENDER = 2;
 
-    boolean mOpaque;
+    private HardwareRenderer mRenderer;
+    private Finalizer mFinalizer;
+    private DisplayList mDisplayList;
+    private final int mLayerType;
 
-    /**
-     * Creates a new hardware layer with undefined dimensions.
-     */
-    HardwareLayer() {
-        this(DIMENSION_UNDEFINED, DIMENSION_UNDEFINED, false);
+    private HardwareLayer(HardwareRenderer renderer, long deferredUpdater, int type) {
+        if (renderer == null || deferredUpdater == 0) {
+            throw new IllegalArgumentException("Either hardware renderer: " + renderer
+                    + " or deferredUpdater: " + deferredUpdater + " is invalid");
+        }
+        mRenderer = renderer;
+        mLayerType = type;
+        mFinalizer = new Finalizer(deferredUpdater);
+
+        // Layer is considered initialized at this point, notify the HardwareRenderer
+        mRenderer.onLayerCreated(this);
     }
 
-    /**
-     * Creates a new hardware layer at least as large as the supplied
-     * dimensions.
-     * 
-     * @param width The minimum width of the layer
-     * @param height The minimum height of the layer
-     * @param isOpaque Whether the layer should be opaque or not
-     */
-    HardwareLayer(int width, int height, boolean isOpaque) {
-        mWidth = width;
-        mHeight = height;
-        mOpaque = isOpaque;
+    private void assertType(int type) {
+        if (mLayerType != type) {
+            throw new IllegalAccessError("Method not appropriate for this layer type! " + mLayerType);
+        }
     }
 
     /**
@@ -68,158 +65,225 @@
      * @param paint The paint used when the layer is drawn into the destination canvas.
      * @see View#setLayerPaint(android.graphics.Paint)
      */
-    void setLayerPaint(Paint paint) { }
-
-    /**
-     * Returns the minimum width of the layer.
-     * 
-     * @return The minimum desired width of the hardware layer 
-     */
-    int getWidth() {
-        return mWidth;
+    public void setLayerPaint(Paint paint) {
+        nSetLayerPaint(mFinalizer.mDeferredUpdater, paint.mNativePaint,
+                paint.getColorFilter() != null ? paint.getColorFilter().native_instance : 0);
     }
 
     /**
-     * Returns the minimum height of the layer.
-     * 
-     * @return The minimum desired height of the hardware layer 
-     */
-    int getHeight() {
-        return mHeight;
-    }
-
-    /**
-     * Returns the DisplayList for the layer.
-     *
-     * @return The DisplayList of the hardware layer
-     */
-    DisplayList getDisplayList() {
-        return mDisplayList;
-    }
-
-    /**
-     * Sets the DisplayList for the layer.
-     *
-     * @param displayList The new DisplayList for this layer
-     */
-    void setDisplayList(DisplayList displayList) {
-        mDisplayList = displayList;
-    }
-
-    /**
-     * Returns whether or not this layer is opaque.
-     * 
-     * @return True if the layer is opaque, false otherwise
-     */
-    boolean isOpaque() {
-        return mOpaque;
-    }
-
-    /**
-     * Sets whether or not this layer should be considered opaque.
-     * 
-     * @param isOpaque True if the layer is opaque, false otherwise
-     */
-    abstract void setOpaque(boolean isOpaque);
-
-    /**
      * Indicates whether this layer can be rendered.
-     * 
+     *
      * @return True if the layer can be rendered into, false otherwise
      */
-    abstract boolean isValid();
+    public boolean isValid() {
+        return mFinalizer != null && mFinalizer.mDeferredUpdater != 0;
+    }
 
     /**
-     * Resize the layer, if necessary, to be at least as large
-     * as the supplied dimensions.
-     * 
-     * @param width The new desired minimum width for this layer
-     * @param height The new desired minimum height for this layer
-     * @return True if the resulting layer is valid, false otherwise
+     * Destroys resources without waiting for a GC.
      */
-    abstract boolean resize(int width, int height);
+    public void destroy() {
+        if (!isValid()) {
+            // Already destroyed
+            return;
+        }
+
+        if (mDisplayList != null) {
+            mDisplayList.reset();
+            mDisplayList = null;
+        }
+        if (mRenderer != null) {
+            mRenderer.onLayerDestroyed(this);
+            mRenderer = null;
+        }
+        doDestroyLayerUpdater();
+    }
 
     /**
-     * Returns a hardware canvas that can be used to render onto
-     * this layer.
-     * 
-     * @return A hardware canvas, or null if a canvas cannot be created
+     * Destroys the deferred layer updater but not the backing layer. The
+     * backing layer is instead returned and is the caller's responsibility
+     * to destroy/recycle as appropriate.
      *
-     * @see #start(android.graphics.Canvas)
-     * @see #end(android.graphics.Canvas)
+     * It is safe to call this in onLayerDestroyed only
      */
-    abstract HardwareCanvas getCanvas();
+    public long detachBackingLayer() {
+        long backingLayer = nDetachBackingLayer(mFinalizer.mDeferredUpdater);
+        doDestroyLayerUpdater();
+        return backingLayer;
+    }
 
-    /**
-     * Destroys resources without waiting for a GC. 
-     */
-    abstract void destroy();
+    private void doDestroyLayerUpdater() {
+        if (mFinalizer != null) {
+            mFinalizer.destroy();
+            mFinalizer = null;
+        }
+    }
 
-    /**
-     * This must be invoked before drawing onto this layer.
-     *
-     * @param currentCanvas The canvas whose rendering needs to be interrupted
-     */
-    abstract HardwareCanvas start(Canvas currentCanvas);
+    public DisplayList startRecording() {
+        assertType(LAYER_TYPE_RENDER);
 
-    /**
-     * This must be invoked before drawing onto this layer.
-     *
-     * @param dirty The dirty area to repaint
-     * @param currentCanvas The canvas whose rendering needs to be interrupted
-     */
-    abstract HardwareCanvas start(Canvas currentCanvas, Rect dirty);
+        if (mDisplayList == null) {
+            mDisplayList = DisplayList.create("HardwareLayer");
+        }
+        return mDisplayList;
+    }
 
-    /**
-     * This must be invoked after drawing onto this layer.
-     *
-     * @param currentCanvas The canvas whose rendering needs to be resumed
-     */
-    abstract void end(Canvas currentCanvas);
+    public void endRecording(Rect dirtyRect) {
+        nUpdateRenderLayer(mFinalizer.mDeferredUpdater, mDisplayList.getNativeDisplayList(),
+                dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom);
+        mRenderer.pushLayerUpdate(this);
+    }
 
     /**
      * Copies this layer into the specified bitmap.
-     * 
+     *
      * @param bitmap The bitmap to copy they layer into
-     * 
+     *
      * @return True if the copy was successful, false otherwise
      */
-    abstract boolean copyInto(Bitmap bitmap);
+    public boolean copyInto(Bitmap bitmap) {
+        return mRenderer.copyLayerInto(this, bitmap);
+    }
 
     /**
-     * Update the layer's properties. This method should be used
-     * when the underlying storage is modified by an external entity.
-     * To change the underlying storage, use the {@link #resize(int, int)}
-     * method instead.
-     * 
+     * Update the layer's properties. Note that after calling this isValid() may
+     * return false if the requested width/height cannot be satisfied
+     *
      * @param width The new width of this layer
      * @param height The new height of this layer
      * @param isOpaque Whether this layer is opaque
+     *
+     * @return true if the layer's properties will change, false if they already
+     *         match the desired values.
      */
-    void update(int width, int height, boolean isOpaque) {
-        mWidth = width;
-        mHeight = height;
-        mOpaque = isOpaque;
+    public boolean prepare(int width, int height, boolean isOpaque) {
+        return nPrepare(mFinalizer.mDeferredUpdater, width, height, isOpaque);
     }
 
     /**
      * Sets an optional transform on this layer.
-     * 
+     *
      * @param matrix The transform to apply to the layer.
      */
-    abstract void setTransform(Matrix matrix);
+    public void setTransform(Matrix matrix) {
+        nSetTransform(mFinalizer.mDeferredUpdater, matrix.native_instance);
+    }
 
     /**
-     * Specifies the display list to use to refresh the layer.
-     *
-     * @param displayList The display list containing the drawing commands to
-     *                    execute in this layer
-     * @param dirtyRect The dirty region of the layer that needs to be redrawn
+     * Indicates that this layer has lost its texture.
      */
-    abstract void redrawLater(DisplayList displayList, Rect dirtyRect);
+    public void onTextureDestroyed() {
+        assertType(LAYER_TYPE_TEXTURE);
+        nOnTextureDestroyed(mFinalizer.mDeferredUpdater);
+    }
 
     /**
-     * Indicates that this layer has lost its underlying storage.
+     * This exists to minimize impact into the current HardwareLayer paths as
+     * some of the specifics of how to handle error cases in the fully
+     * deferred model will work
      */
-    abstract void clearStorage();
+    @Deprecated
+    public void flushChanges() {
+        if (HardwareRenderer.sUseRenderThread) {
+            // Not supported, don't try.
+            return;
+        }
+
+        boolean success = nFlushChanges(mFinalizer.mDeferredUpdater);
+        if (!success) {
+            destroy();
+        }
+    }
+
+    public long getLayer() {
+        return nGetLayer(mFinalizer.mDeferredUpdater);
+    }
+
+    public void setSurfaceTexture(SurfaceTexture surface) {
+        assertType(LAYER_TYPE_TEXTURE);
+        nSetSurfaceTexture(mFinalizer.mDeferredUpdater, surface, false);
+    }
+
+    public void updateSurfaceTexture() {
+        assertType(LAYER_TYPE_TEXTURE);
+        nUpdateSurfaceTexture(mFinalizer.mDeferredUpdater);
+    }
+
+    /**
+     * This should only be used by HardwareRenderer! Do not call directly
+     */
+    SurfaceTexture createSurfaceTexture() {
+        assertType(LAYER_TYPE_TEXTURE);
+        SurfaceTexture st = new SurfaceTexture(nGetTexName(mFinalizer.mDeferredUpdater));
+        nSetSurfaceTexture(mFinalizer.mDeferredUpdater, st, true);
+        return st;
+    }
+
+    /**
+     * This should only be used by HardwareRenderer! Do not call directly
+     */
+    static HardwareLayer createTextureLayer(HardwareRenderer renderer) {
+        return new HardwareLayer(renderer, nCreateTextureLayer(), LAYER_TYPE_TEXTURE);
+    }
+
+    /**
+     * This should only be used by HardwareRenderer! Do not call directly
+     */
+    static HardwareLayer createRenderLayer(HardwareRenderer renderer,
+            int width, int height) {
+        return new HardwareLayer(renderer, nCreateRenderLayer(width, height), LAYER_TYPE_RENDER);
+    }
+
+    /** This also creates the underlying layer */
+    private static native long nCreateTextureLayer();
+    private static native long nCreateRenderLayer(int width, int height);
+
+    private static native void nOnTextureDestroyed(long layerUpdater);
+    private static native long nDetachBackingLayer(long layerUpdater);
+
+    /** This also destroys the underlying layer if it is still attached.
+     *  Note it does not recycle the underlying layer, but instead queues it
+     *  for deferred deletion.
+     *  The HardwareRenderer should use detachBackingLayer() in the
+     *  onLayerDestroyed() callback to do recycling if desired.
+     */
+    private static native void nDestroyLayerUpdater(long layerUpdater);
+
+    private static native boolean nPrepare(long layerUpdater, int width, int height, boolean isOpaque);
+    private static native void nSetLayerPaint(long layerUpdater, long paint, long colorFilter);
+    private static native void nSetTransform(long layerUpdater, long matrix);
+    private static native void nSetSurfaceTexture(long layerUpdater,
+            SurfaceTexture surface, boolean isAlreadyAttached);
+    private static native void nUpdateSurfaceTexture(long layerUpdater);
+    private static native void nUpdateRenderLayer(long layerUpdater, long displayList,
+            int left, int top, int right, int bottom);
+
+    private static native boolean nFlushChanges(long layerUpdater);
+
+    private static native long nGetLayer(long layerUpdater);
+    private static native int nGetTexName(long layerUpdater);
+
+    private static class Finalizer {
+        private long mDeferredUpdater;
+
+        public Finalizer(long deferredUpdater) {
+            mDeferredUpdater = deferredUpdater;
+        }
+
+        @Override
+        protected void finalize() throws Throwable {
+            try {
+                destroy();
+            } finally {
+                super.finalize();
+            }
+        }
+
+        void destroy() {
+            if (mDeferredUpdater != 0) {
+                nDestroyLayerUpdater(mDeferredUpdater);
+                mDeferredUpdater = 0;
+            }
+        }
+    }
 }
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index 2013494..93cc9d1 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -16,6 +16,7 @@
 
 package android.view;
 
+import android.graphics.Bitmap;
 import android.graphics.Paint;
 import android.graphics.Rect;
 import android.graphics.SurfaceTexture;
@@ -153,14 +154,6 @@
     public static final String OVERDRAW_PROPERTY_SHOW = "show";
 
     /**
-     * Value for {@link #DEBUG_OVERDRAW_PROPERTY}. When the property is set to this
-     * value, an overdraw counter will be shown on screen.
-     *
-     * @hide
-     */
-    public static final String OVERDRAW_PROPERTY_COUNT = "count";
-
-    /**
      * Turn on to debug non-rectangular clip operations.
      *
      * Possible values:
@@ -352,19 +345,20 @@
      * @param layer The hardware layer that needs an update
      *
      * @see #flushLayerUpdates()
-     * @see #cancelLayerUpdate(HardwareLayer)
      */
     abstract void pushLayerUpdate(HardwareLayer layer);
 
     /**
-     * Cancels a queued layer update. If the specified layer was not
-     * queued for update, this method has no effect.
-     *
-     * @param layer The layer whose update to cancel
-     *
-     * @see #pushLayerUpdate(HardwareLayer)
+     * Tells the HardwareRenderer that a layer was created. The renderer should
+     * make sure to apply any pending layer changes at the start of a new frame
      */
-    abstract void cancelLayerUpdate(HardwareLayer layer);
+    abstract void onLayerCreated(HardwareLayer hardwareLayer);
+
+    /**
+     * Tells the HardwareRenderer that the layer is destroyed. The renderer
+     * should remove the layer from any update queues.
+     */
+    abstract void onLayerDestroyed(HardwareLayer layer);
 
     /**
      * Forces all enqueued layer updates to be executed immediately.
@@ -411,22 +405,19 @@
      * Creates a new hardware layer. A hardware layer built by calling this
      * method will be treated as a texture layer, instead of as a render target.
      *
-     * @param isOpaque Whether the layer should be opaque or not
-     *
      * @return A hardware layer
      */
-    abstract HardwareLayer createHardwareLayer(boolean isOpaque);
+    abstract HardwareLayer createTextureLayer();
 
     /**
      * Creates a new hardware layer.
      *
      * @param width The minimum width of the layer
      * @param height The minimum height of the layer
-     * @param isOpaque Whether the layer should be opaque or not
      *
      * @return A hardware layer
      */
-    abstract HardwareLayer createHardwareLayer(int width, int height, boolean isOpaque);
+    abstract HardwareLayer createDisplayListLayer(int width, int height);
 
     /**
      * Creates a new {@link SurfaceTexture} that can be used to render into the
@@ -438,14 +429,7 @@
      */
     abstract SurfaceTexture createSurfaceTexture(HardwareLayer layer);
 
-    /**
-     * Sets the {@link android.graphics.SurfaceTexture} that will be used to
-     * render into the specified hardware layer.
-     *
-     * @param layer The layer to render into using a {@link android.graphics.SurfaceTexture}
-     * @param surfaceTexture The {@link android.graphics.SurfaceTexture} to use for the layer
-     */
-    abstract void setSurfaceTexture(HardwareLayer layer, SurfaceTexture surfaceTexture);
+    abstract boolean copyLayerInto(HardwareLayer layer, Bitmap bitmap);
 
     /**
      * Detaches the specified functor from the current functor execution queue.
diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java
index 161fe33..e789407 100644
--- a/core/java/android/view/TextureView.java
+++ b/core/java/android/view/TextureView.java
@@ -250,7 +250,7 @@
             mSurface.detachFromGLContext();
             // SurfaceTexture owns the texture name and detachFromGLContext
             // should have deleted it
-            mLayer.clearStorage();
+            mLayer.onTextureDestroyed();
 
             boolean shouldRelease = true;
             if (mListener != null) {
@@ -375,7 +375,7 @@
                 return null;
             }
 
-            mLayer = mAttachInfo.mHardwareRenderer.createHardwareLayer(mOpaque);
+            mLayer = mAttachInfo.mHardwareRenderer.createTextureLayer();
             if (!mUpdateSurface) {
                 // Create a new SurfaceTexture for the layer.
                 mSurface = mAttachInfo.mHardwareRenderer.createSurfaceTexture(mLayer);
@@ -416,7 +416,7 @@
             updateLayer();
             mMatrixChanged = true;
 
-            mAttachInfo.mHardwareRenderer.setSurfaceTexture(mLayer, mSurface);
+            mLayer.setSurfaceTexture(mSurface);
             mSurface.setDefaultBufferSize(getWidth(), getHeight());
         }
 
@@ -469,7 +469,8 @@
             }
         }
         
-        mLayer.update(getWidth(), getHeight(), mOpaque);
+        mLayer.prepare(getWidth(), getHeight(), mOpaque);
+        mLayer.updateSurfaceTexture();
 
         if (mListener != null) {
             mListener.onSurfaceTextureUpdated(mSurface);
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index 2c9f1d9..1d7e5b2 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -16,6 +16,7 @@
 
 package android.view;
 
+import android.graphics.Bitmap;
 import android.graphics.Rect;
 import android.graphics.SurfaceTexture;
 import android.os.SystemClock;
@@ -112,8 +113,8 @@
 
     @Override
     boolean safelyRun(Runnable action) {
-        // TODO:
-        return false;
+        nRunWithGlContext(mNativeProxy, action);
+        return true;
     }
 
     @Override
@@ -155,7 +156,12 @@
     }
 
     @Override
-    void cancelLayerUpdate(HardwareLayer layer) {
+    void onLayerCreated(HardwareLayer layer) {
+        throw new NoSuchMethodError();
+    }
+
+    @Override
+    void onLayerDestroyed(HardwareLayer layer) {
         throw new NoSuchMethodError();
     }
 
@@ -197,12 +203,12 @@
     }
 
     @Override
-    HardwareLayer createHardwareLayer(boolean isOpaque) {
+    HardwareLayer createTextureLayer() {
         throw new NoSuchMethodError();
     }
 
     @Override
-    HardwareLayer createHardwareLayer(int width, int height, boolean isOpaque) {
+    HardwareLayer createDisplayListLayer(int width, int height) {
         throw new NoSuchMethodError();
     }
 
@@ -212,7 +218,7 @@
     }
 
     @Override
-    void setSurfaceTexture(HardwareLayer layer, SurfaceTexture surfaceTexture) {
+    boolean copyLayerInto(HardwareLayer layer, Bitmap bitmap) {
         throw new NoSuchMethodError();
     }
 
@@ -250,6 +256,7 @@
     private static native void nSetup(long nativeProxy, int width, int height);
     private static native void nDrawDisplayList(long nativeProxy, long displayList,
             int dirtyLeft, int dirtyTop, int dirtyRight, int dirtyBottom);
+    private static native void nRunWithGlContext(long nativeProxy, Runnable runnable);
     private static native void nDestroyCanvas(long nativeProxy);
 
     private static native void nAttachFunctor(long nativeProxy, long functor);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 4b6f2b0..393b166 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -87,7 +87,6 @@
 import com.android.internal.R;
 import com.android.internal.util.Predicate;
 import com.android.internal.view.menu.MenuBuilder;
-
 import com.google.android.collect.Lists;
 import com.google.android.collect.Maps;
 
@@ -665,6 +664,7 @@
  * @attr ref android.R.styleable#View_scrollbarTrackVertical
  * @attr ref android.R.styleable#View_scrollbarAlwaysDrawHorizontalTrack
  * @attr ref android.R.styleable#View_scrollbarAlwaysDrawVerticalTrack
+ * @attr ref android.R.styleable#View_sharedElementName
  * @attr ref android.R.styleable#View_soundEffectsEnabled
  * @attr ref android.R.styleable#View_tag
  * @attr ref android.R.styleable#View_textAlignment
@@ -2334,7 +2334,6 @@
      *                               1   PFLAG3_IS_LAID_OUT
      *                              1    PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT
      *                             1     PFLAG3_CALLED_SUPER
-     *                            1      PFLAG3_PROJECT_BACKGROUND
      * |-------|-------|-------|-------|
      */
 
@@ -2371,10 +2370,30 @@
     static final int PFLAG3_CALLED_SUPER = 0x10;
 
     /**
-     * Flag indicating that the background of this view will be drawn into a
-     * display list and projected onto the closest parent projection surface.
+     * Flag indicating that an view will be clipped to its outline.
      */
-    static final int PFLAG3_PROJECT_BACKGROUND = 0x20;
+    static final int PFLAG3_CLIP_TO_OUTLINE = 0x20;
+
+    /**
+     * 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;
+
+    /**
+     * Flag indicating that an view will cast a shadow onto the Z=0 plane if elevated.
+     */
+    static final int PFLAG3_CASTS_SHADOW = 0x100;
+
+    /**
+     * Flag indicating that view will be transformed by the global camera if rotated in 3d, or given
+     * a non-0 Z translation.
+     */
+    static final int PFLAG3_SHARES_GLOBAL_CAMERA = 0x200;
 
     /* End of masks for mPrivateFlags3 */
 
@@ -3303,6 +3322,8 @@
         private OnDragListener mOnDragListener;
 
         private OnSystemUiVisibilityChangeListener mOnSystemUiVisibilityChangeListener;
+
+        OnApplyWindowInsetsListener mOnApplyWindowInsetsListener;
     }
 
     ListenerInfo mListenerInfo;
@@ -3321,7 +3342,8 @@
     private int[] mDrawableState = null;
 
     /**
-     * Stores the outline of the view, passed down to the DisplayList level for shadow shape.
+     * Stores the outline of the view, passed down to the DisplayList level for
+     * defining shadow shape and clipping.
      */
     private Path mOutline;
 
@@ -4038,6 +4060,9 @@
                 case R.styleable.View_accessibilityLiveRegion:
                     setAccessibilityLiveRegion(a.getInt(attr, ACCESSIBILITY_LIVE_REGION_DEFAULT));
                     break;
+                case R.styleable.View_sharedElementName:
+                    setSharedElementName(a.getString(attr));
+                    break;
             }
         }
 
@@ -6119,10 +6144,33 @@
      * @return {@code true} if this view applied the insets and it should not
      * continue propagating further down the hierarchy, {@code false} otherwise.
      * @see #getFitsSystemWindows()
-     * @see #setFitsSystemWindows(boolean) 
+     * @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;
@@ -6142,6 +6190,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.
      */
@@ -6213,6 +6352,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) {
@@ -6221,6 +6361,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
      */
@@ -10689,6 +10836,78 @@
     }
 
     /**
+     * @hide
+     */
+    public final boolean getClipToOutline() {
+        return ((mPrivateFlags3 & PFLAG3_CLIP_TO_OUTLINE) != 0);
+    }
+
+    /**
+     * @hide
+     */
+    public void setClipToOutline(boolean clipToOutline) {
+        // TODO : Add a fast invalidation here.
+        if (getClipToOutline() != clipToOutline) {
+            if (clipToOutline) {
+                mPrivateFlags3 |= PFLAG3_CLIP_TO_OUTLINE;
+            } else {
+                mPrivateFlags3 &= ~PFLAG3_CLIP_TO_OUTLINE;
+            }
+            if (mDisplayList != null) {
+                mDisplayList.setClipToOutline(clipToOutline);
+            }
+        }
+    }
+
+    /**
+     * @hide
+     */
+    public final boolean getCastsShadow() {
+        return ((mPrivateFlags3 & PFLAG3_CASTS_SHADOW) != 0);
+    }
+
+    /**
+     * @hide
+     */
+    public void setCastsShadow(boolean castsShadow) {
+        // TODO : Add a fast invalidation here.
+        if (getCastsShadow() != castsShadow) {
+            if (castsShadow) {
+                mPrivateFlags3 |= PFLAG3_CASTS_SHADOW;
+            } else {
+                mPrivateFlags3 &= ~PFLAG3_CASTS_SHADOW;
+            }
+            if (mDisplayList != null) {
+                mDisplayList.setCastsShadow(castsShadow);
+            }
+        }
+    }
+
+    /**
+     * @hide
+     */
+    public final boolean getSharesGlobalCamera() {
+        return ((mPrivateFlags3 & PFLAG3_SHARES_GLOBAL_CAMERA) != 0);
+    }
+
+    /**
+     * @hide
+     */
+    public void setSharesGlobalCamera(boolean sharesGlobalCamera) {
+        // TODO : Add a fast invalidation here.
+        if (getSharesGlobalCamera() != sharesGlobalCamera) {
+            if (sharesGlobalCamera) {
+                mPrivateFlags3 |= PFLAG3_SHARES_GLOBAL_CAMERA;
+            } else {
+                mPrivateFlags3 &= ~PFLAG3_SHARES_GLOBAL_CAMERA;
+            }
+            if (mDisplayList != null) {
+                mDisplayList.setSharesGlobalCamera(sharesGlobalCamera);
+            }
+        }
+    }
+
+    /**
      * Hit rectangle in parent's coordinates
      *
      * @param outRect The hit rectangle of the view.
@@ -13409,16 +13628,10 @@
 
         if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0 || mHardwareLayer == null) {
             if (mHardwareLayer == null) {
-                mHardwareLayer = mAttachInfo.mHardwareRenderer.createHardwareLayer(
-                        width, height, isOpaque());
+                mHardwareLayer = mAttachInfo.mHardwareRenderer.createDisplayListLayer(
+                        width, height);
                 mLocalDirtyRect.set(0, 0, width, height);
-            } else {
-                if (mHardwareLayer.getWidth() != width || mHardwareLayer.getHeight() != height) {
-                    if (mHardwareLayer.resize(width, height)) {
-                        mLocalDirtyRect.set(0, 0, width, height);
-                    }
-                }
-
+            } else if (mHardwareLayer.isValid()) {
                 // This should not be necessary but applications that change
                 // the parameters of their background drawable without calling
                 // this.setBackground(Drawable) can leave the view in a bad state
@@ -13426,23 +13639,24 @@
                 // not opaque.)
                 computeOpaqueFlags();
 
-                final boolean opaque = isOpaque();
-                if (mHardwareLayer.isValid() && mHardwareLayer.isOpaque() != opaque) {
-                    mHardwareLayer.setOpaque(opaque);
+                if (mHardwareLayer.prepare(width, height, isOpaque())) {
                     mLocalDirtyRect.set(0, 0, width, height);
                 }
             }
 
             // The layer is not valid if the underlying GPU resources cannot be allocated
+            mHardwareLayer.flushChanges();
             if (!mHardwareLayer.isValid()) {
                 return null;
             }
 
             mHardwareLayer.setLayerPaint(mLayerPaint);
-            mHardwareLayer.redrawLater(getHardwareLayerDisplayList(mHardwareLayer), mLocalDirtyRect);
-            ViewRootImpl viewRoot = getViewRootImpl();
-            if (viewRoot != null) viewRoot.pushHardwareLayerUpdate(mHardwareLayer);
-
+            DisplayList displayList = mHardwareLayer.startRecording();
+            if (getDisplayList(displayList, true) != displayList) {
+                throw new IllegalStateException("getDisplayList() didn't return"
+                        + " the input displaylist for a hardware layer!");
+            }
+            mHardwareLayer.endRecording(mLocalDirtyRect);
             mLocalDirtyRect.setEmpty();
         }
 
@@ -13459,18 +13673,11 @@
      */
     boolean destroyLayer(boolean valid) {
         if (mHardwareLayer != null) {
-            AttachInfo info = mAttachInfo;
-            if (info != null && info.mHardwareRenderer != null &&
-                    info.mHardwareRenderer.isEnabled() &&
-                    (valid || info.mHardwareRenderer.validate())) {
+            mHardwareLayer.destroy();
+            mHardwareLayer = null;
 
-                info.mHardwareRenderer.cancelLayerUpdate(mHardwareLayer);
-                mHardwareLayer.destroy();
-                mHardwareLayer = null;
-
-                invalidate(true);
-                invalidateParentCaches();
-            }
+            invalidate(true);
+            invalidateParentCaches();
             return true;
         }
         return false;
@@ -13691,19 +13898,6 @@
     }
 
     /**
-     * Get the DisplayList for the HardwareLayer
-     *
-     * @param layer The HardwareLayer whose DisplayList we want
-     * @return A DisplayList fopr the specified HardwareLayer
-     */
-    private DisplayList getHardwareLayerDisplayList(HardwareLayer layer) {
-        DisplayList displayList = getDisplayList(layer.getDisplayList(), true);
-        layer.setDisplayList(displayList);
-        return displayList;
-    }
-
-
-    /**
      * <p>Returns a display list that can be used to draw this view again
      * without executing its draw method.</p>
      *
@@ -14340,6 +14534,9 @@
                         (((ViewGroup) this).mGroupFlags & ViewGroup.FLAG_ISOLATED_Z_VOLUME) != 0);
             }
             displayList.setOutline(mOutline);
+            displayList.setClipToOutline(getClipToOutline());
+            displayList.setCastsShadow(getCastsShadow());
+            displayList.setSharesGlobalCamera(getSharesGlobalCamera());
             float alpha = 1;
             if (mParent instanceof ViewGroup && (((ViewGroup) mParent).mGroupFlags &
                     ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) {
@@ -14979,7 +15176,6 @@
      * @param displayList Valid display list for the background drawable
      */
     private void setBackgroundDisplayListProperties(DisplayList displayList) {
-        displayList.setProjectBackwards((mPrivateFlags3 & PFLAG3_PROJECT_BACKGROUND) != 0);
         displayList.setTranslationX(mScrollX);
         displayList.setTranslationY(mScrollY);
     }
@@ -15010,6 +15206,8 @@
 
         // Set up drawable properties that are view-independent.
         displayList.setLeftTopRightBottom(bounds.left, bounds.top, bounds.right, bounds.bottom);
+        displayList.setProjectBackwards(drawable.isProjected());
+        displayList.setProjectionReceiver(true);
         displayList.setClipToBounds(false);
         return displayList;
     }
@@ -15359,18 +15557,16 @@
     public void invalidateDrawable(Drawable drawable) {
         if (verifyDrawable(drawable)) {
             if (drawable == mBackground && mBackgroundDisplayList != null) {
-                // If we're using a background display list, we only need to
-                // invalidate the display list and notify the parent to redraw.
+                // We'll need to redraw the display list.
                 mBackgroundDisplayList.clear();
-                invalidateViewProperty(true, false);
-            } else {
-                final Rect dirty = drawable.getBounds();
-                final int scrollX = mScrollX;
-                final int scrollY = mScrollY;
-
-                invalidate(dirty.left + scrollX, dirty.top + scrollY,
-                        dirty.right + scrollX, dirty.bottom + scrollY);
             }
+
+            final Rect dirty = drawable.getDirtyBounds();
+            final int scrollX = mScrollX;
+            final int scrollY = mScrollY;
+
+            invalidate(dirty.left + scrollX, dirty.top + scrollY,
+                    dirty.right + scrollX, dirty.bottom + scrollY);
         }
     }
 
@@ -15382,6 +15578,7 @@
      * @param when the time at which the action must occur. Uses the
      *        {@link SystemClock#uptimeMillis} timebase.
      */
+    @Override
     public void scheduleDrawable(Drawable who, Runnable what, long when) {
         if (verifyDrawable(who) && what != null) {
             final long delay = when - SystemClock.uptimeMillis();
@@ -15401,6 +15598,7 @@
      * @param who the recipient of the action
      * @param what the action to cancel
      */
+    @Override
     public void unscheduleDrawable(Drawable who, Runnable what) {
         if (verifyDrawable(who) && what != null) {
             if (mAttachInfo != null) {
@@ -18872,6 +19070,35 @@
     }
 
     /**
+     * Specifies that the shared name of the View to be shared with another Activity.
+     * When transitioning between Activities, the name links a UI element in the starting
+     * Activity to UI element in the called Activity. Names should be unique in the
+     * View hierarchy.
+     *
+     * @param sharedElementName The cross-Activity View identifier. The called Activity will use
+     *                 the name to match the location with a View in its layout.
+     * @see android.app.ActivityOptions#makeSceneTransitionAnimation(android.os.Bundle)
+     */
+    public void setSharedElementName(String sharedElementName) {
+        setTagInternal(com.android.internal.R.id.shared_element_name, sharedElementName);
+    }
+
+    /**
+     * Returns the shared name of the View to be shared with another Activity.
+     * When transitioning between Activities, the name links a UI element in the starting
+     * Activity to UI element in the called Activity. Names should be unique in the
+     * View hierarchy.
+     *
+     * <p>This returns null if the View is not a shared element or the name if it is.</p>
+     *
+     * @return The name used for this View for cross-Activity transitions or null if
+     * this View has not been identified as shared.
+     */
+    public String getSharedElementName() {
+        return (String) getTag(com.android.internal.R.id.shared_element_name);
+    }
+
+    /**
      * Interface definition for a callback to be invoked when a hardware key event is
      * dispatched to this view. The callback will be invoked before the key event is
      * given to the view. This is only useful for hardware keyboards; a software input
@@ -19071,6 +19298,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);
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index b91091f..c3bf533 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -360,6 +360,10 @@
      */
     static final int FLAG_ISOLATED_Z_VOLUME = 0x1000000;
 
+    static final int FLAG_IS_TRANSITION_GROUP = 0x2000000;
+
+    static final int FLAG_IS_TRANSITION_GROUP_SET = 0x4000000;
+
     /**
      * Indicates which types of drawing caches are to be kept in memory.
      * This field should be made private, so it is hidden from the SDK.
@@ -556,6 +560,9 @@
                 case R.styleable.ViewGroup_layoutMode:
                     setLayoutMode(a.getInt(attr, LAYOUT_MODE_UNDEFINED));
                     break;
+                case R.styleable.ViewGroup_transitionGroup:
+                    setTransitionGroup(a.getBoolean(attr, false));
+                    break;
             }
         }
 
@@ -2288,6 +2295,41 @@
     }
 
     /**
+     * Returns true if this ViewGroup should be considered as a single entity for removal
+     * when executing an Activity transition. If this is false, child elements will move
+     * individually during the transition.
+     * @return True if the ViewGroup should be acted on together during an Activity transition.
+     * The default value is false when the background is null and true when the background
+     * is not null.
+     * @see android.app.ActivityOptions#makeSceneTransitionAnimation(android.os.Bundle)
+     */
+    public boolean isTransitionGroup() {
+        if ((mGroupFlags & FLAG_IS_TRANSITION_GROUP_SET) != 0) {
+            return ((mGroupFlags & FLAG_IS_TRANSITION_GROUP) != 0);
+        } else {
+            return getBackground() != null;
+        }
+    }
+
+    /**
+     * Changes whether or not this ViewGroup should be treated as a single entity during
+     * ActivityTransitions.
+     * @param isTransitionGroup Whether or not the ViewGroup should be treated as a unit
+     *                          in Activity transitions. If false, the ViewGroup won't transition,
+     *                          only its children. If true, the entire ViewGroup will transition
+     *                          together.
+     * @see android.app.ActivityOptions#makeSceneTransitionAnimation(android.os.Bundle)
+     */
+    public void setTransitionGroup(boolean isTransitionGroup) {
+        mGroupFlags |= FLAG_IS_TRANSITION_GROUP_SET;
+        if (isTransitionGroup) {
+            mGroupFlags |= FLAG_IS_TRANSITION_GROUP;
+        } else {
+            mGroupFlags &= ~FLAG_IS_TRANSITION_GROUP;
+        }
+    }
+
+    /**
      * {@inheritDoc}
      */
     public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
@@ -3136,7 +3178,7 @@
      *         inherited Z ordering volume.
      */
     public void setIsolatedZVolume(boolean isolateZVolume) {
-        boolean previousValue = (mGroupFlags & FLAG_ISOLATED_Z_VOLUME) == FLAG_ISOLATED_Z_VOLUME;
+        boolean previousValue = (mGroupFlags & FLAG_ISOLATED_Z_VOLUME) != 0;
         if (isolateZVolume != previousValue) {
             setBooleanFlag(FLAG_ISOLATED_Z_VOLUME, isolateZVolume);
             if (mDisplayList != null) {
@@ -5472,21 +5514,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 ccb85a6..ef69948 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -642,12 +642,6 @@
         }
     }
 
-    void pushHardwareLayerUpdate(HardwareLayer layer) {
-        if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) {
-            mAttachInfo.mHardwareRenderer.pushLayerUpdate(layer);
-        }
-    }
-
     void flushHardwareLayerUpdates() {
         if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled() &&
                 mAttachInfo.mHardwareRenderer.validate()) {
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 1064a08..11740ab 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.app.ActivityOptions;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.TypedArray;
@@ -1374,8 +1375,41 @@
     /**
      * Set options that can affect the transition behavior within this window.
      * @param options Options to set or null for none
+     * @hide
      */
-    public void setTransitionOptions(Bundle options) {
-        throw new UnsupportedOperationException();
+    public void setTransitionOptions(ActivityOptions options, SceneTransitionListener listener) {
+    }
+
+    /**
+     * A callback for Activity transitions to be told when the shared element is ready to be shown
+     * and start the transition to its target location.
+     * @hide
+     */
+    public interface SceneTransitionListener {
+        void enterSharedElement(Bundle transitionArgs);
+        void nullPendingTransition();
+        void convertFromTranslucent();
+        void convertToTranslucent();
+    }
+
+    /**
+     * Controls how the background fade is triggered. If fadeEarly is true, the Window background
+     * will fade in as soon as the shared elements are ready to switch. If fadeEarly is false,
+     * the background will fade only after the calling Activity's exit transition completes.
+     * By default, the Window will fade in when the calling Activity's exit transition completes.
+     *
+     * @param fadeEarly Set to true to fade out the exiting Activity as soon as the shared elements
+     *                  are transferred. Set to false to fade out the exiting Activity as soon as
+     *                  the shared element is transferred.
+     * @hide
+     */
+    public void setEarlyBackgroundTransition(boolean fadeEarly) {
+    }
+
+    /**
+     * Start the exit transition.
+     * @hide
+     */
+    public void startExitTransition(ActivityOptions activityOptions) {
     }
 }
diff --git a/core/java/android/view/WindowInsets.java b/core/java/android/view/WindowInsets.java
new file mode 100644
index 0000000..cdfcb43
--- /dev/null
+++ b/core/java/android/view/WindowInsets.java
@@ -0,0 +1,278 @@
+/*
+ * 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 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) {
+        mSystemWindowInsets = systemWindowInsets;
+        mWindowDecorInsets = windowDecorInsets;
+    }
+
+    /**
+     * 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;
+    }
+
+    /** @hide */
+    public WindowInsets(Rect systemWindowInsets) {
+        mSystemWindowInsets = systemWindowInsets;
+        mWindowDecorInsets = 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();
+    }
+
+    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 + "}";
+    }
+}
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 7ee33c1..826bcec 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -845,8 +845,8 @@
 
     /**
      * Loads the URL with postData using "POST" method into this WebView. If url
-     * is not a network URL, it will be loaded with {link
-     * {@link #loadUrl(String)} instead.
+     * is not a network URL, it will be loaded with {@link #loadUrl(String)}
+     * instead, ignoring the postData param.
      *
      * @param url the URL of the resource to load
      * @param postData the data will be passed to "POST" request, which must be
@@ -855,7 +855,11 @@
     public void postUrl(String url, byte[] postData) {
         checkThread();
         if (DebugFlags.TRACE_API) Log.d(LOGTAG, "postUrl=" + url);
-        mProvider.postUrl(url, postData);
+        if (URLUtil.isNetworkUrl(url)) {
+            mProvider.postUrl(url, postData);
+        } else {
+            mProvider.loadUrl(url);
+        }
     }
 
     /**
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 3be23b7..65b79fc 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -4814,6 +4814,8 @@
 
     @Override
     public void invalidateDrawable(Drawable drawable) {
+        boolean handled = false;
+
         if (verifyDrawable(drawable)) {
             final Rect dirty = drawable.getBounds();
             int scrollX = mScrollX;
@@ -4831,6 +4833,7 @@
 
                     scrollX += mPaddingLeft;
                     scrollY += compoundPaddingTop + (vspace - drawables.mDrawableHeightLeft) / 2;
+                    handled = true;
                 } else if (drawable == drawables.mDrawableRight) {
                     final int compoundPaddingTop = getCompoundPaddingTop();
                     final int compoundPaddingBottom = getCompoundPaddingBottom();
@@ -4838,6 +4841,7 @@
 
                     scrollX += (mRight - mLeft - mPaddingRight - drawables.mDrawableSizeRight);
                     scrollY += compoundPaddingTop + (vspace - drawables.mDrawableHeightRight) / 2;
+                    handled = true;
                 } else if (drawable == drawables.mDrawableTop) {
                     final int compoundPaddingLeft = getCompoundPaddingLeft();
                     final int compoundPaddingRight = getCompoundPaddingRight();
@@ -4845,6 +4849,7 @@
 
                     scrollX += compoundPaddingLeft + (hspace - drawables.mDrawableWidthTop) / 2;
                     scrollY += mPaddingTop;
+                    handled = true;
                 } else if (drawable == drawables.mDrawableBottom) {
                     final int compoundPaddingLeft = getCompoundPaddingLeft();
                     final int compoundPaddingRight = getCompoundPaddingRight();
@@ -4852,11 +4857,18 @@
 
                     scrollX += compoundPaddingLeft + (hspace - drawables.mDrawableWidthBottom) / 2;
                     scrollY += (mBottom - mTop - mPaddingBottom - drawables.mDrawableSizeBottom);
+                    handled = true;
                 }
             }
 
-            invalidate(dirty.left + scrollX, dirty.top + scrollY,
-                    dirty.right + scrollX, dirty.bottom + scrollY);
+            if (handled) {
+                invalidate(dirty.left + scrollX, dirty.top + scrollY,
+                        dirty.right + scrollX, dirty.bottom + scrollY);
+            }
+        }
+
+        if (!handled) {
+            super.invalidateDrawable(drawable);
         }
     }
 
diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl
index 1946d86..9a04760 100644
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -35,10 +35,11 @@
 
     void noteEvent(int code, String name, int uid);
 
-    void noteStartWakelock(int uid, int pid, String name, int type);
+    void noteStartWakelock(int uid, int pid, String name, int type, boolean unimportantForLogging);
     void noteStopWakelock(int uid, int pid, String name, int type);
 
-    void noteStartWakelockFromSource(in WorkSource ws, int pid, String name, int type);
+    void noteStartWakelockFromSource(in WorkSource ws, int pid, String name, int type,
+            boolean unimportantForLogging);
     void noteStopWakelockFromSource(in WorkSource ws, int pid, String name, int type);
 
     void noteVibratorOn(int uid, long durationMillis);
diff --git a/core/java/com/android/internal/os/BatteryStatsHelper.java b/core/java/com/android/internal/os/BatteryStatsHelper.java
index e7e8006f..c22a5e9 100644
--- a/core/java/com/android/internal/os/BatteryStatsHelper.java
+++ b/core/java/com/android/internal/os/BatteryStatsHelper.java
@@ -54,7 +54,7 @@
  */
 public class BatteryStatsHelper {
 
-    private static final boolean DEBUG = true;
+    private static final boolean DEBUG = false;
 
     private static final String TAG = BatteryStatsHelper.class.getSimpleName();
 
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 68c41fa..82dcbdb 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -45,6 +45,7 @@
 import android.util.Printer;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.util.SparseBooleanArray;
 import android.util.SparseIntArray;
 import android.util.TimeUtils;
 
@@ -87,7 +88,7 @@
     private static final int MAGIC = 0xBA757475; // 'BATSTATS'
 
     // Current on-disk Parcel version
-    private static final int VERSION = 75 + (USE_OLD_HISTORY ? 1000 : 0);
+    private static final int VERSION = 79 + (USE_OLD_HISTORY ? 1000 : 0);
 
     // Maximum number of items we will record in the history.
     private static final int MAX_HISTORY_ITEMS = 2000;
@@ -178,6 +179,9 @@
 
     boolean mShuttingDown;
 
+    HashMap<String, SparseBooleanArray>[] mActiveEvents
+            = (HashMap<String, SparseBooleanArray>[]) new HashMap[HistoryItem.EVENT_COUNT];
+
     long mHistoryBaseTime;
     boolean mHaveBatteryLevel = false;
     boolean mRecordingHistory = true;
@@ -226,6 +230,9 @@
     long mRealtimeStart;
     long mLastRealtime;
 
+    int mWakeLockNesting;
+    boolean mWakeLockImportant;
+
     boolean mScreenOn;
     StopwatchTimer mScreenOnTimer;
 
@@ -1513,23 +1520,33 @@
     }
 
     // Part of initial delta int that specifies the time delta.
-    static final int DELTA_TIME_MASK = 0x1ffff;
-    static final int DELTA_TIME_LONG = 0x1ffff;   // The delta is a following long
-    static final int DELTA_TIME_INT = 0x1fffe;    // The delta is a following int
-    static final int DELTA_TIME_ABS = 0x1fffd;    // Following is an entire abs update.
-    // Part of initial delta int holding the command code.
-    static final int DELTA_CMD_MASK = 0x3;
-    static final int DELTA_CMD_SHIFT = 17;
+    static final int DELTA_TIME_MASK = 0xfffff;
+    static final int DELTA_TIME_LONG = 0xfffff;   // The delta is a following long
+    static final int DELTA_TIME_INT = 0xffffe;    // The delta is a following int
+    static final int DELTA_TIME_ABS = 0xffffd;    // Following is an entire abs update.
     // Flag in delta int: a new battery level int follows.
-    static final int DELTA_BATTERY_LEVEL_FLAG = 0x00080000;
+    static final int DELTA_BATTERY_LEVEL_FLAG   = 0x00100000;
     // Flag in delta int: a new full state and battery status int follows.
-    static final int DELTA_STATE_FLAG = 0x00100000;
+    static final int DELTA_STATE_FLAG           = 0x00200000;
     // Flag in delta int: contains a wakelock tag.
-    static final int DELTA_WAKELOCK_FLAG = 0x00200000;
-    static final int DELTA_STATE_MASK = 0xffc00000;
+    static final int DELTA_WAKELOCK_FLAG        = 0x00400000;
+    // Flag in delta int: contains an event description.
+    static final int DELTA_EVENT_FLAG           = 0x00800000;
+    // These upper bits are the frequently changing state bits.
+    static final int DELTA_STATE_MASK           = 0xff000000;
+
+    // These are the pieces of battery state that are packed in to the upper bits of
+    // the state int that have been packed in to the first delta int.  They must fit
+    // in DELTA_STATE_MASK.
+    static final int STATE_BATTERY_STATUS_MASK  = 0x00000007;
+    static final int STATE_BATTERY_STATUS_SHIFT = 29;
+    static final int STATE_BATTERY_HEALTH_MASK  = 0x00000007;
+    static final int STATE_BATTERY_HEALTH_SHIFT = 26;
+    static final int STATE_BATTERY_PLUG_MASK    = 0x00000003;
+    static final int STATE_BATTERY_PLUG_SHIFT   = 24;
 
     public void writeHistoryDelta(Parcel dest, HistoryItem cur, HistoryItem last) {
-        if (last == null || !last.isDeltaData() || !cur.isDeltaData()) {
+        if (last == null || cur.cmd != HistoryItem.CMD_UPDATE) {
             dest.writeInt(DELTA_TIME_ABS);
             cur.writeToParcel(dest, 0);
             return;
@@ -1547,9 +1564,7 @@
         } else {
             deltaTimeToken = (int)deltaTime;
         }
-        int firstToken = deltaTimeToken
-                | (cur.cmd<<DELTA_CMD_SHIFT)
-                | (cur.states&DELTA_STATE_MASK);
+        int firstToken = deltaTimeToken | (cur.states&DELTA_STATE_MASK);
         final int batteryLevelInt = buildBatteryLevelInt(cur);
         final boolean batteryLevelIntChanged = batteryLevelInt != lastBatteryLevelInt;
         if (batteryLevelIntChanged) {
@@ -1563,6 +1578,9 @@
         if (cur.wakelockTag != null) {
             firstToken |= DELTA_WAKELOCK_FLAG;
         }
+        if (cur.eventCode != HistoryItem.EVENT_NONE) {
+            firstToken |= DELTA_EVENT_FLAG;
+        }
         dest.writeInt(firstToken);
         if (DEBUG) Slog.i(TAG, "WRITE DELTA: firstToken=0x" + Integer.toHexString(firstToken)
                 + " deltaTime=" + deltaTime);
@@ -1599,7 +1617,7 @@
             if (DEBUG) Slog.i(TAG, "WRITE DELTA: wakelockTag=#" + cur.wakelockTag.poolIdx
                 + " " + cur.wakelockTag.uid + ":" + cur.wakelockTag.string);
         }
-        if (cur.cmd == HistoryItem.CMD_EVENT) {
+        if (cur.eventCode != HistoryItem.EVENT_NONE) {
             int index = writeHistoryTag(cur.eventTag);
             int codeAndIndex = (cur.eventCode&0xffff) | (index<<16);
             dest.writeInt(codeAndIndex);
@@ -1616,16 +1634,24 @@
     }
 
     private int buildStateInt(HistoryItem h) {
-        return ((((int)h.batteryStatus)<<28)&0xf0000000)
-                | ((((int)h.batteryHealth)<<24)&0x0f000000)
-                | ((((int)h.batteryPlugType)<<22)&0x00c00000)
+        int plugType = 0;
+        if ((h.batteryPlugType&BatteryManager.BATTERY_PLUGGED_AC) != 0) {
+            plugType = 1;
+        } else if ((h.batteryPlugType&BatteryManager.BATTERY_PLUGGED_USB) != 0) {
+            plugType = 2;
+        } else if ((h.batteryPlugType&BatteryManager.BATTERY_PLUGGED_WIRELESS) != 0) {
+            plugType = 3;
+        }
+        return ((h.batteryStatus&STATE_BATTERY_STATUS_MASK)<<STATE_BATTERY_STATUS_SHIFT)
+                | ((h.batteryHealth&STATE_BATTERY_HEALTH_MASK)<<STATE_BATTERY_HEALTH_SHIFT)
+                | ((plugType&STATE_BATTERY_PLUG_MASK)<<STATE_BATTERY_PLUG_SHIFT)
                 | (h.states&(~DELTA_STATE_MASK));
     }
 
     public void readHistoryDelta(Parcel src, HistoryItem cur) {
         int firstToken = src.readInt();
         int deltaTimeToken = firstToken&DELTA_TIME_MASK;
-        cur.cmd = (byte)((firstToken>>DELTA_CMD_SHIFT)&DELTA_CMD_MASK);
+        cur.cmd = HistoryItem.CMD_UPDATE;
         cur.numReadInts = 1;
         if (DEBUG) Slog.i(TAG, "READ DELTA: firstToken=0x" + Integer.toHexString(firstToken)
                 + " deltaTimeToken=" + deltaTimeToken);
@@ -1666,9 +1692,23 @@
         if ((firstToken&DELTA_STATE_FLAG) != 0) {
             int stateInt = src.readInt();
             cur.states = (firstToken&DELTA_STATE_MASK) | (stateInt&(~DELTA_STATE_MASK));
-            cur.batteryStatus = (byte)((stateInt>>28)&0xf);
-            cur.batteryHealth = (byte)((stateInt>>24)&0xf);
-            cur.batteryPlugType = (byte)((stateInt>>22)&0x3);
+            cur.batteryStatus = (byte)((stateInt>>STATE_BATTERY_STATUS_SHIFT)
+                    & STATE_BATTERY_STATUS_MASK);
+            cur.batteryHealth = (byte)((stateInt>>STATE_BATTERY_HEALTH_SHIFT)
+                    & STATE_BATTERY_HEALTH_MASK);
+            cur.batteryPlugType = (byte)((stateInt>>STATE_BATTERY_PLUG_SHIFT)
+                    & STATE_BATTERY_PLUG_MASK);
+            switch (cur.batteryPlugType) {
+                case 1:
+                    cur.batteryPlugType = BatteryManager.BATTERY_PLUGGED_AC;
+                    break;
+                case 2:
+                    cur.batteryPlugType = BatteryManager.BATTERY_PLUGGED_USB;
+                    break;
+                case 3:
+                    cur.batteryPlugType = BatteryManager.BATTERY_PLUGGED_WIRELESS;
+                    break;
+            }
             cur.numReadInts += 1;
             if (DEBUG) Slog.i(TAG, "READ DELTA: stateToken=0x"
                     + Integer.toHexString(stateInt)
@@ -1691,7 +1731,7 @@
             cur.wakelockTag = null;
         }
 
-        if (cur.cmd == HistoryItem.CMD_EVENT) {
+        if ((firstToken&DELTA_EVENT_FLAG) != 0) {
             cur.eventTag = cur.localEventTag;
             final int codeAndIndex = src.readInt();
             cur.eventCode = (codeAndIndex&0xffff);
@@ -1720,6 +1760,8 @@
         if (mHistoryBufferLastPos >= 0 && mHistoryLastWritten.cmd == HistoryItem.CMD_UPDATE
                 && timeDiff < 1000 && (diffStates&lastDiffStates) == 0
                 && (mHistoryLastWritten.wakelockTag == null || mHistoryCur.wakelockTag == null)
+                && (mHistoryLastWritten.eventCode == HistoryItem.EVENT_NONE
+                        || mHistoryCur.eventCode == HistoryItem.EVENT_NONE)
                 && mHistoryLastWritten.batteryLevel == mHistoryCur.batteryLevel
                 && mHistoryLastWritten.batteryStatus == mHistoryCur.batteryStatus
                 && mHistoryLastWritten.batteryHealth == mHistoryCur.batteryHealth
@@ -1742,6 +1784,14 @@
                 mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag;
                 mHistoryCur.wakelockTag.setTo(mHistoryLastWritten.wakelockTag);
             }
+            // If the last written history had an event, we need to retain it.
+            // Note that the condition above made sure that we aren't in a case where
+            // both it and the current history item have an event.
+            if (mHistoryLastWritten.eventCode != HistoryItem.EVENT_NONE) {
+                mHistoryCur.eventCode = mHistoryLastWritten.eventCode;
+                mHistoryCur.eventTag = mHistoryCur.localEventTag;
+                mHistoryCur.eventTag.setTo(mHistoryLastWritten.eventTag);
+            }
             mHistoryLastWritten.setTo(mHistoryLastLastWritten);
         }
 
@@ -1772,26 +1822,18 @@
         addHistoryBufferLocked(curTime, HistoryItem.CMD_UPDATE);
     }
 
-    void addHistoryBufferLocked(long curTime, byte cmd) {
-        addHistoryBufferLocked(curTime, cmd, HistoryItem.EVENT_NONE, null, 0);
-    }
-
-    void addHistoryBufferEventLocked(long curTime, int eventCode, String eventName, int eventUid) {
-        addHistoryBufferLocked(curTime, HistoryItem.CMD_EVENT, eventCode, eventName, eventUid);
-    }
-
-    private void addHistoryBufferLocked(long curTime, byte cmd,
-            int eventCode, String eventName, int eventUid) {
+    private void addHistoryBufferLocked(long curTime, byte cmd) {
         if (mIteratingHistory) {
             throw new IllegalStateException("Can't do this while iterating history!");
         }
         mHistoryBufferLastPos = mHistoryBuffer.dataPosition();
         mHistoryLastLastWritten.setTo(mHistoryLastWritten);
-        mHistoryLastWritten.setTo(mHistoryBaseTime + curTime, cmd,
-                eventCode, eventUid, eventName, mHistoryCur);
+        mHistoryLastWritten.setTo(mHistoryBaseTime + curTime, cmd, mHistoryCur);
         writeHistoryDelta(mHistoryBuffer, mHistoryLastWritten, mHistoryLastLastWritten);
         mLastHistoryTime = curTime;
         mHistoryCur.wakelockTag = null;
+        mHistoryCur.eventCode = HistoryItem.EVENT_NONE;
+        mHistoryCur.eventTag = null;
         if (DEBUG_HISTORY) Slog.i(TAG, "Writing history buffer: was " + mHistoryBufferLastPos
                 + " now " + mHistoryBuffer.dataPosition()
                 + " size is now " + mHistoryBuffer.dataSize());
@@ -1829,8 +1871,7 @@
                 mHistoryLastEnd = null;
             } else {
                 mChangedStates |= mHistoryEnd.states^mHistoryCur.states;
-                mHistoryEnd.setTo(mHistoryEnd.time, HistoryItem.CMD_UPDATE,
-                        HistoryItem.EVENT_NONE, 0, null, mHistoryCur);
+                mHistoryEnd.setTo(mHistoryEnd.time, HistoryItem.CMD_UPDATE, mHistoryCur);
             }
             return;
         }
@@ -1860,7 +1901,11 @@
     }
 
     void addHistoryEventLocked(long curTime, int code, String name, int uid) {
-        addHistoryBufferEventLocked(curTime, code, name, uid);
+        mHistoryCur.eventCode = code;
+        mHistoryCur.eventTag = mHistoryCur.localEventTag;
+        mHistoryCur.eventTag.string = name;
+        mHistoryCur.eventTag.uid = uid;
+        addHistoryBufferLocked(curTime);
     }
 
     void addHistoryRecordLocked(long curTime, byte cmd) {
@@ -1870,8 +1915,7 @@
         } else {
             rec = new HistoryItem();
         }
-        rec.setTo(mHistoryBaseTime + curTime, cmd,
-                HistoryItem.EVENT_NONE, 0, null, mHistoryCur);
+        rec.setTo(mHistoryBaseTime + curTime, cmd, mHistoryCur);
 
         addHistoryRecordLocked(rec);
     }
@@ -1905,8 +1949,8 @@
         mHistoryBuffer.setDataSize(0);
         mHistoryBuffer.setDataPosition(0);
         mHistoryBuffer.setDataCapacity(MAX_HISTORY_BUFFER / 2);
-        mHistoryLastLastWritten.cmd = HistoryItem.CMD_NULL;
-        mHistoryLastWritten.cmd = HistoryItem.CMD_NULL;
+        mHistoryLastLastWritten.clear();
+        mHistoryLastWritten.clear();
         mHistoryTagPool.clear();
         mNextHistoryTagIdx = 0;
         mNumHistoryTagChars = 0;
@@ -1942,8 +1986,6 @@
         mBluetoothPingStart = -1;
     }
 
-    int mWakeLockNesting;
-
     public void addIsolatedUidLocked(int isolatedUid, int appUid) {
         mIsolatedUids.put(isolatedUid, appUid);
     }
@@ -1962,10 +2004,50 @@
 
     public void noteEventLocked(int code, String name, int uid) {
         uid = mapUid(uid);
+        if ((code&HistoryItem.EVENT_FLAG_START) != 0) {
+            int idx = code&~HistoryItem.EVENT_FLAG_START;
+            HashMap<String, SparseBooleanArray> active = mActiveEvents[idx];
+            if (active == null) {
+                active = new HashMap<String, SparseBooleanArray>();
+                mActiveEvents[idx] = active;
+            }
+            SparseBooleanArray uids = active.get(name);
+            if (uids == null) {
+                uids = new SparseBooleanArray();
+                active.put(name, uids);
+            }
+            if (uids.get(uid)) {
+                // Already set, nothing to do!
+                return;
+            }
+            uids.put(uid, true);
+        } else if ((code&HistoryItem.EVENT_FLAG_FINISH) != 0) {
+            int idx = code&~HistoryItem.EVENT_FLAG_FINISH;
+            HashMap<String, SparseBooleanArray> active = mActiveEvents[idx];
+            if (active == null) {
+                // not currently active, nothing to do.
+                return;
+            }
+            SparseBooleanArray uids = active.get(name);
+            if (uids == null) {
+                // not currently active, nothing to do.
+                return;
+            }
+            idx = uids.indexOfKey(uid);
+            if (idx < 0 || !uids.valueAt(idx)) {
+                // not currently active, nothing to do.
+                return;
+            }
+            uids.removeAt(idx);
+            if (uids.size() <= 0) {
+                active.remove(name);
+            }
+        }
         addHistoryEventLocked(SystemClock.elapsedRealtime(), code, name, uid);
     }
 
-    public void noteStartWakeLocked(int uid, int pid, String name, int type) {
+    public void noteStartWakeLocked(int uid, int pid, String name, int type,
+            boolean unimportantForLogging) {
         uid = mapUid(uid);
         if (type == WAKE_TYPE_PARTIAL) {
             // Only care about partial wake locks, since full wake locks
@@ -1977,7 +2059,18 @@
                 mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag;
                 mHistoryCur.wakelockTag.string = name;
                 mHistoryCur.wakelockTag.uid = uid;
+                mWakeLockImportant = !unimportantForLogging;
                 addHistoryRecordLocked(SystemClock.elapsedRealtime());
+            } else if (!mWakeLockImportant && !unimportantForLogging) {
+                if (mHistoryLastWritten.wakelockTag != null) {
+                    // We'll try to update the last tag.
+                    mHistoryLastWritten.wakelockTag = null;
+                    mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag;
+                    mHistoryCur.wakelockTag.string = name;
+                    mHistoryCur.wakelockTag.uid = uid;
+                    addHistoryRecordLocked(SystemClock.elapsedRealtime());
+                }
+                mWakeLockImportant = true;
             }
             mWakeLockNesting++;
         }
@@ -2010,10 +2103,11 @@
         }
     }
 
-    public void noteStartWakeFromSourceLocked(WorkSource ws, int pid, String name, int type) {
+    public void noteStartWakeFromSourceLocked(WorkSource ws, int pid, String name, int type,
+            boolean unimportantForLogging) {
         int N = ws.size();
         for (int i=0; i<N; i++) {
-            noteStartWakeLocked(ws.get(i), pid, name, type);
+            noteStartWakeLocked(ws.get(i), pid, name, type, unimportantForLogging);
         }
     }
 
@@ -2224,7 +2318,7 @@
 
             // Fake a wake lock, so we consider the device waked as long
             // as the screen is on.
-            noteStartWakeLocked(-1, -1, "screen", WAKE_TYPE_PARTIAL);
+            noteStartWakeLocked(-1, -1, "screen", WAKE_TYPE_PARTIAL, false);
             
             // Update discharge amounts.
             if (mOnBatteryInternal) {
@@ -4979,6 +5073,9 @@
     public boolean startIteratingHistoryLocked() {
         if (DEBUG_HISTORY) Slog.i(TAG, "ITERATING: buff size=" + mHistoryBuffer.dataSize()
                 + " pos=" + mHistoryBuffer.dataPosition());
+        if (mHistoryBuffer.dataSize() <= 0) {
+            return false;
+        }
         mHistoryBuffer.setDataPosition(0);
         mReadOverflow = false;
         mIteratingHistory = true;
@@ -4992,7 +5089,7 @@
             mReadHistoryUids[idx] = tag.uid;
             mReadHistoryChars += tag.string.length() + 1;
         }
-        return mHistoryBuffer.dataSize() > 0;
+        return true;
     }
 
     @Override
@@ -5075,8 +5172,38 @@
         mDischargeAmountScreenOff = 0;
         mDischargeAmountScreenOffSinceCharge = 0;
     }
-    
-    public void resetAllStatsLocked() {
+
+    public void resetAllStatsCmdLocked() {
+        resetAllStatsLocked();
+        long uptime = SystemClock.uptimeMillis() * 1000;
+        long mSecRealtime = SystemClock.elapsedRealtime();
+        long realtime = mSecRealtime * 1000;
+        mDischargeStartLevel = mHistoryCur.batteryLevel;
+        pullPendingStateUpdatesLocked();
+        addHistoryRecordLocked(mSecRealtime);
+        mDischargeCurrentLevel = mDischargeUnplugLevel = mHistoryCur.batteryLevel;
+        if ((mHistoryCur.states&HistoryItem.STATE_BATTERY_PLUGGED_FLAG) != 0) {
+            mTrackBatteryPastUptime = 0;
+            mTrackBatteryPastRealtime = 0;
+        } else {
+            mTrackBatteryUptimeStart = uptime;
+            mTrackBatteryRealtimeStart = realtime;
+            mUnpluggedBatteryUptime = getBatteryUptimeLocked(uptime);
+            mUnpluggedBatteryRealtime = getBatteryRealtimeLocked(realtime);
+            if (mScreenOn) {
+                mDischargeScreenOnUnplugLevel = mHistoryCur.batteryLevel;
+                mDischargeScreenOffUnplugLevel = 0;
+            } else {
+                mDischargeScreenOnUnplugLevel = 0;
+                mDischargeScreenOffUnplugLevel = mHistoryCur.batteryLevel;
+            }
+            mDischargeAmountScreenOn = 0;
+            mDischargeAmountScreenOff = 0;
+        }
+        initActiveHistoryEventsLocked(mSecRealtime);
+    }
+
+    private void resetAllStatsLocked() {
         mStartCount = 0;
         initTimes();
         mScreenOnTimer.reset(this, false);
@@ -5121,6 +5248,23 @@
         clearHistoryLocked();
     }
 
+    private void initActiveHistoryEventsLocked(long nowRealtime) {
+        for (int i=0; i<HistoryItem.EVENT_COUNT; i++) {
+            HashMap<String, SparseBooleanArray> active = mActiveEvents[i];
+            if (active == null) {
+                continue;
+            }
+            for (HashMap.Entry<String, SparseBooleanArray> ent : active.entrySet()) {
+                SparseBooleanArray uids = ent.getValue();
+                for (int j=0; j<uids.size(); j++) {
+                    if (uids.valueAt(j)) {
+                        addHistoryEventLocked(nowRealtime, i, ent.getKey(), uids.keyAt(j));
+                    }
+                }
+            }
+        }
+    }
+
     void updateDischargeScreenLevelsLocked(boolean oldScreenOn, boolean newScreenOn) {
         if (oldScreenOn) {
             int diff = mDischargeScreenOnUnplugLevel - mDischargeCurrentLevel;
@@ -5170,12 +5314,14 @@
             // battery was last full, or the level is at 100, or
             // we have gone through a significant charge (from a very low
             // level to a now very high level).
+            boolean reset = false;
             if (oldStatus == BatteryManager.BATTERY_STATUS_FULL
                     || level >= 90
                     || (mDischargeCurrentLevel < 20 && level >= 80)) {
                 doWrite = true;
                 resetAllStatsLocked();
                 mDischargeStartLevel = level;
+                reset = true;
             }
             pullPendingStateUpdatesLocked();
             mHistoryCur.batteryLevel = (byte)level;
@@ -5198,6 +5344,9 @@
             mDischargeAmountScreenOn = 0;
             mDischargeAmountScreenOff = 0;
             doUnplugLocked(realtime, mUnpluggedBatteryUptime, mUnpluggedBatteryRealtime);
+            if (reset) {
+                initActiveHistoryEventsLocked(mSecRealtime);
+            }
         } else {
             pullPendingStateUpdatesLocked();
             mHistoryCur.batteryLevel = (byte)level;
@@ -5292,7 +5441,7 @@
             if (!onBattery && status == BatteryManager.BATTERY_STATUS_FULL) {
                 // We don't record history while we are plugged in and fully charged.
                 // The next time we are unplugged, history will be cleared.
-                mRecordingHistory = false;
+                mRecordingHistory = DEBUG;
             }
         }
     }
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/server/SystemService.java b/core/java/com/android/server/SystemService.java
index d69293a..0c89f94 100644
--- a/core/java/com/android/server/SystemService.java
+++ b/core/java/com/android/server/SystemService.java
@@ -23,24 +23,24 @@
 /**
  * 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:
- *
- * {@link #onCreate(android.content.Context)} is called to initialize the
- * service.
- *
- * {@link #onStart()} is called to get the service running. It is common
- * for services to publish their Binder interface at this point. All required
- * dependencies are also assumed to be ready to use.
- *
- * Then {@link #onBootPhase(int)} is called as many times as there are boot phases
+ * </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.
- *
- * NOTE: All lifecycle methods are called from the same thread that created the
- * SystemService.
+ * </ul><p>
+ * NOTE: All lifecycle methods are called from the system server's main looper thread.
+ * </p>
  *
  * {@hide}
  */
@@ -54,17 +54,34 @@
     public static final int PHASE_THIRD_PARTY_APPS_CAN_START = 600;
     public static final int PHASE_BOOT_COMPLETE = 1000;
 
-    private SystemServiceManager mManager;
-    private Context mContext;
+    private final Context mContext;
 
-    final void init(Context context, SystemServiceManager manager) {
+    /**
+     * 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;
-        mManager = manager;
-        onCreate(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 mManager.isSafeMode();
+        return getManager().isSafeMode();
     }
 
     /**
@@ -126,8 +143,8 @@
         return LocalServices.getService(type);
     }
 
-    public final Context getContext() {
-        return mContext;
+    private SystemServiceManager getManager() {
+        return LocalServices.getService(SystemServiceManager.class);
     }
 
 //    /**
diff --git a/core/java/com/android/server/SystemServiceManager.java b/core/java/com/android/server/SystemServiceManager.java
index 06ad7f4..6c853be 100644
--- a/core/java/com/android/server/SystemServiceManager.java
+++ b/core/java/com/android/server/SystemServiceManager.java
@@ -17,14 +17,15 @@
 package com.android.server;
 
 import android.content.Context;
-import android.util.Log;
 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}s.
+ * {@link com.android.server.SystemService system services}.
  *
  * {@hide}
  */
@@ -68,24 +69,43 @@
      */
     @SuppressWarnings("unchecked")
     public <T extends SystemService> T startService(Class<T> serviceClass) {
-        final T serviceInstance = (T)createInstance(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 {
-            Slog.i(TAG, "Creating " + serviceClass.getSimpleName());
-            serviceInstance.init(mContext, this);
-        } catch (Throwable e) {
-            throw new RuntimeException("Failed to create service " + serviceClass.getName(), e);
+            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);
         }
 
-        mServices.add(serviceInstance);
+        // Register it.
+        mServices.add(service);
 
+        // Start it.
         try {
-            Slog.i(TAG, "Starting " + serviceClass.getSimpleName());
-            serviceInstance.onStart();
-        } catch (Throwable e) {
-            throw new RuntimeException("Failed to start service " + serviceClass.getName(), e);
+            service.onStart();
+        } catch (RuntimeException ex) {
+            throw new RuntimeException("Failed to start service " + name
+                    + ": onStart threw an exception", ex);
         }
-
-        return serviceInstance;
+        return service;
     }
 
     /**
@@ -107,9 +127,11 @@
             final SystemService service = mServices.get(i);
             try {
                 service.onBootPhase(mCurrentPhase);
-            } catch (Throwable e) {
-                reportWtf("Service " + service.getClass().getName() +
-                        " threw an Exception processing boot phase " + mCurrentPhase, e);
+            } catch (Exception ex) {
+                throw new RuntimeException("Failed to boot service "
+                        + service.getClass().getName()
+                        + ": onBootPhase threw an exception during phase "
+                        + mCurrentPhase, ex);
             }
         }
     }
@@ -144,34 +166,4 @@
 
         Slog.e(TAG, builder.toString());
     }
-
-    private SystemService createInstance(Class<?> clazz) {
-        // Make sure it's a type we expect
-        if (!SystemService.class.isAssignableFrom(clazz)) {
-            reportWtf("Class " + clazz.getName() + " does not extend " +
-                    SystemService.class.getName());
-        }
-
-        try {
-            return (SystemService) clazz.newInstance();
-        } catch (InstantiationException e) {
-            reportWtf("Class " + clazz.getName() + " is abstract", e);
-        } catch (IllegalAccessException e) {
-            reportWtf("Class " + clazz.getName() +
-                    " must have a public no-arg constructor", e);
-        }
-        return null;
-    }
-
-    private static void reportWtf(String message) {
-        reportWtf(message, null);
-    }
-
-    private static void reportWtf(String message, Throwable e) {
-        Slog.i(TAG, "******************************");
-        Log.wtf(TAG, message, e);
-
-        // Make sure we die
-        throw new RuntimeException(message, e);
-    }
 }
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index f8d96e3..d8041c5 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -57,6 +57,7 @@
 	android_view_GraphicBuffer.cpp \
 	android_view_GLRenderer.cpp \
 	android_view_GLES20Canvas.cpp \
+	android_view_HardwareLayer.cpp \
 	android_view_ThreadedRenderer.cpp \
 	android_view_MotionEvent.cpp \
 	android_view_PointerIcon.cpp \
@@ -193,6 +194,7 @@
 	libui \
 	libgui \
 	libinput \
+	libinputflinger \
 	libcamera_client \
 	libcamera_metadata \
 	libskia \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 7ed6641..77c5c18 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -123,6 +123,7 @@
 extern int register_android_view_GraphicBuffer(JNIEnv* env);
 extern int register_android_view_GLES20Canvas(JNIEnv* env);
 extern int register_android_view_GLRenderer(JNIEnv* env);
+extern int register_android_view_HardwareLayer(JNIEnv* env);
 extern int register_android_view_ThreadedRenderer(JNIEnv* env);
 extern int register_android_view_Surface(JNIEnv* env);
 extern int register_android_view_SurfaceControl(JNIEnv* env);
@@ -1127,6 +1128,7 @@
     REG_JNI(register_android_view_GraphicBuffer),
     REG_JNI(register_android_view_GLES20Canvas),
     REG_JNI(register_android_view_GLRenderer),
+    REG_JNI(register_android_view_HardwareLayer),
     REG_JNI(register_android_view_ThreadedRenderer),
     REG_JNI(register_android_view_Surface),
     REG_JNI(register_android_view_SurfaceControl),
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index 3e1f26a..fae93ba 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -474,6 +474,12 @@
             bitmapCreateFlags, ninePatchChunk, layoutBounds, -1);
 }
 
+// Need to buffer enough input to be able to rewind as much as might be read by a decoder
+// trying to determine the stream's format. Currently the most is 64, read by
+// SkImageDecoder_libwebp.
+// FIXME: Get this number from SkImageDecoder
+#define BYTES_TO_BUFFER 64
+
 static jobject nativeDecodeStream(JNIEnv* env, jobject clazz, jobject is, jbyteArray storage,
         jobject padding, jobject options) {
 
@@ -481,11 +487,8 @@
     SkAutoTUnref<SkStream> stream(CreateJavaInputStreamAdaptor(env, is, storage));
 
     if (stream.get()) {
-        // Need to buffer enough input to be able to rewind as much as might be read by a decoder
-        // trying to determine the stream's format. Currently the most is 64, read by
-        // SkImageDecoder_libwebp.
-        // FIXME: Get this number from SkImageDecoder
-        SkAutoTUnref<SkStreamRewindable> bufferedStream(SkFrontBufferedStream::Create(stream, 64));
+        SkAutoTUnref<SkStreamRewindable> bufferedStream(
+                SkFrontBufferedStream::Create(stream, BYTES_TO_BUFFER));
         SkASSERT(bufferedStream.get() != NULL);
         // for now we don't allow purgeable with java inputstreams
         bitmap = doDecode(env, bufferedStream, padding, options, false, false);
@@ -506,30 +509,48 @@
         return nullObjectReturn("fstat return -1");
     }
 
-    bool isPurgeable = optionsPurgeable(env, bitmapFactoryOptions);
-    bool isShareable = optionsShareable(env, bitmapFactoryOptions);
-    bool weOwnTheFD = false;
-    if (isPurgeable && isShareable) {
-        int newFD = ::dup(descriptor);
-        if (-1 != newFD) {
-            weOwnTheFD = true;
-            descriptor = newFD;
-        }
-    }
+    // Restore the descriptor's offset on exiting this function.
+    AutoFDSeek autoRestore(descriptor);
 
     FILE* file = fdopen(descriptor, "r");
     if (file == NULL) {
         return nullObjectReturn("Could not open file");
     }
 
-    SkAutoTUnref<SkFILEStream> stream(new SkFILEStream(file,
-            weOwnTheFD ? SkFILEStream::kCallerPasses_Ownership :
+    SkAutoTUnref<SkFILEStream> fileStream(new SkFILEStream(file,
                          SkFILEStream::kCallerRetains_Ownership));
 
-    /* Allow purgeable iff we own the FD, i.e., in the puregeable and
-       shareable case.
-    */
-    return doDecode(env, stream, padding, bitmapFactoryOptions, weOwnTheFD);
+    SkAutoTUnref<SkStreamRewindable> stream;
+
+    // Retain the old behavior of allowing purgeable if both purgeable and
+    // shareable are set to true.
+    bool isPurgeable = optionsPurgeable(env, bitmapFactoryOptions)
+                       && optionsShareable(env, bitmapFactoryOptions);
+    if (isPurgeable) {
+        // Copy the stream, so the image can be decoded multiple times without
+        // continuing to modify the original file descriptor.
+        // Copy beginning from the current position.
+        const size_t fileSize = fileStream->getLength() - fileStream->getPosition();
+        void* buffer = sk_malloc_flags(fileSize, 0);
+        if (buffer == NULL) {
+            return nullObjectReturn("Could not make a copy for ashmem");
+        }
+
+        SkAutoTUnref<SkData> data(SkData::NewFromMalloc(buffer, fileSize));
+
+        if (fileStream->read(buffer, fileSize) != fileSize) {
+            return nullObjectReturn("Could not read the file.");
+        }
+
+        stream.reset(new SkMemoryStream(data));
+    } else {
+        // Use a buffered stream. Although an SkFILEStream can be rewound, this
+        // ensures that SkImageDecoder::Factory never rewinds beyond the
+        // current position of the file descriptor.
+        stream.reset(SkFrontBufferedStream::Create(fileStream, BYTES_TO_BUFFER));
+    }
+
+    return doDecode(env, stream, padding, bitmapFactoryOptions, isPurgeable);
 }
 
 static jobject nativeDecodeAsset(JNIEnv* env, jobject clazz, jlong native_asset,
diff --git a/core/jni/android/graphics/Canvas.cpp b/core/jni/android/graphics/Canvas.cpp
index 2cb2812..e98d45b 100644
--- a/core/jni/android/graphics/Canvas.cpp
+++ b/core/jni/android/graphics/Canvas.cpp
@@ -327,9 +327,10 @@
     }
 
     static jboolean clipPath(JNIEnv* env, jobject, jlong canvasHandle,
-                             SkPath* path, jint op) {
+                             jlong pathHandle, jint op) {
         SkCanvas* canvas = reinterpret_cast<SkCanvas*>(canvasHandle);
-        bool result = canvas->clipPath(*path, static_cast<SkRegion::Op>(op));
+        bool result = canvas->clipPath(*reinterpret_cast<SkPath*>(pathHandle),
+                                       static_cast<SkRegion::Op>(op));
         return result ? JNI_TRUE : JNI_FALSE;
     }
 
@@ -342,9 +343,9 @@
     }
 
     static void setDrawFilter(JNIEnv* env, jobject, jlong canvasHandle,
-                              SkDrawFilter* filter) {
+                              jlong filterHandle) {
         SkCanvas* canvas = reinterpret_cast<SkCanvas*>(canvasHandle);
-        canvas->setDrawFilter(filter);
+        canvas->setDrawFilter(reinterpret_cast<SkDrawFilter*>(filterHandle));
     }
 
     static jboolean quickReject__RectF(JNIEnv* env, jobject, jlong canvasHandle,
@@ -356,9 +357,9 @@
     }
 
     static jboolean quickReject__Path(JNIEnv* env, jobject, jlong canvasHandle,
-                                       SkPath* path) {
+                                       jlong pathHandle) {
         SkCanvas* canvas = reinterpret_cast<SkCanvas*>(canvasHandle);
-        bool result = canvas->quickReject(*path);
+        bool result = canvas->quickReject(*reinterpret_cast<SkPath*>(pathHandle));
         return result ? JNI_TRUE : JNI_FALSE;
     }
 
diff --git a/core/jni/android/graphics/ColorFilter.cpp b/core/jni/android/graphics/ColorFilter.cpp
index da40acff..09589bd 100644
--- a/core/jni/android/graphics/ColorFilter.cpp
+++ b/core/jni/android/graphics/ColorFilter.cpp
@@ -23,7 +23,6 @@
 #include "SkColorMatrixFilter.h"
 #include "SkPorterDuff.h"
 
-#include <SkiaColorFilter.h>
 #include <Caches.h>
 
 namespace android {
@@ -32,64 +31,9 @@
 
 class SkColorFilterGlue {
 public:
-    static void finalizer(JNIEnv* env, jobject clazz, jlong objHandle, jlong fHandle) {
-        SkColorFilter* obj = reinterpret_cast<SkColorFilter *>(objHandle);
-        SkiaColorFilter* f = reinterpret_cast<SkiaColorFilter *>(fHandle);
-        if (obj) SkSafeUnref(obj);
-        // f == NULL when not !USE_OPENGL_RENDERER, so no need to delete outside the ifdef
-#ifdef USE_OPENGL_RENDERER
-        if (f && android::uirenderer::Caches::hasInstance()) {
-            android::uirenderer::Caches::getInstance().resourceCache.destructor(f);
-        } else {
-            delete f;
-        }
-#endif
-    }
-
-    static jlong glCreatePorterDuffFilter(JNIEnv* env, jobject, jlong skFilterHandle,
-            jint srcColor, jint modeHandle) {
-        SkColorFilter *skFilter = reinterpret_cast<SkColorFilter *>(skFilterHandle);
-        SkPorterDuff::Mode mode = static_cast<SkPorterDuff::Mode>(modeHandle);
-#ifdef USE_OPENGL_RENDERER
-        return reinterpret_cast<jlong>(new SkiaBlendFilter(skFilter, srcColor, SkPorterDuff::ToXfermodeMode(mode)));
-#else
-        return NULL;
-#endif
-    }
-
-    static jlong glCreateLightingFilter(JNIEnv* env, jobject, jlong skFilterHandle,
-            jint mul, jint add) {
-        SkColorFilter *skFilter = reinterpret_cast<SkColorFilter *>(skFilterHandle);
-#ifdef USE_OPENGL_RENDERER
-        return reinterpret_cast<jlong>(new SkiaLightingFilter(skFilter, mul, add));
-#else
-        return NULL;
-#endif
-    }
-
-    static jlong glCreateColorMatrixFilter(JNIEnv* env, jobject, jlong skFilterHandle,
-            jfloatArray jarray) {
-        SkColorFilter *skFilter = reinterpret_cast<SkColorFilter *>(skFilterHandle);
-#ifdef USE_OPENGL_RENDERER
-        AutoJavaFloatArray autoArray(env, jarray, 20);
-        const float* src = autoArray.ptr();
-
-        float* colorMatrix = new float[16];
-        memcpy(colorMatrix, src, 4 * sizeof(float));
-        memcpy(&colorMatrix[4], &src[5], 4 * sizeof(float));
-        memcpy(&colorMatrix[8], &src[10], 4 * sizeof(float));
-        memcpy(&colorMatrix[12], &src[15], 4 * sizeof(float));
-
-        float* colorVector = new float[4];
-        colorVector[0] = src[4];
-        colorVector[1] = src[9];
-        colorVector[2] = src[14];
-        colorVector[3] = src[19];
-
-        return reinterpret_cast<jlong>(new SkiaColorMatrixFilter(skFilter, colorMatrix, colorVector));
-#else
-        return NULL;
-#endif
+    static void finalizer(JNIEnv* env, jobject clazz, jlong skFilterHandle) {
+        SkColorFilter* filter = reinterpret_cast<SkColorFilter *>(skFilterHandle);
+        if (filter) SkSafeUnref(filter);
     }
 
     static jlong CreatePorterDuffFilter(JNIEnv* env, jobject, jint srcColor,
@@ -119,22 +63,19 @@
 };
 
 static JNINativeMethod colorfilter_methods[] = {
-    {"destroyFilter", "(JJ)V", (void*) SkColorFilterGlue::finalizer}
+    {"destroyFilter", "(J)V", (void*) SkColorFilterGlue::finalizer}
 };
 
 static JNINativeMethod porterduff_methods[] = {
     { "native_CreatePorterDuffFilter", "(II)J", (void*) SkColorFilterGlue::CreatePorterDuffFilter   },
-    { "nCreatePorterDuffFilter",       "(JII)J", (void*) SkColorFilterGlue::glCreatePorterDuffFilter }
 };
 
 static JNINativeMethod lighting_methods[] = {
     { "native_CreateLightingFilter", "(II)J", (void*) SkColorFilterGlue::CreateLightingFilter   },
-    { "nCreateLightingFilter",       "(JII)J", (void*) SkColorFilterGlue::glCreateLightingFilter },
 };
 
 static JNINativeMethod colormatrix_methods[] = {
     { "nativeColorMatrixFilter", "([F)J", (void*) SkColorFilterGlue::CreateColorMatrixFilter   },
-    { "nColorMatrixFilter",      "(J[F)J", (void*) SkColorFilterGlue::glCreateColorMatrixFilter }
 };
 
 #define REG(env, name, array) \
diff --git a/core/jni/android/graphics/SurfaceTexture.cpp b/core/jni/android/graphics/SurfaceTexture.cpp
index 3116955..5d49204 100644
--- a/core/jni/android/graphics/SurfaceTexture.cpp
+++ b/core/jni/android/graphics/SurfaceTexture.cpp
@@ -141,7 +141,8 @@
     *needsDetach = false;
     JNIEnv* env = AndroidRuntime::getJNIEnv();
     if (env == NULL) {
-        JavaVMAttachArgs args = {JNI_VERSION_1_4, NULL, NULL};
+        JavaVMAttachArgs args = {
+            JNI_VERSION_1_4, "JNISurfaceTextureContext", NULL };
         JavaVM* vm = AndroidRuntime::getJavaVM();
         int result = vm->AttachCurrentThread(&env, (void*) &args);
         if (result != JNI_OK) {
diff --git a/core/jni/android/graphics/pdf/PdfDocument.cpp b/core/jni/android/graphics/pdf/PdfDocument.cpp
index 6175a8f..d54aaa8 100644
--- a/core/jni/android/graphics/pdf/PdfDocument.cpp
+++ b/core/jni/android/graphics/pdf/PdfDocument.cpp
@@ -113,24 +113,24 @@
     PageRecord* mCurrentPage;
 };
 
-static jint nativeCreateDocument(JNIEnv* env, jobject thiz) {
-    return reinterpret_cast<jint>(new PdfDocument());
+static jlong nativeCreateDocument(JNIEnv* env, jobject thiz) {
+    return reinterpret_cast<jlong>(new PdfDocument());
 }
 
-static jint nativeStartPage(JNIEnv* env, jobject thiz, jint documentPtr,
+static jlong nativeStartPage(JNIEnv* env, jobject thiz, jlong documentPtr,
         jint pageWidth, jint pageHeight,
         jint contentLeft, jint contentTop, jint contentRight, jint contentBottom) {
     PdfDocument* document = reinterpret_cast<PdfDocument*>(documentPtr);
-    return reinterpret_cast<jint>(document->startPage(pageWidth, pageHeight,
+    return reinterpret_cast<jlong>(document->startPage(pageWidth, pageHeight,
             contentLeft, contentTop, contentRight, contentBottom));
 }
 
-static void nativeFinishPage(JNIEnv* env, jobject thiz, jint documentPtr) {
+static void nativeFinishPage(JNIEnv* env, jobject thiz, jlong documentPtr) {
     PdfDocument* document = reinterpret_cast<PdfDocument*>(documentPtr);
     document->finishPage();
 }
 
-static void nativeWriteTo(JNIEnv* env, jobject thiz, jint documentPtr, jobject out,
+static void nativeWriteTo(JNIEnv* env, jobject thiz, jlong documentPtr, jobject out,
         jbyteArray chunk) {
     PdfDocument* document = reinterpret_cast<PdfDocument*>(documentPtr);
     SkWStream* skWStream = CreateJavaOutputStreamAdaptor(env, out, chunk);
@@ -138,17 +138,17 @@
     delete skWStream;
 }
 
-static void nativeClose(JNIEnv* env, jobject thiz, jint documentPtr) {
+static void nativeClose(JNIEnv* env, jobject thiz, jlong documentPtr) {
     PdfDocument* document = reinterpret_cast<PdfDocument*>(documentPtr);
     document->close();
 }
 
 static JNINativeMethod gPdfDocument_Methods[] = {
-    {"nativeCreateDocument", "()I", (void*) nativeCreateDocument},
-    {"nativeStartPage", "(IIIIIII)I", (void*) nativeStartPage},
-    {"nativeFinishPage", "(I)V", (void*) nativeFinishPage},
-    {"nativeWriteTo", "(ILjava/io/OutputStream;[B)V", (void*) nativeWriteTo},
-    {"nativeClose", "(I)V", (void*) nativeClose}
+    {"nativeCreateDocument", "()J", (void*) nativeCreateDocument},
+    {"nativeStartPage", "(JIIIIII)J", (void*) nativeStartPage},
+    {"nativeFinishPage", "(J)V", (void*) nativeFinishPage},
+    {"nativeWriteTo", "(JLjava/io/OutputStream;[B)V", (void*) nativeWriteTo},
+    {"nativeClose", "(J)V", (void*) nativeClose}
 };
 
 int register_android_graphics_pdf_PdfDocument(JNIEnv* env) {
diff --git a/core/jni/android_database_SQLiteGlobal.cpp b/core/jni/android_database_SQLiteGlobal.cpp
index acc2276..89d64fa 100644
--- a/core/jni/android_database_SQLiteGlobal.cpp
+++ b/core/jni/android_database_SQLiteGlobal.cpp
@@ -39,7 +39,7 @@
     bool verboseLog = !!data;
     if (iErrCode == 0 || iErrCode == SQLITE_CONSTRAINT || iErrCode == SQLITE_SCHEMA) {
         if (verboseLog) {
-            ALOGV(LOG_VERBOSE, SQLITE_LOG_TAG, "(%d) %s\n", iErrCode, zMsg);
+            ALOG(LOG_VERBOSE, SQLITE_LOG_TAG, "(%d) %s\n", iErrCode, zMsg);
         }
     } else {
         ALOG(LOG_ERROR, SQLITE_LOG_TAG, "(%d) %s\n", iErrCode, zMsg);
diff --git a/core/jni/android_emoji_EmojiFactory.cpp b/core/jni/android_emoji_EmojiFactory.cpp
index 5276934..f127d29 100644
--- a/core/jni/android_emoji_EmojiFactory.cpp
+++ b/core/jni/android_emoji_EmojiFactory.cpp
@@ -104,7 +104,7 @@
 static jobject create_java_EmojiFactory(
     JNIEnv* env, EmojiFactory* factory, jstring name) {
   jobject obj = env->NewObject(gEmojiFactory_class, gEmojiFactory_constructorMethodID,
-      static_cast<jint>(reinterpret_cast<uintptr_t>(factory)), name);
+      reinterpret_cast<jlong>(factory), name);
   if (env->ExceptionCheck() != 0) {
     ALOGE("*** Uncaught exception returned from Java call!\n");
     env->ExceptionDescribe();
@@ -155,7 +155,7 @@
 }
 
 static jobject android_emoji_EmojiFactory_getBitmapFromAndroidPua(
-    JNIEnv* env, jobject clazz, jint nativeEmojiFactory, jint pua) {
+    JNIEnv* env, jobject clazz, jlong nativeEmojiFactory, jint pua) {
   EmojiFactory *factory = reinterpret_cast<EmojiFactory *>(nativeEmojiFactory);
 
   int size;
@@ -175,7 +175,7 @@
 }
 
 static void android_emoji_EmojiFactory_destructor(
-    JNIEnv* env, jobject obj, jint nativeEmojiFactory) {
+    JNIEnv* env, jobject obj, jlong nativeEmojiFactory) {
   /*
   // Must not delete this object!!
   EmojiFactory *factory = reinterpret_cast<EmojiFactory *>(nativeEmojiFactory);
@@ -184,49 +184,49 @@
 }
 
 static jint android_emoji_EmojiFactory_getAndroidPuaFromVendorSpecificSjis(
-    JNIEnv* env, jobject obj, jint nativeEmojiFactory, jchar sjis) {
+    JNIEnv* env, jobject obj, jlong nativeEmojiFactory, jchar sjis) {
   EmojiFactory *factory = reinterpret_cast<EmojiFactory *>(nativeEmojiFactory);
   return factory->GetAndroidPuaFromVendorSpecificSjis(sjis);
 }
 
 static jint android_emoji_EmojiFactory_getVendorSpecificSjisFromAndroidPua(
-    JNIEnv* env, jobject obj, jint nativeEmojiFactory, jint pua) {
+    JNIEnv* env, jobject obj, jlong nativeEmojiFactory, jint pua) {
   EmojiFactory *factory = reinterpret_cast<EmojiFactory *>(nativeEmojiFactory);
   return factory->GetVendorSpecificSjisFromAndroidPua(pua);
 }
 
 static jint android_emoji_EmojiFactory_getAndroidPuaFromVendorSpecificPua(
-    JNIEnv* env, jobject obj, jint nativeEmojiFactory, jint vsu) {
+    JNIEnv* env, jobject obj, jlong nativeEmojiFactory, jint vsu) {
   EmojiFactory *factory = reinterpret_cast<EmojiFactory *>(nativeEmojiFactory);
   return factory->GetAndroidPuaFromVendorSpecificPua(vsu);
 }
 
 static jint android_emoji_EmojiFactory_getVendorSpecificPuaFromAndroidPua(
-    JNIEnv* env, jobject obj, jint nativeEmojiFactory, jint pua) {
+    JNIEnv* env, jobject obj, jlong nativeEmojiFactory, jint pua) {
   EmojiFactory *factory = reinterpret_cast<EmojiFactory *>(nativeEmojiFactory);
   return factory->GetVendorSpecificPuaFromAndroidPua(pua);
 }
 
 static jint android_emoji_EmojiFactory_getMaximumVendorSpecificPua(
-    JNIEnv* env, jobject obj, jint nativeEmojiFactory) {
+    JNIEnv* env, jobject obj, jlong nativeEmojiFactory) {
   EmojiFactory *factory = reinterpret_cast<EmojiFactory *>(nativeEmojiFactory);
   return factory->GetMaximumVendorSpecificPua();
 }
 
 static jint android_emoji_EmojiFactory_getMinimumVendorSpecificPua(
-    JNIEnv* env, jobject obj, jint nativeEmojiFactory) {
+    JNIEnv* env, jobject obj, jlong nativeEmojiFactory) {
   EmojiFactory *factory = reinterpret_cast<EmojiFactory *>(nativeEmojiFactory);
   return factory->GetMinimumVendorSpecificPua();
 }
 
 static jint android_emoji_EmojiFactory_getMaximumAndroidPua(
-    JNIEnv* env, jobject obj, jint nativeEmojiFactory) {
+    JNIEnv* env, jobject obj, jlong nativeEmojiFactory) {
   EmojiFactory *factory = reinterpret_cast<EmojiFactory *>(nativeEmojiFactory);
   return factory->GetMaximumAndroidPua();
 }
 
 static jint android_emoji_EmojiFactory_getMinimumAndroidPua(
-    JNIEnv* env, jobject obj, jint nativeEmojiFactory) {
+    JNIEnv* env, jobject obj, jlong nativeEmojiFactory) {
   EmojiFactory *factory = reinterpret_cast<EmojiFactory *>(nativeEmojiFactory);
   return factory->GetMinimumAndroidPua();
 }
@@ -236,25 +236,25 @@
     (void*)android_emoji_EmojiFactory_newInstance},
   { "newAvailableInstance", "()Landroid/emoji/EmojiFactory;",
     (void*)android_emoji_EmojiFactory_newAvailableInstance},
-  { "nativeDestructor", "(I)V",
+  { "nativeDestructor", "(J)V",
     (void*)android_emoji_EmojiFactory_destructor},
-  { "nativeGetBitmapFromAndroidPua", "(II)Landroid/graphics/Bitmap;",
+  { "nativeGetBitmapFromAndroidPua", "(JI)Landroid/graphics/Bitmap;",
     (void*)android_emoji_EmojiFactory_getBitmapFromAndroidPua},
-  { "nativeGetAndroidPuaFromVendorSpecificSjis", "(IC)I",
+  { "nativeGetAndroidPuaFromVendorSpecificSjis", "(JC)I",
     (void*)android_emoji_EmojiFactory_getAndroidPuaFromVendorSpecificSjis},
-  { "nativeGetVendorSpecificSjisFromAndroidPua", "(II)I",
+  { "nativeGetVendorSpecificSjisFromAndroidPua", "(JI)I",
     (void*)android_emoji_EmojiFactory_getVendorSpecificSjisFromAndroidPua},
-  { "nativeGetAndroidPuaFromVendorSpecificPua", "(II)I",
+  { "nativeGetAndroidPuaFromVendorSpecificPua", "(JI)I",
     (void*)android_emoji_EmojiFactory_getAndroidPuaFromVendorSpecificPua},
-  { "nativeGetVendorSpecificPuaFromAndroidPua", "(II)I",
+  { "nativeGetVendorSpecificPuaFromAndroidPua", "(JI)I",
     (void*)android_emoji_EmojiFactory_getVendorSpecificPuaFromAndroidPua},
-  { "nativeGetMaximumVendorSpecificPua", "(I)I",
+  { "nativeGetMaximumVendorSpecificPua", "(J)I",
     (void*)android_emoji_EmojiFactory_getMaximumVendorSpecificPua},
-  { "nativeGetMinimumVendorSpecificPua", "(I)I",
+  { "nativeGetMinimumVendorSpecificPua", "(J)I",
     (void*)android_emoji_EmojiFactory_getMinimumVendorSpecificPua},
-  { "nativeGetMaximumAndroidPua", "(I)I",
+  { "nativeGetMaximumAndroidPua", "(J)I",
     (void*)android_emoji_EmojiFactory_getMaximumAndroidPua},
-  { "nativeGetMinimumAndroidPua", "(I)I",
+  { "nativeGetMinimumAndroidPua", "(J)I",
     (void*)android_emoji_EmojiFactory_getMinimumAndroidPua}
 };
 
@@ -276,7 +276,7 @@
 int register_android_emoji_EmojiFactory(JNIEnv* env) {
   gEmojiFactory_class = make_globalref(env, "android/emoji/EmojiFactory");
   gEmojiFactory_constructorMethodID = env->GetMethodID(
-      gEmojiFactory_class, "<init>", "(ILjava/lang/String;)V");
+      gEmojiFactory_class, "<init>", "(JLjava/lang/String;)V");
   return jniRegisterNativeMethods(env, "android/emoji/EmojiFactory",
                                   gMethods, NELEM(gMethods));
 }
diff --git a/core/jni/android_os_SELinux.cpp b/core/jni/android_os_SELinux.cpp
index 2b85fef..db84d000 100644
--- a/core/jni/android_os_SELinux.cpp
+++ b/core/jni/android_os_SELinux.cpp
@@ -411,7 +411,7 @@
 
     ScopedUtfChars pathname(env, pathnameStr);
     if (pathname.c_str() == NULL) {
-        ALOGV("restorecon(%p) => threw exception", pathname);
+        ALOGV("restorecon(%p) => threw exception", pathnameStr);
         return false;
     }
 
diff --git a/core/jni/android_view_DisplayList.cpp b/core/jni/android_view_DisplayList.cpp
index 9379375..de68b97 100644
--- a/core/jni/android_view_DisplayList.cpp
+++ b/core/jni/android_view_DisplayList.cpp
@@ -117,6 +117,12 @@
     displayList->setProjectBackwards(shouldProject);
 }
 
+static void android_view_DisplayList_setProjectionReceiver(JNIEnv* env,
+        jobject clazz, jlong displayListPtr, jboolean shouldRecieve) {
+    DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr);
+    displayList->setProjectionReceiver(shouldRecieve);
+}
+
 static void android_view_DisplayList_setOutline(JNIEnv* env,
         jobject clazz, jlong displayListPtr, jlong outlinePathPtr) {
     DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr);
@@ -124,6 +130,24 @@
     displayList->setOutline(outline);
 }
 
+static void android_view_DisplayList_setClipToOutline(JNIEnv* env,
+        jobject clazz, jlong displayListPtr, jboolean clipToOutline) {
+    DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr);
+    displayList->setClipToOutline(clipToOutline);
+}
+
+static void android_view_DisplayList_setCastsShadow(JNIEnv* env,
+        jobject clazz, jlong displayListPtr, jboolean castsShadow) {
+    DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr);
+    displayList->setCastsShadow(castsShadow);
+}
+
+static void android_view_DisplayList_setSharesGlobalCamera(JNIEnv* env,
+        jobject clazz, jlong displayListPtr, jboolean sharesGlobalCamera) {
+    DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr);
+    displayList->setSharesGlobalCamera(sharesGlobalCamera);
+}
+
 static void android_view_DisplayList_setAlpha(JNIEnv* env,
         jobject clazz, jlong displayListPtr, float alpha) {
     DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr);
@@ -391,8 +415,12 @@
     { "nSetAnimationMatrix",   "(JJ)V",  (void*) android_view_DisplayList_setAnimationMatrix },
     { "nSetClipToBounds",      "(JZ)V",  (void*) android_view_DisplayList_setClipToBounds },
     { "nSetIsolatedZVolume",   "(JZ)V",  (void*) android_view_DisplayList_setIsolatedZVolume },
-    { "nSetProjectBackwards",  "(JZ)V", (void*) android_view_DisplayList_setProjectBackwards },
+    { "nSetProjectBackwards",  "(JZ)V",  (void*) android_view_DisplayList_setProjectBackwards },
+    { "nSetProjectionReceiver","(JZ)V",  (void*) android_view_DisplayList_setProjectionReceiver },
     { "nSetOutline",           "(JJ)V",  (void*) android_view_DisplayList_setOutline },
+    { "nSetClipToOutline",     "(JZ)V",  (void*) android_view_DisplayList_setClipToOutline },
+    { "nSetCastsShadow",       "(JZ)V",  (void*) android_view_DisplayList_setCastsShadow },
+    { "nSetSharesGlobalCamera","(JZ)V",  (void*) android_view_DisplayList_setSharesGlobalCamera },
     { "nSetAlpha",             "(JF)V",  (void*) android_view_DisplayList_setAlpha },
     { "nSetHasOverlappingRendering", "(JZ)V",
             (void*) android_view_DisplayList_setHasOverlappingRendering },
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index 6cc94e3..dd089f2 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -47,7 +47,6 @@
 #include <LayerRenderer.h>
 #include <OpenGLRenderer.h>
 #include <SkiaShader.h>
-#include <SkiaColorFilter.h>
 #include <Stencil.h>
 #include <Rect.h>
 
@@ -81,7 +80,6 @@
 
 #define MODIFIER_SHADOW 1
 #define MODIFIER_SHADER 2
-#define MODIFIER_COLOR_FILTER 4
 
 // ----------------------------------------------------------------------------
 
@@ -197,18 +195,6 @@
     env->ReleaseStringUTFChars(name, valueCharArray);
 }
 
-static void android_view_GLES20Canvas_setCountOverdrawEnabled(JNIEnv* env, jobject clazz,
-        jlong rendererPtr, jboolean enabled) {
-    OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
-    renderer->setCountOverdrawEnabled(enabled);
-}
-
-static jfloat android_view_GLES20Canvas_getOverdraw(JNIEnv* env, jobject clazz,
-        jlong rendererPtr) {
-    OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
-    return renderer->getOverdraw();
-}
-
 // ----------------------------------------------------------------------------
 // Functor
 // ----------------------------------------------------------------------------
@@ -222,7 +208,7 @@
 }
 
 static void android_view_GLES20Canvas_detachFunctor(JNIEnv* env,
-        jobject clazz, jlong rendererPtr, jint functorPtr) {
+        jobject clazz, jlong rendererPtr, jlong functorPtr) {
     OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
     Functor* functor = reinterpret_cast<Functor*>(functorPtr);
     renderer->detachFunctor(functor);
@@ -650,7 +636,6 @@
     OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
     if (modifiers & MODIFIER_SHADOW) renderer->resetShadow();
     if (modifiers & MODIFIER_SHADER) renderer->resetShader();
-    if (modifiers & MODIFIER_COLOR_FILTER) renderer->resetColorFilter();
 }
 
 static void android_view_GLES20Canvas_setupShader(JNIEnv* env, jobject clazz,
@@ -660,12 +645,6 @@
     renderer->setupShader(shader);
 }
 
-static void android_view_GLES20Canvas_setupColorFilter(JNIEnv* env, jobject clazz,
-        jlong rendererPtr, jlong colorFilterPtr) {
-    OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
-    SkiaColorFilter* colorFilter = reinterpret_cast<SkiaColorFilter*>(colorFilterPtr);
-    renderer->setupColorFilter(colorFilter);
-}
 
 static void android_view_GLES20Canvas_setupShadow(JNIEnv* env, jobject clazz,
         jlong rendererPtr, jfloat radius, jfloat dx, jfloat dy, jint color) {
@@ -935,147 +914,6 @@
     renderer->resume();
 }
 
-static jint android_view_GLES20Canvas_createLayerRenderer(JNIEnv* env,
-        jobject clazz, jlong layerPtr) {
-    Layer* layer = reinterpret_cast<Layer*>(layerPtr);
-    if (layer) {
-        OpenGLRenderer* renderer = new LayerRenderer(layer);
-        renderer->initProperties();
-        return reinterpret_cast<jint>(renderer);
-    }
-    return NULL;
-}
-
-static jlong android_view_GLES20Canvas_createTextureLayer(JNIEnv* env, jobject clazz,
-        jboolean isOpaque, jintArray layerInfo) {
-    Layer* layer = LayerRenderer::createTextureLayer(isOpaque);
-
-    if (layer) {
-        jint* storage = env->GetIntArrayElements(layerInfo, NULL);
-        storage[0] = layer->getTexture();
-        env->ReleaseIntArrayElements(layerInfo, storage, 0);
-    }
-
-    return reinterpret_cast<jlong>(layer);
-}
-
-static jlong android_view_GLES20Canvas_createLayer(JNIEnv* env, jobject clazz,
-        jint width, jint height, jboolean isOpaque, jintArray layerInfo) {
-    Layer* layer = LayerRenderer::createLayer(width, height, isOpaque);
-
-    if (layer) {
-        jint* storage = env->GetIntArrayElements(layerInfo, NULL);
-        storage[0] = layer->getWidth();
-        storage[1] = layer->getHeight();
-        env->ReleaseIntArrayElements(layerInfo, storage, 0);
-    }
-
-    return reinterpret_cast<jlong>(layer);
-}
-
-static jboolean android_view_GLES20Canvas_resizeLayer(JNIEnv* env, jobject clazz,
-        jlong layerPtr, jint width, jint height, jintArray layerInfo) {
-    Layer* layer = reinterpret_cast<Layer*>(layerPtr);
-    if (LayerRenderer::resizeLayer(layer, width, height)) {
-        jint* storage = env->GetIntArrayElements(layerInfo, NULL);
-        storage[0] = layer->getWidth();
-        storage[1] = layer->getHeight();
-        env->ReleaseIntArrayElements(layerInfo, storage, 0);
-        return JNI_TRUE;
-    }
-    return JNI_FALSE;
-}
-
-static void android_view_GLES20Canvas_setLayerPaint(JNIEnv* env, jobject clazz,
-        jlong layerPtr, jlong paintPtr) {
-    Layer* layer = reinterpret_cast<Layer*>(layerPtr);
-    if (layer) {
-        SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr);
-        layer->setPaint(paint);
-    }
-}
-
-static void android_view_GLES20Canvas_setLayerColorFilter(JNIEnv* env, jobject clazz,
-        jlong layerPtr, jlong colorFilterPtr) {
-    Layer* layer = reinterpret_cast<Layer*>(layerPtr);
-    if (layer) {
-        SkiaColorFilter* colorFilter = reinterpret_cast<SkiaColorFilter*>(colorFilterPtr);
-        layer->setColorFilter(colorFilter);
-    }
-}
-
-static void android_view_GLES20Canvas_setOpaqueLayer(JNIEnv* env, jobject clazz,
-        jlong layerPtr, jboolean isOpaque) {
-    Layer* layer = reinterpret_cast<Layer*>(layerPtr);
-    if (layer) {
-        layer->setBlend(!isOpaque);
-    }
-}
-
-static void android_view_GLES20Canvas_updateTextureLayer(JNIEnv* env, jobject clazz,
-        jlong layerPtr, jint width, jint height, jboolean isOpaque, jobject surface) {
-    float transform[16];
-    sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, surface));
-
-    if (surfaceTexture->updateTexImage() == NO_ERROR) {
-        int64_t frameNumber = surfaceTexture->getFrameNumber();
-        // If the GLConsumer queue is in synchronous mode, need to discard all
-        // but latest frame, using the frame number to tell when we no longer
-        // have newer frames to target. Since we can't tell which mode it is in,
-        // do this unconditionally.
-        int dropCounter = 0;
-        while (surfaceTexture->updateTexImage() == NO_ERROR) {
-            int64_t newFrameNumber = surfaceTexture->getFrameNumber();
-            if (newFrameNumber == frameNumber) break;
-            frameNumber = newFrameNumber;
-            dropCounter++;
-        }
-        #if DEBUG_RENDERER
-        if (dropCounter > 0) {
-            RENDERER_LOGD("Dropped %d frames on texture layer update", dropCounter);
-        }
-        #endif
-        surfaceTexture->getTransformMatrix(transform);
-        GLenum renderTarget = surfaceTexture->getCurrentTextureTarget();
-
-        Layer* layer = reinterpret_cast<Layer*>(layerPtr);
-        LayerRenderer::updateTextureLayer(layer, width, height, isOpaque, renderTarget, transform);
-    }
-}
-
-static void android_view_GLES20Canvas_updateRenderLayer(JNIEnv* env, jobject clazz,
-        jlong layerPtr, jlong rendererPtr, jlong displayListPtr,
-        jint left, jint top, jint right, jint bottom) {
-    Layer* layer = reinterpret_cast<Layer*>(layerPtr);
-    OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
-    DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr);
-    layer->updateDeferred(renderer, displayList, left, top, right, bottom);
-}
-
-static void android_view_GLES20Canvas_clearLayerTexture(JNIEnv* env, jobject clazz,
-        jlong layerPtr) {
-    Layer* layer = reinterpret_cast<Layer*>(layerPtr);
-    layer->clearTexture();
-}
-
-static void android_view_GLES20Canvas_setTextureLayerTransform(JNIEnv* env, jobject clazz,
-        jlong layerPtr, jlong matrixPtr) {
-    Layer* layer = reinterpret_cast<Layer*>(layerPtr);
-    SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixPtr);
-    layer->getTransform().load(*matrix);
-}
-
-static void android_view_GLES20Canvas_destroyLayer(JNIEnv* env, jobject clazz, jlong layerPtr) {
-    Layer* layer = reinterpret_cast<Layer*>(layerPtr);
-    LayerRenderer::destroyLayer(layer);
-}
-
-static void android_view_GLES20Canvas_destroyLayerDeferred(JNIEnv* env,
-        jobject clazz, jlong layerPtr) {
-    Layer* layer = reinterpret_cast<Layer*>(layerPtr);
-    LayerRenderer::destroyLayerDeferred(layer);
-}
-
 static void android_view_GLES20Canvas_drawLayer(JNIEnv* env, jobject clazz,
         jlong rendererPtr, jlong layerPtr, jfloat x, jfloat y) {
     OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
@@ -1176,8 +1014,6 @@
     { "nSetProperty",           "(Ljava/lang/String;Ljava/lang/String;)V",
             (void*) android_view_GLES20Canvas_setProperty },
 
-    { "nSetCountOverdrawEnabled", "(JZ)V",     (void*) android_view_GLES20Canvas_setCountOverdrawEnabled },
-    { "nGetOverdraw",             "(J)F",      (void*) android_view_GLES20Canvas_getOverdraw },
 
     { "nGetStencilSize",    "()I",             (void*) android_view_GLES20Canvas_getStencilSize },
 
@@ -1236,7 +1072,6 @@
 
     { "nResetModifiers",    "(JI)V",           (void*) android_view_GLES20Canvas_resetModifiers },
     { "nSetupShader",       "(JJ)V",           (void*) android_view_GLES20Canvas_setupShader },
-    { "nSetupColorFilter",  "(JJ)V",           (void*) android_view_GLES20Canvas_setupColorFilter },
     { "nSetupShadow",       "(JFFFI)V",        (void*) android_view_GLES20Canvas_setupShadow },
 
     { "nSetupPaintFilter",  "(JII)V",          (void*) android_view_GLES20Canvas_setupPaintFilter },
@@ -1271,19 +1106,6 @@
     { "nInterrupt",              "(J)V",       (void*) android_view_GLES20Canvas_interrupt },
     { "nResume",                 "(J)V",       (void*) android_view_GLES20Canvas_resume },
 
-    { "nCreateLayerRenderer",    "(J)J",       (void*) android_view_GLES20Canvas_createLayerRenderer },
-    { "nCreateLayer",            "(IIZ[I)J",   (void*) android_view_GLES20Canvas_createLayer },
-    { "nResizeLayer",            "(JII[I)Z" ,  (void*) android_view_GLES20Canvas_resizeLayer },
-    { "nSetLayerPaint",          "(JJ)V",      (void*) android_view_GLES20Canvas_setLayerPaint },
-    { "nSetLayerColorFilter",    "(JJ)V",      (void*) android_view_GLES20Canvas_setLayerColorFilter },
-    { "nSetOpaqueLayer",         "(JZ)V",      (void*) android_view_GLES20Canvas_setOpaqueLayer },
-    { "nCreateTextureLayer",     "(Z[I)J",     (void*) android_view_GLES20Canvas_createTextureLayer },
-    { "nUpdateTextureLayer",     "(JIIZLandroid/graphics/SurfaceTexture;)V",
-            (void*) android_view_GLES20Canvas_updateTextureLayer },
-    { "nUpdateRenderLayer",      "(JJJIIII)V", (void*) android_view_GLES20Canvas_updateRenderLayer },
-    { "nClearLayerTexture",      "(J)V",       (void*) android_view_GLES20Canvas_clearLayerTexture },
-    { "nDestroyLayer",           "(J)V",       (void*) android_view_GLES20Canvas_destroyLayer },
-    { "nDestroyLayerDeferred",   "(J)V",       (void*) android_view_GLES20Canvas_destroyLayerDeferred },
     { "nDrawLayer",              "(JJFF)V",    (void*) android_view_GLES20Canvas_drawLayer },
     { "nCopyLayer",              "(JJ)Z",      (void*) android_view_GLES20Canvas_copyLayer },
     { "nClearLayerUpdates",      "(J)V",       (void*) android_view_GLES20Canvas_clearLayerUpdates },
@@ -1291,8 +1113,6 @@
     { "nPushLayerUpdate",        "(JJ)V",      (void*) android_view_GLES20Canvas_pushLayerUpdate },
     { "nCancelLayerUpdate",      "(JJ)V",      (void*) android_view_GLES20Canvas_cancelLayerUpdate },
 
-    { "nSetTextureLayerTransform", "(JJ)V",    (void*) android_view_GLES20Canvas_setTextureLayerTransform },
-
     { "nGetMaximumTextureWidth",  "()I",       (void*) android_view_GLES20Canvas_getMaxTextureWidth },
     { "nGetMaximumTextureHeight", "()I",       (void*) android_view_GLES20Canvas_getMaxTextureHeight },
 
diff --git a/core/jni/android_view_HardwareLayer.cpp b/core/jni/android_view_HardwareLayer.cpp
new file mode 100644
index 0000000..8a0a011
--- /dev/null
+++ b/core/jni/android_view_HardwareLayer.cpp
@@ -0,0 +1,183 @@
+/*
+ * 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 "OpenGLRenderer"
+
+#include "jni.h"
+#include "GraphicsJNI.h"
+#include <nativehelper/JNIHelp.h>
+
+#include <android_runtime/AndroidRuntime.h>
+#include <android_runtime/android_graphics_SurfaceTexture.h>
+
+#include <gui/GLConsumer.h>
+
+#include <SkBitmap.h>
+#include <SkCanvas.h>
+#include <SkMatrix.h>
+#include <SkPaint.h>
+#include <SkXfermode.h>
+
+#include <DeferredLayerUpdater.h>
+#include <DisplayList.h>
+#include <LayerRenderer.h>
+#include <SkiaShader.h>
+#include <Rect.h>
+
+namespace android {
+
+using namespace uirenderer;
+
+#ifdef USE_OPENGL_RENDERER
+
+static jlong android_view_HardwareLayer_createTextureLayer(JNIEnv* env, jobject clazz) {
+    Layer* layer = LayerRenderer::createTextureLayer();
+    if (!layer) return 0;
+
+    return reinterpret_cast<jlong>( new DeferredLayerUpdater(layer) );
+}
+
+static jlong android_view_HardwareLayer_createRenderLayer(JNIEnv* env, jobject clazz,
+        jint width, jint height) {
+    Layer* layer = LayerRenderer::createRenderLayer(width, height);
+    if (!layer) return 0;
+
+    OpenGLRenderer* renderer = new LayerRenderer(layer);
+    renderer->initProperties();
+    return reinterpret_cast<jlong>( new DeferredLayerUpdater(layer, renderer) );
+}
+
+static void android_view_HardwareLayer_onTextureDestroyed(JNIEnv* env, jobject clazz,
+        jlong layerUpdaterPtr) {
+    DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerUpdaterPtr);
+    layer->backingLayer()->clearTexture();
+}
+
+static jlong android_view_HardwareLayer_detachBackingLayer(JNIEnv* env, jobject clazz,
+        jlong layerUpdaterPtr) {
+    DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerUpdaterPtr);
+    return reinterpret_cast<jlong>( layer->detachBackingLayer() );
+}
+
+static void android_view_HardwareLayer_destroyLayerUpdater(JNIEnv* env, jobject clazz,
+        jlong layerUpdaterPtr) {
+    DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerUpdaterPtr);
+    delete layer;
+}
+
+static jboolean android_view_HardwareLayer_prepare(JNIEnv* env, jobject clazz,
+        jlong layerUpdaterPtr, jint width, jint height, jboolean isOpaque) {
+    DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerUpdaterPtr);
+    bool changed = false;
+    changed |= layer->setSize(width, height);
+    changed |= layer->setBlend(!isOpaque);
+    return changed;
+}
+
+static void android_view_HardwareLayer_setLayerPaint(JNIEnv* env, jobject clazz,
+        jlong layerUpdaterPtr, jlong paintPtr, jlong colorFilterPtr) {
+    DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerUpdaterPtr);
+    if (layer) {
+        SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr);
+        SkColorFilter* colorFilter = reinterpret_cast<SkColorFilter*>(colorFilterPtr);
+        layer->setPaint(paint);
+        layer->setColorFilter(colorFilter);
+    }
+}
+
+static void android_view_HardwareLayer_setTransform(JNIEnv* env, jobject clazz,
+        jlong layerUpdaterPtr, jlong matrixPtr) {
+    DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerUpdaterPtr);
+    SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixPtr);
+    layer->setTransform(matrix);
+}
+
+static void android_view_HardwareLayer_setSurfaceTexture(JNIEnv* env, jobject clazz,
+        jlong layerUpdaterPtr, jobject surface, jboolean isAlreadyAttached) {
+    DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerUpdaterPtr);
+    sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, surface));
+    layer->setSurfaceTexture(surfaceTexture, !isAlreadyAttached);
+}
+
+static void android_view_HardwareLayer_updateSurfaceTexture(JNIEnv* env, jobject clazz,
+        jlong layerUpdaterPtr) {
+    DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerUpdaterPtr);
+    layer->updateTexImage();
+}
+
+static void android_view_HardwareLayer_updateRenderLayer(JNIEnv* env, jobject clazz,
+        jlong layerUpdaterPtr, jlong displayListPtr,
+        jint left, jint top, jint right, jint bottom) {
+    DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerUpdaterPtr);
+    DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr);
+    layer->setDisplayList(displayList, left, top, right, bottom);
+}
+
+static jboolean android_view_HardwareLayer_flushChanges(JNIEnv* env, jobject clazz,
+        jlong layerUpdaterPtr) {
+    DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerUpdaterPtr);
+    return layer->apply();
+}
+
+static jlong android_view_HardwareLayer_getLayer(JNIEnv* env, jobject clazz,
+        jlong layerUpdaterPtr) {
+    DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerUpdaterPtr);
+    return reinterpret_cast<jlong>( layer->backingLayer() );
+}
+
+static jint android_view_HardwareLayer_getTexName(JNIEnv* env, jobject clazz,
+        jlong layerUpdaterPtr) {
+    DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerUpdaterPtr);
+    return layer->backingLayer()->getTexture();
+}
+
+#endif // USE_OPENGL_RENDERER
+
+// ----------------------------------------------------------------------------
+// JNI Glue
+// ----------------------------------------------------------------------------
+
+const char* const kClassPathName = "android/view/HardwareLayer";
+
+static JNINativeMethod gMethods[] = {
+#ifdef USE_OPENGL_RENDERER
+
+    { "nCreateTextureLayer",     "()J",        (void*) android_view_HardwareLayer_createTextureLayer },
+    { "nCreateRenderLayer",      "(II)J",      (void*) android_view_HardwareLayer_createRenderLayer },
+    { "nOnTextureDestroyed",     "(J)V",       (void*) android_view_HardwareLayer_onTextureDestroyed },
+    { "nDetachBackingLayer",     "(J)J",       (void*) android_view_HardwareLayer_detachBackingLayer },
+    { "nDestroyLayerUpdater",    "(J)V",       (void*) android_view_HardwareLayer_destroyLayerUpdater },
+
+    { "nPrepare",                "(JIIZ)Z",    (void*) android_view_HardwareLayer_prepare },
+    { "nSetLayerPaint",          "(JJJ)V",     (void*) android_view_HardwareLayer_setLayerPaint },
+    { "nSetTransform",           "(JJ)V",      (void*) android_view_HardwareLayer_setTransform },
+    { "nSetSurfaceTexture",      "(JLandroid/graphics/SurfaceTexture;Z)V",
+            (void*) android_view_HardwareLayer_setSurfaceTexture },
+    { "nUpdateSurfaceTexture",   "(J)V",       (void*) android_view_HardwareLayer_updateSurfaceTexture },
+    { "nUpdateRenderLayer",      "(JJIIII)V",  (void*) android_view_HardwareLayer_updateRenderLayer },
+
+    { "nFlushChanges",           "(J)Z",       (void*) android_view_HardwareLayer_flushChanges },
+
+    { "nGetLayer",               "(J)J",       (void*) android_view_HardwareLayer_getLayer },
+    { "nGetTexName",             "(J)I",       (void*) android_view_HardwareLayer_getTexName },
+#endif
+};
+
+int register_android_view_HardwareLayer(JNIEnv* env) {
+    return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
+}
+
+};
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index 8e121de..e86a2d4 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -131,6 +131,13 @@
     proxy->detachFunctor(functor);
 }
 
+static void android_view_ThreadedRenderer_runWithGlContext(JNIEnv* env, jobject clazz,
+        jlong proxyPtr, jobject jrunnable) {
+    RenderProxy* proxy = reinterpret_cast<RenderProxy*>( proxyPtr);
+    RenderTask* task = new JavaTask(env, jrunnable);
+    proxy->runWithGlContext(task);
+}
+
 #endif
 
 // ----------------------------------------------------------------------------
@@ -151,6 +158,7 @@
     { "nDestroyCanvas", "(J)V", (void*) android_view_ThreadedRenderer_destroyCanvas},
     { "nAttachFunctor", "(JJ)V", (void*) android_view_ThreadedRenderer_attachFunctor},
     { "nDetachFunctor", "(JJ)V", (void*) android_view_ThreadedRenderer_detachFunctor},
+    { "nRunWithGlContext", "(JLjava/lang/Runnable;)V", (void*) android_view_ThreadedRenderer_runWithGlContext },
 #endif
 };
 
diff --git a/core/jni/com_google_android_gles_jni_EGLImpl.cpp b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
index a0982bd..3035d15 100644
--- a/core/jni/com_google_android_gles_jni_EGLImpl.cpp
+++ b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
@@ -50,36 +50,41 @@
 
 static inline EGLDisplay getDisplay(JNIEnv* env, jobject o) {
     if (!o) return EGL_NO_DISPLAY;
-    return (EGLDisplay)env->GetIntField(o, gDisplay_EGLDisplayFieldID);
+    return (EGLDisplay)env->GetLongField(o, gDisplay_EGLDisplayFieldID);
 }
 static inline EGLSurface getSurface(JNIEnv* env, jobject o) {
     if (!o) return EGL_NO_SURFACE;
-    return (EGLSurface)env->GetIntField(o, gSurface_EGLSurfaceFieldID);
+    return (EGLSurface)env->GetLongField(o, gSurface_EGLSurfaceFieldID);
 }
 static inline EGLContext getContext(JNIEnv* env, jobject o) {
     if (!o) return EGL_NO_CONTEXT;
-    return (EGLContext)env->GetIntField(o, gContext_EGLContextFieldID);
+    return (EGLContext)env->GetLongField(o, gContext_EGLContextFieldID);
 }
 static inline EGLConfig getConfig(JNIEnv* env, jobject o) {
     if (!o) return 0;
-    return (EGLConfig)env->GetIntField(o, gConfig_EGLConfigFieldID);
+    return (EGLConfig)env->GetLongField(o, gConfig_EGLConfigFieldID);
 }
+
+static inline jboolean EglBoolToJBool(EGLBoolean eglBool) {
+    return eglBool == EGL_TRUE ? JNI_TRUE : JNI_FALSE;
+}
+
 static void nativeClassInit(JNIEnv *_env, jclass eglImplClass)
 {
     jclass config_class = _env->FindClass("com/google/android/gles_jni/EGLConfigImpl");
     gConfig_class = (jclass) _env->NewGlobalRef(config_class);
-    gConfig_ctorID = _env->GetMethodID(gConfig_class,  "<init>", "(I)V");
-    gConfig_EGLConfigFieldID = _env->GetFieldID(gConfig_class,  "mEGLConfig",  "I");
+    gConfig_ctorID = _env->GetMethodID(gConfig_class,  "<init>", "(J)V");
+    gConfig_EGLConfigFieldID = _env->GetFieldID(gConfig_class,  "mEGLConfig",  "J");
 
     jclass display_class = _env->FindClass("com/google/android/gles_jni/EGLDisplayImpl");
-    gDisplay_EGLDisplayFieldID = _env->GetFieldID(display_class, "mEGLDisplay", "I");
+    gDisplay_EGLDisplayFieldID = _env->GetFieldID(display_class, "mEGLDisplay", "J");
 
     jclass context_class = _env->FindClass("com/google/android/gles_jni/EGLContextImpl");
-    gContext_EGLContextFieldID = _env->GetFieldID(context_class, "mEGLContext", "I");
+    gContext_EGLContextFieldID = _env->GetFieldID(context_class, "mEGLContext", "J");
 
     jclass surface_class = _env->FindClass("com/google/android/gles_jni/EGLSurfaceImpl");
-    gSurface_EGLSurfaceFieldID = _env->GetFieldID(surface_class, "mEGLSurface", "I");
-    gSurface_NativePixelRefFieldID = _env->GetFieldID(surface_class, "mNativePixelRef", "I");
+    gSurface_EGLSurfaceFieldID = _env->GetFieldID(surface_class, "mEGLSurface", "J");
+    gSurface_NativePixelRefFieldID = _env->GetFieldID(surface_class, "mNativePixelRef", "J");
 
     jclass bitmap_class = _env->FindClass("android/graphics/Bitmap");
     gBitmap_NativeBitmapFieldID = _env->GetFieldID(bitmap_class, "mNativeBitmap", "J");
@@ -123,7 +128,7 @@
     }
 
     EGLDisplay dpy = getDisplay(_env, display);
-    jboolean success = eglInitialize(dpy, NULL, NULL);
+    EGLBoolean success = eglInitialize(dpy, NULL, NULL);
     if (success && major_minor) {
         int len = _env->GetArrayLength(major_minor);
         if (len) {
@@ -134,7 +139,7 @@
             _env->ReleasePrimitiveArrayCritical(major_minor, base, JNI_ABORT);
         }
     }
-    return success;
+    return EglBoolToJBool(success);
 }
 
 static jboolean jni_eglQueryContext(JNIEnv *_env, jobject _this, jobject display,
@@ -146,14 +151,14 @@
     }
     EGLDisplay dpy = getDisplay(_env, display);
     EGLContext ctx = getContext(_env, context);
-    jboolean success = JNI_FALSE;
+    EGLBoolean success = EGL_FALSE;
     int len = _env->GetArrayLength(value);
     if (len) {
         jint* base = (jint *)_env->GetPrimitiveArrayCritical(value, (jboolean *)0);
         success = eglQueryContext(dpy, ctx, attribute, base);
         _env->ReleasePrimitiveArrayCritical(value, base, JNI_ABORT);
     }
-    return success;
+    return EglBoolToJBool(success);
 }
 
 static jboolean jni_eglQuerySurface(JNIEnv *_env, jobject _this, jobject display,
@@ -166,14 +171,14 @@
     EGLDisplay dpy = getDisplay(_env, display);
     EGLContext sur = getSurface(_env, surface);
 
-    jboolean success = JNI_FALSE;
+    EGLBoolean success = EGL_FALSE;
     int len = _env->GetArrayLength(value);
     if (len) {
         jint* base = (jint *)_env->GetPrimitiveArrayCritical(value, (jboolean *)0);
         success = eglQuerySurface(dpy, sur, attribute, base);
         _env->ReleasePrimitiveArrayCritical(value, base, JNI_ABORT);
     }
-    return success;
+    return EglBoolToJBool(success);
 }
 
 static jint jni_getInitCount(JNIEnv *_env, jobject _clazz, jobject display) {
@@ -183,7 +188,7 @@
 }
 
 static jboolean jni_eglReleaseThread(JNIEnv *_env, jobject _this) {
-    return eglReleaseThread();
+    return EglBoolToJBool(eglReleaseThread());
 }
 
 static jboolean jni_eglChooseConfig(JNIEnv *_env, jobject _this, jobject display,
@@ -196,7 +201,7 @@
         return JNI_FALSE;
     }
     EGLDisplay dpy = getDisplay(_env, display);
-    jboolean success = JNI_FALSE;
+    EGLBoolean success = EGL_FALSE;
 
     if (configs == NULL) {
         config_size = 0;
@@ -214,14 +219,14 @@
 
     if (success && configs!=NULL) {
         for (int i=0 ; i<num ; i++) {
-            jobject obj = _env->NewObject(gConfig_class, gConfig_ctorID, (jint)nativeConfigs[i]);
+            jobject obj = _env->NewObject(gConfig_class, gConfig_ctorID, reinterpret_cast<jlong>(nativeConfigs[i]));
             _env->SetObjectArrayElement(configs, i, obj);
         }
     }
-    return success;
+    return EglBoolToJBool(success);
 }
 
-static jint jni_eglCreateContext(JNIEnv *_env, jobject _this, jobject display,
+static jlong jni_eglCreateContext(JNIEnv *_env, jobject _this, jobject display,
         jobject config, jobject share_context, jintArray attrib_list) {
     if (display == NULL || config == NULL || share_context == NULL
         || !validAttribList(_env, attrib_list)) {
@@ -234,10 +239,10 @@
     jint* base = beginNativeAttribList(_env, attrib_list);
     EGLContext ctx = eglCreateContext(dpy, cnf, shr, base);
     endNativeAttributeList(_env, attrib_list, base);
-    return (jint)ctx;
+    return reinterpret_cast<jlong>(ctx);
 }
 
-static jint jni_eglCreatePbufferSurface(JNIEnv *_env, jobject _this, jobject display,
+static jlong jni_eglCreatePbufferSurface(JNIEnv *_env, jobject _this, jobject display,
         jobject config, jintArray attrib_list) {
     if (display == NULL || config == NULL
         || !validAttribList(_env, attrib_list)) {
@@ -249,7 +254,7 @@
     jint* base = beginNativeAttribList(_env, attrib_list);
     EGLSurface sur = eglCreatePbufferSurface(dpy, cnf, base);
     endNativeAttributeList(_env, attrib_list, base);
-    return (jint)sur;
+    return reinterpret_cast<jlong>(sur);
 }
 
 static PixelFormat convertPixelFormat(SkBitmap::Config format)
@@ -300,15 +305,15 @@
     endNativeAttributeList(_env, attrib_list, base);
 
     if (sur != EGL_NO_SURFACE) {
-        _env->SetIntField(out_sur, gSurface_EGLSurfaceFieldID, (int)sur);
-        _env->SetIntField(out_sur, gSurface_NativePixelRefFieldID, (int)ref);
+        _env->SetLongField(out_sur, gSurface_EGLSurfaceFieldID, reinterpret_cast<jlong>(sur));
+        _env->SetLongField(out_sur, gSurface_NativePixelRefFieldID, reinterpret_cast<jlong>(ref));
     } else {
         ref->unlockPixels();
         SkSafeUnref(ref);
     }
 }
 
-static jint jni_eglCreateWindowSurface(JNIEnv *_env, jobject _this, jobject display,
+static jlong jni_eglCreateWindowSurface(JNIEnv *_env, jobject _this, jobject display,
         jobject config, jobject native_window, jintArray attrib_list) {
     if (display == NULL || config == NULL
         || !validAttribList(_env, attrib_list)) {
@@ -332,15 +337,15 @@
     jint* base = beginNativeAttribList(_env, attrib_list);
     EGLSurface sur = eglCreateWindowSurface(dpy, cnf, window.get(), base);
     endNativeAttributeList(_env, attrib_list, base);
-    return (jint)sur;
+    return reinterpret_cast<jlong>(sur);
 }
 
-static jint jni_eglCreateWindowSurfaceTexture(JNIEnv *_env, jobject _this, jobject display,
+static jlong jni_eglCreateWindowSurfaceTexture(JNIEnv *_env, jobject _this, jobject display,
         jobject config, jobject native_window, jintArray attrib_list) {
     if (display == NULL || config == NULL
         || !validAttribList(_env, attrib_list)) {
         jniThrowException(_env, "java/lang/IllegalArgumentException", NULL);
-        return JNI_FALSE;
+        return 0;
     }
     EGLDisplay dpy = getDisplay(_env, display);
     EGLContext cnf = getConfig(_env, config);
@@ -360,7 +365,7 @@
     jint* base = beginNativeAttribList(_env, attrib_list);
     EGLSurface sur = eglCreateWindowSurface(dpy, cnf, window.get(), base);
     endNativeAttributeList(_env, attrib_list, base);
-    return (jint)sur;
+    return reinterpret_cast<jlong>(sur);
 }
 
 static jboolean jni_eglGetConfigAttrib(JNIEnv *_env, jobject _this, jobject display,
@@ -372,13 +377,13 @@
     }
     EGLDisplay dpy = getDisplay(_env, display);
     EGLContext cnf = getConfig(_env, config);
-    jboolean success = JNI_FALSE;
+    EGLBoolean success = EGL_FALSE;
     jint localValue;
     success = eglGetConfigAttrib(dpy, cnf, attribute, &localValue);
     if (success) {
         _env->SetIntArrayRegion(value, 0, 1, &localValue);
     }
-    return success;
+    return EglBoolToJBool(success);
 }
 
 static jboolean jni_eglGetConfigs(JNIEnv *_env, jobject _this, jobject display,
@@ -389,7 +394,7 @@
         return JNI_FALSE;
     }
     EGLDisplay dpy = getDisplay(_env, display);
-    jboolean success = JNI_FALSE;
+    EGLBoolean success = EGL_FALSE;
     if (configs == NULL) {
         config_size = 0;
     }
@@ -401,11 +406,11 @@
     }
     if (success && configs) {
         for (int i=0 ; i<num ; i++) {
-            jobject obj = _env->NewObject(gConfig_class, gConfig_ctorID, (jint)nativeConfigs[i]);
+            jobject obj = _env->NewObject(gConfig_class, gConfig_ctorID, reinterpret_cast<jlong>(nativeConfigs[i]));
             _env->SetObjectArrayElement(configs, i, obj);
         }
     }
-    return success;
+    return EglBoolToJBool(success);
 }
 
 static jint jni_eglGetError(JNIEnv *_env, jobject _this) {
@@ -413,20 +418,20 @@
     return error;
 }
 
-static jint jni_eglGetCurrentContext(JNIEnv *_env, jobject _this) {
-    return (jint)eglGetCurrentContext();
+static jlong jni_eglGetCurrentContext(JNIEnv *_env, jobject _this) {
+    return reinterpret_cast<jlong>(eglGetCurrentContext());
 }
 
-static jint jni_eglGetCurrentDisplay(JNIEnv *_env, jobject _this) {
-    return (jint)eglGetCurrentDisplay();
+static jlong jni_eglGetCurrentDisplay(JNIEnv *_env, jobject _this) {
+    return reinterpret_cast<jlong>(eglGetCurrentDisplay());
 }
 
-static jint jni_eglGetCurrentSurface(JNIEnv *_env, jobject _this, jint readdraw) {
+static jlong jni_eglGetCurrentSurface(JNIEnv *_env, jobject _this, jint readdraw) {
     if ((readdraw != EGL_READ) && (readdraw != EGL_DRAW)) {
         jniThrowException(_env, "java/lang/IllegalArgumentException", NULL);
         return 0;
     }
-    return (jint)eglGetCurrentSurface(readdraw);
+    return reinterpret_cast<jlong>(eglGetCurrentSurface(readdraw));
 }
 
 static jboolean jni_eglDestroyContext(JNIEnv *_env, jobject _this, jobject display, jobject context) {
@@ -436,7 +441,7 @@
     }
     EGLDisplay dpy = getDisplay(_env, display);
     EGLContext ctx = getContext(_env, context);
-    return eglDestroyContext(dpy, ctx);
+    return EglBoolToJBool(eglDestroyContext(dpy, ctx));
 }
 
 static jboolean jni_eglDestroySurface(JNIEnv *_env, jobject _this, jobject display, jobject surface) {
@@ -448,18 +453,18 @@
     EGLSurface sur = getSurface(_env, surface);
 
     if (sur) {
-        SkPixelRef* ref = (SkPixelRef*)(_env->GetIntField(surface,
+        SkPixelRef* ref = (SkPixelRef*)(_env->GetLongField(surface,
                 gSurface_NativePixelRefFieldID));
         if (ref) {
             ref->unlockPixels();
             SkSafeUnref(ref);
         }
     }
-    return eglDestroySurface(dpy, sur);
+    return EglBoolToJBool(eglDestroySurface(dpy, sur));
 }
 
-static jint jni_eglGetDisplay(JNIEnv *_env, jobject _this, jobject native_display) {
-    return (jint)eglGetDisplay(EGL_DEFAULT_DISPLAY);
+static jlong jni_eglGetDisplay(JNIEnv *_env, jobject _this, jobject native_display) {
+    return reinterpret_cast<jlong>(eglGetDisplay(EGL_DEFAULT_DISPLAY));
 }
 
 static jboolean jni_eglMakeCurrent(JNIEnv *_env, jobject _this, jobject display, jobject draw, jobject read, jobject context) {
@@ -471,7 +476,7 @@
     EGLSurface sdr = getSurface(_env, draw);
     EGLSurface srd = getSurface(_env, read);
     EGLContext ctx = getContext(_env, context);
-    return eglMakeCurrent(dpy, sdr, srd, ctx);
+    return EglBoolToJBool(eglMakeCurrent(dpy, sdr, srd, ctx));
 }
 
 static jstring jni_eglQueryString(JNIEnv *_env, jobject _this, jobject display, jint name) {
@@ -491,7 +496,7 @@
     }
     EGLDisplay dpy = getDisplay(_env, display);
     EGLSurface sur = getSurface(_env, surface);
-    return eglSwapBuffers(dpy, sur);
+    return EglBoolToJBool(eglSwapBuffers(dpy, sur));
 }
 
 static jboolean jni_eglTerminate(JNIEnv *_env, jobject _this, jobject display) {
@@ -500,7 +505,7 @@
         return JNI_FALSE;
     }
     EGLDisplay dpy = getDisplay(_env, display);
-    return eglTerminate(dpy);
+    return EglBoolToJBool(eglTerminate(dpy));
 }
 
 static jboolean jni_eglCopyBuffers(JNIEnv *_env, jobject _this, jobject display,
@@ -514,11 +519,11 @@
 }
 
 static jboolean jni_eglWaitGL(JNIEnv *_env, jobject _this) {
-    return eglWaitGL();
+    return EglBoolToJBool(eglWaitGL());
 }
 
 static jboolean jni_eglWaitNative(JNIEnv *_env, jobject _this, jint engine, jobject bindTarget) {
-    return eglWaitNative(engine);
+    return EglBoolToJBool(eglWaitNative(engine));
 }
 
 
@@ -540,21 +545,21 @@
 {"eglReleaseThread","()Z", (void*)jni_eglReleaseThread },
 {"getInitCount",    "(" DISPLAY ")I", (void*)jni_getInitCount },
 {"eglChooseConfig", "(" DISPLAY "[I[" CONFIG "I[I)Z", (void*)jni_eglChooseConfig },
-{"_eglCreateContext","(" DISPLAY CONFIG CONTEXT "[I)I", (void*)jni_eglCreateContext },
+{"_eglCreateContext","(" DISPLAY CONFIG CONTEXT "[I)J", (void*)jni_eglCreateContext },
 {"eglGetConfigs",   "(" DISPLAY "[" CONFIG "I[I)Z", (void*)jni_eglGetConfigs },
 {"eglTerminate",    "(" DISPLAY ")Z", (void*)jni_eglTerminate },
 {"eglCopyBuffers",  "(" DISPLAY SURFACE OBJECT ")Z", (void*)jni_eglCopyBuffers },
 {"eglWaitNative",   "(I" OBJECT ")Z", (void*)jni_eglWaitNative },
 {"eglGetError",     "()I", (void*)jni_eglGetError },
 {"eglGetConfigAttrib", "(" DISPLAY CONFIG "I[I)Z", (void*)jni_eglGetConfigAttrib },
-{"_eglGetDisplay",   "(" OBJECT ")I", (void*)jni_eglGetDisplay },
-{"_eglGetCurrentContext",  "()I", (void*)jni_eglGetCurrentContext },
-{"_eglGetCurrentDisplay",  "()I", (void*)jni_eglGetCurrentDisplay },
-{"_eglGetCurrentSurface",  "(I)I", (void*)jni_eglGetCurrentSurface },
-{"_eglCreatePbufferSurface","(" DISPLAY CONFIG "[I)I", (void*)jni_eglCreatePbufferSurface },
+{"_eglGetDisplay",   "(" OBJECT ")J", (void*)jni_eglGetDisplay },
+{"_eglGetCurrentContext",  "()J", (void*)jni_eglGetCurrentContext },
+{"_eglGetCurrentDisplay",  "()J", (void*)jni_eglGetCurrentDisplay },
+{"_eglGetCurrentSurface",  "(I)J", (void*)jni_eglGetCurrentSurface },
+{"_eglCreatePbufferSurface","(" DISPLAY CONFIG "[I)J", (void*)jni_eglCreatePbufferSurface },
 {"_eglCreatePixmapSurface", "(" SURFACE DISPLAY CONFIG OBJECT "[I)V", (void*)jni_eglCreatePixmapSurface },
-{"_eglCreateWindowSurface", "(" DISPLAY CONFIG OBJECT "[I)I", (void*)jni_eglCreateWindowSurface },
-{"_eglCreateWindowSurfaceTexture", "(" DISPLAY CONFIG OBJECT "[I)I", (void*)jni_eglCreateWindowSurfaceTexture },
+{"_eglCreateWindowSurface", "(" DISPLAY CONFIG OBJECT "[I)J", (void*)jni_eglCreateWindowSurface },
+{"_eglCreateWindowSurfaceTexture", "(" DISPLAY CONFIG OBJECT "[I)J", (void*)jni_eglCreateWindowSurfaceTexture },
 {"eglDestroyContext",      "(" DISPLAY CONTEXT ")Z", (void*)jni_eglDestroyContext },
 {"eglDestroySurface",      "(" DISPLAY SURFACE ")Z", (void*)jni_eglDestroySurface },
 {"eglMakeCurrent",         "(" DISPLAY SURFACE SURFACE CONTEXT")Z", (void*)jni_eglMakeCurrent },
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 315b119..7ea08af 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -583,7 +583,7 @@
     <!-- =============================================================== -->
     <eat-comment />
 
-    <!-- Used for permissions that provide access to the user voicemail box. -->
+    <!-- Used for permissions that provide access to device alarms. -->
     <permission-group android:name="android.permission-group.DEVICE_ALARMS"
         android:label="@string/permgrouplab_deviceAlarms"
         android:icon="@drawable/perm_group_device_alarms"
@@ -1061,7 +1061,7 @@
     <!-- =========================================== -->
     <eat-comment />
 
-    <!-- Used for permissions that are associated with accessing and modifyign
+    <!-- Used for permissions that are associated with accessing and modifying
          telephony state: placing calls, intercepting outgoing calls, reading
          and modifying the phone state. -->
     <permission-group android:name="android.permission-group.PHONE_CALLS"
diff --git a/core/res/res/drawable-hdpi/ic_search_api_holo_dark.png b/core/res/res/drawable-hdpi/ic_search_api_holo_dark.png
new file mode 100644
index 0000000..8d529b8
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_search_api_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_search_api_holo_light.png b/core/res/res/drawable-hdpi/ic_search_api_holo_light.png
index 72e207b..8b15ecb 100644
--- a/core/res/res/drawable-hdpi/ic_search_api_holo_light.png
+++ b/core/res/res/drawable-hdpi/ic_search_api_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_voice_search_api_holo_dark.png b/core/res/res/drawable-hdpi/ic_voice_search_api_holo_dark.png
new file mode 100644
index 0000000..32062a6
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_voice_search_api_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_voice_search_api_holo_light.png b/core/res/res/drawable-hdpi/ic_voice_search_api_holo_light.png
index 3481c98..d2b2d21 100644
--- a/core/res/res/drawable-hdpi/ic_voice_search_api_holo_light.png
+++ b/core/res/res/drawable-hdpi/ic_voice_search_api_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_search.png b/core/res/res/drawable-mdpi/ic_search.png
index 4be72f1..66145e0 100644
--- a/core/res/res/drawable-mdpi/ic_search.png
+++ b/core/res/res/drawable-mdpi/ic_search.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_search_api_holo_dark.png b/core/res/res/drawable-mdpi/ic_search_api_holo_dark.png
new file mode 100644
index 0000000..4771a56
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_search_api_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_search_api_holo_light.png b/core/res/res/drawable-mdpi/ic_search_api_holo_light.png
index f2e26f8..60a55f8 100644
--- a/core/res/res/drawable-mdpi/ic_search_api_holo_light.png
+++ b/core/res/res/drawable-mdpi/ic_search_api_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_voice_search.png b/core/res/res/drawable-mdpi/ic_voice_search.png
index 73c6be6..b2535fb 100644
--- a/core/res/res/drawable-mdpi/ic_voice_search.png
+++ b/core/res/res/drawable-mdpi/ic_voice_search.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_voice_search_api_holo_dark.png b/core/res/res/drawable-mdpi/ic_voice_search_api_holo_dark.png
new file mode 100644
index 0000000..fcc2105
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_voice_search_api_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_voice_search_api_holo_light.png b/core/res/res/drawable-mdpi/ic_voice_search_api_holo_light.png
index 71d838e..b516b95 100644
--- a/core/res/res/drawable-mdpi/ic_voice_search_api_holo_light.png
+++ b/core/res/res/drawable-mdpi/ic_voice_search_api_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_search.png b/core/res/res/drawable-xhdpi/ic_search.png
index 998f91b..738a392 100644
--- a/core/res/res/drawable-xhdpi/ic_search.png
+++ b/core/res/res/drawable-xhdpi/ic_search.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_search_api_holo_dark.png b/core/res/res/drawable-xhdpi/ic_search_api_holo_dark.png
new file mode 100644
index 0000000..b0d7acf
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_search_api_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_search_api_holo_light.png b/core/res/res/drawable-xhdpi/ic_search_api_holo_light.png
index a4cdf1c..c9626a0 100644
--- a/core/res/res/drawable-xhdpi/ic_search_api_holo_light.png
+++ b/core/res/res/drawable-xhdpi/ic_search_api_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_search_category_default.png b/core/res/res/drawable-xhdpi/ic_search_category_default.png
index 7d5170e..351cfe0 100644
--- a/core/res/res/drawable-xhdpi/ic_search_category_default.png
+++ b/core/res/res/drawable-xhdpi/ic_search_category_default.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_voice_search.png b/core/res/res/drawable-xhdpi/ic_voice_search.png
index c625a36..3f0518b 100644
--- a/core/res/res/drawable-xhdpi/ic_voice_search.png
+++ b/core/res/res/drawable-xhdpi/ic_voice_search.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_voice_search_api_holo_dark.png b/core/res/res/drawable-xhdpi/ic_voice_search_api_holo_dark.png
new file mode 100644
index 0000000..eb6e5fa
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_voice_search_api_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_voice_search_api_holo_light.png b/core/res/res/drawable-xhdpi/ic_voice_search_api_holo_light.png
index c332ba0..c6b40bb 100644
--- a/core/res/res/drawable-xhdpi/ic_voice_search_api_holo_light.png
+++ b/core/res/res/drawable-xhdpi/ic_voice_search_api_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_search_api_holo_dark.png b/core/res/res/drawable-xxhdpi/ic_search_api_holo_dark.png
new file mode 100644
index 0000000..eb30465
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_search_api_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_search_api_holo_light.png b/core/res/res/drawable-xxhdpi/ic_search_api_holo_light.png
new file mode 100644
index 0000000..bc14415
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_search_api_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_voice_search_api_holo_dark.png b/core/res/res/drawable-xxhdpi/ic_voice_search_api_holo_dark.png
new file mode 100644
index 0000000..813048c
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_voice_search_api_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_voice_search_api_holo_light.png b/core/res/res/drawable-xxhdpi/ic_voice_search_api_holo_light.png
new file mode 100644
index 0000000..8addde0
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_voice_search_api_holo_light.png
Binary files differ
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index b550545..d74c404 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Laat die program toe om enige geïnstalleer mediadekodeerder te gebruik om te kan dekodeer vir terugspeel."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"bestuur vertroude eiebewyse"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Laat die program CA-sertifikate as vertroude eiebewyse installeer en deïnstalleer."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"bind aan ledige dienste"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Hierdie toestemming laat die Android-stelsel toe om aan \'n program se ledige dienste te bind."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"lees/skryf na bronne wat diag besit"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Laat die program toe om na enige hulpbron wat deur die diag-groep besit word, te skryf, byvoorbeeld lêers in /dev. Dit kan potensieel stelselstabiliteit en sekuriteit affekteer. Dit moet NET gebruik word vir hardewarespesifieke diagnose deur die vervaardiger of operateur."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"aktiveer of deaktiveer programkomponente"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 861ae68..56bdd24 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"ለመልሰህ አጫውት ፍታን በማንኛውም የተጫኑ በማህደረ መረጃ ዲኮደር ለመጠቀም  ለመተግበሪያ ይፈቅዳል።"</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"የታመኑ ምስክርነቶችን ያስተዳድሩ"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"መተግበሪያው CA የምስክር ወረቀቶችን እንደሚታመኑ ምስክርነቶች አንዲጭን እና እንዲያራግፍ ይፍቀዱ።"</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"ከስራ ፈት አገልግሎቶች ጋር ይሰሩ"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"ይህ ፍቃድ የAndroid ስርዓቱ የአንድ መተግበሪያ ስራ-ፈት አገልግሎቶችን እንዲያስር ያስችለዋል።"</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"በdiag ባለቤትነት ያሉ ንብረቶችን አንብብ/ፃፍ"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"በዲያግ ቡድን ባለቤትነት ወደ አለ ማንኛውም ንብረት ለምሳሌ በ/dev ያሉ ፋይሎች ለማንበብ እና ለመፃፍ ለመተግበሪያው ይፈቅዳሉ። ይህ በመሰረቱ የስርዓት መረጋጋትን እና ደህንነትን ሊጎዳ ይችላል። ይህ ውስን የሀርድዌር-ተኮር ዲያግኖስቲክስ በአምራቹ ወይም ከዋኙ ብቻ መሆን አለበት።"</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"የመተግበሪያ ምንዝሮችን አንቃ ወይም አቦዝን"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index e20b7b4..56addd1 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"السماح للتطبيق باستخدام أي برنامج فك تشفير وسائط مثبت لفك التشفير من أجل التشغيل."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"إدارة بيانات الاعتماد الموثوقة"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"‏السماح للتطبيق بتثبيت شهادات CA وإلغاء تثبيتها باعتبارها بيانات اعتماد محل ثقة."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"الالتزام بالخدمات الخاملة"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"‏يتيح هذا الإذن لنظام Android الارتباط بخدمات وضع الخمول لأحد التطبيقات."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"قراءة/كتابة إلى الموارد المملوكة بواسطة التشخيص"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"‏للسماح للتطبيق بالقراءة والكتابة إلى أي مورد مملوك بواسطة مجموعة التشخيصات؛ على سبيل المثال، الملفات في /dev. من المحتمل أن يؤثر ذلك في استقرار النظام وأمانه. يجب ألا يستخدم ذلك سوى للتشخيصات الخاصة بالنظام من قِبل المصنِّع أو المشغِّل."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"تمكين مكونات التطبيق أو تعطيلها"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 1dbb050..218d54a 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Разрешава на приложението да използва всеки инсталиран медиен декодер с цел декодиране за възпроизвеждане."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"управление на надеждните идентификационни данни"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Разрешава на приложението да инсталира и деинсталира сертификати от сертифициращи органи като надеждни идентификационни данни."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"обвързване с услуги при неактивност"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Това разрешение позволява на системата Android да се свързва с неактивните услуги на приложението."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"четене/запис в ресурси, притежавани от diag"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Разрешава на приложението да чете и записва във всеки ресурс, притежаван от групата diag, например файловете в /dev. Това потенциално може да засегне стабилността и сигурността на системата. То трябва да се използва САМО за диагностика, конкретно за хардуера, от страна на производителя или оператора."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"активиране или деактивиране на компоненти на приложенията"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 8eadf2c..415e248 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Permet que l\'aplicació utilitzi qualsevol descodificador de mitjans instal·lat per descodificar per a la reproducció."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"gestiona les credencials de confiança"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Permet que l\'aplicació instal·li i desinstal·li certificats de CA com a credencials de confiança."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"vincula als serveis inactius"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Amb aquest permís, el sistema Android podrà vincular-se amb els serveis inactius d\'una aplicació."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"llegir/escriure recursos propietat de diag"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Permet que l\'aplicació llegeixi i escrigui a qualsevol recurs propietat del grup diag; per exemple, els fitxers de /dev. Això podria afectar l\'estabilitat i la seguretat del sistema. NOMÉS l\'hauria d\'utilitzar el fabricant o l\'operador per a diagnòstics específics de maquinari."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"activa o desactiva els components de l\'aplicació"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 8cf6d8d..c338661 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Umožňuje aplikaci používat libovolný nainstalovaný dekodér médií k dekódování při přehrávání."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"správa důvěryhodných identifikačních údajů"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Umožňuje aplikaci instalovat a odinstalovat certifikáty CA jako důvěryhodné identifikační údaje."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"napojit se na nečinné služby"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Toto oprávnění umožní systému Android vázat se na nečinné služby aplikace."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"čtení nebo zápis do prostředků funkce diag"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Umožňuje aplikaci číst libovolné prostředky ve skupině diag, např. soubory ve složce /dev, a zapisovat do nich. Může dojít k ovlivnění stability a bezpečnosti systému. Toto nastavení by měl používat POUZE výrobce či operátor pro diagnostiku hardwaru."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"aktivace či deaktivace komponent aplikací"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 565578f..bd4a3ec 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Tillader, at appen bruger enhver installeret medieafkoder til at afkode til afspilning."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"administrer pålidelige logonoplysninger"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Tillader, at appen installerer og afinstallerer CA-certifikater som pålidelige loginoplysninger."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"knyt til tjenester i dvale"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Med denne tilladelse kan Android-systemet bindes til en applikations dvaletjenester."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"læs/skriv til ressourcer ejet af diag"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Tillader, at appen kan læse og skrive til alle ressourcer, der ejes af diag-gruppen,  f.eks. filer i /dev. Dette kan muligvis påvirke systemets stabilitet og sikkerhed. Dette bør KUN bruges til hardwarespecifik diagnosticering, som foretages af producenten eller udbyderen."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"aktivere eller deaktivere appkomponenter"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index b244fd9..4da2043 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Ermöglicht der App, alle installierten Mediendecodierer zur Wiedergabe zu verwenden."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"Vertrauenswürdige Anmeldedaten verwalten"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Ermöglicht der App, CA-Zertifikate als vertrauenswürdige Anmeldedaten zu installieren und zu deinstallieren."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"An inaktive Dienste binden"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Mit dieser Berechtigung kann sich das Android-System an die inaktiven Dienste einer App binden."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"Lese-/Schreibberechtigung für zu Diagnosegruppe gehörige Elemente"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Ermöglicht der App, alle Elemente in der Diagnosegruppe zu lesen und zu bearbeiten, etwa Dateien in \"/dev\". Dies könnte eine potenzielle Gefährdung für die Stabilität und Sicherheit des Systems darstellen und sollte NUR für hardwarespezifische Diagnosen des Herstellers oder Mobilfunkanbieters verwendet werden."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"App-Komponenten aktivieren oder deaktivieren"</string>
@@ -1425,7 +1427,7 @@
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Löschen"</string>
     <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Fertig"</string>
     <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Modusänderung"</string>
-    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Umschalttaste"</string>
+    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Eingabetaste"</string>
     <string name="activitychooserview_choose_application" msgid="2125168057199941199">"App auswählen"</string>
     <string name="activitychooserview_choose_application_error" msgid="8624618365481126668">"<xliff:g id="APPLICATION_NAME">%s</xliff:g> konnte nicht gestartet werden."</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index b7050dc..9e06e2a 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Επιτρέπει στην εφαρμογή τη χρήση οποιουδήποτε εγκατεστημένου αποκωδικοποιητή μέσων για αναπαραγωγή."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"διαχείριση αξιόπιστων διαπιστευτηρίων"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Επιτρέπει στην εφαρμογή την εγκατάσταση και την απεγκατάσταση πιστοποιητικών CA ως αξιόπιστων διαπιστευτηρίων."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"σύνδεση σε υπηρεσίες αδράνειας"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Αυτή η άδεια επιτρέπει στο σύστημα Android να συνδέεται στις υπηρεσίες αδράνειας μιας εφαρμογής."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"ανάγνωση/εγγραφή σε πόρους που ανήκουν στο διαγνωστικό"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Επιτρέπει στην εφαρμογή την ανάγνωση και την εγγραφή σε οποιονδήποτε πόρο που ανήκει στην ομάδα διαγνωστικού (π.χ. αρχεία στον κατάλογο /dev). Αυτό ενδέχεται να επηρεάσει την σταθερότητα και την ασφάλεια του συστήματος. Θα πρέπει να χρησιμοποιείται ΜΟΝΟ για διαγνωστικά υλικού από τον κατασκευαστή ή τον χειριστή."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"ενεργοποίηση ή απενεργοποίηση στοιχείων εφαρμογής"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index fdaae8b..a4b2f93 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Allows the app to use any installed media decoder to decode for playback."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"manage trusted credentials"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Allows the app to install and uninstall CA certificates as trusted credentials."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"bind to idle services"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"This permission allows the Android system to bind to an application\'s idle services."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"read/write to resources owned by diag"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Allows the app to read and write to any resource owned by the diag group; for example, files in /dev. This could potentially affect system stability and security. This should ONLY be used for hardware-specific diagnostics by the manufacturer or operator."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"enable or disable app components"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index fdaae8b..a4b2f93 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Allows the app to use any installed media decoder to decode for playback."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"manage trusted credentials"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Allows the app to install and uninstall CA certificates as trusted credentials."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"bind to idle services"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"This permission allows the Android system to bind to an application\'s idle services."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"read/write to resources owned by diag"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Allows the app to read and write to any resource owned by the diag group; for example, files in /dev. This could potentially affect system stability and security. This should ONLY be used for hardware-specific diagnostics by the manufacturer or operator."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"enable or disable app components"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 1e94bd9..f8e789c 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Permite que la aplicación use cualquier decodificador de archivos multimedia instalado para la reproducción."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"administrar credenciales de confianza"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Permite que la aplicación instale y desinstale certificados de CA como credenciales de confianza."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"vincular con servicios inactivos"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Este permiso autoriza al sistema Android a vincularse con los servicios inactivos de una aplicación."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"leer y escribir a recursos dentro del grupo de diagnóstico"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Permite que la aplicación lea y escriba en cualquier recurso propiedad del grupo de diagnóstico como, por ejemplo, archivos in/dev. Este permiso podría afectar la seguridad y estabilidad del sistema. SOLO se debe utilizar para diagnósticos específicos de hardware realizados por el fabricante o el operador."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"activar o desactivar componentes de la aplicación"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 75f1c6d..5010841 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Permite que la aplicación use cualquier decodificador de archivos multimedia instalado para la reproducción."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"administrar credenciales de confianza"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Permite que la aplicación instale y desinstale certificados de CA como credenciales de confianza."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"ocultar para servicios inactivos"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Esto permite que el sistema Android enlace con servicios inactivos de una aplicación."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"leer/escribir en los recursos propiedad del grupo de diagnóstico"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Permite que la aplicación consulte y escriba en cualquier recurso del grupo de diagnóstico como, por ejemplo, archivos en /dev. Este permiso podría afectar a la seguridad y estabilidad del sistema. SOLO se debe usar para diagnósticos específicos de hardware realizados por el fabricante o el operador."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"habilitar o inhabilitar componentes de la aplicación"</string>
@@ -1526,7 +1528,7 @@
     <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Desbloqueando tarjeta SIM…"</string>
     <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Código PIN incorrecto"</string>
     <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Introduce un código PIN con una longitud comprendida entre cuatro y ocho dígitos."</string>
-    <string name="kg_invalid_sim_puk_hint" msgid="6025069204539532000">"El código PUK debe tener ocho números."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="6025069204539532000">"El código PUK debe tener 8 números."</string>
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Vuelve a introducir el código PUK correcto. Si introduces un código incorrecto varias veces, se inhabilitará la tarjeta SIM."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Los códigos PIN no coinciden."</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Demasiados intentos incorrectos de crear el patrón"</string>
diff --git a/core/res/res/values-et-rEE/strings.xml b/core/res/res/values-et-rEE/strings.xml
index dcf38ac..29feb3e 100644
--- a/core/res/res/values-et-rEE/strings.xml
+++ b/core/res/res/values-et-rEE/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Võimaldab rakendusel taasesituseks kasutada mis tahes installitud meediumidekooderit."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"usaldusväärsete mandaatide haldamine"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Lubab rakendusel installida ja desinstallida usaldusväärsete mandaatidena CA-sertifikaate."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"sidumine tegevusetute teenustega"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"See luba võimaldab Androidi süsteemil siduda end rakenduse tegevusetute teenustega."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"loe/kirjuta valija allikaid"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Võimaldab rakendusel lugeda valimisrühma mis tahes ressurssi ja sellesse kirjutada (näiteks kaustas /dev olevad failid). See võib mõjutada süsteemi stabiilsust ja turvet. Seda tohiks kasutada tootja või operaator AINULT riistvaraspetsiifiliseks diagnostikaks."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"Rakenduse komponentide lubamine või keelamine"</string>
@@ -1526,7 +1528,7 @@
     <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"SIM-kaardi avamine ..."</string>
     <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Vale PIN-kood."</string>
     <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Sisestage 4–8-numbriline PIN-kood."</string>
-    <string name="kg_invalid_sim_puk_hint" msgid="6025069204539532000">"PUK-kood peab sisaldama 8 numbrit."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="6025069204539532000">"PUK-kood peab koosnema 8 numbrist."</string>
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Sisestage uuesti õige PUK-kood. Korduvkatsete korral keelatakse SIM jäädavalt."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN-koodid ei ole vastavuses"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Liiga palju mustrikatseid"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 465d1e2..34ee392 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"‏اجازه می‎دهد برنامه از هر رمزگشای رسانه نصب شده‌ای استفاده کند تا برای پخش رمزگشایی شود."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"مدیریت اطلاعات کاربری مورد اعتماد"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"‏به برنامه امکان می‌دهد گواهینامه‌های CA را به عنوان اطلاعات کاربری مورد اعتماد نصب یا حذف نصب کند."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"اتصال با سرویس‌های غیرفعال"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"‏این مجوز به سیستم Android امکان می‌دهد به سرویس‌های غیرفعال یک برنامه متصل شود."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"خواندن/نوشتن منابع متعلق به تشخیص"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"‏به برنامه اجازه می‌دهد هر منبعی را که متعلق به گروه تشخیص است بخواند و در آن بنویسد؛ به‌عنوان مثال، فایل‌های /dev. این امر به‌صورت بالقوه می‌تواند بر پایدار بودن و امنیت سیستم تأثیر بگذارد. این تنها باید برای تشخیص‎‌های مختص سخت‌افزار توسط تولیدکننده یا اپراتور استفاده شود."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"فعال یا غیر فعال کردن اجزای برنامه"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 5f1ecbd..01f37d5 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Sallii sovelluksen käyttää mitä tahansa asennettua tietovälineen koodin purkajaa toistoa varten."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"hallinnoi luotettavia varmenteita"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Antaa sovellukselle luvan asentaa ja poistaa luotettavia CA-varmenteita."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"sido käyttämättömiin palveluihin"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Tämä käyttöoikeus antaa Android-järjestelmän sitoa sovelluksen käyttämättömiä palveluita."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"lue diag:in omistamia resursseja / kirjoita resursseihin"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Antaa sovelluksen lukea ja kirjoittaa diag-ryhmän omistamiin resursseihin, esimerkiksi /dev-hakemistossa oleviin tiedostoihin. Tämä voi vaikuttaa järjestelmän vakauteen ja turvallisuuteen. Tämä lupa tulee myöntää VAIN valmistajan tai operaattorin laitteistotesteille."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"sovelluskomponenttien ottaminen käyttöön tai pois käytöstä"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 2375194..fe29fb8f 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Permet à une application d\'utiliser n\'importe quel décodeur installé pour lire les fichiers multimédias."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"gérer les certificats de confiance"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Permet à l\'application d\'installer et de désinstaller les certificats CA en tant que certificats de confiance."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"lier aux services inactifs"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Cette autorisation permet à la plateforme Android de se lier aux services inactifs d\'une application."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"lire ou modifier les ressources appartenant au groupe de diagnostics"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Permet à l\'application d\'obtenir des droits en lecture et en écriture pour toute ressource appartenant au groupe de diagnostics (par exemple, les fichiers du répertoire /dev). Cela peut affecter la stabilité et la sécurité du système. Cette fonctionnalité est UNIQUEMENT réservée aux diagnostics matériels effectués par le fabricant ou le fournisseur de services."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"activer ou désactiver les composants d\'une application"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 685ed04..dae681d 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Permet à une application d\'utiliser n\'importe quel décodeur installé pour lire les fichiers multimédias."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"gérer les certificats de confiance"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Permet à l\'application d\'installer et de désinstaller les certificats CA en tant que certificats de confiance."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"associer aux services d\'inactivité"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Cette autorisation permet à la plate-forme Android de se lier aux services inactifs d\'une application."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"Lecture/écriture dans les ressources appartenant aux diagnostics"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Permet à l\'application d\'obtenir des droits en lecture/écriture concernant toute ressource appartenant au groupe de diagnostics (par exemple, les fichiers du répertoire /dev). Ceci peut affecter la stabilité et la sécurité du système. Cette fonctionnalité est UNIQUEMENT réservée aux diagnostics matériels effectués par le fabricant ou l\'opérateur."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"activer ou désactiver les composants de l\'application"</string>
@@ -1491,7 +1493,7 @@
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Affichage sans fil"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Sortie multimédia"</string>
     <string name="media_route_chooser_title" msgid="1751618554539087622">"Connexion à l\'appareil"</string>
-    <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Diffuser l\'écran sur l\'appareil"</string>
+    <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Caster l\'écran sur l\'appareil"</string>
     <string name="media_route_chooser_searching" msgid="4776236202610828706">"Recherche d\'appareils en cours…"</string>
     <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Paramètres"</string>
     <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Déconnecter"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 264a0e5..f0c005d 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"ऐप्स  को प्लेबैक डीकोड करने के लिए किसी भी इंस्टॉल किए गए डीकोडर का उपयोग करने देता है."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"विश्वसनीय क्रेडेंशियल प्रबंधित करें"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"ऐप्स  को CA प्रमाणपत्रों को विश्वसनीय क्रेडेंशियल के रूप में इंस्टॉल और अनइंस्टॉल करने दें"</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"निष्क्रिय सेवाओं से आबद्ध करें"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"यह अनुमति Android सिस्टम को किसी एप्लिकेशन की निष्क्रिय सेवाओं से आबद्ध होने देती है."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"निदान के स्‍वामित्‍व वाले संसाधनों को पढ़ें/लिखें"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"ऐप्स को diag समूह के स्‍वामित्‍व वाले किसी संसाधन को पढ़ने और उसमें लिखने देता है; उदाहरण के लिए, /dev की फ़ाइलें. यह सिस्‍टम की स्‍थिरता और सुरक्षा को संभावित रूप से प्रभावित कर सकता है. इसका उपयोग निर्माता या ऑपरेटर द्वारा केवल हार्डवेयर-विशिष्ट निदान के लिए किया जाना चाहिए."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"ऐप्स घटकों को सक्षम या अक्षम करें"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 0880d2f..5b7a098 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Aplikaciji omogućuje korištenje bilo kojim instaliranim dekoderom medija za dekodiranje radi reprodukcije."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"upravljanje pouzdanim vjerodajnicama"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Omogućuje aplikaciji instaliranje i deinstaliranje CA certifikata kao pouzdanih vjerodajnica."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"veži uz usluge u mirovanju"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"To dopuštenje omogućuje sustavu Android da se veže uz aplikacijine usluge u mirovanju."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"pisanje/čitanje u resursima čije je vlasnik dijagnostika"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Aplikaciji omogućuje čitanje i pisanje na bilo koji resurs u vlasništvu dijag. grupe; na primjer, datoteke u sustavu /dev. To bi moglo utjecati na stabilnost sustava i sigurnost. Dozvolu bi trebao upotrebljavati proizvođač ili operater SAMO za dijagnostiku koja se odnosi na hardver."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"omogućavanje ili onemogućavanje komponenti aplikacije"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 5eadb47..c48ca2a 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Lehetővé teszi egy alkalmazás számára bármely telepített médiadekóder használatát a lejátszás dekódolásához."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"megbízható tanúsítványok kezelése"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Lehetővé teszi az alkalmazás számára a CA tanúsítványok telepítését és eltávolítását."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"csatolás tétlen szolgáltatásokhoz"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Ez az engedély lehetővé teszi az Android számára, hogy összekapcsolódjon egy alkalmazás tétlen szolgáltatásaival."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"a diag tulajdonában lévő erőforrások olvasása és írása"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Lehetővé teszi egy alkalmazás számára, hogy olvassa és írja a diagnosztikai csoport minden erőforrását, például a /dev könyvtárban lévő fájlokat. Ez potenciálisan befolyásolhatja a rendszer stabilitását és biztonságát, ezért CSAK a gyártó vagy a szolgáltató használhatja hardverspecifikus diagnosztizálásra."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"alkalmazáskomponensek be- és kikapcsolása"</string>
diff --git a/core/res/res/values-hy-rAM/strings.xml b/core/res/res/values-hy-rAM/strings.xml
index 1a5228d..c544ddb 100644
--- a/core/res/res/values-hy-rAM/strings.xml
+++ b/core/res/res/values-hy-rAM/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Թույլ է տալիս հավելվածին օգտագործել ցանկացած տեղադրված մեդիա վերծանիչ` նվագարկումը ապակոդավորելու համար:"</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"կառավարել վստահելի հավաստագրերը"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Թույլատրում է հավելվածին տեղադրել և ապատեղադրել CA վկայագրերը՝ որպես վստահելի հավաստագրեր:"</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"կապակցել ոչ ակտիվ ծառայությունների հետ"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Այս թույլտվությունը հնարավորություն է տալիս Android համակարգին կապ հաստատել ծրագրի չաշխատող ծառայությունների հետ:"</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"կարդալ կամ գրել ախտորոշիչին պատկանող ռեսուրսները"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Թույլ է տալիս հավելվածին կարդալ և գրել ախտորոշիչ խմբին պատկանող ցանկացած ռեսուրսում, ինչպես օրինակ ֆայլերը /dev-ում: Դա կարող է ազդել համակարգի կայունության և անվտանգության վրա: Սա պետք է օգտագործել միայն արտադրողի կամ օպերատորի կողմից սարքին հատուկ ախտորոշման համար:"</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"միացնել կամ անջատել հավելվածի բաղադրիչները"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 0e1d5b6..c144c60 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Mengizinkan apl menggunakan pengawasandi media apa pun yang terpasang guna mengawasandikan media untuk diputar."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"kelola kredensial tepercaya"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Izinkan aplikasi memasang dan mencopot pemasangan sertifikat CA sebagai kredensial tepercaya."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"mengikat ke layanan yang sedang menganggur"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Izin ini memungkinkan sistem Android mengikat layanan waktu menganggur aplikasi."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"baca/tulis ke sumber daya yang dimiliki oleh diag"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Mengizinkan apl membaca dan menulis ke sumber daya apa pun yang dimiliki oleh grup diag; misalnya, file dalam /dev. Izin ini berpotensi memengaruhi kestabilan dan keamanan sistem. Sebaiknya ini HANYA digunakan untuk diagnosis khusus perangkat keras oleh pabrikan atau operator."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"mengaktifkan atau menonaktifkan komponen apl"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 75c887ef..a16e5d0 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Consente all\'applicazione di utilizzare qualsiasi decoder multimediale installato per la decodifica ai fini della riproduzione."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"gestione di credenziali attendibili"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Consente all\'app di installare e disinstallare certificati CA come credenziali attendibili."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"associazione a servizi non disponibili"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Questa autorizzazione consente al sistema Android di associarsi ai servizi inattivi di un\'applicazione."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"lettura/scrittura risorse di proprietà di diag"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Consente all\'applicazione di leggere le risorse del gruppo diag e scrivere in esse, ad esempio i file in /dev. Ciò potrebbe influire su stabilità e sicurezza del sistema. Dovrebbe essere utilizzata SOLTANTO per diagnostiche specifiche dell\'hardware effettuate dal produttore o dall\'operatore."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"attivazione/disattivazione componenti applicazioni"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 008d078..20218f2 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"הרשאה זו מאפשרת לאפליקציה להשתמש בכל מפענח מדיה מותקן כדי לבצע פענוח להשמעה."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"ניהול פרטי כניסה מהימנים"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"‏מאפשרת לאפליקציה להתקין ולהסיר אישורי CA כפרטי כניסה מהימנים."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"אגד עם שירותים במצב לא פעיל"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"‏ההרשאה הזו מאפשרת למערכת Android לאגד אל שירותי אפליקציה במצב לא פעיל."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"‏קרא/כתוב במשאבים בבעלות diag"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"‏מאפשר לאפליקציה לקרוא ולכתוב בכל משאב שבבעלות קבוצת ה-diag; לדוגמה, קבצים ב-‎/dev. פעולה זו עשויה להשפיע על היציבות והאבטחה של המערכת. אפשרות זו צריכה לשמש רק את היצרן או המפעיל, לצורך אבחונים ספציפיים לחומרה."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"הפעלה או השבתה של רכיבי אפליקציות"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 4a994b2..58495e8 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"インストール済みのメディアデコーダーを使用して再生用にデコードすることをアプリに許可します。"</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"信頼できる認証情報の管理"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"CA証明書を信頼できる認証情報としてインストールしたりアンインストールしたりすることをアプリに許可します。"</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"アイドルサービスへのバインディング"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"この許可により、Androidシステムはアプリのアイドルサービスにバインディングできるようになります。"</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"diagが所有するリソースの読み書き"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"diagグループが所有するリソース(/dev内のファイルなど)の読み書きをアプリに許可します。許可すると、システムの安定性とセキュリティに影響が生じる可能性があります。メーカー/通信事業者によるハードウェア固有の診断以外には使用しないでください。"</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"アプリのコンポーネントの有効/無効化"</string>
diff --git a/core/res/res/values-ka-rGE/strings.xml b/core/res/res/values-ka-rGE/strings.xml
index 7e13e96..c82b606 100644
--- a/core/res/res/values-ka-rGE/strings.xml
+++ b/core/res/res/values-ka-rGE/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"აპს დასაკრავად შეეძლება გამოიყენოს ნებისმიერი დაყენებული მედია დეკოდერი."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"სანდო მტკიცებულებების მართვა"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"აპისთვის ნების დართვა, მოახდინოს CA სერტიფიკატების სანდო მტკიცებულებებად ინსტალაცია და დეინსტალაცია."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"უქმე სერვისებზე მიბმა"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"ეს უფლება საშუალებას აძლევს Android-ის სისტემას, განახორციელოს აპლიკაციის უქმე სერვისების მიბმა."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"სისტემის დიაგნოსტიკის რესურსებში წაკითხვა/ჩაწერის უფლება"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"აპს შეეძლება, წაიკითხოს ან ჩაწეროს ნებისმიერ რესურსში, რომელიც დიაგნოსტიკის ჯგუფს ეკუთვნის, მაგალითად, ფაილები /dev-ში. ამან შესაძლოა იმოქმედოს სისტემის სტაბილურობასა და უსაფრთხოებაზე. მისი გამოყენება მხოლოდ მწარმოებლის ან ოპერატორის მიერ ტექნიკის სპეციფიკური დიაგნოსტიკისთვის უნდა მოხდეს."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"აპის კომპონენტების ჩართვა ან გამორთვა"</string>
diff --git a/core/res/res/values-km-rKH/strings.xml b/core/res/res/values-km-rKH/strings.xml
index 38d518a..f0026be 100644
--- a/core/res/res/values-km-rKH/strings.xml
+++ b/core/res/res/values-km-rKH/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"ឲ្យ​កម្មវិធី​ប្រើ​កម្មវិធី​ឌិកូដ​មេឌៀ​ដែល​បាន​ដំឡើង ដើម្បី​ឌិកូដ​សម្រាប់​ការ​ចាក់​ឡើងវិញ។"</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"គ្រប់គ្រង​ព័ត៌មាន​សម្ងាត់​ដែល​ទុកចិត្ត"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"អនុញ្ញាត​ឲ្យ​កម្មវិធី​ដំឡើង និង​លុប​វិញ្ញាបនបត្រ CA នៅ​ពេល​មាន​ព័ត៌មាន​សម្ងាត់​ដែល​ទុកចិត្ត។"</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"ភ្ជាប់​​ទៅ​​សេវាកម្ម​ទំនេរ"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"សិទ្ធិ​នេះ​អនុញ្ញាត​ឲ្យ​ប្រព័ន្ធ Android ចង​​សេវាកម្ម​ទំនេរ​របស់​កម្មវិធី។"</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"អាន/សរសេរ​ធនធាន​គ្រប់គ្រង​ប្រអប់"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"ឲ្យ​កម្មវិធី​អាន និង​សរសេរ​ប្រភព​ណាមួយ​ដែល​គ្រប់គ្រង​ដោយ​ក្រុម​អ្នក​វិនិច្ឆ័យ ឧទាហរណ៍ ឯកសារ​នៅ​ក្នុង /dev ។ វា​អាច​ប៉ះពាល់​យ៉ាង​ខ្លាំង​ដល់​ស្ថេរ​ភាព​ និង​សុវត្ថិភាព​ប្រព័ន្ធ។ វា​គួរ​ត្រូវ​បាន​ប្រើ​សម្រាប់​វិនិច្ឆ័យ​ផ្នែក​រឹង​ជាក់​លាក់​ដោយ​ក្រុមហ៊ុន​ផលិត ឬ​ប្រតិបត្តិ​ករ។"</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"បិទ ឬ​បើក​សមាសធាតុ​កម្មវិធី"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index a51e605..5a7f9b8 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"애플리케이션에서 설치된 모든 미디어 디코더를 사용하여 재생하는 데 디코딩할 수 있도록 허용합니다."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"신뢰할 수 있는 자격증명 관리"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"앱에서 CA 인증서를 신뢰할 수 있는 자격증명으로 설치 및 제거하도록 허용합니다."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"유휴 서비스에 연결"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"이 권한을 부여하면 Android 시스템이 애플리케이션의 유휴 서비스에 연결할 수 있습니다."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"진단 그룹 소유의 리소스 읽기/쓰기"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"앱이 진단 그룹 소유의 리소스(예: /dev에 있는 파일)를 읽고 쓸 수 있도록 허용합니다. 이 기능은 시스템 안정성 및 보안에 영향을 미칠 수 있으므로 제조업체 또는 사업자가 하드웨어 관련 진단을 수행하는 경우에만 사용해야 합니다."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"앱 구성요소 사용 또는 사용 안함"</string>
diff --git a/core/res/res/values-lo-rLA/strings.xml b/core/res/res/values-lo-rLA/strings.xml
index c7aed51..abca9cd 100644
--- a/core/res/res/values-lo-rLA/strings.xml
+++ b/core/res/res/values-lo-rLA/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"ອະນຸຍາດໃຫ້ແອັບຯໃຊ້ທຸກຕົວຖອດລະຫັດສື່ທີ່ຕິດຕັ້ງໄວ້ແລ້ວ ເພື່ອການຖອດລະຫັດການຫຼິ້ນໄຟລ໌ຕ່າງໆ."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"ຈັດການໜັງສືຮັບຮອງທີ່ເຊື່ອຖືໄດ້."</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"ອະ​ນຸ​ຍາດ​ໃຫ້ແອັບຯ ຕິດຕັ້ງ ແລະ ຖອນການຕິດຕັ້ງໃບຢັ້ງຢືນ CA ທີ່ເປັນໃບຮັບຮອງທີ່ເຊື່ອຖືໄດ້."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"ເຊື່ອມຫາບໍລິການທີ່ບໍ່ໄດ້ນໍາໃຊ້"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"ສິດນີ້ຈະອະນຸຍາດໃຫ້ລະບົບ Android ສາມາດຜູກກັບການບໍລິການຂອງແອັບພລິເຄຊັນທີ່ບໍ່ໄດ້ເຮັດວຽກຢູ່ໄດ້."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"ອ່ານ/ຂຽນ ໃສ່ຊັບພະຍາກອນທີ່ເປັນຂອງກຸ່ມວິໄຈ"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"ອະນຸຍາດໃຫ້ແອັບພລິເຄຊັນອ່ານ ແລະຂຽນ ໃສ່ທຸກຊັບພະຍາກອນທີ່ເປັນຂອງກຸ່ມວິນິໄສ; ຕົວຢ່າງ: ໄຟລ໌ໃນ /dev. ສິ່ງນີ້ອາດສົ່ງຜົນກະທົບຕໍ່ຄວາມສະຖຽນ ແລະຄວາມປອດໄພຂອງລະບົບ. ສິ່ງນີ້ຄວນໃຊ້ສຳຫຼັບການວິເຄາະບັນຫາຈຳເພາະ ຂອງບາງຮາດແວໂດຍຜູ່ຜະລິດ ຫຼືຜູ່ປະຕິບັດການເທົ່ານັ້ນ."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"ເປີດ ຫຼືປິດນຳໃຊ້ອົງປະກອບຂອງແອັບຯ"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 6b5191d..c4e7d11 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Leidžiama programai naudoti bet kurį įdiegtą medijos dekoderį norint iššifruoti atkūrimą."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"tvarkyti patikimus prisijungimo duomenis"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Programoje galima įdiegti ir iš jos pašalinti CA sertifikatus kaip patikimus prisijungimo duomenis."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"susaistyti su neaktyviomis paslaugomis"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Šiuo leidimu „Android“ sistemai leidžiama susaistyti su programos neaktyviomis paslaugomis."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"skaityti / rašyti ištekliuose, priklausančiuose diagnostikai"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Leidžiama programai skaityti ir rašyti visuose diagnostikos grupei priklausančiuose ištekliuose, pvz., failuose, esančiuose /dev. Tai gali paveikti sistemos stabilumą ir saugą. Tai turėtų būti naudojama TIK gamintojui ar operatoriui atliekant aparatinės įrangos diagnostiką."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"įgalinti programos komponentus arba jų neleisti"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 74022a9..4ba1f96 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Ļauj lietotnei izmantot jebkuru instalētu multivides failu dekodētāju, lai dekodētu failus atskaņošanai."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"Uzticamo akreditācijas datu pārvaldība"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Ļauj lietotnei instalēt un atinstalēt CA sertifikātus kā uzticamus akreditācijas datus."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"saistīšana ar neaktīviem pakalpojumiem"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Pamatojoties uz šo atļauju, Android sistēma var izveidot saiti ar lietojumprogrammas neaktīvajiem pakalpojumiem."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"lasīt grupas “diag” resursus un rakstīt tajos"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Ļauj lietotnei lasīt un rakstīt jebkurā resursā, kas pieder diagnostikas grupai, piemēram, failiem mapē /dev. Tas var ietekmēt sistēmas stabilitāti un drošību. Var izmantot ražotājs vai operators TIKAI konkrētas aparatūras diagnostikai."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"iespējot vai atspējot lietotnes komponentus"</string>
diff --git a/core/res/res/values-mn-rMN/strings.xml b/core/res/res/values-mn-rMN/strings.xml
index 82cdab6..0d2da73 100644
--- a/core/res/res/values-mn-rMN/strings.xml
+++ b/core/res/res/values-mn-rMN/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Апп нь тоглуулах үедээ код тайлахдаа суулгагдсан ямарч медиа код тайлагчийг ашиглах боломжтой."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"итгэмжлэгдсэн жуухуудыг удирдах"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Апп-д CA сертификатуудыг итгэмжлэгдсэн жуух байдлаар суулгах болон устгахыг зөвшөөрнө."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"идэвхгүй үйлчилгээнүүдтэй холбогдох"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Энэ зөвшөөрөл Андройд системд аппликешний идэвхгүй үйлчилгээтэй холбогдох боломж олгоно."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"оношлох грүпийн эзэмшдэг нөөцрүү унших/бичих"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Апп нь оношлох грүпийн эзэмшдэг, жишээ нь /dev доторх файлууд, дурын  нөөцийг унших бичих боломжтой.Энэ нь системийн тогвортой байдал болон аюулгүй байдалд бодитоор нөлөөлнө. Энэ нь үйлдвэрлэгч болон операторын хардверт-зориулсан оношлогоонд ашиглагдана."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"апп компонентыг идэвхжүүлэх эсвэл идэвхгүй болгох"</string>
diff --git a/core/res/res/values-ms-rMY/strings.xml b/core/res/res/values-ms-rMY/strings.xml
index f9d005d..6ebdfe1 100644
--- a/core/res/res/values-ms-rMY/strings.xml
+++ b/core/res/res/values-ms-rMY/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Membenarkan apl untuk menggunakan sebarang penyahkod media yang dipasangkan untuk menyahkod main semula."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"urus bukti kelayakan yang dipercayai"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Membenarkan apl memasang dan menyahpasang sijil CA sebagai bukti kelayakan yang dipercayai."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"diikat ke perkhidmatan melahu"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Kebenaran ini membolehkan sistem Android mengikat kepada perkhidmatan melahu aplikasi."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"baca/tulis ke sumber yang dimiliki oleh diag"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Membenarkan apl membaca dan menulis ke sebarang sumber yang dimiliki oleh kumpulan diag; contohnya, fail dalam /dev. Hal ini berpotensi menjejaskan kestabilan dan keselamatan sistem. Perkara ini seharusnya HANYA digunakan untuk diagnosis khusus perkakasan oleh pengilang atau pengendali."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"dayakan atau lumpuhkan komponen apl"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index e6b29c2..26b27fb 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Lar appen bruke en hvilken som helst installert mediedekoder for å dekode for avspilling."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"administrer pålitelig legitimasjon"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Lar appen installere og avinstallere CA-sertifikater som pålitelig legitimasjon."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"knytt til inaktive tjenester"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Denne tillatelsen gjør at Android-systemet kan binde seg til appers inaktive tjenester."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"lese/skrive ressurser eid av diag"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Lar appen lese og skrive til alle ressurser som eies av gruppen «diag», som for eksempel filer i /dev. Dette kan potensielt påvirke systemets sikkerhet og stabilitet. Dette bør BARE brukes av produsenten eller operatøren til maskinvarespesifikk diagnostikk."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"aktivere eller deaktivere appkomponenter"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 3c0ba73..b8a7122 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Hiermee kan de app alle geïnstalleerde mediadecoders gebruiken om te decoderen voor het afspelen."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"vertrouwde inloggegevens beheren"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Hiermee kan de app CA-certificaten installeren en verwijderen als vertrouwde inloggegevens."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"koppelen aan inactieve services"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Met deze toestemming kan het Android-systeem koppelen aan de inactieve services van een app."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"lezen/schrijven naar bronnen van diag"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Hiermee kan de app lezen en schrijven naar elke bron die hoort bij de diagnostische groep, zoals bestanden in /dev. Hierdoor kan de systeemstabiliteit en -veiligheid worden beïnvloed. Dit mag ALLEEN worden gebruikt voor hardwarespecifieke diagnostiek door de fabrikant of provider."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"componenten van apps in- of uitschakelen"</string>
@@ -1491,7 +1493,7 @@
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Draadloze weergave"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Media-uitvoer"</string>
     <string name="media_route_chooser_title" msgid="1751618554539087622">"Verbinding maken met apparaat"</string>
-    <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Scherm sturen naar apparaat"</string>
+    <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Scherm casten naar apparaat"</string>
     <string name="media_route_chooser_searching" msgid="4776236202610828706">"Zoeken naar apparaten…"</string>
     <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Instellingen"</string>
     <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Verbinding verbreken"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 96f3b39..8aa847f 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Pozwala aplikacji na użycie dowolnego zainstalowanego dekodera multimediów do odtwarzania."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"zarządzanie zaufanymi danymi uwierzytelniającymi"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Zezwala aplikacji na instalowanie i odinstalowywanie certyfikatów CA jako zaufanych danych uwierzytelniających."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"powiązanie z nieaktywnymi usługami"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"To uprawnienie umożliwia powiązanie systemu Android z nieaktywnymi usługami aplikacji."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"czytanie/zapisywanie w zasobach należących do diagnostyki"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Pozwala aplikacji na czytanie i zapisywanie wszystkich zasobów należących do grupy diagnostyki, na przykład plików w katalogu /dev. Może to potencjalnie wpłynąć na stabilność i bezpieczeństwo systemu. Powinno być wykorzystywane WYŁĄCZNIE do diagnozowania sprzętu przez producenta lub operatora."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"włączanie lub wyłączanie składników aplikacji"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 261525c..b87a4b0 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Permite que a aplicação utilize qualquer descodificador de multimédia instalado para descodificar a reprodução."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"gerir credenciais fidedignas"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Permite que a aplicação instale e desinstale certificados da AC (Autoridade de certificação) como credenciais fidedignas."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"associar a serviços inativos"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Esta autorização permite que o sistema Android seja vinculado aos serviços inativos de uma aplicação."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"ler/escrever em recursos propriedade de diag"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Permite à aplicação ler e escrever em qualquer recurso que seja propriedade do grupo diag; por exemplo, ficheiros em /dev. Isto pode potencialmente afetar a estabilidade e a segurança do sistema e deve ser utilizado APENAS para diagnósticos específicos do hardware pelo fabricante ou pelo operador."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"ativar ou desativar componentes da aplicação"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 6a80a78..2cfad8f 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Permite que o aplicativo use qualquer decodificador de mídia instalado para reprodução."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"gerenciar credenciais confiáveis"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Permite que o aplicativo instale e desinstale certificados CA como credenciais confiáveis."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"associar a serviços inativos"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Permite que o sistema Android seja associado aos serviços inativos de um aplicativo."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"ler/gravar em recursos pertencentes ao diag"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Permite que um aplicativo leia e grave em qualquer recurso que pertença ao grupo de diagnósticos, por exemplo, arquivos in/dev. Isso pode afetar a estabilidade e a segurança do sistema. Esse recurso deve ser usado APENAS para diagnósticos específicos do hardware realizados pelo fabricante ou pela operadora."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"ativar ou desativar os componentes do aplicativo"</string>
diff --git a/core/res/res/values-rm/strings.xml b/core/res/res/values-rm/strings.xml
index 87550879..407f6ed 100644
--- a/core/res/res/values-rm/strings.xml
+++ b/core/res/res/values-rm/strings.xml
@@ -678,6 +678,10 @@
     <skip />
     <!-- no translation found for permdesc_manageCaCertificates (4015644047196937014) -->
     <skip />
+    <!-- no translation found for permlab_bindIdleService (7521398788076342815) -->
+    <skip />
+    <!-- no translation found for permdesc_bindIdleService (7747505810143356528) -->
+    <skip />
     <string name="permlab_diagnostic" msgid="8076743953908000342">"leger/scriver en resursas che appartegnan a diagnostics"</string>
     <!-- no translation found for permdesc_diagnostic (6608295692002452283) -->
     <skip />
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index b222103..21c8a11 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Permite aplicaţiei să utilizeze orice decodor media instalat pentru a decodifica redarea."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"gestionarea acreditărilor de încredere"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Permite aplicației să instaleze și să dezinstaleze certificate CA ca acreditări de încredere."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"asociați cu serviciile inactive"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Această autorizare permite sistemului Android să se conecteze la serviciile inactive ale unei aplicații."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"citire/scriere în resursele deţinute de diag"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Permite aplicaţiei să citească şi să scrie în orice resursă deţinută de grupul diag, de ex., fişierele din /dev. Această permisiune ar putea să afecteze stabilitatea şi securitatea sistemului. Permisiunea trebuie utilizată NUMAI de producător sau de operator pentru diagnostice specifice pentru hardware."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"activare sau dezactivare a componentelor aplicaţiei"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index c28a019..9bc6bcd 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Приложение сможет использовать любой установленный дешифратор."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"Управление учетными данными"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Приложение сможет устанавливать сертификаты ЦС в качестве надежных учетных данных, а также удалять их."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"привязка неактивных сервисов"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Android сможет подключаться к неактивным сервисам."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"Чтение/запись данных в системы диагностики"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Приложение сможет считывать и записывать данные системы диагностики (например, файлы в каталоге /dev). Это может повлиять на стабильность и безопасность системы. Это разрешение должно использоваться ТОЛЬКО производителем или оператором для диагностики аппаратного обеспечения."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"Включение/отключение компонентов приложения"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 399eeee..7f4e0ed 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Umožňuje aplikácii používať na reprodukciu ľubovoľný nainštalovaný dekódovač na dekódovanie."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"spravovať dôveryhodné poverenia"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Umožňuje aplikácii inštalovať a odinštalovať certifikáty CA ako dôveryhodné poverenia."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"previazať s nečinnými službami"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Toto povolenie umožní systému Android viazať sa na nečinné služby aplikácie."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"čítanie alebo zápis do prostriedkov funkcie diag"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Umožňuje aplikácii čítať ľubovoľné prostriedky v skupine diag, napr. súbory v priečinku /dev, a zapisovať do nich. Môže dôjsť k ovplyvneniu stability a bezpečnosti systému. Toto nastavenie by mal používať IBA výrobca či operátor na diagnostiku hardvéru."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"povoliť alebo zakázať súčasti aplikácie"</string>
@@ -477,9 +479,9 @@
     <string name="permlab_installLocationProvider" msgid="6578101199825193873">"Oprávnenie na inštaláciu poskytovateľa polohy"</string>
     <string name="permdesc_installLocationProvider" msgid="9066146120470591509">"Vytváranie simulovaných zdrojov polohy na testovanie alebo inštalácia nového poskytovateľa informácií o polohe. Aplikácii to umožní nahradiť polohu a stav, ktoré vracajú iné zdroje informácií o polohe, ako sú napríklad systém GPS alebo poskytovatelia informácií o polohe."</string>
     <string name="permlab_accessFineLocation" msgid="1191898061965273372">"presná poloha (pomocou GPS a siete)"</string>
-    <string name="permdesc_accessFineLocation" msgid="5295047563564981250">"Umožňuje aplikácii získať vašu presnú polohu pomocou systému GPS (Global Positioning System) alebo zdrojov určenia polohy siete, napríklad mobilných veží a sietí Wi-Fi. Tieto služby využívajúce polohu musia byť na vašom zariadení zapnuté a dostupné, inak ich aplikácia nebude môcť využívať. Aplikácie môžu tieto služby využívať na určenie vašej polohy. Tieto služby môžu zvýšiť spotrebu batérie."</string>
+    <string name="permdesc_accessFineLocation" msgid="5295047563564981250">"Umožňuje aplikácii získať vašu presnú polohu pomocou systému GPS (Global Positioning System) alebo zdrojov určenia polohy siete, napríklad mobilných veží a sietí Wi-Fi. Tieto služby určovania polohy musia byť na vašom zariadení zapnuté a dostupné, inak ich aplikácia nebude môcť využívať. Aplikácie môžu tieto služby využívať na určenie vašej polohy. Tieto služby môžu zvýšiť spotrebu batérie."</string>
     <string name="permlab_accessCoarseLocation" msgid="4887895362354239628">"približná poloha (pomocou siete)"</string>
-    <string name="permdesc_accessCoarseLocation" msgid="2538200184373302295">"Umožňuje aplikácii získať vašu približnú polohu. Táto poloha je odvodená zo služieb využívajúcich polohu pomocou zdrojov určenia polohy siete, napríklad mobilných veží a sietí Wi-Fi. Tieto služby využívajúce polohu musia byť na vašom zariadení zapnuté a dostupné, inak ich aplikácia nebude môcť využívať. Aplikácie môžu tieto služby využívať na určenie vašej približnej polohy."</string>
+    <string name="permdesc_accessCoarseLocation" msgid="2538200184373302295">"Umožňuje aplikácii získať vašu približnú polohu. Táto poloha je odvodená zo služieb určovania polohy pomocou zdrojov určenia polohy siete, napríklad mobilných veží a sietí Wi-Fi. Tieto služby určovania polohy musia byť na vašom zariadení zapnuté a dostupné, inak ich aplikácia nebude môcť využívať. Aplikácie môžu tieto služby využívať na určenie vašej približnej polohy."</string>
     <string name="permlab_accessSurfaceFlinger" msgid="2363969641792388947">"prístup k službe SurfaceFlinger"</string>
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Umožňuje aplikácii používať funkcie nízkej úrovne aplikácie SurfaceFlinger."</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"čítanie vyrovnávacej pamäte snímok"</string>
@@ -554,7 +556,7 @@
     <string name="permlab_locationUpdates" msgid="7785408253364335740">"ovládanie upozornení na aktualizáciu polohy"</string>
     <string name="permdesc_locationUpdates" msgid="1120741557891438876">"Umožňuje aplikácii povoliť alebo zakázať upozornenia s aktualizáciami polohy z rádia. Bežné aplikácie toto nastavenie nepoužívajú."</string>
     <string name="permlab_checkinProperties" msgid="7855259461268734914">"prístup k vlastnostiam nahlásenia"</string>
-    <string name="permdesc_checkinProperties" msgid="4024526968630194128">"Umožňuje aplikácii čítať a zapisovať vlastnosti odovzdané službou nahlasovania. Bežné aplikácie toto nastavenie nepoužívajú."</string>
+    <string name="permdesc_checkinProperties" msgid="4024526968630194128">"Umožňuje aplikácii čítať a zapisovať vlastnosti nahrané službou nahlasovania. Bežné aplikácie toto nastavenie nepoužívajú."</string>
     <string name="permlab_bindGadget" msgid="776905339015863471">"zvoliť miniaplikácie"</string>
     <string name="permdesc_bindGadget" msgid="8261326938599049290">"Umožňuje aplikácii povedať systému, ktoré aplikácie môžu používať určité miniaplikácie. Aplikácia s týmto povolením môže iným aplikáciám povoliť prístup k osobným údajom. Bežné aplikácie toto nastavenie nepoužívajú."</string>
     <string name="permlab_modifyPhoneState" msgid="8423923777659292228">"zmeny stavu telefónu"</string>
@@ -1491,7 +1493,7 @@
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Bezdrôtový displej"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Výstup médií"</string>
     <string name="media_route_chooser_title" msgid="1751618554539087622">"Pripojenie k zariadeniu"</string>
-    <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Odovzdanie obraz. na prehratie v zariad."</string>
+    <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Prenos obraz. do zariad."</string>
     <string name="media_route_chooser_searching" msgid="4776236202610828706">"Prebieha vyhľadávanie zariadení…"</string>
     <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Nastavenia"</string>
     <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Odpojiť"</string>
@@ -1505,9 +1507,9 @@
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Prekrytie č. <xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g> x <xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
     <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", zabezpečené"</string>
-    <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Odovzdávanie obrazovky na prehratie"</string>
+    <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Nahrávanie obrazovky na prehratie"</string>
     <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"Prebieha pripájanie k obrazovke <xliff:g id="NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Odovzdávanie obrazovky na prehratie"</string>
+    <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Nahrávanie obrazovky na prehratie"</string>
     <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"Pripojené k obrazovke <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Odpojiť"</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Tiesňové volanie"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 7c0dc63..1f1ab78 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Programu omogoča, da uporabi kateri koli dekodirnik večpredstavnosti za predvajanje."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"upravljanje preverjenih poverilnic"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Aplikaciji dovoli nameščanje in odstranjevanje potrdil overitelja potrdil kot preverjenih poverilnic."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"vezanje na nedejavne storitve"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"To dovoljenje dovoli sistemu Android vezanje nedejavnih storitev aplikacije."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"branje/pisanje v sredstva, ki so v lasti skupine za diagnostiko"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Programu omogoča branje in pisanje na poljuben vir, ki je v lasti skupine za diagnostiko; na primer datoteke v mapi /dev. To lahko vpliva na stabilnost in varnost sistema. To naj uporablja SAMO izdelovalec ali operater za diagnostiko, specifično za strojno opremo."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"omogočanje ali onemogočanje komponent programa"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 5b5f451..4a29310 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Омогућава апликацији да користи било који инсталирани декодер медија за декодирање за репродукцију."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"управљање поузданим акредитивима"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Дозвољава апликацији да инсталира и деинсталира CA сертификате као поуздане акредитиве."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"повезивање са неактивним услугама"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Ова дозвола дозвољава систему Android да се веже за неактивне услуге апликације."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"читање ресурса у власништву дијагностике и уписивање података у њих"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Дозвољава апликацији да чита и уписује податке у било који ресурс у власништву групе за дијагностиковање, на пример, датотеке у директоријуму /dev. То може да угрози стабилност и безбедност система и треба да је користе САМО произвођач или оператер у сврхе дијагностиковањa хардвера."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"омогућавање или онемогућавање компоненти апликације"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index bdd8e76..09763b1 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Tillåter att appen använder installerade medieavkodare för att avkoda media för uppspelning."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"hantera betrodda uppgifter"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Tillåter att appen installerar och avinstallerar CA-certifikat som betrodda uppgifter."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"knyt till inaktiva tjänster"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Med den här behörigheten kan Android-systemet bindas till en apps inaktiva tjänster."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"läsa/skriva till resurser som ägs av diag"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Tillåter att appen läser och skriver till en resurs som ägs av diag-gruppen, till exempel filer i /dev. Detta kan eventuellt påverka systemets stabilitet och säkerhet. Detta bör ENDAST användas av tillverkaren eller operatören för maskinvaruspecifik diagnostik."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"aktivera eller inaktivera appkomponenter"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index d0fcc09..e840e37 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -359,8 +359,8 @@
     <string name="permdesc_setAnimationScale" msgid="7690063428924343571">"Huruhusu programu kubadilisha kasi ya uhuishaji kijumla (uhuisho wa haraka zaidi au wa polepole zaidi) wakati wowote."</string>
     <string name="permlab_manageAppTokens" msgid="1286505717050121370">"Dhibiti shuhuda za programu"</string>
     <string name="permdesc_manageAppTokens" msgid="8043431713014395671">"Inaruhusu programu kuunda na kudhibiti shuhuda zake, kukwepa mipangilio yao ya kawaida. Haitahitajika kamwe na programu za kawaida."</string>
-    <string name="permlab_freezeScreen" msgid="4708181184441880175">"lemaza skrini"</string>
-    <string name="permdesc_freezeScreen" msgid="8558923789222670064">"Inaruhusu programu kulemaza kwa muda skrini kwa ajili ya mpito kamili wa skrinimaombi kwa muda kufungia screen kwa ajili ya mpito full-screen."</string>
+    <string name="permlab_freezeScreen" msgid="4708181184441880175">"fanya skrini isisonge"</string>
+    <string name="permdesc_freezeScreen" msgid="8558923789222670064">"Huruhusu programu kufanya skrini isisonge kwa muda ili kuruhusu kubadilisha hadi skrini nzima."</string>
     <string name="permlab_injectEvents" msgid="1378746584023586600">"bonyeza vitufe na vitufe vya kudhibiti"</string>
     <string name="permdesc_injectEvents" product="tablet" msgid="206352565599968632">"Huruhusu programu kuwasilisha matukio yake ya ingizo (mibonyezo ya vitufe, nk.) kwa programu zingine. programu hasidi zinaweza kutumia hii ili kutawala kompyuta kibao."</string>
     <string name="permdesc_injectEvents" product="default" msgid="653128057572326253">"Inaruhusu programu kuwasilisha matukio yake ya ingizo (mibonyezo ya kitufe, nk.)kwa programu zingine.Programu hasidi zinaweza kutumia hii kutawala simu."</string>
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Huruhusu programu kutumia vyombo vyovyote vya habari vilivyosakinishwa ili kusimbua kwa ajili ya kucheza tena."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"dhibiti vitambulisho vinavyoaminika"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Huruhusu programu kusakinisha na kusanidua vyeti vya CA kama vitambulisho vinavyoaminika."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"funga kwenye huduma zisizofanya kitu"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Ruhusa hii huruhusu mfumo wa Android kuunga kwenye huduma za programu amabazo hazitumiki."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"soma/andika kwa vyanzo vinavyomilikiwa na diag"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Inaruhusu programu kusoma na kuandika kwa chanzo chochote kinachomilikiwa na kikundi cha diag; kwa mfano, faili katika /dev. Hii inaweza kuathiri udhabiti na usalama wa mfumo. Hii inapaswa kutumiwa TU kwa utambuzi mahsusi wa maunzi na mtengenezaji au opareta."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"wezesha au lemeza vijenzi vya programu"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index a0b2ee4..c1f1c9b 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"อนุญาตให้แอปพลิเคชันใช้ตัวถอดรหัสสื่อใดก็ได้ที่ติดตั้งไว้เพื่อถอดรหัสสำหรับการเล่น"</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"จัดการข้อมูลรับรองที่เชื่อถือได้"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"อนุญาตให้แอปติดตั้งและถอนการติดตั้งใบรับรอง CA ในฐานะข้อมูลรับรองที่เชื่อถือได้"</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"เชื่อมโยงกับบริการที่ไม่ได้ใช้งาน"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"สิทธิ์นี้จะทำให้ระบบแอนดรอยด์สามารถเชื่อมโยงกับบริการรายงานเวลาที่ไม่มีการใช้งานของแอปพลิเคชัน"</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"อ่าน/เขียนไปยังรีซอร์สที่เป็นเจ้าของโดยกลุ่มวินิจฉัย"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"อนุญาตให้แอปพลิเคชันอ่านและเขียนไปยังทรัพยากรที่เป็นของกลุ่มวินิจฉัย เช่น ไฟล์ใน /dev การทำเช่นนี้อาจส่งผลต่อความเสถียรและความปลอดภัยของระบบ และควรใช้สำหรับการวินิจฉัยเกี่ยวกับฮาร์ดแวร์โดยเฉพาะที่ทำโดยผู้ผลิตหรือผู้ให้บริการเท่านั้น"</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"เปิดหรือปิดใช้งานคอมโพเนนต์ของแอปพลิเคชัน"</string>
@@ -1526,7 +1528,7 @@
     <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"กำลังปลดล็อกซิมการ์ด…"</string>
     <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"รหัส PIN ไม่ถูกต้อง"</string>
     <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"พิมพ์ PIN ซึ่งเป็นเลข 4 ถึง 8 หลัก"</string>
-    <string name="kg_invalid_sim_puk_hint" msgid="6025069204539532000">"รหัส PUK ต้องเป็นตัวเลข 8 ตัว"</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="6025069204539532000">"รหัส PUK ต้องเป็นตัวเลข 8 หลัก"</string>
     <string name="kg_invalid_puk" msgid="3638289409676051243">"ใส่รหัส PUK ที่ถูกต้องอีกครั้ง การพยายามซ้ำหลายครั้งจะทำให้ซิมการ์ดถูกปิดใช้งานอย่างถาวร"</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"รหัส PIN ไม่ตรง"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"ลองหลายรูปแบบมากเกินไป"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index af36cee..4196a82 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Pinapayagan ang app na gumamit ng anumang naka-install na media decoder upang mag-decode para sa pag-playback."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"mga pinamamahalaang pinagkakatiwalaang kredensyal"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Pinapayagan ang app na mag-install at mag-uninstall ng mga CA certificate bilang mga pinagkakatiwalaang kredensyal."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"sumailalim sa mga idle na serbisyo"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Nagbibigay-daan ang pahintulot na ito sa Android system na sumailalim sa mga idle na serbisyo ng isang application."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"magbasa/magsulat sa mga mapagkukunang pag-aari ng diag"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Pinapayagan ang app na magbasa at magsulat sa anumang mapagkukunang pag-aari ng pangkat ng diag; halimbawa, mga file sa /dev. Maaaring potensyal na maapektuhan nito ang katatagan at seguridad ng system. Dapat LAMANG itong gamitin para sa diagnostics na tukoy sa hardware ng tagagawa o operator."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"paganahin o huwag paganahin ang mga bahagi ng app"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 99d415a..132d9f0 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Uygulamaya, oynatma kodunu çözmek için herhangi bir yüklü medya kod çözücüyü kullanma izni verir."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"güvenilen kimlik bilgilerini yönetme"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Uygulamaya, güvenilir kimlik bilgileri olarak CA sertifikaları yükleme veya sertifikaların yüklemelerini kaldırma izni verir."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"boşta kalma hizmetlerine bağlan"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Bu izin, Android sistemin, bir uygulamanın boşta kalma hizmetlerine bağlanmasına olanak sağlar."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"sahibi tanılama olan kaynakları oku/bunlara yaz"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Uygulamaya, tanılama grubunun sahip olduğu tüm kaynaklara (örneğin /dev içindeki dosyalar) okuma ve yazma izni verir. Bu işlevin sistem kararlılığını ve güvenliğini olumsuz etkileme olasılığı vardır. Üretici veya operatör tarafından YALNIZCA donanıma özgü tanılama için kullanılmalıdır."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"uygulama bileşenlerini etkinleştir veya devre dışı bırak"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index da50f73..3922b0c 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Дозволяє програмі використовувати будь-який установлений медіа-декодер для декодування з метою відтворення."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"керувати захищеними обліковими даними"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Дозволяє програмі встановлювати та видаляти сертифікати центру сертифікації (CA) як захищені облікові дані."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"взаємодіяти з неактивними службами"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Такий дозвіл дає змогу системі Android прив’язуватися до неактивних служб програми."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"чит./зап. на ресури., якими вол. діаг."</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Дозволяє програмі читати та писати на будь-який ресурс, яким володіє діагностична група; наприклад, у файли в папці /dev. Це потенційно може вплинути на стабільність і безпеку системи. Потрібно використовувати ЛИШЕ для певної діагностики обладнання, яку виконує виробник чи оператор."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"вмикати чи вимикати компоненти програми"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 0cabb12..e774e8e 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Cho phép ứng dụng sử dụng bất kỳ trình giải mã phương tiện nào đã cài đặt nhằm giải mã để phát lại."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"quản lý thông tin xác thực đáng tin cậy"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Cho phép ứng dụng cài đặt và gỡ cài đặt chứng chỉ CA dưới dạng thông tin xác thực đáng tin cậy."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"liên kết với dịch vụ không dùng đến"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Quyền này cho phép hệ thống Android liên kết với các dịch vụ ở trạng thái rảnh của ứng dụng."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"đọc/ghi vào tài nguyên do chẩn đoán sở hữu"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Cho phép ứng dụng đọc và ghi vào bất kỳ tài nguyên nào do nhóm chẩn đoán sở hữu; ví dụ: các tệp trong /dev. Quyền này có thể ảnh hưởng đến sự ổn định và tính bảo mật của hệ thống. CHỈ nên sử dụng quyền này cho các chẩn đoán phần cứng cụ thể của nhà sản xuất hoặc nhà cung cấp."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"bật hoặc tắt cấu phần ứng dụng"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 507b29b..035c5b6 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"允许该应用使用任何已安装的媒体解码器进行解码,以便播放媒体。"</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"管理受信任的凭据"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"允许应用安装和卸载 CA 证书(作为受信任的凭据)。"</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"绑定到闲置服务"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"此权限允许Android系统绑定至应用的闲置服务。"</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"读取/写入诊断所拥有的资源"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"允许应用读取/写入诊断组拥有的所有资源(例如 /dev 中的文件)。这可能会影响系统的稳定性和安全性。此权限仅供制造商或运营商诊断硬件方面的问题时使用。"</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"启用或停用应用组件"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index e5441a2..42aaf93 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"允許應用程式使用任何已安裝的媒體解碼器為播放解碼。"</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"管理信任的憑證"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"允許應用程式安裝 CA 憑證為信任的憑證及解除安裝 CA 憑證。"</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"繫結至閒置服務"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"此權限允許 Android 系統繫結至應用程式的閒置服務。"</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"讀取/寫入由診斷應用程式擁有的資源"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"允許應用程式讀取及寫入診斷群組所擁有的任何資源 (例如:位於 /dev 中的檔案)。這可能會影響系統的穩定性及安全性,只應對製造商或網絡供應商所使用的硬件專用診斷程式開放這項權限。"</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"啟用或停用應用程式元件"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 153f85f..6c3f1c4 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"允許應用程式使用任何已安裝的媒體解碼器進行解碼以播放影片。"</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"管理信任的憑證"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"允許應用程式安裝 CA 憑證 (做為信任的憑證) 及解除安裝 CA 憑證。"</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"繫結至閒置服務"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"此權限允許 Android 系統繫結至應用程式的閒置服務。"</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"讀寫 diag 擁有的資源"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"允許應用程式讀取或寫入診斷群組擁有的任何資源,例如 /dev 底下的檔案。這可能會影響系統的穩定性和安全性,因此應由製造商或電信業者操作,且只用在特定硬體診斷。"</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"啟用或停用應用程式元件"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 2687603..c897bdc 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Ivumela uhlelo lokusebenza ukusebenzisa noma isiphi isiqophi semidiya esifakiwe ukuqopha ukudlala."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"phatha ukuqinisekisa okuthenjiwe"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Ivumela uhlelo lokusebenza ukuthi lifake liphinde likhiphe izitifiketi ze-CA njengokuqinisekiswa okuthenjiwe."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"bophezela kumasevisi angenzi lutho"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Le mvume ivumela isistimu ye-Android ukuthi ibophezeleke kumasevisi angenzi lutho wohlelo lokusebenza."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"funda/bhalela emithombweni ephethwe idayegi"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Ivumela uhlelo lokusebenza ukufunda nokubhala kunoma yimuphi umthombo weqembu ledayegi; ngokwesibonelo, amafayela akwi/dev. Lokhu kungase kuthinte kakhulu ukuba nokuphepha kohlelo. Lokhu kumele kusebenziselwe KUPHELA ukuhlola ihadiwe okucacile ngumkhiqizi noma u-opheretha."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"vumela noma vimbela izingxenye zensiza"</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index f77d66b..9526e13 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2250,6 +2250,11 @@
              view with a theme override will inherit the themed context. -->
         <attr name="theme" />
 
+        <!-- Specifies that the shared name of the View to be shared with another Activity.
+             When transitioning between Activities, the name links a UI element in the starting
+             Activity to UI element in the called Activity. Names should be unique in the
+             View hierarchy. -->
+        <attr name="sharedElementName" format="string" />
     </declare-styleable>
 
     <!-- Attributes that can be used with a {@link android.view.ViewGroup} or any
@@ -2336,6 +2341,14 @@
             <!-- Use the children's optical bounds when laying out this container. -->
             <enum name="opticalBounds" value="1" />
         </attr>
+
+        <!-- Sets whether or not this ViewGroup should be treated as a single entity
+             when doing an Activity transition. Typically, the elements inside a
+             ViewGroup are each transitioned from the scene individually. The default
+             for a ViewGroup is false unless it has a background.
+             See {@link android.app.ActivityOptions#makeSceneTransitionAnimation(android.os.Bundle)}
+             for more information. -->
+        <attr name="transitionGroup" format="boolean" />
     </declare-styleable>
 
     <!-- A {@link android.view.ViewStub} lets you lazily include other XML layouts
diff --git a/core/res/res/values/ids.xml b/core/res/res/values/ids.xml
index 5c0baaa..56bb15f 100644
--- a/core/res/res/values/ids.xml
+++ b/core/res/res/values/ids.xml
@@ -82,4 +82,5 @@
   <item type="id" name="action_bar_spinner" />
   <item type="id" name="current_scene" />
   <item type="id" name="scene_layoutid_cache" />
+  <item type="id" name="shared_element_name" />
 </resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index e99b5ba..722f965 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2104,6 +2104,12 @@
   <public type="attr" name="controlY1" />
   <public type="attr" name="controlX2" />
   <public type="attr" name="controlY2" />
+  <public type="attr" name="fromSceneName" />
+  <public type="attr" name="toSceneName" />
+  <public type="attr" name="sharedElementName" />
+  <public type="attr" name="transitionGroup" />
+
+  <public type="id" name="shared_element_name" />
 
   <public type="style" name="Widget.Holo.FragmentBreadCrumbs" />
   <public type="style" name="Widget.Holo.Light.FragmentBreadCrumbs" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index ee68199..d70ce0a 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1178,7 +1178,7 @@
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_bindIdleService">bind to idle services</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_bindIdleService">Allows the app to interact with application-defined idle services.</string>
+    <string name="permdesc_bindIdleService">This permission allows the Android system to bind to an application\'s idle services.</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_diagnostic">read/write to resources owned by diag</string>
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index 76fbded..7a654e6 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -363,7 +363,7 @@
         <item name="searchViewTextField">@drawable/textfield_searchview_holo_dark</item>
         <item name="searchViewTextFieldRight">@drawable/textfield_searchview_right_holo_dark</item>
         <item name="searchViewCloseIcon">@android:drawable/ic_clear</item>
-        <item name="searchViewSearchIcon">@android:drawable/ic_search</item>
+        <item name="searchViewSearchIcon">@android:drawable/ic_search_api_holo_dark</item>
         <item name="searchViewGoIcon">@android:drawable/ic_go</item>
         <item name="searchViewVoiceIcon">@android:drawable/ic_voice_search</item>
         <item name="searchViewEditQuery">@android:drawable/ic_commit_search_api_holo_dark</item>
diff --git a/core/tests/coretests/src/android/os/FileUtilsTest.java b/core/tests/coretests/src/android/os/FileUtilsTest.java
index 616f5ab..93e68eb 100644
--- a/core/tests/coretests/src/android/os/FileUtilsTest.java
+++ b/core/tests/coretests/src/android/os/FileUtilsTest.java
@@ -140,7 +140,7 @@
         touch("file3", 2 * DAY_IN_MILLIS + HOUR_IN_MILLIS);
         touch("file4", 3 * DAY_IN_MILLIS + HOUR_IN_MILLIS);
         touch("file5", 4 * DAY_IN_MILLIS + HOUR_IN_MILLIS);
-        FileUtils.deleteOlderFiles(mDir, 3, DAY_IN_MILLIS);
+        assertTrue(FileUtils.deleteOlderFiles(mDir, 3, DAY_IN_MILLIS));
         assertDirContents("file1", "file2", "file3");
     }
 
@@ -148,13 +148,13 @@
         touch("file1", -HOUR_IN_MILLIS);
         touch("file2", HOUR_IN_MILLIS);
         touch("file3", WEEK_IN_MILLIS);
-        FileUtils.deleteOlderFiles(mDir, 0, DAY_IN_MILLIS);
+        assertTrue(FileUtils.deleteOlderFiles(mDir, 0, DAY_IN_MILLIS));
         assertDirContents("file1", "file2");
 
         touch("file1", -HOUR_IN_MILLIS);
         touch("file2", HOUR_IN_MILLIS);
         touch("file3", WEEK_IN_MILLIS);
-        FileUtils.deleteOlderFiles(mDir, 0, DAY_IN_MILLIS);
+        assertTrue(FileUtils.deleteOlderFiles(mDir, 0, DAY_IN_MILLIS));
         assertDirContents("file1", "file2");
     }
 
@@ -164,7 +164,8 @@
         touch("file3", 2 * DAY_IN_MILLIS + HOUR_IN_MILLIS);
         touch("file4", 3 * DAY_IN_MILLIS + HOUR_IN_MILLIS);
         touch("file5", 4 * DAY_IN_MILLIS + HOUR_IN_MILLIS);
-        FileUtils.deleteOlderFiles(mDir, 0, DAY_IN_MILLIS);
+        assertTrue(FileUtils.deleteOlderFiles(mDir, 0, DAY_IN_MILLIS));
+        assertFalse(FileUtils.deleteOlderFiles(mDir, 0, DAY_IN_MILLIS));
         assertDirContents("file1");
     }
 
@@ -174,7 +175,8 @@
         touch("file3", 2 * DAY_IN_MILLIS + HOUR_IN_MILLIS);
         touch("file4", 3 * DAY_IN_MILLIS + HOUR_IN_MILLIS);
         touch("file5", 4 * DAY_IN_MILLIS + HOUR_IN_MILLIS);
-        FileUtils.deleteOlderFiles(mDir, 2, 0);
+        assertTrue(FileUtils.deleteOlderFiles(mDir, 2, 0));
+        assertFalse(FileUtils.deleteOlderFiles(mDir, 2, 0));
         assertDirContents("file1", "file2");
     }
 
diff --git a/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/downloadmanagertests/DownloadManagerTestApp.java b/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/downloadmanagertests/DownloadManagerTestApp.java
index 0518e64..06c6c34 100644
--- a/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/downloadmanagertests/DownloadManagerTestApp.java
+++ b/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/downloadmanagertests/DownloadManagerTestApp.java
@@ -23,6 +23,9 @@
 import android.os.ParcelFileDescriptor;
 import android.util.Log;
 
+import com.android.frameworks.downloadmanagertests.DownloadManagerBaseTest;
+import com.android.frameworks.downloadmanagertests.DownloadManagerTestRunner;
+
 import java.io.DataInputStream;
 import java.io.DataOutputStream;
 import java.io.File;
@@ -38,14 +41,8 @@
     protected static String LOG_TAG =
             "com.android.frameworks.downloadmanagertests.DownloadManagerTestApp";
 
-    protected static String DOWNLOAD_500K_FILENAME = "External541kb.apk";
-    protected static long DOWNLOAD_500K_FILESIZE = 570927;
-    protected static String DOWNLOAD_1MB_FILENAME = "External1mb.apk";
-    protected static long DOWNLOAD_1MB_FILESIZE = 1041262;
-    protected static String DOWNLOAD_5MB_FILENAME = "External5mb.apk";
-    protected static long DOWNLOAD_5MB_FILESIZE = 5138700;
-    protected static String DOWNLOAD_10MB_FILENAME = "External10mb.apk";
-    protected static long DOWNLOAD_10MB_FILESIZE = 10258741;
+    protected static final String DOWNLOAD_FILENAME = "External93mb.apk";
+    protected static final long DOWNLOAD_FILESIZE = 95251708;
 
     private static final String FILE_CONCURRENT_DOWNLOAD_FILE_PREFIX = "file";
     private static final String FILE_CONCURRENT_DOWNLOAD_FILE_EXTENSION = ".bin";
@@ -126,7 +123,7 @@
      * @throws Exception if unsuccessful
      */
     public void initiateDownload() throws Exception {
-        String filename = DOWNLOAD_5MB_FILENAME;
+        String filename = DOWNLOAD_FILENAME;
         mContext.deleteFile(DOWNLOAD_STARTED_FLAG);
         FileOutputStream fileOutput = mContext.openFileOutput(DOWNLOAD_STARTED_FLAG, 0);
         DataOutputStream outputFile = null;
@@ -162,8 +159,8 @@
      * @throws Exception if unsuccessful
      */
     public void verifyFileDownloadSucceeded() throws Exception {
-        String filename = DOWNLOAD_5MB_FILENAME;
-        long filesize = DOWNLOAD_5MB_FILESIZE;
+        String filename = DOWNLOAD_FILENAME;
+        long filesize = DOWNLOAD_FILESIZE;
         long dlRequest = -1;
         boolean rebootMarkerValid = false;
         DataInputStream dataInputFile = null;
@@ -223,8 +220,8 @@
      * @throws Exception if unsuccessful
      */
     public void runLargeDownloadOverWiFi() throws Exception {
-        String filename = DOWNLOAD_10MB_FILENAME;
-        long filesize = DOWNLOAD_10MB_FILESIZE;
+        String filename = DOWNLOAD_FILENAME;
+        long filesize = DOWNLOAD_FILESIZE;
         long dlRequest = -1;
         doCommonDownloadSetup();
 
@@ -265,8 +262,8 @@
      * @throws Exception if unsuccessful
      */
     public void runDownloadMultipleSwitching() throws Exception {
-        String filename = DOWNLOAD_5MB_FILENAME;
-        long filesize = DOWNLOAD_5MB_FILESIZE;
+        String filename = DOWNLOAD_FILENAME;
+        long filesize = DOWNLOAD_FILESIZE;
         doCommonDownloadSetup();
 
         String localDownloadDirectory = Environment.getExternalStorageDirectory().getPath();
@@ -340,8 +337,8 @@
      * @throws Exception if unsuccessful
      */
     public void runDownloadMultipleWiFiEnableDisable() throws Exception {
-        String filename = DOWNLOAD_5MB_FILENAME;
-        long filesize = DOWNLOAD_5MB_FILESIZE;
+        String filename = DOWNLOAD_FILENAME;
+        long filesize = DOWNLOAD_FILESIZE;
         doCommonDownloadSetup();
 
         String localDownloadDirectory = Environment.getExternalStorageDirectory().getPath();
@@ -409,8 +406,8 @@
      * @throws Exception if unsuccessful
      */
     public void runDownloadMultipleAirplaneModeEnableDisable() throws Exception {
-        String filename = DOWNLOAD_5MB_FILENAME;
-        long filesize = DOWNLOAD_5MB_FILESIZE;
+        String filename = DOWNLOAD_FILENAME;
+        long filesize = DOWNLOAD_FILESIZE;
         // make sure WiFi is enabled, and airplane mode is not on
         doCommonDownloadSetup();
 
diff --git a/docs/html/distribute/googleplay/spotlight/index.jd b/docs/html/distribute/googleplay/spotlight/index.jd
index b501f20..6f92c78b 100644
--- a/docs/html/distribute/googleplay/spotlight/index.jd
+++ b/docs/html/distribute/googleplay/spotlight/index.jd
@@ -7,6 +7,34 @@
 
 <p>Android developers, their apps, and their successes with Android and Google Play. </p>
 
+<div id="Kiwi" style="background: #F0F0F0;
+            border-top: 1px solid #DDD;
+            padding: 0px 0 24px 0;
+            overflow: auto;
+            clear:both;
+            margin-bottom:40px;
+            margin-top:30px;">
+   <div style="padding:0 0 0 29px;">
+        <h4>Developer Story: Kiwi, Inc.</h4>
+          <img alt="" class="screenshot thumbnail" style="-webkit-border-radius: 5px;
+            -moz-border-radius: 5px;
+            border-radius: 5px height:78px;
+            width: 78px;
+            float: left;
+            margin: 17px 20px 9px 0;" 
+            src="//lh4.ggpht.com/qUI-8MJy70l4qoVBR_sx-56ckR_m0R_ZXcJ1DiTYUR3R_owWzsCFTYkAk4p5DMnaSdY3=w124" >
+          <div style="width:700px;">
+          <p style="margin-top:26px;
+                    margin-bottom:12px;">
+          Android-first developer <a href="//play.google.com/store/apps/developer?id=Kiwi,+Inc." target="_android">Kiwi, Inc.</a> has five of the top 25 grossing games on Google Play, including <a href="https://play.google.com/store/apps/details?id=com.kiwi.shipwrecked" target="_android">Shipwrecked: Lost Island</a>, <a href="https://play.google.com/store/apps/details?id=com.kiwi.monsterpark" target="_android">Monsterama Park</a>, and <a href="https://play.google.com/store/apps/details?id=com.kiwi.mysteryestate" target="_android">Hidden Object: Mystery Estate</a>. Hear how Google Play helped them double revenue every six months with features like instant updates, staged rollouts, and more.</p>
+           </div>
+           <iframe style="float:left;
+             margin-right:24px;
+             margin-top:14px;" width="700" height="394" src=
+             "http://www.youtube.com/embed/WWArLD6nqrk?HD=1;rel=0;origin=developer.android.com;" frameborder="0" allowfullscreen>
+           </iframe>
+   </div>
+</div>
 <div style="background: #F0F0F0;
             border-top: 1px solid #DDD;
             padding: 0px 0 24px 0;
diff --git a/docs/html/google/gcm/client.jd b/docs/html/google/gcm/client.jd
index 916ecee..ac446dc 100644
--- a/docs/html/google/gcm/client.jd
+++ b/docs/html/google/gcm/client.jd
@@ -75,7 +75,7 @@
 {@code dependency} section of your application's {@code build.gradle} file:</p>
 
 <pre>dependencies {
-   compile: "com.google.android.gms:play-services:3.1.+"
+  compile "com.google.android.gms:play-services:3.1.+"
 }
 </pre>
 
diff --git a/docs/html/google/gcm/gs.jd b/docs/html/google/gcm/gs.jd
index d2e65d4..4cfe1bc 100644
--- a/docs/html/google/gcm/gs.jd
+++ b/docs/html/google/gcm/gs.jd
@@ -64,14 +64,10 @@
 
  <li>Under <strong>Public API access</strong>, click <strong>Create new key</strong>.</li>
 
-<li>In the <strong>Create a new key</strong> dialog, click <strong>Android key</strong>.</li>
+<li>In the <strong>Create a new key</strong> dialog, click <strong>Server key</strong>.</li>
 
-<li>In the resulting configuration dialog, supply one SHA1 fingerprint and
-the package name for your app, separated by a semicolon. For example,
-{@code 45:B5:E4:6F:36:AD:0A:98:94:B4:02:66:2B:12:17:F2:56:26:A0:E0;com.myexample}.
-<p>To get the value for the SHA1 fingerprint, follow the instructions in the
-<a href="http://developers.google.com/console/help/new/#installedapplications">console
-help</a>.</p></li>
+<li>In the resulting configuration dialog, supply your server's IP address. For testing
+purposes, you can use {@code 0.0.0.0/0}.</p></li>
 <li>Click <strong>Create</strong>.</li>
 
 <li>In the refreshed page, copy the
@@ -102,4 +98,3 @@
 <li>Write your client app. This is the GCM-enabled Android application that runs
 on a device. See <a href="client.html">Implementing GCM Client</a> for more information.</li>
 </ol>
-
diff --git a/docs/html/google/gcm/server.jd b/docs/html/google/gcm/server.jd
index 7ba1bd5..ccd1267 100644
--- a/docs/html/google/gcm/server.jd
+++ b/docs/html/google/gcm/server.jd
@@ -120,7 +120,6 @@
   <li>Able to store the API key and client registration IDs. The
 API key is included in the header of POST requests that send
 messages.</li>
- <li>Able to store the API key and client registration IDs.</li>
  <li>Able to generate message IDs to uniquely identify each message it sends.</li>
 </ul>
 
diff --git a/docs/html/guide/topics/renderscript/compute.jd b/docs/html/guide/topics/renderscript/compute.jd
index c62510b..297a2dc 100644
--- a/docs/html/guide/topics/renderscript/compute.jd
+++ b/docs/html/guide/topics/renderscript/compute.jd
@@ -56,7 +56,9 @@
 RenderScript kernel language used in this script. Currently, 1 is the only valid value.</li>
 
 <li>A pragma declaration (<code>#pragma rs java_package_name(com.example.app)</code>) that
-declares the package name of the Java classes reflected from this script.</li>
+declares the package name of the Java classes reflected from this script.
+Note that your .rs file must be part of your application package, and not in a
+library project.</li>
 
 <li>Some number of invokable functions. An invokable function is a single-threaded RenderScript
 function that you can call from your Java code with arbitrary arguments. These are often useful for
@@ -308,4 +310,4 @@
 <li><strong>Tear down the RenderScript context.</strong> The RenderScript context can be destroyed
 with {@link android.renderscript.RenderScript#destroy} or by allowing the RenderScript context
 object to be garbage collected. This will cause any further use of any object belonging to that
-context to throw an exception.</li> </ol>
\ No newline at end of file
+context to throw an exception.</li> </ol>
diff --git a/docs/html/guide/topics/resources/runtime-changes.jd b/docs/html/guide/topics/resources/runtime-changes.jd
index 695647b..0e03fe0 100644
--- a/docs/html/guide/topics/resources/runtime-changes.jd
+++ b/docs/html/guide/topics/resources/runtime-changes.jd
@@ -53,7 +53,7 @@
 <ol type="a">
   <li><a href="#RetainingAnObject">Retain an object during a configuration change</a>
   <p>Allow your activity to restart when a configuration changes, but carry a stateful
-{@link java.lang.Object} to the new instance of your activity.</p>
+object to the new instance of your activity.</p>
 
   </li>
   <li><a href="#HandlingTheChange">Handle the configuration change yourself</a>
@@ -73,40 +73,53 @@
 android.app.Activity#onSaveInstanceState(Bundle) onSaveInstanceState()} callback&mdash;it is not
 designed to carry large objects (such as bitmaps) and the data within it must be serialized then
 deserialized, which can consume a lot of memory and make the configuration change slow. In such a
-situation, you can alleviate the burden of reinitializing your activity by retaining a stateful
-{@link java.lang.Object} when your activity is restarted due to a configuration change.</p>
+situation, you can alleviate the burden of reinitializing your activity by retaining a {@link
+android.app.Fragment} when your activity is restarted due to a configuration change. This fragment
+can contain references to stateful objects that you want to retain.</p>
 
-<p>To retain an object during a runtime configuration change:</p>
+<p>When the Android system shuts down your activity due to a configuration change, the fragments
+of your activity that you have marked to retain are not destroyed. You can add such fragments to
+your activity to preserve stateful objects.</p>
+
+<p>To retain stateful objects in a fragment during a runtime configuration change:</p>
+
 <ol>
-  <li>Override the {@link android.app.Activity#onRetainNonConfigurationInstance()} method to return
-the object you would like to retain.</li>
-  <li>When your activity is created again, call {@link
-android.app.Activity#getLastNonConfigurationInstance()} to recover your object.</li>
+  <li>Extend the {@link android.app.Fragment} class and declare references to your stateful 
+      objects.</li>
+  <li>Call {@link android.app.Fragment#setRetainInstance(boolean)} when the fragment is created.
+      </li>
+  <li>Add the fragment to your activity.</li>
+  <li>Use {@link android.app.FragmentManager} to retrieve the fragment when the activity is 
+      restarted.</li>
 </ol>
 
-<p>When the Android system shuts down your activity due to a configuration change, it calls {@link
-android.app.Activity#onRetainNonConfigurationInstance()} between the {@link
-android.app.Activity#onStop()} and {@link android.app.Activity#onDestroy()} callbacks. In your
-implementation of {@link android.app.Activity#onRetainNonConfigurationInstance()}, you can return
-any {@link java.lang.Object} that you need in order to efficiently restore your state after the
-configuration change.</p>
-
-<p>A scenario in which this can be valuable is if your application loads a lot of data from the
-web. If the user changes the orientation of the device and the activity restarts, your application
-must re-fetch the data, which could be slow. What you can do instead is implement
-{@link android.app.Activity#onRetainNonConfigurationInstance()} to return an object carrying your
-data and then retrieve the data when your activity starts again with {@link
-android.app.Activity#getLastNonConfigurationInstance()}. For example:</p>
+<p>For example, define your fragment as follows:</p>
 
 <pre>
-&#64;Override
-public Object onRetainNonConfigurationInstance() {
-    final MyDataObject data = collectMyLoadedData();
-    return data;
+public class RetainedFragment extends Fragment {
+
+    // data object we want to retain
+    private MyDataObject data;
+
+    // this method is only called once for this fragment
+    &#64;Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        // retain this fragment
+        setRetainInstance(true);
+    }
+
+    public void setData(MyDataObject data) {
+        this.data = data;
+    }
+
+    public MyDataObject getData() {
+        return data;
+    }
 }
 </pre>
 
-<p class="caution"><strong>Caution:</strong> While you can return any object, you
+<p class="caution"><strong>Caution:</strong> While you can store any object, you
 should never pass an object that is tied to the {@link android.app.Activity}, such as a {@link
 android.graphics.drawable.Drawable}, an {@link android.widget.Adapter}, a {@link android.view.View}
 or any other object that's associated with a {@link android.content.Context}. If you do, it will
@@ -114,26 +127,51 @@
 means that your application maintains a hold on them and they cannot be garbage-collected, so
 lots of memory can be lost.)</p>
 
-<p>Then retrieve the data when your activity starts again:</p>
+<p>Then use {@link android.app.FragmentManager} to add the fragment to the activity. 
+You can obtain the data object from the fragment when the activity starts again during runtime 
+configuration changes. For example, define your activity as follows:</p>
 
 <pre>
-&#64;Override
-public void onCreate(Bundle savedInstanceState) {
-    super.onCreate(savedInstanceState);
-    setContentView(R.layout.main);
+public class MyActivity extends Activity {
 
-    final MyDataObject data = (MyDataObject) getLastNonConfigurationInstance();
-    if (data == null) {
-        data = loadMyData();
+    private RetainedFragment dataFragment;
+
+    &#64;Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.main);
+
+        // find the retained fragment on activity restarts
+        FragmentManager fm = getFragmentManager();
+        dataFragment = (DataFragment) fm.findFragmentByTag(“data”);
+
+        // create the fragment and data the first time
+        if (dataFragment == null) {
+            // add the fragment
+            dataFragment = new DataFragment();
+            fm.beginTransaction().add(dataFragment, “data”).commit();
+            // load the data from the web
+            dataFragment.setData(loadMyData());
+        }
+
+        // the data is available in dataFragment.getData()
+        ...
     }
-    ...
+
+    &#64;Override
+    public void onDestroy() {
+        super.onDestroy();
+        // store the data in the fragment
+        dataFragment.setData(collectMyLoadedData());
+    }
 }
 </pre>
 
-<p>In this case, {@link android.app.Activity#getLastNonConfigurationInstance()} returns the data
-saved by {@link android.app.Activity#onRetainNonConfigurationInstance()}. If {@code data} is null
-(which happens when the activity starts due to any reason other than a configuration change) then
-this code loads the data object from the original source.</p>
+<p>In this example, {@link android.app.Activity#onCreate(Bundle) onCreate()} adds a fragment
+or restores a reference to it. {@link android.app.Activity#onCreate(Bundle) onCreate()} also
+stores the stateful object inside the fragment instance.
+{@link android.app.Activity#onDestroy() onDestroy()} updates the stateful object inside the 
+retained fragment instance.</p>
 
 
 
diff --git a/docs/html/images/video-kiwi.jpg b/docs/html/images/video-kiwi.jpg
new file mode 100644
index 0000000..1c1146c
--- /dev/null
+++ b/docs/html/images/video-kiwi.jpg
Binary files differ
diff --git a/docs/html/index.jd b/docs/html/index.jd
index 191e0fb..d976c1e 100644
--- a/docs/html/index.jd
+++ b/docs/html/index.jd
@@ -18,6 +18,52 @@
                 <!-- set explicit widths as needed to prevent overflow issues -->
 
                 <li class="item carousel-home">
+                    <div class="content-left col-11" style="padding-top:65px;">
+                      <script src="//ajax.googleapis.com/ajax/libs/swfobject/2.2/swfobject.js"></script>
+                      <div style="box-shadow: 3px 10px 18px 1px #999;width:600px;height:336px">
+                        <div id="ytapiplayer">
+                          <a href="http://www.youtube.com/watch?v=WWArLD6nqrk"><img width=600 src="{@docRoot}images/video-kiwi.jpg"></a><!--You need Flash player 8+ and JavaScript enabled to view this video. -->
+                        </div>
+                        <script type="text/javascript">
+                            var params = { allowScriptAccess: "always" };
+                            var atts = { id: "ytapiplayer" };
+                            swfobject.embedSWF("//www.youtube.com/v/WWArLD6nqrk?enablejsapi=1&playerapiid=ytplayer&version=3&HD=1;rel=0;showinfo=0;modestbranding;origin=developer.android.com;autohide=1",
+                              "ytapiplayer", "600", "336", "8", null, null, params, atts);
+
+                            // Callback used to pause/resume carousel based on video state
+                            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>
+                    <div class="content-right col-4">
+                    <h1 style="white-space:nowrap;line-height:1.2em;">Developer Story: <br />Kiwi, Inc.</h1>
+                    <p>Game developer Kiwi has five of the top 25 grossing titles on Google Play. Hear how Google Play
+                      has helped them double revenue every six months.</p>
+                      <p><a href="{@docRoot}distribute/googleplay/spotlight/index.html" class="button">Watch more videos </a></p>
+                    </div>
+                </li>
+
+                <li class="item carousel-home">
                   <div class="content-left col-7" style="width:400px;">
                     <a href="{@docRoot}about/versions/kitkat.html">
                       <img src="{@docRoot}images/home/kk-hero.jpg" width="242" style="padding-top:72px;">
diff --git a/docs/html/tools/help/proguard.jd b/docs/html/tools/help/proguard.jd
index 3ba7db2..aa9a0bc 100644
--- a/docs/html/tools/help/proguard.jd
+++ b/docs/html/tools/help/proguard.jd
@@ -25,11 +25,14 @@
       <h2>See also</h2>
 
       <ol>
-        <li><a href="http://proguard.sourceforge.net/manual/introduction.html">ProGuard
-        Manual &raquo;</a></li>
-
-        <li><a href="http://proguard.sourceforge.net/manual/retrace/introduction.html">ProGuard
-        ReTrace Manual &raquo;</a></li>
+        <li>
+          <a href="http://stuff.mit.edu/afs/sipb/project/android/sdk/android-sdk-linux/tools/proguard/docs/index.html#manual/introduction.html">ProGuard
+          Manual &raquo;</a>
+        </li>
+        <li>
+          <a href="http://stuff.mit.edu/afs/sipb/project/android/sdk/android-sdk-linux/tools/proguard/docs/index.html#manual/retrace/introduction.html">ProGuard
+          ReTrace Manual &raquo;</a>
+        </li>
       </ol>
     </div>
   </div>
@@ -146,14 +149,14 @@
 </pre>
 
   <p>There are many options and considerations when using the <code>-keep</code> option, so it is
-  highly recommended that you read the <a href="http://proguard.sourceforge.net/manual/introduction.html">ProGuard
-  Manual</a> for more information about customizing your configuration file. The <a href=
-  "http://proguard.sourceforge.net/manual/usage.html#keepoverview">Overview of Keep options</a> and
-  <a href="http://proguard.sourceforge.net/index.html#/manual/examples.html">Examples section</a>
-  are particularly helpful. The <a href=
-  "http://proguard.sourceforge.net/manual/troubleshooting.html">Troubleshooting</a> section of the
-  ProGuard Manual outlines other common problems you might encounter when your code gets stripped
-  away.</p>
+  highly recommended that you read the 
+  <a href="http://stuff.mit.edu/afs/sipb/project/android/sdk/android-sdk-linux/tools/proguard/docs/index.html#manual/introduction.html">ProGuard
+  Manual</a> for more information about customizing your configuration file. The 
+  <em>Overview of Keep options</em> and <em>Examples</em> sections are particularly helpful. 
+  The <a href=
+  "http://stuff.mit.edu/afs/sipb/project/android/sdk/android-sdk-linux/tools/proguard/docs/index.html#manual/troubleshooting.html">Troubleshooting
+  </a> section of the ProGuard Manual outlines other common problems you might encounter 
+  when your code gets stripped away.</p>
 
   <h2 id="decoding">Decoding Obfuscated Stack Traces</h2>
 
@@ -192,4 +195,4 @@
 
   <p>How you save the <code>mapping.txt</code> file is your decision. For example, you can rename them to
   include a version or build number, or you can version control them along with your source
-  code.</p>
\ No newline at end of file
+  code.</p>
diff --git a/docs/html/training/animation/screen-slide.jd b/docs/html/training/animation/screen-slide.jd
index 07d779f..a68d475 100644
--- a/docs/html/training/animation/screen-slide.jd
+++ b/docs/html/training/animation/screen-slide.jd
@@ -63,22 +63,23 @@
     contains a text view to display some text:
 
 <pre>
-&lt;com.example.android.animationsdemo.ScrollView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/content"
+&lt;!-- fragment_screen_slide_page.xml --&gt;
+&lt;ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="&#64;+id/content"
     android:layout_width="match_parent"
-    android:layout_height="match_parent"&gt;
+    android:layout_height="match_parent" &gt;
 
-        &lt;TextView style="?android:textAppearanceMedium"
-            android:padding="16dp"
-            android:lineSpacingMultiplier="1.2"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:text="@string/lorem_ipsum" /&gt;
-
-&lt;/com.example.android.animationsdemo.ScrollView&gt;
+    &lt;TextView style="?android:textAppearanceMedium"
+        android:padding="16dp"
+        android:lineSpacingMultiplier="1.2"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/lorem_ipsum" /&gt;
+&lt;/ScrollView&gt;
 </pre>
 
+  <p>Define also a string for the contents of the fragment.</p>
+
 <h2 id="fragment">Create the Fragment</h2>
 <p>Create a {@link android.support.v4.app.Fragment} class that returns the layout
 that you just created in the {@link android.app.Fragment#onCreateView onCreateView()}
@@ -87,6 +88,8 @@
 
 
 <pre>
+import android.support.v4.app.Fragment;
+...
 public class ScreenSlidePageFragment extends Fragment {
 
     &#64;Override
@@ -111,6 +114,7 @@
 <p>To begin, create a layout that contains a {@link android.support.v4.view.ViewPager}:</p>
 
 <pre>
+&lt;!-- activity_screen_slide.xml --&gt;
 &lt;android.support.v4.view.ViewPager
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/pager"
@@ -133,6 +137,9 @@
 </ul>
 
 <pre>
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentManager;
+...
 public class ScreenSlidePagerActivity extends FragmentActivity {
     /**
      * The number of pages (wizard steps) to show in this demo.
@@ -153,11 +160,11 @@
     &#64;Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        setContentView(R.layout.activity_screen_slide_pager);
+        setContentView(R.layout.activity_screen_slide);
 
         // Instantiate a ViewPager and a PagerAdapter.
         mPager = (ViewPager) findViewById(R.id.pager);
-        mPagerAdapter = new ScreenSlidePagerAdapter(getFragmentManager());
+        mPagerAdapter = new ScreenSlidePagerAdapter(getSupportFragmentManager());
         mPager.setAdapter(mPagerAdapter);
     }
 
@@ -224,9 +231,9 @@
   <code>ZoomOutPageTransformer</code>, you can set your custom animations
   like this:</p>
 <pre>
-ViewPager pager = (ViewPager) findViewById(R.id.pager);
+ViewPager mPager = (ViewPager) findViewById(R.id.pager);
 ...
-pager.setPageTransformer(true, new ZoomOutPageTransformer());
+mPager.setPageTransformer(true, new ZoomOutPageTransformer());
 </pre>
 
 
@@ -257,8 +264,8 @@
 
 <pre>
 public class ZoomOutPageTransformer implements ViewPager.PageTransformer {
-    private static float MIN_SCALE = 0.85f;
-    private static float MIN_ALPHA = 0.5f;
+    private static final float MIN_SCALE = 0.85f;
+    private static final float MIN_ALPHA = 0.5f;
 
     public void transformPage(View view, float position) {
         int pageWidth = view.getWidth();
@@ -332,7 +339,7 @@
 <pre>
 
 public class DepthPageTransformer implements ViewPager.PageTransformer {
-    private static float MIN_SCALE = 0.75f;
+    private static final float MIN_SCALE = 0.75f;
 
     public void transformPage(View view, float position) {
         int pageWidth = view.getWidth();
diff --git a/docs/html/training/scheduling/alarms.jd b/docs/html/training/scheduling/alarms.jd
index 758dc95..8373d95 100644
--- a/docs/html/training/scheduling/alarms.jd
+++ b/docs/html/training/scheduling/alarms.jd
@@ -12,6 +12,7 @@
 <!-- table of contents -->
 <h2>This lesson teaches you to</h2>
 <ol>
+  <li><a href="#tradeoffs">Understand the Trade-offs</a></li>
   <li><a href="#set">Set a Repeating Alarm</a></li>
   <li><a href="#cancel">Cancel an Alarm</a></li>
   <li><a href="#boot">Start an Alarm When the Device Boots</a></li>
@@ -28,6 +29,21 @@
 </div>
 </div>
 
+<a class="notice-developers-video wide" href="http://www.youtube.com/watch?v=yxW29JVXCqc">
+<div>
+    <h3>Video</h3>
+    <p>The App Clinic: Cricket</p>
+</div>
+</a>
+
+<a class="notice-developers-video wide"
+href="https://www.youtube.com/playlist?list=PLWz5rJ2EKKc-VJS9WQlj9xM_ygPopZ-Qd">
+<div>
+    <h3>Video</h3>
+    <p>DevBytes: Efficient Data Transfers</p>
+</div>
+</a>
+
 <p>Alarms (based on the {@link android.app.AlarmManager} class) give you a way to perform
 time-based operations outside the lifetime of your application.
 For example, you could use an alarm to initiate a long-running operation, such
@@ -55,6 +71,76 @@
 {@link java.util.Timer} and {@link java.lang.Thread}. This approach gives Android better
 control over system resources.</p>
 
+<h2 id="tradeoffs">Understand the Trade-offs</h2>
+
+<p>A repeating alarm is a relatively simple mechanism with limited flexibility.
+It may
+not be the best choice for your app, particularly if you need to trigger network
+operations. A poorly designed alarm can cause battery drain and put a significant load on
+servers.</p>
+
+<p>A common scenario for triggering an operation outside the lifetime of your app is
+syncing data with a server. This is a case where you might be tempted to use a
+repeating alarm. But if you own the server that is hosting your app's
+data, using <a href="{@docRoot}google/gcm/index.html">Google Cloud Messaging</a> (GCM)
+in conjunction with <a href="{@docRoot}training/sync-adapters/index.html">sync adapter</a>
+is a better solution than {@link android.app.AlarmManager}. A sync adapter gives you all
+the same scheduling options as {@link android.app.AlarmManager}, but it offers
+you significantly more flexibility. For example,
+a sync could be based on a "new data" message from the server/device (see
+<a href="{@docRoot}training/sync-adapters/running-sync-adapter.html">Running a Sync
+Adapter</a> for details), the user's activity (or inactivity), the time of day, and so on.
+See the linked videos at the top of this page for a detailed discussion of when and how
+to use GCM and sync adapter.</p>
+
+<h3>Best practices</h3>
+
+<p>Every choice you make in designing your repeating alarm can have consequences in how your
+app uses (or abuses) system resources. For example, imagine a popular app that
+syncs with a server. If the sync operation is based on clock time and every instance of the
+app syncs at 11:00 p.m., the load on the server could result in high latency or even
+"denial of service." Follow these best practices in using alarms:</p>
+
+<ul>
+<li>Add randomness (jitter) to any network requests that
+trigger as a result of a repeating alarm:
+<ul>
+<li>Do any local work when the alarm triggers. "Local work" means anything that doesn't
+hit a server or require the data from the server.</li>
+<li>At the same time, schedule the alarm that contains the network requests to fire at some
+random period of time.</li> </ul></li>
+
+
+<li>Keep your alarm frequency to a minimum.</li>
+<li>Don't wake up the device unnecessarily (this behavior is determined by the alarm type,
+as described in <a href="#type">Choose an alarm type</a>).</li>
+<li>Don't make your alarm's trigger time any more precise than it has to be.
+
+
+<p>Use {@link android.app.AlarmManager#setInexactRepeating setInexactRepeating()} instead
+of {@link android.app.AlarmManager#setRepeating setRepeating()}.
+When you use {@link android.app.AlarmManager#setInexactRepeating setInexactRepeating()},
+Android synchronizes repeating alarms from multiple apps and fires
+them at the same time. This reduces the total number of times the system must wake the
+device, thus reducing drain on the battery. As of Android 4.4
+(API Level 19), all repeating alarms are inexact. Note that while
+{@link android.app.AlarmManager#setInexactRepeating setInexactRepeating()} is an
+improvement over {@link android.app.AlarmManager#setRepeating setRepeating()}, it can
+still overwhelm a server if every instance of an app hits the server around the same time.
+Therefore, for network requests, add some randomness to your alarms, as discussed above.</p>
+</li>
+
+<li>Avoid basing your alarm on clock time if possible.
+
+<p>Repeating alarms that are based on a precise trigger time don't scale well.
+Use {@link android.app.AlarmManager#ELAPSED_REALTIME} if you can. The different alarm
+types are described in more detail in the following section.</p>
+
+</li>
+
+</ul>
+
+
 <h2 id="set">Set a Repeating Alarm</h2>
 
 <p>As described above, repeating alarms are a good choice for scheduling regular events or
@@ -69,29 +155,6 @@
 that uses the same pending intent, it replaces the original alarm.</li>
 </ul>
 
-<p>Every choice you make in designing your repeating alarm can have consequences in how your
-app uses (or abuses) system resources. Even a carefully managed alarm can have a major impact
-on battery life. Follow these guidelines as you design your app:</p>
-
-<ul>
-<li>Keep your alarm frequency to a minimum.</li>
-<li>Don't wake up the device unnecessarily (this behavior is determined by the alarm type,
-as described in <a href="#type">Choose an alarm type</a>).</li>
-<li>Don't make your alarm's trigger time any more precise than it has to be:
-
-<ul>
-<li>Use {@link android.app.AlarmManager#setInexactRepeating setInexactRepeating()} instead
-of {@link android.app.AlarmManager#setRepeating setRepeating()} whenever possible.
-When you use {@link android.app.AlarmManager#setInexactRepeating setInexactRepeating()},
-Android synchronizes multiple inexact repeating alarms and fires
-them at the same time. This reduces the drain on the battery.</li>
-<li>If your alarm's behavior is based on an interval (for example, your alarm
-fires once an hour) rather than a precise trigger time (for example, your alarm fires at
-7 a.m. sharp and every 20 minutes after that), use an {@code ELAPSED_REALTIME}
-alarm type.</li>
-</ul></li>
-
-</ul>
 
 <h3 id="type">Choose an alarm type</h3>
 
@@ -119,7 +182,9 @@
 <p>If you need your alarm to fire at a particular time of day,
 then choose one of the clock-based real time clock types. Note, however, that this approach can
 have some drawbacks&mdash;the app may not translate well to other locales, and if the user
-changes the device's time setting, it could cause unexpected behavior in your app.</p>
+changes the device's time setting, it could cause unexpected behavior in your app. Using a
+real time clock alarm type also does not scale well, as discussed above. We recommend
+that you use a "elapsed real time" alarm if you can.</p>
 
 <p>Here is the list of types:</p>
 
diff --git a/drm/java/android/drm/DrmOutputStream.java b/drm/java/android/drm/DrmOutputStream.java
index 87677b8..22e7ac2 100644
--- a/drm/java/android/drm/DrmOutputStream.java
+++ b/drm/java/android/drm/DrmOutputStream.java
@@ -18,18 +18,23 @@
 
 import static android.drm.DrmConvertedStatus.STATUS_OK;
 import static android.drm.DrmManagerClient.INVALID_SESSION;
+import static libcore.io.OsConstants.SEEK_SET;
 
+import android.os.ParcelFileDescriptor;
 import android.util.Log;
 
+import libcore.io.ErrnoException;
+import libcore.io.IoBridge;
+import libcore.io.Libcore;
+import libcore.io.Streams;
+
+import java.io.FileDescriptor;
 import java.io.FilterOutputStream;
 import java.io.IOException;
 import java.io.OutputStream;
-import java.io.RandomAccessFile;
 import java.net.UnknownServiceException;
 import java.util.Arrays;
 
-import libcore.io.Streams;
-
 /**
  * Stream that applies a {@link DrmManagerClient} transformation to data before
  * writing to disk, similar to a {@link FilterOutputStream}.
@@ -40,17 +45,19 @@
     private static final String TAG = "DrmOutputStream";
 
     private final DrmManagerClient mClient;
-    private final RandomAccessFile mFile;
+    private final ParcelFileDescriptor mPfd;
+    private final FileDescriptor mFd;
 
     private int mSessionId = INVALID_SESSION;
 
     /**
-     * @param file Opened with "rw" mode.
+     * @param pfd Opened with "rw" mode.
      */
-    public DrmOutputStream(DrmManagerClient client, RandomAccessFile file, String mimeType)
+    public DrmOutputStream(DrmManagerClient client, ParcelFileDescriptor pfd, String mimeType)
             throws IOException {
         mClient = client;
-        mFile = file;
+        mPfd = pfd;
+        mFd = pfd.getFileDescriptor();
 
         mSessionId = mClient.openConvertSession(mimeType);
         if (mSessionId == INVALID_SESSION) {
@@ -61,8 +68,12 @@
     public void finish() throws IOException {
         final DrmConvertedStatus status = mClient.closeConvertSession(mSessionId);
         if (status.statusCode == STATUS_OK) {
-            mFile.seek(status.offset);
-            mFile.write(status.convertedData);
+            try {
+                Libcore.os.lseek(mFd, status.offset, SEEK_SET);
+            } catch (ErrnoException e) {
+                e.rethrowAsIOException();
+            }
+            IoBridge.write(mFd, status.convertedData, 0, status.convertedData.length);
             mSessionId = INVALID_SESSION;
         } else {
             throw new IOException("Unexpected DRM status: " + status.statusCode);
@@ -75,7 +86,7 @@
             Log.w(TAG, "Closing stream without finishing");
         }
 
-        mFile.close();
+        mPfd.close();
     }
 
     @Override
@@ -92,7 +103,7 @@
 
         final DrmConvertedStatus status = mClient.convertData(mSessionId, exactBuffer);
         if (status.statusCode == STATUS_OK) {
-            mFile.write(status.convertedData);
+            IoBridge.write(mFd, status.convertedData, 0, status.convertedData.length);
         } else {
             throw new IOException("Unexpected DRM status: " + status.statusCode);
         }
diff --git a/graphics/java/android/graphics/ColorFilter.java b/graphics/java/android/graphics/ColorFilter.java
index d3c1974..4838aa0 100644
--- a/graphics/java/android/graphics/ColorFilter.java
+++ b/graphics/java/android/graphics/ColorFilter.java
@@ -27,24 +27,21 @@
  * never be used directly.
  */
 public class ColorFilter {
-    // Holds the pointer to the native SkColorFilter instance
-    long native_instance;
-
     /**
-     * Holds the pointer to the native SkiaColorFilter instance, from libhwui.
+     * Holds the pointer to the native SkColorFilter instance.
      *
      * @hide
      */
-    public long nativeColorFilter;
+    public long native_instance;
 
     @Override
     protected void finalize() throws Throwable {
         try {
             super.finalize();
         } finally {
-            destroyFilter(native_instance, nativeColorFilter);
+            destroyFilter(native_instance);
         }
     }
 
-    static native void destroyFilter(long native_instance, long nativeColorFilter);
+    static native void destroyFilter(long native_instance);
 }
diff --git a/graphics/java/android/graphics/ColorMatrixColorFilter.java b/graphics/java/android/graphics/ColorMatrixColorFilter.java
index 3f7331d..7822c41 100644
--- a/graphics/java/android/graphics/ColorMatrixColorFilter.java
+++ b/graphics/java/android/graphics/ColorMatrixColorFilter.java
@@ -114,11 +114,9 @@
 
     private void update() {
         final float[] colorMatrix = mMatrix.getArray();
-        destroyFilter(native_instance, nativeColorFilter);
+        destroyFilter(native_instance);
         native_instance = nativeColorMatrixFilter(colorMatrix);
-        nativeColorFilter = nColorMatrixFilter(native_instance, colorMatrix);
     }
 
     private static native long nativeColorMatrixFilter(float[] array);
-    private static native long nColorMatrixFilter(long nativeFilter, float[] array);
 }
diff --git a/graphics/java/android/graphics/LightingColorFilter.java b/graphics/java/android/graphics/LightingColorFilter.java
index 5829edf..70a3fe8 100644
--- a/graphics/java/android/graphics/LightingColorFilter.java
+++ b/graphics/java/android/graphics/LightingColorFilter.java
@@ -99,11 +99,9 @@
     }
 
     private void update() {
-        destroyFilter(native_instance, nativeColorFilter);
+        destroyFilter(native_instance);
         native_instance = native_CreateLightingFilter(mMul, mAdd);
-        nativeColorFilter = nCreateLightingFilter(native_instance, mMul, mAdd);
     }
 
     private static native long native_CreateLightingFilter(int mul, int add);
-    private static native long nCreateLightingFilter(long nativeFilter, int mul, int add);
 }
diff --git a/graphics/java/android/graphics/PorterDuffColorFilter.java b/graphics/java/android/graphics/PorterDuffColorFilter.java
index 93fc1c7..c078c1c 100644
--- a/graphics/java/android/graphics/PorterDuffColorFilter.java
+++ b/graphics/java/android/graphics/PorterDuffColorFilter.java
@@ -91,12 +91,9 @@
     }
 
     private void update() {
-        destroyFilter(native_instance, nativeColorFilter);
+        destroyFilter(native_instance);
         native_instance = native_CreatePorterDuffFilter(mColor, mMode.nativeInt);
-        nativeColorFilter = nCreatePorterDuffFilter(native_instance, mColor, mMode.nativeInt);
     }
 
     private static native long native_CreatePorterDuffFilter(int srcColor, int porterDuffMode);
-    private static native long nCreatePorterDuffFilter(long nativeFilter, int srcColor,
-            int porterDuffMode);
 }
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index b8365aa..b81e1c0 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -228,6 +228,20 @@
     }
 
     /**
+     * Return the drawable's dirty bounds Rect. Note: for efficiency, the
+     * returned object may be the same object stored in the drawable (though
+     * this is not guaranteed).
+     * <p>
+     * By default, this returns the full drawable bounds. Custom drawables may
+     * override this method to perform more precise invalidation.
+     *
+     * @hide
+     */
+    public Rect getDirtyBounds() {
+        return getBounds();
+    }
+
+    /**
      * Set a mask of the configuration parameters for which this drawable
      * may change, requiring that it be re-created.
      *
@@ -508,6 +522,15 @@
     public void clearHotspots() {}
 
     /**
+     * Whether this drawable requests projection.
+     *
+     * @hide
+     */
+    public boolean isProjected() {
+        return false;
+    }
+
+    /**
      * Indicates whether this view will change its appearance based on state.
      * Clients can use this to determine whether it is necessary to calculate
      * their state and call setState.
@@ -962,6 +985,8 @@
             drawable = new TransitionDrawable();
         } else if (name.equals("reveal")) {
             drawable = new RevealDrawable();
+        } else if (name.equals("touch-feedback")) {
+            drawable = new TouchFeedbackDrawable();
         } else if (name.equals("color")) {
             drawable = new ColorDrawable();
         } else if (name.equals("shape")) {
diff --git a/graphics/java/android/graphics/drawable/InsetDrawable.java b/graphics/java/android/graphics/drawable/InsetDrawable.java
index 8188782..f841d6a 100644
--- a/graphics/java/android/graphics/drawable/InsetDrawable.java
+++ b/graphics/java/android/graphics/drawable/InsetDrawable.java
@@ -182,6 +182,38 @@
         }
     }
 
+    /**
+     * @hide
+     */
+    @Override
+    public boolean supportsHotspots() {
+        return mInsetState.mDrawable.supportsHotspots();
+    }
+
+    /**
+     * @hide
+     */
+    @Override
+    public void setHotspot(int id, float x, float y) {
+        mInsetState.mDrawable.setHotspot(id, x, y);
+    }
+
+    /**
+     * @hide
+     */
+    @Override
+    public void removeHotspot(int id) {
+        mInsetState.mDrawable.removeHotspot(id);
+    }
+
+    /**
+     * @hide
+     */
+    @Override
+    public void clearHotspots() {
+        mInsetState.mDrawable.clearHotspots();
+    }
+
     @Override
     public boolean setVisible(boolean visible, boolean restart) {
         mInsetState.mDrawable.setVisible(visible, restart);
diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java
index e8b3f64..2e098a0 100644
--- a/graphics/java/android/graphics/drawable/LayerDrawable.java
+++ b/graphics/java/android/graphics/drawable/LayerDrawable.java
@@ -423,6 +423,58 @@
         }
     }
 
+    /**
+     * @hide
+     */
+    @Override
+    public boolean supportsHotspots() {
+        final ChildDrawable[] array = mLayerState.mChildren;
+        final int N = mLayerState.mNum;
+        for (int i = 0; i < N; i++) {
+            if (array[i].mDrawable.supportsHotspots()) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * @hide
+     */
+    @Override
+    public void setHotspot(int id, float x, float y) {
+        final ChildDrawable[] array = mLayerState.mChildren;
+        final int N = mLayerState.mNum;
+        for (int i = 0; i < N; i++) {
+            array[i].mDrawable.setHotspot(id, x, y);
+        }
+    }
+
+    /**
+     * @hide
+     */
+    @Override
+    public void removeHotspot(int id) {
+        final ChildDrawable[] array = mLayerState.mChildren;
+        final int N = mLayerState.mNum;
+        for (int i = 0; i < N; i++) {
+            array[i].mDrawable.removeHotspot(id);
+        }
+    }
+
+    /**
+     * @hide
+     */
+    @Override
+    public void clearHotspots() {
+        final ChildDrawable[] array = mLayerState.mChildren;
+        final int N = mLayerState.mNum;
+        for (int i = 0; i < N; i++) {
+            array[i].mDrawable.clearHotspots();
+        }
+    }
+
     private void computeStackedPadding(Rect padding) {
         padding.left = 0;
         padding.top = 0;
diff --git a/graphics/java/android/graphics/drawable/Ripple.java b/graphics/java/android/graphics/drawable/Ripple.java
index 543d2a6..cbe20dc 100644
--- a/graphics/java/android/graphics/drawable/Ripple.java
+++ b/graphics/java/android/graphics/drawable/Ripple.java
@@ -251,4 +251,13 @@
 
         return false;
     }
+
+    public void getBounds(Rect bounds) {
+        final int x = (int) mX;
+        final int y = (int) mY;
+        final int dX = Math.max(x, mBounds.right - x);
+        final int dY = Math.max(x, mBounds.bottom - y);
+        final int maxRadius = (int) Math.ceil(Math.sqrt(dX * dX + dY * dY));
+        bounds.set(x - maxRadius, y - maxRadius, x + maxRadius, y + maxRadius);
+    }
 }
diff --git a/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java b/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java
new file mode 100644
index 0000000..1bfdc4d
--- /dev/null
+++ b/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java
@@ -0,0 +1,371 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics.drawable;
+
+import android.content.res.ColorStateList;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorFilter;
+import android.graphics.Paint;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.graphics.Xfermode;
+import android.os.SystemClock;
+import android.util.AttributeSet;
+import android.util.DisplayMetrics;
+import android.util.SparseArray;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.util.ArrayList;
+
+/**
+ * An extension of LayerDrawable that is intended to react to touch hotspots
+ * and reveal the second layer atop the first.
+ * <p>
+ * It can be defined in an XML file with the <code>&lt;reveal&gt;</code> element.
+ * Each Drawable in the transition is defined in a nested <code>&lt;item&gt;</code>.
+ * For more information, see the guide to <a href="{@docRoot}
+ * guide/topics/resources/drawable-resource.html">Drawable Resources</a>.
+ *
+ * @attr ref android.R.styleable#LayerDrawableItem_left
+ * @attr ref android.R.styleable#LayerDrawableItem_top
+ * @attr ref android.R.styleable#LayerDrawableItem_right
+ * @attr ref android.R.styleable#LayerDrawableItem_bottom
+ * @attr ref android.R.styleable#LayerDrawableItem_drawable
+ * @attr ref android.R.styleable#LayerDrawableItem_id
+ * @hide
+ */
+public class TouchFeedbackDrawable extends Drawable {
+    private final Rect mTempRect = new Rect();
+    private final Rect mPaddingRect = new Rect();
+
+    /** Current drawing bounds, used to compute dirty region. */
+    private final Rect mDrawingBounds = new Rect();
+
+    /** Current dirty bounds, union of current and previous drawing bounds. */
+    private final Rect mDirtyBounds = new Rect();
+
+    private final TouchFeedbackState mState;
+
+    /** Lazily-created map of touch hotspot IDs to ripples. */
+    private SparseArray<Ripple> mTouchedRipples;
+
+    /** Lazily-created list of actively animating ripples. */
+    private ArrayList<Ripple> mActiveRipples;
+
+    /** Lazily-created runnable for scheduling invalidation. */
+    private Runnable mAnimationRunnable;
+
+    /** Paint used to control appearance of ripples. */
+    private Paint mRipplePaint;
+
+    /** Target density of the display into which ripples are drawn. */
+    private int mTargetDensity;
+
+    /** Whether the animation runnable has been posted. */
+    private boolean mAnimating;
+
+    TouchFeedbackDrawable() {
+        this(new TouchFeedbackState(null), null);
+    }
+
+    TouchFeedbackDrawable(TouchFeedbackState state, Resources res) {
+        if (res != null) {
+            mTargetDensity = res.getDisplayMetrics().densityDpi;
+        } else if (state != null) {
+            mTargetDensity = state.mTargetDensity;
+        }
+
+        mState = state;
+    }
+
+    @Override
+    public void setColorFilter(ColorFilter cf) {
+        // Not supported.
+    }
+
+    @Override
+    public void setAlpha(int alpha) {
+        // Not supported.
+    }
+
+    @Override
+    public int getOpacity() {
+        return mActiveRipples != null && !mActiveRipples.isEmpty() ?
+                PixelFormat.TRANSLUCENT : PixelFormat.TRANSPARENT;
+    }
+
+    @Override
+    public boolean onStateChange(int[] stateSet) {
+        final ColorStateList stateList = mState.mColorStateList;
+        if (stateList != null && mRipplePaint != null) {
+            final int newColor = stateList.getColorForState(stateSet, 0);
+            final int oldColor = mRipplePaint.getColor();
+            if (oldColor != newColor) {
+                mRipplePaint.setColor(newColor);
+                invalidateSelf();
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * @hide
+     */
+    @Override
+    public boolean isProjected() {
+        return true;
+    }
+
+    @Override
+    public boolean isStateful() {
+        return mState.mColorStateList != null && mState.mColorStateList.isStateful();
+    }
+
+    /**
+     * Set the density at which this drawable will be rendered.
+     *
+     * @param density The density scale for this drawable.
+     */
+    public void setTargetDensity(int density) {
+        if (mTargetDensity != density) {
+            mTargetDensity = density == 0 ? DisplayMetrics.DENSITY_DEFAULT : density;
+            // TODO: Update density in ripples?
+            invalidateSelf();
+        }
+    }
+
+    @Override
+    public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs)
+            throws XmlPullParserException, IOException {
+        super.inflate(r, parser, attrs);
+
+        final TypedArray a = r.obtainAttributes(attrs,
+                com.android.internal.R.styleable.ColorDrawable);
+        mState.mColorStateList = a.getColorStateList(
+                com.android.internal.R.styleable.ColorDrawable_color);
+        a.recycle();
+
+        mState.mXfermode = null; //new PorterDuffXfermode(Mode.SRC_ATOP);
+        mState.mProjected = false;
+    }
+
+    /**
+     * @hide until hotspot APIs are finalized
+     */
+    @Override
+    public boolean supportsHotspots() {
+        return true;
+    }
+
+    /**
+     * @hide until hotspot APIs are finalized
+     */
+    @Override
+    public void setHotspot(int id, float x, float y) {
+        if (mTouchedRipples == null) {
+            mTouchedRipples = new SparseArray<Ripple>();
+            mActiveRipples = new ArrayList<Ripple>();
+        }
+
+        final Ripple ripple = mTouchedRipples.get(id);
+        if (ripple == null) {
+            final Rect padding = mPaddingRect;
+            getPadding(padding);
+
+            final Rect bounds = getBounds();
+            final Ripple newRipple = new Ripple(bounds, padding, bounds.exactCenterX(),
+                    bounds.exactCenterY(), mTargetDensity);
+            newRipple.enter();
+
+            mActiveRipples.add(newRipple);
+            mTouchedRipples.put(id, newRipple);
+        } else {
+            //ripple.move(x, y);
+        }
+
+        scheduleAnimation();
+    }
+
+    /**
+     * @hide until hotspot APIs are finalized
+     */
+    @Override
+    public void removeHotspot(int id) {
+        if (mTouchedRipples == null) {
+            return;
+        }
+
+        final Ripple ripple = mTouchedRipples.get(id);
+        if (ripple != null) {
+            ripple.exit();
+
+            mTouchedRipples.remove(id);
+            scheduleAnimation();
+        }
+    }
+
+    /**
+     * @hide until hotspot APIs are finalized
+     */
+    @Override
+    public void clearHotspots() {
+        if (mTouchedRipples == null) {
+            return;
+        }
+
+        final int n = mTouchedRipples.size();
+        for (int i = 0; i < n; i++) {
+            final Ripple ripple = mTouchedRipples.valueAt(i);
+            ripple.exit();
+        }
+
+        if (n > 0) {
+            mTouchedRipples.clear();
+            scheduleAnimation();
+        }
+    }
+
+    /**
+     * Schedules the next animation, if necessary.
+     */
+    private void scheduleAnimation() {
+        if (mActiveRipples == null || mActiveRipples.isEmpty()) {
+            mAnimating = false;
+        } else if (!mAnimating) {
+            mAnimating = true;
+
+            if (mAnimationRunnable == null) {
+                mAnimationRunnable = new Runnable() {
+                    @Override
+                    public void run() {
+                        mAnimating = false;
+                        scheduleAnimation();
+                        invalidateSelf();
+                    }
+                };
+            }
+
+            scheduleSelf(mAnimationRunnable, SystemClock.uptimeMillis() + 1000 / 60);
+        }
+    }
+
+    @Override
+    public void draw(Canvas canvas) {
+        final ArrayList<Ripple> activeRipples = mActiveRipples;
+        if (activeRipples == null || activeRipples.isEmpty()) {
+            // Nothing to draw, we're done here.
+            return;
+        }
+
+        final ColorStateList stateList = mState.mColorStateList;
+        if (stateList == null) {
+            // No color, we're done here.
+            return;
+        }
+
+        final int color = stateList.getColorForState(getState(), Color.TRANSPARENT);
+        if (color == Color.TRANSPARENT) {
+            // No color, we're done here.
+            return;
+        }
+
+        if (mRipplePaint == null) {
+            mRipplePaint = new Paint();
+            mRipplePaint.setAntiAlias(true);
+        }
+
+        mRipplePaint.setXfermode(mState.mXfermode);
+        mRipplePaint.setColor(color);
+
+        final int restoreCount = canvas.save();
+
+        // Draw ripples directly onto the canvas.
+        int n = activeRipples.size();
+        for (int i = 0; i < n; i++) {
+            final Ripple ripple = activeRipples.get(i);
+            if (!ripple.active()) {
+                activeRipples.remove(i);
+                i--;
+                n--;
+            } else {
+                ripple.draw(canvas, mRipplePaint);
+            }
+        }
+
+        canvas.restoreToCount(restoreCount);
+    }
+
+    @Override
+    public Rect getDirtyBounds() {
+        final Rect dirtyBounds = mDirtyBounds;
+        final Rect drawingBounds = mDrawingBounds;
+        dirtyBounds.set(drawingBounds);
+        drawingBounds.setEmpty();
+
+        final Rect rippleBounds = mTempRect;
+        final ArrayList<Ripple> activeRipples = mActiveRipples;
+        if (activeRipples != null) {
+           final int N = activeRipples.size();
+           for (int i = 0; i < N; i++) {
+               activeRipples.get(i).getBounds(rippleBounds);
+               drawingBounds.union(rippleBounds);
+           }
+        }
+
+        dirtyBounds.union(drawingBounds);
+        return dirtyBounds;
+    }
+
+    private static class TouchFeedbackState extends ConstantState {
+        private ColorStateList mColorStateList;
+        private Xfermode mXfermode;
+        private int mTargetDensity;
+        private boolean mProjected;
+
+        public TouchFeedbackState(TouchFeedbackState orig) {
+            if (orig != null) {
+                mColorStateList = orig.mColorStateList;
+                mXfermode = orig.mXfermode;
+                mTargetDensity = orig.mTargetDensity;
+                mProjected = orig.mProjected;
+            }
+        }
+
+        @Override
+        public int getChangingConfigurations() {
+            return 0;
+        }
+
+        @Override
+        public Drawable newDrawable() {
+            return newDrawable(null);
+        }
+
+        @Override
+        public Drawable newDrawable(Resources res) {
+            return new TouchFeedbackDrawable(this, res);
+        }
+    }
+}
diff --git a/graphics/java/android/graphics/pdf/PdfDocument.java b/graphics/java/android/graphics/pdf/PdfDocument.java
index 29d14a2..f5b07c1 100644
--- a/graphics/java/android/graphics/pdf/PdfDocument.java
+++ b/graphics/java/android/graphics/pdf/PdfDocument.java
@@ -82,7 +82,7 @@
 
     private final List<PageInfo> mPages = new ArrayList<PageInfo>();
 
-    private int mNativeDocument;
+    private long mNativeDocument;
 
     private Page mCurrentPage;
 
@@ -235,20 +235,20 @@
         }
     }
 
-    private native int nativeCreateDocument();
+    private native long nativeCreateDocument();
 
-    private native void nativeClose(int document);
+    private native void nativeClose(long nativeDocument);
 
-    private native void nativeFinishPage(int document);
+    private native void nativeFinishPage(long nativeDocument);
 
-    private native void nativeWriteTo(int document, OutputStream out, byte[] chunk);
+    private native void nativeWriteTo(long nativeDocument, OutputStream out, byte[] chunk);
 
-    private static native int nativeStartPage(int documentPtr, int pageWidth, int pageHeight,
+    private static native long nativeStartPage(long nativeDocument, int pageWidth, int pageHeight,
             int contentLeft, int contentTop, int contentRight, int contentBottom);
 
     private final class PdfCanvas extends Canvas {
 
-        public PdfCanvas(int nativeCanvas) {
+        public PdfCanvas(long nativeCanvas) {
             super(nativeCanvas);
         }
 
diff --git a/include/androidfw/AssetManager.h b/include/androidfw/AssetManager.h
index a010957..503377c 100644
--- a/include/androidfw/AssetManager.h
+++ b/include/androidfw/AssetManager.h
@@ -69,6 +69,7 @@
  */
 class AssetManager : public AAssetManager {
 public:
+    static const char* RESOURCES_FILENAME;
     typedef enum CacheMode {
         CACHE_UNKNOWN = 0,
         CACHE_OFF,          // don't try to cache file locations
@@ -218,6 +219,13 @@
      */
     void getLocales(Vector<String8>* locales) const;
 
+    /**
+     * Generate idmap data to translate resources IDs between a package and a
+     * corresponding overlay package.
+     */
+    bool createIdmap(const char* targetApkPath, const char* overlayApkPath,
+        uint32_t targetCrc, uint32_t overlayCrc, uint32_t** outData, size_t* outSize);
+
 private:
     struct asset_path
     {
diff --git a/include/androidfw/PowerManager.h b/include/androidfw/PowerManager.h
deleted file mode 100644
index ba98db0..0000000
--- a/include/androidfw/PowerManager.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _ANDROIDFW_POWER_MANAGER_H
-#define _ANDROIDFW_POWER_MANAGER_H
-
-
-namespace android {
-
-enum {
-    USER_ACTIVITY_EVENT_OTHER = 0,
-    USER_ACTIVITY_EVENT_BUTTON = 1,
-    USER_ACTIVITY_EVENT_TOUCH = 2,
-
-    USER_ACTIVITY_EVENT_LAST = USER_ACTIVITY_EVENT_TOUCH, // Last valid event code.
-};
-
-} // namespace android
-
-#endif // _ANDROIDFW_POWER_MANAGER_H
diff --git a/include/androidfw/ResourceTypes.h b/include/androidfw/ResourceTypes.h
index 6799766..0f51826 100644
--- a/include/androidfw/ResourceTypes.h
+++ b/include/androidfw/ResourceTypes.h
@@ -808,6 +808,19 @@
     uint32_t lastPublicKey;
 };
 
+// The most specific locale can consist of:
+//
+// - a 3 char language code
+// - a 3 char region code prefixed by a 'r'
+// - a 4 char script code prefixed by a 's'
+// - a 8 char variant code prefixed by a 'v'
+//
+// each separated by a single char separator, which sums up to a total of 24
+// chars, (25 include the string terminator) rounded up to 28 to be 4 byte
+// aligned.
+#define RESTABLE_MAX_LOCALE_LEN 28
+
+
 /**
  * Describes a particular resource configuration.
  */
@@ -828,10 +841,42 @@
     
     union {
         struct {
-            // \0\0 means "any".  Otherwise, en, fr, etc.
+            // This field can take three different forms:
+            // - \0\0 means "any".
+            //
+            // - Two 7 bit ascii values interpreted as ISO-639-1 language
+            //   codes ('fr', 'en' etc. etc.). The high bit for both bytes is
+            //   zero.
+            //
+            // - A single 16 bit little endian packed value representing an
+            //   ISO-639-2 3 letter language code. This will be of the form:
+            //
+            //   {1, t, t, t, t, t, s, s, s, s, s, f, f, f, f, f}
+            //
+            //   bit[0, 4] = first letter of the language code
+            //   bit[5, 9] = second letter of the language code
+            //   bit[10, 14] = third letter of the language code.
+            //   bit[15] = 1 always
+            //
+            // For backwards compatibility, languages that have unambiguous
+            // two letter codes are represented in that format.
+            //
+            // The layout is always bigendian irrespective of the runtime
+            // architecture.
             char language[2];
             
-            // \0\0 means "any".  Otherwise, US, CA, etc.
+            // This field can take three different forms:
+            // - \0\0 means "any".
+            //
+            // - Two 7 bit ascii values interpreted as 2 letter region
+            //   codes ('US', 'GB' etc.). The high bit for both bytes is zero.
+            //
+            // - An UN M.49 3 digit region code. For simplicity, these are packed
+            //   in the same manner as the language codes, though we should need
+            //   only 10 bits to represent them, instead of the 15.
+            //
+            // The layout is always bigendian irrespective of the runtime
+            // architecture.
             char country[2];
         };
         uint32_t locale;
@@ -933,7 +978,7 @@
         SDKVERSION_ANY = 0
     };
     
-    enum {
+  enum {
         MINORVERSION_ANY = 0
     };
     
@@ -1006,6 +1051,15 @@
         uint32_t screenSizeDp;
     };
 
+    // The ISO-15924 short name for the script corresponding to this
+    // configuration. (eg. Hant, Latn, etc.). Interpreted in conjunction with
+    // the locale field.
+    char localeScript[4];
+
+    // A single BCP-47 variant subtag. Will vary in length between 5 and 8
+    // chars. Interpreted in conjunction with the locale field.
+    char localeVariant[8];
+
     void copyFromDeviceNoSwap(const ResTable_config& o);
     
     void copyFromDtoH(const ResTable_config& o);
@@ -1063,7 +1117,46 @@
     // settings is the requested settings
     bool match(const ResTable_config& settings) const;
 
-    void getLocale(char str[6]) const;
+    // Get the string representation of the locale component of this
+    // Config. The maximum size of this representation will be
+    // |RESTABLE_MAX_LOCALE_LEN| (including a terminating '\0').
+    //
+    // Example: en-US, en-Latn-US, en-POSIX.
+    void getBcp47Locale(char* out) const;
+
+    // Sets the values of language, region, script and variant to the
+    // well formed BCP-47 locale contained in |in|. The input locale is
+    // assumed to be valid and no validation is performed.
+    void setBcp47Locale(const char* in);
+
+    inline void clearLocale() {
+        locale = 0;
+        memset(localeScript, 0, sizeof(localeScript));
+        memset(localeVariant, 0, sizeof(localeVariant));
+    }
+
+    // Get the 2 or 3 letter language code of this configuration. Trailing
+    // bytes are set to '\0'.
+    size_t unpackLanguage(char language[4]) const;
+    // Get the 2 or 3 letter language code of this configuration. Trailing
+    // bytes are set to '\0'.
+    size_t unpackRegion(char region[4]) const;
+
+    // Sets the language code of this configuration to the first three
+    // chars at |language|.
+    //
+    // If |language| is a 2 letter code, the trailing byte must be '\0' or
+    // the BCP-47 separator '-'.
+    void packLanguage(const char* language);
+    // Sets the region code of this configuration to the first three bytes
+    // at |region|. If |region| is a 2 letter code, the trailing byte must be '\0'
+    // or the BCP-47 separator '-'.
+    void packRegion(const char* region);
+
+    // Returns a positive integer if this config is more specific than |o|
+    // with respect to their locales, a negative integer if |o| is more specific
+    // and 0 if they're equally specific.
+    int isLocaleMoreSpecificThan(const ResTable_config &o) const;
 
     String8 toString() const;
 };
@@ -1284,7 +1377,7 @@
     ~ResTable();
 
     status_t add(Asset* asset, const int32_t cookie, bool copyData,
-                 const void* idmap);
+                 const void* idmap = NULL);
     status_t add(const void *data, size_t size);
     status_t add(ResTable* src);
 
@@ -1545,9 +1638,19 @@
     // Return value: on success: NO_ERROR; caller is responsible for free-ing
     // outData (using free(3)). On failure, any status_t value other than
     // NO_ERROR; the caller should not free outData.
-    status_t createIdmap(const ResTable& overlay, uint32_t originalCrc, uint32_t overlayCrc,
+    status_t createIdmap(const ResTable& overlay, uint32_t targetCrc, uint32_t overlayCrc,
                          void** outData, size_t* outSize) const;
 
+    status_t createIdmap(const ResTable& overlay,
+            uint32_t targetCrc, uint32_t overlayCrc,
+            const char* targetPath, const char* overlayPath,
+            void** outData, size_t* outSize) const
+    {
+        (void)targetPath;
+        (void)overlayPath;
+        return createIdmap(overlay, targetCrc, overlayCrc, outData, outSize);
+    }
+
     enum {
         IDMAP_HEADER_SIZE_BYTES = 3 * sizeof(uint32_t),
     };
@@ -1556,7 +1659,18 @@
     // This function only requires the idmap header (the first
     // IDMAP_HEADER_SIZE_BYTES) bytes of an idmap file.
     static bool getIdmapInfo(const void* idmap, size_t size,
-                             uint32_t* pOriginalCrc, uint32_t* pOverlayCrc);
+                             uint32_t* pTargetCrc, uint32_t* pOverlayCrc);
+
+    static bool getIdmapInfo(const void* idmap, size_t size,
+            uint32_t* pTargetCrc, uint32_t* pOverlayCrc,
+            String8* pTargetPath, String8* pOverlayPath)
+    {
+        if (*pTargetPath)
+            *pTargetPath = String8();
+        if (*pOverlayPath)
+            *pOverlayPath = String8();
+        return getIdmapInfo(idmap, size, pTargetCrc, pOverlayCrc);
+    }
 
     void print(bool inclValues) const;
     static String8 normalizeForOutput(const char* input);
diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java
index 8ad973d..6f8292d 100644
--- a/keystore/java/android/security/KeyChain.java
+++ b/keystore/java/android/security/KeyChain.java
@@ -94,6 +94,11 @@
     private static final String ACTION_CHOOSER = "com.android.keychain.CHOOSER";
 
     /**
+     * Package name for the Certificate Installer.
+     */
+    private static final String CERT_INSTALLER_PACKAGE = "com.android.certinstaller";
+
+    /**
      * Extra for use with {@link #ACTION_CHOOSER}
      * @hide Also used by KeyChainActivity implementation
      */
@@ -201,7 +206,7 @@
      */
     public static Intent createInstallIntent() {
         Intent intent = new Intent(ACTION_INSTALL);
-        intent.setClassName("com.android.certinstaller",
+        intent.setClassName(CERT_INSTALLER_PACKAGE,
                             "com.android.certinstaller.CertInstallerMain");
         return intent;
     }
@@ -267,6 +272,7 @@
             throw new NullPointerException("response == null");
         }
         Intent intent = new Intent(ACTION_CHOOSER);
+        intent.setPackage(CERT_INSTALLER_PACKAGE);
         intent.putExtra(EXTRA_RESPONSE, new AliasResponse(response));
         intent.putExtra(EXTRA_HOST, host);
         intent.putExtra(EXTRA_PORT, port);
diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp
index 501b83e..a24a8b3 100644
--- a/libs/androidfw/AssetManager.cpp
+++ b/libs/androidfw/AssetManager.cpp
@@ -83,6 +83,8 @@
 
 static volatile int32_t gCount = 0;
 
+const char* AssetManager::RESOURCES_FILENAME = "resources.arsc";
+
 namespace {
     // Transform string /a/b/c.apk to /data/resource-cache/a@b@c.apk@idmap
     String8 idmapPathForPackagePath(const String8& pkgPath)
@@ -239,6 +241,29 @@
     return true;
 }
 
+bool AssetManager::createIdmap(const char* targetApkPath, const char* overlayApkPath,
+        uint32_t targetCrc, uint32_t overlayCrc, uint32_t** outData, size_t* outSize)
+{
+    AutoMutex _l(mLock);
+    const String8 paths[2] = { String8(targetApkPath), String8(overlayApkPath) };
+    ResTable tables[2];
+
+    for (int i = 0; i < 2; ++i) {
+        asset_path ap;
+        ap.type = kFileTypeRegular;
+        ap.path = paths[i];
+        Asset* ass = openNonAssetInPathLocked("resources.arsc", Asset::ACCESS_BUFFER, ap);
+        if (ass == NULL) {
+            ALOGW("failed to find resources.arsc in %s\n", ap.path.string());
+            return false;
+        }
+        tables[i].add(ass, 1, false);
+    }
+
+    return tables[0].createIdmap(tables[1], targetCrc, overlayCrc,
+            targetApkPath, overlayApkPath, (void**)outData, outSize) == NO_ERROR;
+}
+
 bool AssetManager::isIdmapStaleLocked(const String8& originalPath, const String8& overlayPath,
                                       const String8& idmapPath)
 {
@@ -463,17 +488,8 @@
     if (locale) {
         setLocaleLocked(locale);
     } else if (config.language[0] != 0) {
-        char spec[9];
-        spec[0] = config.language[0];
-        spec[1] = config.language[1];
-        if (config.country[0] != 0) {
-            spec[2] = '_';
-            spec[3] = config.country[0];
-            spec[4] = config.country[1];
-            spec[5] = 0;
-        } else {
-            spec[3] = 0;
-        }
+        char spec[RESTABLE_MAX_LOCALE_LEN];
+        config.getBcp47Locale(spec);
         setLocaleLocked(spec);
     } else {
         updateResourceParamsLocked();
@@ -733,20 +749,11 @@
         return;
     }
 
-    size_t llen = mLocale ? strlen(mLocale) : 0;
-    mConfig->language[0] = 0;
-    mConfig->language[1] = 0;
-    mConfig->country[0] = 0;
-    mConfig->country[1] = 0;
-    if (llen >= 2) {
-        mConfig->language[0] = mLocale[0];
-        mConfig->language[1] = mLocale[1];
+    if (mLocale) {
+        mConfig->setBcp47Locale(mLocale);
+    } else {
+        mConfig->clearLocale();
     }
-    if (llen >= 5) {
-        mConfig->country[0] = mLocale[3];
-        mConfig->country[1] = mLocale[4];
-    }
-    mConfig->size = sizeof(*mConfig);
 
     res->setParameters(mConfig);
 }
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 72d331c..be163c2 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -66,11 +66,6 @@
 // size measured in sizeof(uint32_t)
 #define IDMAP_HEADER_SIZE (ResTable::IDMAP_HEADER_SIZE_BYTES / sizeof(uint32_t))
 
-static void printToLogFunc(int32_t cookie, const char* txt)
-{
-    ALOGV("[cookie=%d] %s", cookie, txt);
-}
-
 // Standard C isspace() is only required to look at the low byte of its input, so
 // produces incorrect results for UTF-16 characters.  For safety's sake, assume that
 // any high-byte UTF-16 code point is not whitespace.
@@ -1539,6 +1534,71 @@
     }
 }
 
+/* static */ size_t unpackLanguageOrRegion(const char in[2], const char base,
+        char out[4]) {
+  if (in[0] & 0x80) {
+      // The high bit is "1", which means this is a packed three letter
+      // language code.
+
+      // The smallest 5 bits of the second char are the first alphabet.
+      const uint8_t first = in[1] & 0x1f;
+      // The last three bits of the second char and the first two bits
+      // of the first char are the second alphabet.
+      const uint8_t second = ((in[1] & 0xe0) >> 5) + ((in[0] & 0x03) << 3);
+      // Bits 3 to 7 (inclusive) of the first char are the third alphabet.
+      const uint8_t third = (in[0] & 0x7c) >> 2;
+
+      out[0] = first + base;
+      out[1] = second + base;
+      out[2] = third + base;
+      out[3] = 0;
+
+      return 3;
+  }
+
+  if (in[0]) {
+      memcpy(out, in, 2);
+      memset(out + 2, 0, 2);
+      return 2;
+  }
+
+  memset(out, 0, 4);
+  return 0;
+}
+
+/* static */ void packLanguageOrRegion(const char* in, const char base,
+        char out[2]) {
+  if (in[2] == 0 || in[2] == '-') {
+      out[0] = in[0];
+      out[1] = in[1];
+  } else {
+      uint8_t first = (in[0] - base) & 0x00ef;
+      uint8_t second = (in[1] - base) & 0x00ef;
+      uint8_t third = (in[2] - base) & 0x00ef;
+
+      out[0] = (0x80 | (third << 2) | (second >> 3));
+      out[1] = ((second << 5) | first);
+  }
+}
+
+
+void ResTable_config::packLanguage(const char* language) {
+    packLanguageOrRegion(language, 'a', this->language);
+}
+
+void ResTable_config::packRegion(const char* region) {
+    packLanguageOrRegion(region, '0', this->country);
+}
+
+size_t ResTable_config::unpackLanguage(char language[4]) const {
+    return unpackLanguageOrRegion(this->language, 'a', language);
+}
+
+size_t ResTable_config::unpackRegion(char region[4]) const {
+    return unpackLanguageOrRegion(this->country, '0', region);
+}
+
+
 void ResTable_config::copyFromDtoH(const ResTable_config& o) {
     copyFromDeviceNoSwap(o);
     size = sizeof(ResTable_config);
@@ -1568,10 +1628,30 @@
     screenHeightDp = htods(screenHeightDp);
 }
 
+/* static */ inline int compareLocales(const ResTable_config &l, const ResTable_config &r) {
+    if (l.locale != r.locale) {
+        // NOTE: This is the old behaviour with respect to comparison orders.
+        // The diff value here doesn't make much sense (given our bit packing scheme)
+        // but it's stable, and that's all we need.
+        return l.locale - r.locale;
+    }
+
+    // The language & region are equal, so compare the scripts and variants.
+    int script = memcmp(l.localeScript, r.localeScript, sizeof(l.localeScript));
+    if (script) {
+        return script;
+    }
+
+    // The language, region and script are equal, so compare variants.
+    //
+    // This should happen very infrequently (if at all.)
+    return memcmp(l.localeVariant, r.localeVariant, sizeof(l.localeVariant));
+}
+
 int ResTable_config::compare(const ResTable_config& o) const {
     int32_t diff = (int32_t)(imsi - o.imsi);
     if (diff != 0) return diff;
-    diff = (int32_t)(locale - o.locale);
+    diff = compareLocales(*this, o);
     if (diff != 0) return diff;
     diff = (int32_t)(screenType - o.screenType);
     if (diff != 0) return diff;
@@ -1598,18 +1678,15 @@
     if (mnc != o.mnc) {
         return mnc < o.mnc ? -1 : 1;
     }
-    if (language[0] != o.language[0]) {
-        return language[0] < o.language[0] ? -1 : 1;
+
+    int diff = compareLocales(*this, o);
+    if (diff < 0) {
+        return -1;
     }
-    if (language[1] != o.language[1]) {
-        return language[1] < o.language[1] ? -1 : 1;
+    if (diff > 0) {
+        return 1;
     }
-    if (country[0] != o.country[0]) {
-        return country[0] < o.country[0] ? -1 : 1;
-    }
-    if (country[1] != o.country[1]) {
-        return country[1] < o.country[1] ? -1 : 1;
-    }
+
     if ((screenLayout & MASK_LAYOUTDIR) != (o.screenLayout & MASK_LAYOUTDIR)) {
         return (screenLayout & MASK_LAYOUTDIR) < (o.screenLayout & MASK_LAYOUTDIR) ? -1 : 1;
     }
@@ -1656,7 +1733,6 @@
     int diffs = 0;
     if (mcc != o.mcc) diffs |= CONFIG_MCC;
     if (mnc != o.mnc) diffs |= CONFIG_MNC;
-    if (locale != o.locale) diffs |= CONFIG_LOCALE;
     if (orientation != o.orientation) diffs |= CONFIG_ORIENTATION;
     if (density != o.density) diffs |= CONFIG_DENSITY;
     if (touchscreen != o.touchscreen) diffs |= CONFIG_TOUCHSCREEN;
@@ -1671,9 +1747,44 @@
     if (uiMode != o.uiMode) diffs |= CONFIG_UI_MODE;
     if (smallestScreenWidthDp != o.smallestScreenWidthDp) diffs |= CONFIG_SMALLEST_SCREEN_SIZE;
     if (screenSizeDp != o.screenSizeDp) diffs |= CONFIG_SCREEN_SIZE;
+
+    const int diff = compareLocales(*this, o);
+    if (diff) diffs |= CONFIG_LOCALE;
+
     return diffs;
 }
 
+int ResTable_config::isLocaleMoreSpecificThan(const ResTable_config& o) const {
+    if (locale || o.locale) {
+        if (language[0] != o.language[0]) {
+            if (!language[0]) return -1;
+            if (!o.language[0]) return 1;
+        }
+
+        if (country[0] != o.country[0]) {
+            if (!country[0]) return -1;
+            if (!o.country[0]) return 1;
+        }
+    }
+
+    // There isn't a well specified "importance" order between variants and
+    // scripts. We can't easily tell whether, say "en-Latn-US" is more or less
+    // specific than "en-US-POSIX".
+    //
+    // We therefore arbitrarily decide to give priority to variants over
+    // scripts since it seems more useful to do so. We will consider
+    // "en-US-POSIX" to be more specific than "en-Latn-US".
+
+    const int score = ((localeScript[0] != 0) ? 1 : 0) +
+        ((localeVariant[0] != 0) ? 2 : 0);
+
+    const int oScore = ((o.localeScript[0] != 0) ? 1 : 0) +
+        ((o.localeVariant[0] != 0) ? 2 : 0);
+
+    return score - oScore;
+
+}
+
 bool ResTable_config::isMoreSpecificThan(const ResTable_config& o) const {
     // The order of the following tests defines the importance of one
     // configuration parameter over another.  Those tests first are more
@@ -1691,14 +1802,13 @@
     }
 
     if (locale || o.locale) {
-        if (language[0] != o.language[0]) {
-            if (!language[0]) return false;
-            if (!o.language[0]) return true;
+        const int diff = isLocaleMoreSpecificThan(o);
+        if (diff < 0) {
+            return false;
         }
 
-        if (country[0] != o.country[0]) {
-            if (!country[0]) return false;
-            if (!o.country[0]) return true;
+        if (diff > 0) {
+            return true;
         }
     }
 
@@ -1834,6 +1944,18 @@
             }
         }
 
+        if (localeScript[0] || o.localeScript[0]) {
+            if (localeScript[0] != o.localeScript[0] && requested->localeScript[0]) {
+                return localeScript[0];
+            }
+        }
+
+        if (localeVariant[0] || o.localeVariant[0]) {
+            if (localeVariant[0] != o.localeVariant[0] && requested->localeVariant[0]) {
+                return localeVariant[0];
+            }
+        }
+
         if (screenLayout || o.screenLayout) {
             if (((screenLayout^o.screenLayout) & MASK_LAYOUTDIR) != 0
                     && (requested->screenLayout & MASK_LAYOUTDIR)) {
@@ -2054,17 +2176,23 @@
         }
     }
     if (locale != 0) {
+        // Don't consider the script & variants when deciding matches.
+        //
+        // If we two configs differ only in their script or language, they
+        // can be weeded out in the isMoreSpecificThan test.
         if (language[0] != 0
             && (language[0] != settings.language[0]
                 || language[1] != settings.language[1])) {
             return false;
         }
+
         if (country[0] != 0
             && (country[0] != settings.country[0]
                 || country[1] != settings.country[1])) {
             return false;
         }
     }
+
     if (screenConfig != 0) {
         const int layoutDir = screenLayout&MASK_LAYOUTDIR;
         const int setLayoutDir = settings.screenLayout&MASK_LAYOUTDIR;
@@ -2166,17 +2294,92 @@
     return true;
 }
 
-void ResTable_config::getLocale(char str[6]) const {
-    memset(str, 0, 6);
-    if (language[0]) {
-        str[0] = language[0];
-        str[1] = language[1];
-        if (country[0]) {
-            str[2] = '_';
-            str[3] = country[0];
-            str[4] = country[1];
-        }
+void ResTable_config::getBcp47Locale(char str[RESTABLE_MAX_LOCALE_LEN]) const {
+    memset(str, 0, RESTABLE_MAX_LOCALE_LEN);
+
+    // This represents the "any" locale value, which has traditionally been
+    // represented by the empty string.
+    if (!language[0] && !country[0]) {
+        return;
     }
+
+    size_t charsWritten = 0;
+    if (language[0]) {
+        charsWritten += unpackLanguage(str);
+    }
+
+    if (localeScript[0]) {
+        if (charsWritten) {
+            str[charsWritten++] = '-';
+        }
+        memcpy(str + charsWritten, localeScript, sizeof(localeScript));
+        charsWritten += sizeof(localeScript);
+    }
+
+    if (country[0]) {
+        if (charsWritten) {
+            str[charsWritten++] = '-';
+        }
+        charsWritten += unpackRegion(str + charsWritten);
+    }
+
+    if (localeVariant[0]) {
+        if (charsWritten) {
+            str[charsWritten++] = '-';
+        }
+        memcpy(str + charsWritten, localeVariant, sizeof(localeVariant));
+    }
+}
+
+/* static */ inline bool assignLocaleComponent(ResTable_config* config,
+        const char* start, size_t size) {
+
+  switch (size) {
+       case 0:
+           return false;
+       case 2:
+       case 3:
+           config->language[0] ? config->packRegion(start) : config->packLanguage(start);
+           break;
+       case 4:
+           config->localeScript[0] = toupper(start[0]);
+           for (size_t i = 1; i < 4; ++i) {
+               config->localeScript[i] = tolower(start[i]);
+           }
+           break;
+       case 5:
+       case 6:
+       case 7:
+       case 8:
+           for (size_t i = 0; i < size; ++i) {
+               config->localeVariant[i] = tolower(start[i]);
+           }
+           break;
+       default:
+           return false;
+  }
+
+  return true;
+}
+
+void ResTable_config::setBcp47Locale(const char* in) {
+    locale = 0;
+    memset(localeScript, 0, sizeof(localeScript));
+    memset(localeVariant, 0, sizeof(localeVariant));
+
+    const char* separator = in;
+    const char* start = in;
+    while ((separator = strchr(start, '-')) != NULL) {
+        const size_t size = separator - start;
+        if (!assignLocaleComponent(this, start, size)) {
+            fprintf(stderr, "Invalid BCP-47 locale string: %s", in);
+        }
+
+        start = (separator + 1);
+    }
+
+    const size_t size = in + strlen(in) - start;
+    assignLocaleComponent(this, start, size);
 }
 
 String8 ResTable_config::toString() const {
@@ -2190,14 +2393,10 @@
         if (res.size() > 0) res.append("-");
         res.appendFormat("%dmnc", dtohs(mnc));
     }
-    if (language[0] != 0) {
-        if (res.size() > 0) res.append("-");
-        res.append(language, 2);
-    }
-    if (country[0] != 0) {
-        if (res.size() > 0) res.append("-");
-        res.append(country, 2);
-    }
+    char localeStr[RESTABLE_MAX_LOCALE_LEN];
+    getBcp47Locale(localeStr);
+    res.append(localeStr);
+
     if ((screenLayout&MASK_LAYOUTDIR) != 0) {
         if (res.size() > 0) res.append("-");
         switch (screenLayout&ResTable_config::MASK_LAYOUTDIR) {
@@ -4950,18 +5149,20 @@
                 const size_t L = type->configs.size();
                 for (size_t l=0; l<L; l++) {
                     const ResTable_type* config = type->configs[l];
-                    const ResTable_config* cfg = &config->config;
+                    ResTable_config cfg;
+                    memset(&cfg, 0, sizeof(ResTable_config));
+                    cfg.copyFromDtoH(config->config);
                     // only insert unique
                     const size_t M = configs->size();
                     size_t m;
                     for (m=0; m<M; m++) {
-                        if (0 == (*configs)[m].compare(*cfg)) {
+                        if (0 == (*configs)[m].compare(cfg)) {
                             break;
                         }
                     }
                     // if we didn't find it
                     if (m == M) {
-                        configs->add(*cfg);
+                        configs->add(cfg);
                     }
                 }
             }
@@ -4976,9 +5177,10 @@
     getConfigurations(&configs);
     ALOGV("called getConfigurations size=%d", (int)configs.size());
     const size_t I = configs.size();
+
+    char locale[RESTABLE_MAX_LOCALE_LEN];
     for (size_t i=0; i<I; i++) {
-        char locale[6];
-        configs[i].getLocale(locale);
+        configs[i].getBcp47Locale(locale);
         const size_t J = locales->size();
         size_t j;
         for (j=0; j<J; j++) {
@@ -5368,7 +5570,7 @@
                 | (0x00ff0000 & ((typeIndex+1)<<16))
                 | (0x0000ffff & (entryIndex));
             resource_name resName;
-            if (!this->getResourceName(resID, true, &resName)) {
+            if (!this->getResourceName(resID, false, &resName)) {
                 ALOGW("idmap: resource 0x%08x has spec but lacks values, skipping\n", resID);
                 // add dummy value, or trimming leading/trailing zeroes later will fail
                 vector.push(0);
@@ -5601,9 +5803,9 @@
         printf("mError=0x%x (%s)\n", mError, strerror(mError));
     }
 #if 0
-    printf("mParams=%c%c-%c%c,\n",
-            mParams.language[0], mParams.language[1],
-            mParams.country[0], mParams.country[1]);
+    char localeStr[RESTABLE_MAX_LOCALE_LEN];
+    mParams.getBcp47Locale(localeStr);
+    printf("mParams=%s,\n" localeStr);
 #endif
     size_t pgCount = mPackageGroups.size();
     printf("Package Groups (%d)\n", (int)pgCount);
@@ -5732,7 +5934,7 @@
                             continue;
                         }
                         
-                        uint16_t esize = dtohs(ent->size);
+                        uintptr_t esize = dtohs(ent->size);
                         if ((esize&0x3) != 0) {
                             printf("NON-INTEGER ResTable_entry SIZE: %p\n", (void*)esize);
                             continue;
diff --git a/libs/androidfw/tests/Android.mk b/libs/androidfw/tests/Android.mk
index 6e6522c..9e9649c 100644
--- a/libs/androidfw/tests/Android.mk
+++ b/libs/androidfw/tests/Android.mk
@@ -6,7 +6,8 @@
 test_src_files := \
     BackupData_test.cpp \
     ObbFile_test.cpp \
-    ZipUtils_test.cpp
+    ZipUtils_test.cpp \
+    ResourceTypes_test.cpp
 
 shared_libraries := \
     libandroidfw \
diff --git a/libs/androidfw/tests/ResourceTypes_test.cpp b/libs/androidfw/tests/ResourceTypes_test.cpp
new file mode 100644
index 0000000..4888b4a
--- /dev/null
+++ b/libs/androidfw/tests/ResourceTypes_test.cpp
@@ -0,0 +1,185 @@
+/*
+ * 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.
+ */
+
+#include <androidfw/ResourceTypes.h>
+#include <utils/Log.h>
+#include <utils/String8.h>
+
+#include <gtest/gtest.h>
+namespace android {
+
+TEST(ResourceTypesTest, ResourceConfig_packAndUnpack2LetterLanguage) {
+     ResTable_config config;
+     config.packLanguage("en");
+
+     EXPECT_EQ('e', config.language[0]);
+     EXPECT_EQ('n', config.language[1]);
+
+     char out[4] = { 1, 1, 1, 1};
+     config.unpackLanguage(out);
+     EXPECT_EQ('e', out[0]);
+     EXPECT_EQ('n', out[1]);
+     EXPECT_EQ(0, out[2]);
+     EXPECT_EQ(0, out[3]);
+
+     memset(out, 1, sizeof(out));
+     config.locale = 0;
+     config.unpackLanguage(out);
+     EXPECT_EQ(0, out[0]);
+     EXPECT_EQ(0, out[1]);
+     EXPECT_EQ(0, out[2]);
+     EXPECT_EQ(0, out[3]);
+}
+
+TEST(ResourceTypesTest, ResourceConfig_packAndUnpack2LetterRegion) {
+     ResTable_config config;
+     config.packRegion("US");
+
+     EXPECT_EQ('U', config.country[0]);
+     EXPECT_EQ('S', config.country[1]);
+
+     char out[4] = { 1, 1, 1, 1};
+     config.unpackRegion(out);
+     EXPECT_EQ('U', out[0]);
+     EXPECT_EQ('S', out[1]);
+     EXPECT_EQ(0, out[2]);
+     EXPECT_EQ(0, out[3]);
+}
+
+TEST(ResourceTypesTest, ResourceConfig_packAndUnpack3LetterLanguage) {
+     ResTable_config config;
+     config.packLanguage("eng");
+
+     // 1-00110-01 101-00100
+     EXPECT_EQ(0x99, config.language[0]);
+     EXPECT_EQ(0xa4, config.language[1]);
+
+     char out[4] = { 1, 1, 1, 1};
+     config.unpackLanguage(out);
+     EXPECT_EQ('e', out[0]);
+     EXPECT_EQ('n', out[1]);
+     EXPECT_EQ('g', out[2]);
+     EXPECT_EQ(0, out[3]);
+}
+
+TEST(ResourceTypesTest, ResourceConfig_packAndUnpack3LetterRegion) {
+     ResTable_config config;
+     config.packRegion("419");
+
+     char out[4] = { 1, 1, 1, 1};
+     config.unpackRegion(out);
+
+     EXPECT_EQ('4', out[0]);
+     EXPECT_EQ('1', out[1]);
+     EXPECT_EQ('9', out[2]);
+}
+
+/* static */ void fillIn(const char* lang, const char* country,
+        const char* script, const char* variant, ResTable_config* out) {
+     memset(out, 0, sizeof(ResTable_config));
+     if (lang != NULL) {
+         out->packLanguage(lang);
+     }
+
+     if (country != NULL) {
+         out->packRegion(country);
+     }
+
+     if (script != NULL) {
+         memcpy(out->localeScript, script, 4);
+     }
+
+     if (variant != NULL) {
+         memcpy(out->localeVariant, variant, strlen(variant));
+     }
+}
+
+TEST(ResourceTypesTest, IsMoreSpecificThan) {
+    ResTable_config l;
+    ResTable_config r;
+
+    fillIn("en", NULL, NULL, NULL, &l);
+    fillIn(NULL, NULL, NULL, NULL, &r);
+
+    EXPECT_TRUE(l.isMoreSpecificThan(r));
+    EXPECT_FALSE(r.isMoreSpecificThan(l));
+
+    fillIn("eng", NULL, NULL, NULL, &l);
+    EXPECT_TRUE(l.isMoreSpecificThan(r));
+    EXPECT_FALSE(r.isMoreSpecificThan(l));
+
+    fillIn("eng", "419", NULL, NULL, &r);
+    EXPECT_FALSE(l.isMoreSpecificThan(r));
+    EXPECT_TRUE(r.isMoreSpecificThan(l));
+
+    fillIn("en", NULL, NULL, NULL, &l);
+    fillIn("en", "US", NULL, NULL, &r);
+    EXPECT_FALSE(l.isMoreSpecificThan(r));
+    EXPECT_TRUE(r.isMoreSpecificThan(l));
+
+    fillIn("en", "US", NULL, NULL, &l);
+    fillIn("en", "US", "Latn", NULL, &r);
+    EXPECT_FALSE(l.isMoreSpecificThan(r));
+    EXPECT_TRUE(r.isMoreSpecificThan(l));
+
+    fillIn("en", "US", NULL, NULL, &l);
+    fillIn("en", "US", NULL, "POSIX", &r);
+    EXPECT_FALSE(l.isMoreSpecificThan(r));
+    EXPECT_TRUE(r.isMoreSpecificThan(l));
+
+    fillIn("en", "US", "Latn", NULL, &l);
+    fillIn("en", "US", NULL, "POSIX", &r);
+    EXPECT_FALSE(l.isMoreSpecificThan(r));
+    EXPECT_TRUE(r.isMoreSpecificThan(l));
+}
+
+TEST(ResourceTypesTest, setLocale) {
+    ResTable_config test;
+    test.setBcp47Locale("en-US");
+    EXPECT_EQ('e', test.language[0]);
+    EXPECT_EQ('n', test.language[1]);
+    EXPECT_EQ('U', test.country[0]);
+    EXPECT_EQ('S', test.country[1]);
+    EXPECT_EQ(0, test.localeScript[0]);
+    EXPECT_EQ(0, test.localeVariant[0]);
+
+    test.setBcp47Locale("eng-419");
+    char out[4] = { 1, 1, 1, 1};
+    test.unpackLanguage(out);
+    EXPECT_EQ('e', out[0]);
+    EXPECT_EQ('n', out[1]);
+    EXPECT_EQ('g', out[2]);
+    EXPECT_EQ(0, out[3]);
+    memset(out, 1, 4);
+    test.unpackRegion(out);
+    EXPECT_EQ('4', out[0]);
+    EXPECT_EQ('1', out[1]);
+    EXPECT_EQ('9', out[2]);
+
+
+    test.setBcp47Locale("en-Latn-419");
+    memset(out, 1, 4);
+    EXPECT_EQ('e', test.language[0]);
+    EXPECT_EQ('n', test.language[1]);
+
+    EXPECT_EQ(0, memcmp("Latn", test.localeScript, 4));
+    test.unpackRegion(out);
+    EXPECT_EQ('4', out[0]);
+    EXPECT_EQ('1', out[1]);
+    EXPECT_EQ('9', out[2]);
+}
+
+}  // namespace android.
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index e4648f6..495ad19 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -17,6 +17,7 @@
 		Caches.cpp \
 		DisplayList.cpp \
 		DeferredDisplayList.cpp \
+		DeferredLayerUpdater.cpp \
 		DisplayListLogBuffer.cpp \
 		DisplayListRenderer.cpp \
 		Dither.cpp \
@@ -39,7 +40,6 @@
 		RenderBufferCache.cpp \
 		ResourceCache.cpp \
 		ShadowTessellator.cpp \
-		SkiaColorFilter.cpp \
 		SkiaShader.cpp \
 		Snapshot.cpp \
 		SpotShadow.cpp \
@@ -71,7 +71,7 @@
 	LOCAL_CFLAGS += -DUSE_OPENGL_RENDERER -DEGL_EGLEXT_PROTOTYPES -DGL_GLEXT_PROTOTYPES
 	LOCAL_CFLAGS += -Wno-unused-parameter
 	LOCAL_MODULE_CLASS := SHARED_LIBRARIES
-	LOCAL_SHARED_LIBRARIES := liblog libcutils libutils libEGL libGLESv2 libskia libui
+	LOCAL_SHARED_LIBRARIES := liblog libcutils libutils libEGL libGLESv2 libskia libui libgui
 	LOCAL_MODULE := libhwui
 	LOCAL_MODULE_TAGS := optional
 
diff --git a/libs/hwui/DeferredDisplayList.cpp b/libs/hwui/DeferredDisplayList.cpp
index 7eb7028..3d58964 100644
--- a/libs/hwui/DeferredDisplayList.cpp
+++ b/libs/hwui/DeferredDisplayList.cpp
@@ -224,6 +224,11 @@
 
         if (op->getPaintAlpha() != mOps[0].op->getPaintAlpha()) return false;
 
+        if (op->mPaint && mOps[0].op->mPaint &&
+            op->mPaint->getColorFilter() != mOps[0].op->mPaint->getColorFilter()) {
+            return false;
+        }
+
         /* Draw Modifiers compatibility check
          *
          * Shadows are ignored, as only text uses them, and in that case they are drawn
@@ -239,7 +244,6 @@
         const DrawModifiers& lhsMod = lhs->mDrawModifiers;
         const DrawModifiers& rhsMod = rhs->mDrawModifiers;
         if (lhsMod.mShader != rhsMod.mShader) return false;
-        if (lhsMod.mColorFilter != rhsMod.mColorFilter) return false;
 
         // Draw filter testing expects bit fields to be clear if filter not set.
         if (lhsMod.mHasDrawFilter != rhsMod.mHasDrawFilter) return false;
diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp
new file mode 100644
index 0000000..ed05d04
--- /dev/null
+++ b/libs/hwui/DeferredLayerUpdater.cpp
@@ -0,0 +1,150 @@
+/*
+ * 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.
+ */
+#include "DeferredLayerUpdater.h"
+
+#include "OpenGLRenderer.h"
+
+#include "LayerRenderer.h"
+
+namespace android {
+namespace uirenderer {
+
+DeferredLayerUpdater::DeferredLayerUpdater(Layer* layer, OpenGLRenderer* renderer)
+        : mDisplayList(0)
+        , mSurfaceTexture(0)
+        , mTransform(0)
+        , mNeedsGLContextAttach(false)
+        , mUpdateTexImage(false)
+        , mLayer(layer)
+        , mRenderer(renderer)
+        , mCaches(Caches::getInstance()) {
+    mCaches.resourceCache.incrementRefcount(mLayer);
+    mWidth = mLayer->layer.getWidth();
+    mHeight = mLayer->layer.getHeight();
+    mBlend = mLayer->isBlend();
+    mColorFilter = mLayer->getColorFilter();
+    mAlpha = mLayer->getAlpha();
+    mMode = mLayer->getMode();
+    mDirtyRect.setEmpty();
+}
+
+DeferredLayerUpdater::~DeferredLayerUpdater() {
+    setColorFilter(NULL);
+    if (mLayer) {
+        mCaches.resourceCache.decrementRefcount(mLayer);
+    }
+    delete mRenderer;
+}
+
+void DeferredLayerUpdater::setColorFilter(SkColorFilter* colorFilter) {
+    SkRefCnt_SafeAssign(mColorFilter, colorFilter);
+}
+
+void DeferredLayerUpdater::setDisplayList(DisplayList* displayList,
+        int left, int top, int right, int bottom) {
+    mDisplayList = displayList;
+    if (mDirtyRect.isEmpty()) {
+        mDirtyRect.set(left, top, right, bottom);
+    } else {
+        mDirtyRect.unionWith(Rect(left, top, right, bottom));
+    }
+}
+
+bool DeferredLayerUpdater::apply() {
+    bool success = true;
+    // These properties are applied the same to both layer types
+    mLayer->setColorFilter(mColorFilter);
+    mLayer->setAlpha(mAlpha, mMode);
+
+    if (mDisplayList) {
+        if (mWidth != mLayer->layer.getWidth() || mHeight != mLayer->layer.getHeight()) {
+            success = LayerRenderer::resizeLayer(mLayer, mWidth, mHeight);
+        }
+        mLayer->setBlend(mBlend);
+        mLayer->updateDeferred(mRenderer, mDisplayList,
+                mDirtyRect.left, mDirtyRect.top, mDirtyRect.right, mDirtyRect.bottom);
+        mDirtyRect.setEmpty();
+        mDisplayList = 0;
+    } else if (mSurfaceTexture.get()) {
+        if (mNeedsGLContextAttach) {
+            mNeedsGLContextAttach = false;
+            mSurfaceTexture->attachToContext(mLayer->getTexture());
+        }
+        if (mUpdateTexImage) {
+            mUpdateTexImage = false;
+            doUpdateTexImage();
+        }
+        if (mTransform) {
+            mLayer->getTransform().load(*mTransform);
+            setTransform(0);
+        }
+    }
+    return success;
+}
+
+void DeferredLayerUpdater::doUpdateTexImage() {
+    if (mSurfaceTexture->updateTexImage() == NO_ERROR) {
+        float transform[16];
+
+        int64_t frameNumber = mSurfaceTexture->getFrameNumber();
+        // If the GLConsumer queue is in synchronous mode, need to discard all
+        // but latest frame, using the frame number to tell when we no longer
+        // have newer frames to target. Since we can't tell which mode it is in,
+        // do this unconditionally.
+        int dropCounter = 0;
+        while (mSurfaceTexture->updateTexImage() == NO_ERROR) {
+            int64_t newFrameNumber = mSurfaceTexture->getFrameNumber();
+            if (newFrameNumber == frameNumber) break;
+            frameNumber = newFrameNumber;
+            dropCounter++;
+        }
+        #if DEBUG_RENDERER
+        if (dropCounter > 0) {
+            RENDERER_LOGD("Dropped %d frames on texture layer update", dropCounter);
+        }
+        #endif
+        mSurfaceTexture->getTransformMatrix(transform);
+        GLenum renderTarget = mSurfaceTexture->getCurrentTextureTarget();
+
+        LayerRenderer::updateTextureLayer(mLayer, mWidth, mHeight, !mBlend,
+                renderTarget, transform);
+    }
+}
+
+void DeferredLayerUpdater::applyDeferred(DeferredLayerUpdater* deferredApply) {
+    // Default assignment operator doesn't quite work, and fails due to mCaches anyway
+    deferredApply->mWidth = mWidth;
+    deferredApply->mHeight = mHeight;
+    deferredApply->mBlend = mBlend;
+    deferredApply->mAlpha = mAlpha;
+    deferredApply->mMode = mMode;
+    deferredApply->mDirtyRect.set(mDirtyRect);
+    deferredApply->mDisplayList = mDisplayList;
+    deferredApply->mSurfaceTexture = mSurfaceTexture;
+    deferredApply->mNeedsGLContextAttach = mNeedsGLContextAttach;
+    deferredApply->mUpdateTexImage = mUpdateTexImage;
+    deferredApply->setColorFilter(mColorFilter);
+    deferredApply->setTransform(mTransform);
+
+    mDisplayList = 0;
+    mDirtyRect.setEmpty();
+    mTransform = 0;
+    mNeedsGLContextAttach = false;
+    mUpdateTexImage = false;
+}
+
+} /* namespace uirenderer */
+} /* namespace android */
diff --git a/libs/hwui/DeferredLayerUpdater.h b/libs/hwui/DeferredLayerUpdater.h
new file mode 100644
index 0000000..0350eef
--- /dev/null
+++ b/libs/hwui/DeferredLayerUpdater.h
@@ -0,0 +1,124 @@
+/*
+ * 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.
+ */
+#ifndef DEFERREDLAYERUPDATE_H_
+#define DEFERREDLAYERUPDATE_H_
+
+#include <cutils/compiler.h>
+#include <gui/GLConsumer.h>
+#include <SkColorFilter.h>
+#include <SkMatrix.h>
+#include <utils/StrongPointer.h>
+
+#include "DisplayList.h"
+#include "Layer.h"
+#include "OpenGLRenderer.h"
+#include "Rect.h"
+
+namespace android {
+namespace uirenderer {
+
+// Container to hold the properties a layer should be set to at the start
+// of a render pass
+class DeferredLayerUpdater {
+public:
+    ANDROID_API DeferredLayerUpdater(Layer* layer, OpenGLRenderer* renderer = 0);
+    ANDROID_API ~DeferredLayerUpdater();
+
+    ANDROID_API bool setSize(uint32_t width, uint32_t height) {
+        if (mWidth != width || mHeight != height) {
+            mWidth = width;
+            mHeight = height;
+            return true;
+        }
+        return false;
+    }
+
+    ANDROID_API bool setBlend(bool blend) {
+        if (blend != mBlend) {
+            mBlend = blend;
+            return true;
+        }
+        return false;
+    }
+
+    ANDROID_API void setSurfaceTexture(const sp<GLConsumer>& texture, bool needsAttach) {
+        if (texture.get() != mSurfaceTexture.get()) {
+            mNeedsGLContextAttach = needsAttach;
+            mSurfaceTexture = texture;
+        }
+    }
+
+    ANDROID_API void updateTexImage() {
+        mUpdateTexImage = true;
+    }
+
+    ANDROID_API void setTransform(const SkMatrix* matrix) {
+        delete mTransform;
+        mTransform = matrix ? new SkMatrix(*matrix) : 0;
+    }
+
+    ANDROID_API void setDisplayList(DisplayList* displayList,
+                int left, int top, int right, int bottom);
+
+    ANDROID_API void setPaint(const SkPaint* paint) {
+        OpenGLRenderer::getAlphaAndModeDirect(paint, &mAlpha, &mMode);
+    }
+
+    ANDROID_API void setColorFilter(SkColorFilter* colorFilter);
+
+    ANDROID_API bool apply();
+    ANDROID_API void applyDeferred(DeferredLayerUpdater* deferredApply);
+
+    ANDROID_API Layer* backingLayer() {
+        return mLayer;
+    }
+
+    ANDROID_API Layer* detachBackingLayer() {
+        Layer* layer = mLayer;
+        mLayer = 0;
+        return layer;
+    }
+
+private:
+    // Generic properties
+    uint32_t mWidth;
+    uint32_t mHeight;
+    bool mBlend;
+    SkColorFilter* mColorFilter;
+    int mAlpha;
+    SkXfermode::Mode mMode;
+
+    // Layer type specific properties
+    // displayList and surfaceTexture are mutually exclusive, only 1 may be set
+    // dirtyRect is only valid if displayList is set
+    DisplayList* mDisplayList;
+    Rect mDirtyRect;
+    sp<GLConsumer> mSurfaceTexture;
+    SkMatrix* mTransform;
+    bool mNeedsGLContextAttach;
+    bool mUpdateTexImage;
+
+    Layer* mLayer;
+    OpenGLRenderer* mRenderer;
+    Caches& mCaches;
+
+    void doUpdateTexImage();
+};
+
+} /* namespace uirenderer */
+} /* namespace android */
+
+#endif /* DEFERREDLAYERUPDATE_H_ */
diff --git a/libs/hwui/DisplayList.cpp b/libs/hwui/DisplayList.cpp
index fd3dae7..a5e66fa 100644
--- a/libs/hwui/DisplayList.cpp
+++ b/libs/hwui/DisplayList.cpp
@@ -96,10 +96,6 @@
         caches.resourceCache.destructorLocked(bitmap);
     }
 
-    for (size_t i = 0; i < mFilterResources.size(); i++) {
-        caches.resourceCache.decrementRefcountLocked(mFilterResources.itemAt(i));
-    }
-
     for (size_t i = 0; i < mPatchResources.size(); i++) {
         caches.resourceCache.decrementRefcountLocked(mPatchResources.itemAt(i));
     }
@@ -137,7 +133,6 @@
 
     mBitmapResources.clear();
     mOwnedBitmapResources.clear();
-    mFilterResources.clear();
     mPatchResources.clear();
     mShaders.clear();
     mSourcePaths.clear();
@@ -188,13 +183,6 @@
         caches.resourceCache.incrementRefcountLocked(resource);
     }
 
-    const Vector<SkiaColorFilter*>& filterResources = recorder.getFilterResources();
-    for (size_t i = 0; i < filterResources.size(); i++) {
-        SkiaColorFilter* resource = filterResources.itemAt(i);
-        mFilterResources.add(resource);
-        caches.resourceCache.incrementRefcountLocked(resource);
-    }
-
     const Vector<const Res_png_9patch*>& patchResources = recorder.getPatchResources();
     for (size_t i = 0; i < patchResources.size(); i++) {
         const Res_png_9patch* resource = patchResources.itemAt(i);
@@ -240,7 +228,11 @@
     mClipToBounds = true;
     mIsolatedZVolume = true;
     mProjectBackwards = false;
+    mProjectionReceiver = false;
     mOutline.rewind();
+    mClipToOutline = false;
+    mCastsShadow = false;
+    mSharesGlobalCamera = false;
     mAlpha = 1;
     mHasOverlappingRendering = true;
     mTranslationX = 0;
@@ -299,12 +291,13 @@
 
 void DisplayList::updateMatrix() {
     if (mMatrixDirty) {
-        if (!mTransformMatrix) {
-            mTransformMatrix = new SkMatrix();
-        }
-        if (mMatrixFlags == 0 || mMatrixFlags == TRANSLATION) {
-            mTransformMatrix->reset();
-        } else {
+        // NOTE: mTransformMatrix won't be up to date if a DisplayList goes from a complex transform
+        // to a pure translate. This is safe because the matrix isn't read in pure translate cases.
+        if (mMatrixFlags && mMatrixFlags != TRANSLATION) {
+            if (!mTransformMatrix) {
+                // only allocate a matrix if we have a complex transform
+                mTransformMatrix = new Matrix4();
+            }
             if (!mPivotExplicitlySet) {
                 if (mWidth != mPrevWidth || mHeight != mPrevHeight) {
                     mPrevWidth = mWidth;
@@ -313,28 +306,36 @@
                     mPivotY = mPrevHeight / 2.0f;
                 }
             }
-            if (!Caches::getInstance().propertyEnable3d && (mMatrixFlags & ROTATION_3D) == 0) {
-                mTransformMatrix->setTranslate(mTranslationX, mTranslationY);
-                mTransformMatrix->preRotate(mRotation, mPivotX, mPivotY);
-                mTransformMatrix->preScale(mScaleX, mScaleY, mPivotX, mPivotY);
+            const bool perspectiveEnabled = Caches::getInstance().propertyEnable3d;
+            if (!perspectiveEnabled && (mMatrixFlags & ROTATION_3D) == 0) {
+                mTransformMatrix->loadTranslate(
+                        mPivotX + mTranslationX,
+                        mPivotY + mTranslationY,
+                        0);
+                mTransformMatrix->rotate(mRotation, 0, 0, 1);
+                mTransformMatrix->scale(mScaleX, mScaleY, 1);
+                mTransformMatrix->translate(-mPivotX, -mPivotY);
             } else {
-                if (Caches::getInstance().propertyEnable3d) {
-                    mTransform.loadTranslate(mPivotX + mTranslationX, mPivotY + mTranslationY,
+                if (perspectiveEnabled) {
+                    mTransformMatrix->loadTranslate(
+                            mPivotX + mTranslationX,
+                            mPivotY + mTranslationY,
                             mTranslationZ);
-                    mTransform.rotate(mRotationX, 1, 0, 0);
-                    mTransform.rotate(mRotationY, 0, 1, 0);
-                    mTransform.rotate(mRotation, 0, 0, 1);
-                    mTransform.scale(mScaleX, mScaleY, 1);
-                    mTransform.translate(-mPivotX, -mPivotY);
+                    mTransformMatrix->rotate(mRotationX, 1, 0, 0);
+                    mTransformMatrix->rotate(mRotationY, 0, 1, 0);
+                    mTransformMatrix->rotate(mRotation, 0, 0, 1);
+                    mTransformMatrix->scale(mScaleX, mScaleY, 1);
+                    mTransformMatrix->translate(-mPivotX, -mPivotY);
                 } else {
                     /* TODO: support this old transform approach, based on API level */
                     if (!mTransformCamera) {
                         mTransformCamera = new Sk3DView();
                         mTransformMatrix3D = new SkMatrix();
                     }
-                    mTransformMatrix->reset();
+                    SkMatrix transformMatrix;
+                    transformMatrix.reset();
                     mTransformCamera->save();
-                    mTransformMatrix->preScale(mScaleX, mScaleY, mPivotX, mPivotY);
+                    transformMatrix.preScale(mScaleX, mScaleY, mPivotX, mPivotY);
                     mTransformCamera->rotateX(mRotationX);
                     mTransformCamera->rotateY(mRotationY);
                     mTransformCamera->rotateZ(-mRotation);
@@ -342,8 +343,10 @@
                     mTransformMatrix3D->preTranslate(-mPivotX, -mPivotY);
                     mTransformMatrix3D->postTranslate(mPivotX + mTranslationX,
                             mPivotY + mTranslationY);
-                    mTransformMatrix->postConcat(*mTransformMatrix3D);
+                    transformMatrix.postConcat(*mTransformMatrix3D);
                     mTransformCamera->restore();
+
+                    mTransformMatrix->load(transformMatrix);
                 }
             }
         }
@@ -357,19 +360,20 @@
         ALOGD("%*sTranslate (left, top) %d, %d", level * 2, "", mLeft, mTop);
     }
     if (mStaticMatrix) {
-        ALOGD("%*sConcatMatrix (static) %p: " MATRIX_STRING,
-                level * 2, "", mStaticMatrix, MATRIX_ARGS(mStaticMatrix));
+        ALOGD("%*sConcatMatrix (static) %p: " SK_MATRIX_STRING,
+                level * 2, "", mStaticMatrix, SK_MATRIX_ARGS(mStaticMatrix));
     }
     if (mAnimationMatrix) {
-        ALOGD("%*sConcatMatrix (animation) %p: " MATRIX_STRING,
-                level * 2, "", mAnimationMatrix, MATRIX_ARGS(mAnimationMatrix));
+        ALOGD("%*sConcatMatrix (animation) %p: " SK_MATRIX_STRING,
+                level * 2, "", mAnimationMatrix, SK_MATRIX_ARGS(mAnimationMatrix));
     }
     if (mMatrixFlags != 0) {
         if (mMatrixFlags == TRANSLATION) {
-            ALOGD("%*sTranslate %f, %f", level * 2, "", mTranslationX, mTranslationY);
+            ALOGD("%*sTranslate %.2f, %.2f, %.2f",
+                    level * 2, "", mTranslationX, mTranslationY, mTranslationZ);
         } else {
-            ALOGD("%*sConcatMatrix %p: " MATRIX_STRING,
-                    level * 2, "", mTransformMatrix, MATRIX_ARGS(mTransformMatrix));
+            ALOGD("%*sConcatMatrix %p: " MATRIX_4_STRING,
+                    level * 2, "", mTransformMatrix, MATRIX_4_ARGS(mTransformMatrix));
         }
     }
 
@@ -419,19 +423,11 @@
         renderer.concatMatrix(mAnimationMatrix);
     }
     if (mMatrixFlags != 0) {
-        if (Caches::getInstance().propertyEnable3d) {
-            if (mMatrixFlags == TRANSLATION) {
-                renderer.translate(mTranslationX, mTranslationY, mTranslationZ);
-            } else {
-                renderer.concatMatrix(mTransform);
-            }
+        if (mMatrixFlags == TRANSLATION) {
+            renderer.translate(mTranslationX, mTranslationY,
+                    Caches::getInstance().propertyEnable3d ? mTranslationZ : 0.0f); // TODO: necessary?
         } else {
-            // avoid setting translationZ, use SkMatrix
-            if (mMatrixFlags == TRANSLATION) {
-                renderer.translate(mTranslationX, mTranslationY, 0);
-            } else {
-                renderer.concatMatrix(mTransformMatrix);
-            }
+            renderer.concatMatrix(*mTransformMatrix);
         }
     }
     bool clipToBoundsNeeded = mCaching ? false : mClipToBounds;
@@ -451,8 +447,7 @@
             }
 
             SaveLayerOp* op = new (handler.allocator()) SaveLayerOp(
-                    0, 0, mRight - mLeft, mBottom - mTop,
-                    mAlpha * 255, SkXfermode::kSrcOver_Mode, saveFlags);
+                    0, 0, mRight - mLeft, mBottom - mTop, mAlpha * 255, saveFlags);
             handler(op, PROPERTY_SAVECOUNT, mClipToBounds);
         }
     }
@@ -461,6 +456,10 @@
                 mRight - mLeft, mBottom - mTop, SkRegion::kIntersect_Op);
         handler(op, PROPERTY_SAVECOUNT, mClipToBounds);
     }
+    if (CC_UNLIKELY(mClipToOutline && !mOutline.isEmpty())) {
+        ClipPathOp* op = new (handler.allocator()) ClipPathOp(&mOutline, SkRegion::kIntersect_Op);
+        handler(op, PROPERTY_SAVECOUNT, mClipToBounds);
+    }
 }
 
 /**
@@ -482,12 +481,7 @@
         if (mMatrixFlags == TRANSLATION) {
             matrix.translate(mTranslationX, mTranslationY, mTranslationZ);
         } else {
-            if (Caches::getInstance().propertyEnable3d) {
-                matrix.multiply(mTransform);
-            } else {
-                mat4 temp(*mTransformMatrix);
-                matrix.multiply(temp);
-            }
+            matrix.multiply(*mTransformMatrix);
         }
     }
 }
@@ -524,6 +518,7 @@
         const mat4* transformFromProjectionSurface) {
     m3dNodes.clear();
     mProjectedNodes.clear();
+    if (mDisplayListData == NULL || mSize == 0) return;
 
     // TODO: should avoid this calculation in most cases
     // TODO: just calculate single matrix, down to all leaf composited elements
@@ -553,32 +548,46 @@
         opState->mSkipInOrderDraw = false;
     }
 
-    if (mIsolatedZVolume) {
-        // create a new 3d space for descendents by collecting them
-        compositedChildrenOf3dRoot = &m3dNodes;
-        transformFrom3dRoot = &mat4::identity();
-    } else {
-        applyViewPropertyTransforms(localTransformFrom3dRoot);
-        transformFrom3dRoot = &localTransformFrom3dRoot;
-    }
+    if (mDisplayListData->children.size() > 0) {
+        if (mIsolatedZVolume) {
+            // create a new 3d space for descendents by collecting them
+            compositedChildrenOf3dRoot = &m3dNodes;
+            transformFrom3dRoot = &mat4::identity();
+        } else {
+            applyViewPropertyTransforms(localTransformFrom3dRoot);
+            transformFrom3dRoot = &localTransformFrom3dRoot;
+        }
 
-    if (mDisplayListData != NULL && mDisplayListData->projectionIndex >= 0) {
-        // create a new projection surface for descendents by collecting them
-        compositedChildrenOfProjectionSurface = &mProjectedNodes;
-        transformFromProjectionSurface = &mat4::identity();
-    } else {
-        applyViewPropertyTransforms(localTransformFromProjectionSurface);
-        transformFromProjectionSurface = &localTransformFromProjectionSurface;
-    }
-
-    if (mDisplayListData != NULL && mDisplayListData->children.size() > 0) {
+        const bool isProjectionReceiver = mDisplayListData->projectionReceiveIndex >= 0;
+        bool haveAppliedPropertiesToProjection = false;
         for (unsigned int i = 0; i < mDisplayListData->children.size(); i++) {
             DrawDisplayListOp* childOp = mDisplayListData->children[i];
-            childOp->mDisplayList->computeOrderingImpl(childOp,
+            DisplayList* child = childOp->mDisplayList;
+
+            Vector<DrawDisplayListOp*>* projectionChildren = NULL;
+            const mat4* projectionTransform = NULL;
+            if (isProjectionReceiver && !child->mProjectBackwards) {
+                // if receiving projections, collect projecting descendent
+
+                // Note that if a direct descendent is projecting backwards, we pass it's
+                // grandparent projection collection, since it shouldn't project onto it's
+                // parent, where it will already be drawing.
+                projectionChildren = &mProjectedNodes;
+                projectionTransform = &mat4::identity();
+            } else {
+                if (!haveAppliedPropertiesToProjection) {
+                    applyViewPropertyTransforms(localTransformFromProjectionSurface);
+                    haveAppliedPropertiesToProjection = true;
+                }
+                projectionChildren = compositedChildrenOfProjectionSurface;
+                projectionTransform = &localTransformFromProjectionSurface;
+            }
+            child->computeOrderingImpl(childOp,
                     compositedChildrenOf3dRoot, transformFrom3dRoot,
-                    compositedChildrenOfProjectionSurface, transformFromProjectionSurface);
+                    projectionChildren, projectionTransform);
         }
     }
+
 }
 
 class DeferOperationHandler {
@@ -638,11 +647,11 @@
         return;
     }
 
+    int rootRestoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
     LinearAllocator& alloc = handler.allocator();
     ClipRectOp* clipOp = new (alloc) ClipRectOp(0, 0, mWidth, mHeight,
             SkRegion::kIntersect_Op); // clip to 3d root bounds for now
     handler(clipOp, PROPERTY_SAVECOUNT, mClipToBounds);
-    int rootRestoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
 
     for (size_t i = 0; i < m3dNodes.size(); i++) {
         const float zValue = m3dNodes[i].key;
@@ -651,16 +660,13 @@
         if (mode == kPositiveZChildren && zValue < 0.0f) continue;
         if (mode == kNegativeZChildren && zValue > 0.0f) break;
 
-        if (mode == kPositiveZChildren && zValue > 0.0f) {
+        DisplayList* child = childOp->mDisplayList;
+        if (mode == kPositiveZChildren && zValue > 0.0f && child->mCastsShadow) {
             /* draw shadow with parent matrix applied, passing in the child's total matrix
-             *
-             * TODO:
-             * -view must opt-in to shadows
-             * -consider depth in more complex scenarios (neg z, added shadow depth)
+             * TODO: consider depth in more complex scenarios (neg z, added shadow depth)
              */
             mat4 shadowMatrix(childOp->mTransformFromCompositingAncestor);
-            childOp->mDisplayList->applyViewPropertyTransforms(shadowMatrix);
-            DisplayList* child = childOp->mDisplayList;
+            child->applyViewPropertyTransforms(shadowMatrix);
 
             DisplayListOp* shadowOp  = new (alloc) DrawShadowOp(shadowMatrix,
                     child->mAlpha, &(child->mOutline), child->mWidth, child->mHeight);
@@ -677,18 +683,22 @@
 
 template <class T>
 void DisplayList::iterateProjectedChildren(OpenGLRenderer& renderer, T& handler, const int level) {
+    int rootRestoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
     LinearAllocator& alloc = handler.allocator();
     ClipRectOp* clipOp = new (alloc) ClipRectOp(0, 0, mWidth, mHeight,
             SkRegion::kReplace_Op); // clip to projection surface root bounds
     handler(clipOp, PROPERTY_SAVECOUNT, mClipToBounds);
-    int rootRestoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
 
     for (size_t i = 0; i < mProjectedNodes.size(); i++) {
         DrawDisplayListOp* childOp = mProjectedNodes[i];
+
+        // matrix save, concat, and restore can be done safely without allocating operations
+        int restoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag);
         renderer.concatMatrix(childOp->mTransformFromCompositingAncestor);
         childOp->mSkipInOrderDraw = false; // this is horrible, I'm so sorry everyone
         handler(childOp, renderer.getSaveCount() - 1, mClipToBounds);
         childOp->mSkipInOrderDraw = true;
+        renderer.restoreToCount(restoreTo);
     }
     handler(new (alloc) RestoreToCountOp(rootRestoreTo), PROPERTY_SAVECOUNT, mClipToBounds);
 }
@@ -740,7 +750,7 @@
 
         DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance();
         const int saveCountOffset = renderer.getSaveCount() - 1;
-        const int projectionIndex = mDisplayListData->projectionIndex;
+        const int projectionReceiveIndex = mDisplayListData->projectionReceiveIndex;
         for (unsigned int i = 0; i < mDisplayListData->displayListOps.size(); i++) {
             DisplayListOp *op = mDisplayListData->displayListOps[i];
 
@@ -751,7 +761,7 @@
             logBuffer.writeCommand(level, op->name());
             handler(op, saveCountOffset, mClipToBounds);
 
-            if (CC_UNLIKELY(i == projectionIndex && mProjectedNodes.size() > 0)) {
+            if (CC_UNLIKELY(i == projectionReceiveIndex && mProjectedNodes.size() > 0)) {
                 iterateProjectedChildren(renderer, handler, level);
             }
         }
diff --git a/libs/hwui/DisplayList.h b/libs/hwui/DisplayList.h
index 8622d61..c3d9fd7 100644
--- a/libs/hwui/DisplayList.h
+++ b/libs/hwui/DisplayList.h
@@ -61,7 +61,6 @@
 class OpenGLRenderer;
 class Rect;
 class Layer;
-class SkiaColorFilter;
 class SkiaShader;
 
 class ClipRectOp;
@@ -112,7 +111,7 @@
  */
 class DisplayListData : public LightRefBase<DisplayListData> {
 public:
-    DisplayListData() : projectionIndex(-1) {}
+    DisplayListData() : projectionReceiveIndex(-1) {}
     // allocator into which all ops were allocated
     LinearAllocator allocator;
 
@@ -123,8 +122,7 @@
     Vector<DrawDisplayListOp*> children;
 
     // index of DisplayListOp restore, after which projected descendents should be drawn
-    int projectionIndex;
-    Matrix4 projectionTransform;
+    int projectionReceiveIndex;
 };
 
 /**
@@ -194,10 +192,26 @@
         mIsolatedZVolume = shouldIsolate;
     }
 
+    void setCastsShadow(bool castsShadow) {
+        mCastsShadow = castsShadow;
+    }
+
+    void setSharesGlobalCamera(bool sharesGlobalCamera) {
+        mSharesGlobalCamera = sharesGlobalCamera;
+    }
+
     void setProjectBackwards(bool shouldProject) {
         mProjectBackwards = shouldProject;
     }
 
+    void setProjectionReceiver(bool shouldRecieve) {
+        mProjectionReceiver = shouldRecieve;
+    }
+
+    bool isProjectionReceiver() {
+        return mProjectionReceiver;
+    }
+
     void setOutline(const SkPath* outline) {
         if (!outline) {
             mOutline.reset();
@@ -206,6 +220,10 @@
         }
     }
 
+    void setClipToOutline(bool clipToOutline) {
+        mClipToOutline = clipToOutline;
+    }
+
     void setStaticMatrix(SkMatrix* matrix) {
         delete mStaticMatrix;
         mStaticMatrix = new SkMatrix(*matrix);
@@ -575,7 +593,6 @@
 
     Vector<const SkBitmap*> mBitmapResources;
     Vector<const SkBitmap*> mOwnedBitmapResources;
-    Vector<SkiaColorFilter*> mFilterResources;
     Vector<const Res_png_9patch*> mPatchResources;
 
     Vector<const SkPaint*> mPaints;
@@ -600,7 +617,11 @@
     bool mClipToBounds;
     bool mIsolatedZVolume;
     bool mProjectBackwards;
+    bool mProjectionReceiver;
     SkPath mOutline;
+    bool mClipToOutline;
+    bool mCastsShadow;
+    bool mSharesGlobalCamera; // TODO: respect value when rendering
     float mAlpha;
     bool mHasOverlappingRendering;
     float mTranslationX, mTranslationY, mTranslationZ;
@@ -614,13 +635,20 @@
     bool mPivotExplicitlySet;
     bool mMatrixDirty;
     bool mMatrixIsIdentity;
+
+    /**
+     * Stores the total transformation of the DisplayList based upon its scalar
+     * translate/rotate/scale properties.
+     *
+     * In the common translation-only case, the matrix isn't allocated and the mTranslation
+     * properties are used directly.
+     */
+    Matrix4* mTransformMatrix;
     uint32_t mMatrixFlags;
-    SkMatrix* mTransformMatrix;
     Sk3DView* mTransformCamera;
     SkMatrix* mTransformMatrix3D;
     SkMatrix* mStaticMatrix;
     SkMatrix* mAnimationMatrix;
-    Matrix4 mTransform;
     bool mCaching;
 
     /**
diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h
index 20bc93d..0589a022 100644
--- a/libs/hwui/DisplayListOp.h
+++ b/libs/hwui/DisplayListOp.h
@@ -327,9 +327,13 @@
 
 class SaveLayerOp : public StateOp {
 public:
-    SaveLayerOp(float left, float top, float right, float bottom,
-            int alpha, SkXfermode::Mode mode, int flags)
-            : mArea(left, top, right, bottom), mAlpha(alpha), mMode(mode), mFlags(flags) {}
+    SaveLayerOp(float left, float top, float right, float bottom, int alpha, int flags)
+            : mArea(left, top, right, bottom), mPaint(&mCachedPaint), mFlags(flags) {
+        mCachedPaint.setAlpha(alpha);
+    }
+
+    SaveLayerOp(float left, float top, float right, float bottom, const SkPaint* paint, int flags)
+            : mArea(left, top, right, bottom), mPaint(paint), mFlags(flags) {}
 
     virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level,
             bool useQuickReject) {
@@ -340,11 +344,11 @@
         // NOTE: don't issue full saveLayer, since that has side effects/is costly. instead just
         // setup the snapshot for deferral, and re-issue the op at flush time
         deferStruct.mRenderer.saveLayerDeferred(mArea.left, mArea.top, mArea.right, mArea.bottom,
-                mAlpha, mMode, mFlags);
+                mPaint, mFlags);
     }
 
     virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
-        renderer.saveLayer(mArea.left, mArea.top, mArea.right, mArea.bottom, mAlpha, mMode, mFlags);
+        renderer.saveLayer(mArea.left, mArea.top, mArea.right, mArea.bottom, mPaint, mFlags);
     }
 
     virtual void output(int level, uint32_t logFlags) const {
@@ -357,21 +361,15 @@
     int getFlags() { return mFlags; }
 
 private:
-    // Special case, reserved for direct DisplayList usage
-    SaveLayerOp() {}
-    DisplayListOp* reinit(float left, float top, float right, float bottom,
-            int alpha, SkXfermode::Mode mode, int flags) {
-        mArea.set(left, top, right, bottom);
-        mAlpha = alpha;
-        mMode = mode;
-        mFlags = flags;
-        return this;
+    bool isSaveLayerAlpha() const {
+        SkXfermode::Mode mode = OpenGLRenderer::getXfermodeDirect(mPaint);
+        int alpha = OpenGLRenderer::getAlphaDirect(mPaint);
+        return alpha < 255 && mode == SkXfermode::kSrcOver_Mode;
     }
 
-    bool isSaveLayerAlpha() const { return mAlpha < 255 && mMode == SkXfermode::kSrcOver_Mode; }
     Rect mArea;
-    int mAlpha;
-    SkXfermode::Mode mMode;
+    const SkPaint* mPaint;
+    SkPaint mCachedPaint;
     int mFlags;
 };
 
@@ -465,7 +463,7 @@
 
     virtual void output(int level, uint32_t logFlags) const {
         if (mMatrix) {
-            OP_LOG("SetMatrix " MATRIX_STRING, MATRIX_ARGS(mMatrix));
+            OP_LOG("SetMatrix " SK_MATRIX_STRING, SK_MATRIX_ARGS(mMatrix));
         } else {
             OP_LOGS("SetMatrix (reset)");
         }
@@ -487,7 +485,7 @@
     }
 
     virtual void output(int level, uint32_t logFlags) const {
-        OP_LOG("ConcatMatrix " MATRIX_STRING, MATRIX_ARGS(mMatrix));
+        OP_LOG("ConcatMatrix " SK_MATRIX_STRING, SK_MATRIX_ARGS(mMatrix));
     }
 
     virtual const char* name() { return "ConcatMatrix"; }
@@ -622,38 +620,6 @@
     SkiaShader* mShader;
 };
 
-class ResetColorFilterOp : public StateOp {
-public:
-    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
-        renderer.resetColorFilter();
-    }
-
-    virtual void output(int level, uint32_t logFlags) const {
-        OP_LOGS("ResetColorFilter");
-    }
-
-    virtual const char* name() { return "ResetColorFilter"; }
-};
-
-class SetupColorFilterOp : public StateOp {
-public:
-    SetupColorFilterOp(SkiaColorFilter* colorFilter)
-            : mColorFilter(colorFilter) {}
-
-    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
-        renderer.setupColorFilter(mColorFilter);
-    }
-
-    virtual void output(int level, uint32_t logFlags) const {
-        OP_LOG("SetupColorFilter, filter %p", mColorFilter);
-    }
-
-    virtual const char* name() { return "SetupColorFilter"; }
-
-private:
-    SkiaColorFilter* mColorFilter;
-};
-
 class ResetShadowOp : public StateOp {
 public:
     virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
@@ -848,7 +814,7 @@
     }
 
     virtual void output(int level, uint32_t logFlags) const {
-        OP_LOG("Draw bitmap %p matrix " MATRIX_STRING, mBitmap, MATRIX_ARGS(mMatrix));
+        OP_LOG("Draw bitmap %p matrix " SK_MATRIX_STRING, mBitmap, SK_MATRIX_ARGS(mMatrix));
     }
 
     virtual const char* name() { return "DrawBitmapMatrix"; }
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index c8a6c2d..0cbf088 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -53,10 +53,6 @@
         mCaches.resourceCache.decrementRefcountLocked(mOwnedBitmapResources.itemAt(i));
     }
 
-    for (size_t i = 0; i < mFilterResources.size(); i++) {
-        mCaches.resourceCache.decrementRefcountLocked(mFilterResources.itemAt(i));
-    }
-
     for (size_t i = 0; i < mPatchResources.size(); i++) {
         mCaches.resourceCache.decrementRefcountLocked(mPatchResources.itemAt(i));
     }
@@ -77,7 +73,6 @@
 
     mBitmapResources.clear();
     mOwnedBitmapResources.clear();
-    mFilterResources.clear();
     mPatchResources.clear();
     mSourcePaths.clear();
 
@@ -173,17 +168,10 @@
     StatefulBaseRenderer::restoreToCount(saveCount);
 }
 
-void DisplayListRenderer::onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) {
-    bool restoreProjection = removed.flags & Snapshot::kFlagProjectionTarget;
-    if (restoreProjection) {
-        mDisplayListData->projectionIndex = mDisplayListData->displayListOps.size() - 1;
-        mDisplayListData->projectionTransform.load(*currentTransform());
-    }
-}
-
 int DisplayListRenderer::saveLayer(float left, float top, float right, float bottom,
-        int alpha, SkXfermode::Mode mode, int flags) {
-    addStateOp(new (alloc()) SaveLayerOp(left, top, right, bottom, alpha, mode, flags));
+        const SkPaint* paint, int flags) {
+    paint = refPaint(paint);
+    addStateOp(new (alloc()) SaveLayerOp(left, top, right, bottom, paint, flags));
     return StatefulBaseRenderer::save(flags);
 }
 
@@ -254,6 +242,9 @@
             flags, *currentTransform());
     addDrawOp(op);
     mDisplayListData->children.push(op);
+    if (displayList->isProjectionReceiver()) {
+        mDisplayListData->projectionReceiveIndex = mDisplayListData->displayListOps.size() - 1;
+    }
 
     return DrawGlInfo::kStatusDone;
 }
@@ -461,15 +452,6 @@
     addStateOp(new (alloc()) SetupShaderOp(shader));
 }
 
-void DisplayListRenderer::resetColorFilter() {
-    addStateOp(new (alloc()) ResetColorFilterOp());
-}
-
-void DisplayListRenderer::setupColorFilter(SkiaColorFilter* filter) {
-    filter = refColorFilter(filter);
-    addStateOp(new (alloc()) SetupColorFilterOp(filter));
-}
-
 void DisplayListRenderer::resetShadow() {
     addStateOp(new (alloc()) ResetShadowOp());
     OpenGLRenderer::resetShadow();
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index 1360808..7e62c5d 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -82,7 +82,7 @@
     virtual void restore();
     virtual void restoreToCount(int saveCount);
     virtual int saveLayer(float left, float top, float right, float bottom,
-            int alpha, SkXfermode::Mode mode, int flags);
+            const SkPaint* paint, int flags);
 
     // Matrix
     virtual void translate(float dx, float dy, float dz);
@@ -102,9 +102,6 @@
     virtual void resetShader();
     virtual void setupShader(SkiaShader* shader);
 
-    virtual void resetColorFilter();
-    virtual void setupColorFilter(SkiaColorFilter* filter);
-
     virtual void resetShadow();
     virtual void setupShadow(float radius, float dx, float dy, int color);
 
@@ -182,10 +179,6 @@
         return mOwnedBitmapResources;
     }
 
-    const Vector<SkiaColorFilter*>& getFilterResources() const {
-        return mFilterResources;
-    }
-
     const Vector<const Res_png_9patch*>& getPatchResources() const {
         return mPatchResources;
     }
@@ -221,8 +214,6 @@
     uint32_t getFunctorCount() const {
         return mFunctorCount;
     }
-protected:
-    virtual void onSnapshotRestored(const Snapshot& removed, const Snapshot& restored);
 
 private:
     void insertRestoreToCount();
@@ -351,12 +342,6 @@
         return shaderCopy;
     }
 
-    inline SkiaColorFilter* refColorFilter(SkiaColorFilter* colorFilter) {
-        mFilterResources.add(colorFilter);
-        mCaches.resourceCache.incrementRefcount(colorFilter);
-        return colorFilter;
-    }
-
     inline const Res_png_9patch* refPatch(const Res_png_9patch* patch) {
         mPatchResources.add(patch);
         mCaches.resourceCache.incrementRefcount(patch);
@@ -366,7 +351,6 @@
     // TODO: move these to DisplayListData
     Vector<const SkBitmap*> mBitmapResources;
     Vector<const SkBitmap*> mOwnedBitmapResources;
-    Vector<SkiaColorFilter*> mFilterResources;
     Vector<const Res_png_9patch*> mPatchResources;
 
     Vector<const SkPaint*> mPaints;
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index f907d64..b79a3b0 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -72,9 +72,9 @@
             break;
         }
     }
-    renderer->setupDrawColorFilter();
+    renderer->setupDrawColorFilter(paint->getColorFilter());
     renderer->setupDrawShader();
-    renderer->setupDrawBlending(true, mode);
+    renderer->setupDrawBlending(paint);
     renderer->setupDrawProgram();
     renderer->setupDrawModelView(kModelViewMode_Translate, false,
             0.0f, 0.0f, 0.0f, 0.0f, pureTranslate);
@@ -84,7 +84,7 @@
     // needed
     renderer->setupDrawTexture(0);
     renderer->setupDrawPureColorUniforms();
-    renderer->setupDrawColorFilterUniforms();
+    renderer->setupDrawColorFilterUniforms(paint->getColorFilter());
     renderer->setupDrawShaderUniforms(pureTranslate);
     renderer->setupDrawTextGammaUniforms();
 
diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp
index 742ffd47..70eeb39 100644
--- a/libs/hwui/Layer.cpp
+++ b/libs/hwui/Layer.cpp
@@ -51,7 +51,7 @@
 }
 
 Layer::~Layer() {
-    if (colorFilter) caches.resourceCache.decrementRefcount(colorFilter);
+    SkSafeUnref(colorFilter);
     removeFbo();
     deleteTexture();
 
@@ -135,14 +135,8 @@
     OpenGLRenderer::getAlphaAndModeDirect(paint, &alpha, &mode);
 }
 
-void Layer::setColorFilter(SkiaColorFilter* filter) {
-    if (colorFilter) {
-        caches.resourceCache.decrementRefcount(colorFilter);
-    }
-    colorFilter = filter;
-    if (colorFilter) {
-        caches.resourceCache.incrementRefcount(colorFilter);
-    }
+void Layer::setColorFilter(SkColorFilter* filter) {
+    SkRefCnt_SafeAssign(colorFilter, filter);
 }
 
 void Layer::bindTexture() const {
diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h
index 471a4a6..ec80e9c 100644
--- a/libs/hwui/Layer.h
+++ b/libs/hwui/Layer.h
@@ -17,6 +17,7 @@
 #ifndef ANDROID_HWUI_LAYER_H
 #define ANDROID_HWUI_LAYER_H
 
+#include <cutils/compiler.h>
 #include <sys/types.h>
 
 #include <GLES2/gl2.h>
@@ -26,9 +27,9 @@
 #include <SkPaint.h>
 #include <SkXfermode.h>
 
+#include "Matrix.h"
 #include "Rect.h"
 #include "RenderBuffer.h"
-#include "SkiaColorFilter.h"
 #include "Texture.h"
 #include "Vertex.h"
 
@@ -217,11 +218,11 @@
         this->textureLayer = textureLayer;
     }
 
-    inline SkiaColorFilter* getColorFilter() const {
+    inline SkColorFilter* getColorFilter() const {
         return colorFilter;
     }
 
-    ANDROID_API void setColorFilter(SkiaColorFilter* filter);
+    ANDROID_API void setColorFilter(SkColorFilter* filter);
 
     void bindStencilRenderBuffer() const;
 
@@ -339,7 +340,7 @@
     /**
      * Color filter used to draw this layer. Optional.
      */
-    SkiaColorFilter* colorFilter;
+    SkColorFilter* colorFilter;
 
     /**
      * Opacity of the layer.
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index 0b38c4d..ea8eb31 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -184,7 +184,7 @@
 // Layers management
 ///////////////////////////////////////////////////////////////////////////////
 
-Layer* LayerRenderer::createLayer(uint32_t width, uint32_t height, bool isOpaque) {
+Layer* LayerRenderer::createRenderLayer(uint32_t width, uint32_t height) {
     LAYER_RENDERER_LOGD("Requesting new render layer %dx%d", width, height);
 
     Caches& caches = Caches::getInstance();
@@ -221,7 +221,6 @@
     layer->texCoords.set(0.0f, height / float(layer->getHeight()),
             width / float(layer->getWidth()), 0.0f);
     layer->setAlpha(255, SkXfermode::kSrcOver_Mode);
-    layer->setBlend(!isOpaque);
     layer->setColorFilter(NULL);
     layer->setDirty(true);
     layer->region.clear();
@@ -270,13 +269,12 @@
     return true;
 }
 
-Layer* LayerRenderer::createTextureLayer(bool isOpaque) {
+Layer* LayerRenderer::createTextureLayer() {
     LAYER_RENDERER_LOGD("Creating new texture layer");
 
     Layer* layer = new Layer(0, 0);
     layer->setCacheable(false);
     layer->setTextureLayer(true);
-    layer->setBlend(!isOpaque);
     layer->setEmpty(true);
     layer->setFbo(0);
     layer->setAlpha(255, SkXfermode::kSrcOver_Mode);
diff --git a/libs/hwui/LayerRenderer.h b/libs/hwui/LayerRenderer.h
index f24c8d4..84acd44 100644
--- a/libs/hwui/LayerRenderer.h
+++ b/libs/hwui/LayerRenderer.h
@@ -52,8 +52,8 @@
     virtual status_t clear(float left, float top, float right, float bottom, bool opaque);
     virtual void finish();
 
-    ANDROID_API static Layer* createTextureLayer(bool isOpaque);
-    ANDROID_API static Layer* createLayer(uint32_t width, uint32_t height, bool isOpaque = false);
+    ANDROID_API static Layer* createTextureLayer();
+    ANDROID_API static Layer* createRenderLayer(uint32_t width, uint32_t height);
     ANDROID_API static bool resizeLayer(Layer* layer, uint32_t width, uint32_t height);
     ANDROID_API static void updateTextureLayer(Layer* layer, uint32_t width, uint32_t height,
             bool isOpaque, GLenum renderTarget, float* transform);
diff --git a/libs/hwui/Matrix.h b/libs/hwui/Matrix.h
index 00ca050..5cd79b1 100644
--- a/libs/hwui/Matrix.h
+++ b/libs/hwui/Matrix.h
@@ -26,12 +26,20 @@
 namespace android {
 namespace uirenderer {
 
-#define MATRIX_STRING "[%.2f %.2f %.2f] [%.2f %.2f %.2f] [%.2f %.2f %.2f]"
-#define MATRIX_ARGS(m) \
+#define SK_MATRIX_STRING "[%.2f %.2f %.2f] [%.2f %.2f %.2f] [%.2f %.2f %.2f]"
+#define SK_MATRIX_ARGS(m) \
     (m)->get(0), (m)->get(1), (m)->get(2), \
     (m)->get(3), (m)->get(4), (m)->get(5), \
     (m)->get(6), (m)->get(7), (m)->get(8)
 
+#define MATRIX_4_STRING "[%.2f %.2f %.2f %.2f] [%.2f %.2f %.2f %.2f]" \
+    " [%.2f %.2f %.2f %.2f] [%.2f %.2f %.2f %.2f]"
+#define MATRIX_4_ARGS(m) \
+    (m)->data[0], (m)->data[4], (m)->data[8], (m)->data[12], \
+    (m)->data[1], (m)->data[5], (m)->data[9], (m)->data[13], \
+    (m)->data[2], (m)->data[6], (m)->data[10], (m)->data[14], \
+    (m)->data[3], (m)->data[7], (m)->data[11], (m)->data[15] \
+
 ///////////////////////////////////////////////////////////////////////////////
 // Classes
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index b710825..fee916b 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -731,11 +731,11 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 int OpenGLRenderer::saveLayer(float left, float top, float right, float bottom,
-        int alpha, SkXfermode::Mode mode, int flags) {
+        const SkPaint* paint, int flags) {
     const int count = saveSnapshot(flags);
 
     if (!currentSnapshot()->isIgnored()) {
-        createLayer(left, top, right, bottom, alpha, mode, flags);
+        createLayer(left, top, right, bottom, paint, flags);
     }
 
     return count;
@@ -786,7 +786,7 @@
 }
 
 int OpenGLRenderer::saveLayerDeferred(float left, float top, float right, float bottom,
-        int alpha, SkXfermode::Mode mode, int flags) {
+        const SkPaint* paint, int flags) {
     const int count = saveSnapshot(flags);
 
     if (!currentSnapshot()->isIgnored() && (flags & SkCanvas::kClipToLayer_SaveFlag)) {
@@ -797,7 +797,7 @@
         Rect bounds(left, top, right, bottom);
         Rect clip;
         calculateLayerBoundsAndClip(bounds, clip, true);
-        updateSnapshotIgnoreForLayer(bounds, clip, true, alpha);
+        updateSnapshotIgnoreForLayer(bounds, clip, true, getAlphaDirect(paint));
 
         if (!currentSnapshot()->isIgnored()) {
             mSnapshot->resetTransform(-bounds.left, -bounds.top, 0.0f);
@@ -862,12 +862,15 @@
  *     something actually gets drawn are the layers regions cleared.
  */
 bool OpenGLRenderer::createLayer(float left, float top, float right, float bottom,
-        int alpha, SkXfermode::Mode mode, int flags) {
+        const SkPaint* paint, int flags) {
     LAYER_LOGD("Requesting layer %.2fx%.2f", right - left, bottom - top);
     LAYER_LOGD("Layer cache size = %d", mCaches.layerCache.getSize());
 
     const bool fboLayer = flags & SkCanvas::kClipToLayer_SaveFlag;
 
+    SkXfermode::Mode mode = getXfermodeDirect(paint);
+    int alpha = getAlphaDirect(paint);
+
     // Window coordinates of the layer
     Rect clip;
     Rect bounds(left, top, right, bottom);
@@ -889,7 +892,8 @@
     layer->layer.set(bounds);
     layer->texCoords.set(0.0f, bounds.getHeight() / float(layer->getHeight()),
             bounds.getWidth() / float(layer->getWidth()), 0.0f);
-    layer->setColorFilter(mDrawModifiers.mColorFilter);
+
+    layer->setColorFilter(getColorFilter(paint));
     layer->setBlend(true);
     layer->setDirty(false);
 
@@ -1007,8 +1011,13 @@
     }
 
     if (!fboLayer && layer->getAlpha() < 255) {
-        drawColorRect(rect.left, rect.top, rect.right, rect.bottom,
-                layer->getAlpha() << 24, SkXfermode::kDstIn_Mode, true);
+        // TODO: this seems to point to the fact that the layer should store the paint
+        SkPaint layerPaint;
+        layerPaint.setAlpha(layer->getAlpha());
+        layerPaint.setXfermodeMode(SkXfermode::kDstIn_Mode);
+        layerPaint.setColorFilter(layer->getColorFilter());
+
+        drawColorRect(rect.left, rect.top, rect.right, rect.bottom, &layerPaint, true);
         // Required below, composeLayerRect() will divide by 255
         layer->setAlpha(255);
     }
@@ -1021,13 +1030,7 @@
     // drawing only the dirty region
     if (fboLayer) {
         dirtyLayer(rect.left, rect.top, rect.right, rect.bottom, *restored.transform);
-        if (layer->getColorFilter()) {
-            setupColorFilter(layer->getColorFilter());
-        }
         composeLayerRegion(layer, rect);
-        if (layer->getColorFilter()) {
-            resetColorFilter();
-        }
     } else if (!rect.isEmpty()) {
         dirtyLayer(rect.left, rect.top, rect.right, rect.bottom);
 
@@ -1059,11 +1062,11 @@
     }
     setupDrawTextureTransform();
     setupDrawColor(alpha, alpha, alpha, alpha);
-    setupDrawColorFilter();
-    setupDrawBlending(layer->isBlend() || alpha < 1.0f, layer->getMode());
+    setupDrawColorFilter(layer->getColorFilter());
+    setupDrawBlending(layer);
     setupDrawProgram();
     setupDrawPureColorUniforms();
-    setupDrawColorFilterUniforms();
+    setupDrawColorFilterUniforms(layer->getColorFilter());
     if (layer->getRenderTarget() == GL_TEXTURE_2D) {
         setupDrawTexture(layer->getTexture());
     } else {
@@ -1113,10 +1116,14 @@
             layer->setFilter(GL_LINEAR, true);
         }
 
-        float alpha = getLayerAlpha(layer);
-        bool blend = layer->isBlend() || alpha < 1.0f;
+        SkPaint layerPaint;
+        layerPaint.setAlpha(getLayerAlpha(layer) * 255);
+        layerPaint.setXfermodeMode(layer->getMode());
+        layerPaint.setColorFilter(layer->getColorFilter());
+
+        bool blend = layer->isBlend() || getLayerAlpha(layer) < 1.0f;
         drawTextureMesh(x, y, x + rect.getWidth(), y + rect.getHeight(),
-                layer->getTexture(), alpha, layer->getMode(), blend,
+                layer->getTexture(), &layerPaint, blend,
                 &mMeshVertices[0].x, &mMeshVertices[0].u,
                 GL_TRIANGLE_STRIP, gMeshCount, swap, swap || simpleTransform);
 
@@ -1181,12 +1188,12 @@
 
         setupDrawWithTexture();
         setupDrawColor(alpha, alpha, alpha, alpha);
-        setupDrawColorFilter();
-        setupDrawBlending(layer->isBlend() || alpha < 1.0f, layer->getMode(), false);
+        setupDrawColorFilter(layer->getColorFilter());
+        setupDrawBlending(layer);
         setupDrawProgram();
         setupDrawDirtyRegionsDisabled();
         setupDrawPureColorUniforms();
-        setupDrawColorFilterUniforms();
+        setupDrawColorFilterUniforms(layer->getColorFilter());
         setupDrawTexture(layer->getTexture());
         if (currentTransform()->isPureTranslate()) {
             const float x = (int) floorf(rect.left + currentTransform()->getTranslateX() + 0.5f);
@@ -1258,15 +1265,15 @@
             top = rects[i].top;
         }
 
+        SkPaint paint;
+        paint.setColor(colors[offset + (i & 0x1)]);
         Rect r(rects[i].left, rects[i].top, rects[i].right, rects[i].bottom);
-        drawColorRect(r.left, r.top, r.right, r.bottom, colors[offset + (i & 0x1)],
-                SkXfermode::kSrcOver_Mode);
+        drawColorRect(r.left, r.top, r.right, r.bottom, paint);
     }
 }
 #endif
 
-void OpenGLRenderer::drawRegionRects(const SkRegion& region, int color,
-        SkXfermode::Mode mode, bool dirty) {
+void OpenGLRenderer::drawRegionRects(const SkRegion& region, const SkPaint& paint, bool dirty) {
     Vector<float> rects;
 
     SkRegion::Iterator it(region);
@@ -1279,7 +1286,7 @@
         it.next();
     }
 
-    drawColorRects(rects.array(), rects.size(), color, mode, true, dirty, false);
+    drawColorRects(rects.array(), rects.size(), &paint, true, dirty, false);
 }
 
 void OpenGLRenderer::dirtyLayer(const float left, const float top,
@@ -1356,9 +1363,12 @@
         // the same thing again
         mLayers.clear();
 
+        SkPaint clearPaint;
+        clearPaint.setXfermodeMode(SkXfermode::kClear_Mode);
+
         setupDraw(false);
         setupDrawColor(0.0f, 0.0f, 0.0f, 1.0f);
-        setupDrawBlending(true, SkXfermode::kClear_Mode);
+        setupDrawBlending(&clearPaint, true);
         setupDrawProgram();
         setupDrawPureColorUniforms();
         setupDrawModelView(kModelViewMode_Translate, false,
@@ -1517,22 +1527,26 @@
             mCaches.stencil.clear();
             if (resetScissor) mCaches.disableScissor();
 
+            SkPaint paint;
+            paint.setColor(0xff000000);
+            paint.setXfermodeMode(SkXfermode::kSrc_Mode);
+
             // NOTE: We could use the region contour path to generate a smaller mesh
             //       Since we are using the stencil we could use the red book path
             //       drawing technique. It might increase bandwidth usage though.
 
             // The last parameter is important: we are not drawing in the color buffer
             // so we don't want to dirty the current layer, if any
-            drawRegionRects(*(currentSnapshot()->clipRegion),
-                    0xff000000, SkXfermode::kSrc_Mode, false);
+            drawRegionRects(*(currentSnapshot()->clipRegion), paint, false);
 
             mCaches.stencil.enableTest();
 
             // Draw the region used to generate the stencil if the appropriate debug
             // mode is enabled
             if (mCaches.debugStencilClip == Caches::kStencilShowRegion) {
-                drawRegionRects(*(currentSnapshot()->clipRegion),
-                        0x7f0000ff, SkXfermode::kSrcOver_Mode);
+                paint.setColor(0x7f0000ff);
+                paint.setXfermodeMode(SkXfermode::kSrcOver_Mode);
+                drawRegionRects(*(currentSnapshot()->clipRegion), paint);
             }
         } else {
             mCaches.stencil.disable();
@@ -1573,7 +1587,10 @@
 void OpenGLRenderer::debugClip() {
 #if DEBUG_CLIP_REGIONS
     if (!isRecording() && !currentSnapshot()->clipRegion->isEmpty()) {
-        drawRegionRects(*(currentSnapshot()->clipRegion), 0x7f00ff00, SkXfermode::kSrcOver_Mode);
+        SkPaint paint;
+        paint.setColor(0x7f00ff00);
+        drawRegionRects(*(currentSnapshot()->clipRegion, paint);
+
     }
 #endif
 }
@@ -1672,9 +1689,17 @@
     }
 }
 
-void OpenGLRenderer::setupDrawColorFilter() {
-    if (mDrawModifiers.mColorFilter) {
-        mDrawModifiers.mColorFilter->describe(mDescription, mExtensions);
+void OpenGLRenderer::setupDrawColorFilter(const SkColorFilter* filter) {
+    if (filter == NULL) {
+        return;
+    }
+
+    SkXfermode::Mode mode;
+    if (filter->asColorMode(NULL, &mode)) {
+        mDescription.colorOp = ProgramDescription::kColorBlend;
+        mDescription.colorMode = mode;
+    } else if (filter->asColorMatrix(NULL)) {
+        mDescription.colorOp = ProgramDescription::kColorMatrix;
     }
 }
 
@@ -1686,22 +1711,26 @@
     }
 }
 
-void OpenGLRenderer::setupDrawBlending(SkXfermode::Mode mode, bool swapSrcDst) {
+void OpenGLRenderer::setupDrawBlending(const Layer* layer, bool swapSrcDst) {
+    SkXfermode::Mode mode = layer->getMode();
     // When the blending mode is kClear_Mode, we need to use a modulate color
     // argb=1,0,0,0
     accountForClear(mode);
-    bool blend = (mColorSet && mColorA < 1.0f) ||
-            (mDrawModifiers.mShader && mDrawModifiers.mShader->blend());
+    bool blend = layer->isBlend() || getLayerAlpha(layer) < 1.0f ||
+            (mColorSet && mColorA < 1.0f) ||
+            (mDrawModifiers.mShader && mDrawModifiers.mShader->blend()) ||
+            layer->getColorFilter();
     chooseBlending(blend, mode, mDescription, swapSrcDst);
 }
 
-void OpenGLRenderer::setupDrawBlending(bool blend, SkXfermode::Mode mode, bool swapSrcDst) {
+void OpenGLRenderer::setupDrawBlending(const SkPaint* paint, bool blend, bool swapSrcDst) {
+    SkXfermode::Mode mode = getXfermodeDirect(paint);
     // When the blending mode is kClear_Mode, we need to use a modulate color
     // argb=1,0,0,0
     accountForClear(mode);
     blend |= (mColorSet && mColorA < 1.0f) ||
             (mDrawModifiers.mShader && mDrawModifiers.mShader->blend()) ||
-            (mDrawModifiers.mColorFilter && mDrawModifiers.mColorFilter->blend());
+            (paint && paint->getColorFilter());
     chooseBlending(blend, mode, mDescription, swapSrcDst);
 }
 
@@ -1758,10 +1787,47 @@
     }
 }
 
-void OpenGLRenderer::setupDrawColorFilterUniforms() {
-    if (mDrawModifiers.mColorFilter) {
-        mDrawModifiers.mColorFilter->setupProgram(mCaches.currentProgram);
+void OpenGLRenderer::setupDrawColorFilterUniforms(const SkColorFilter* filter) {
+    if (NULL == filter) {
+        return;
     }
+
+    SkColor color;
+    SkXfermode::Mode mode;
+    if (filter->asColorMode(&color, &mode)) {
+        const int alpha = SkColorGetA(color);
+        const GLfloat a = alpha / 255.0f;
+        const GLfloat r = a * SkColorGetR(color) / 255.0f;
+        const GLfloat g = a * SkColorGetG(color) / 255.0f;
+        const GLfloat b = a * SkColorGetB(color) / 255.0f;
+        glUniform4f(mCaches.currentProgram->getUniform("colorBlend"), r, g, b, a);
+        return;
+    }
+
+    SkScalar srcColorMatrix[20];
+    if (filter->asColorMatrix(srcColorMatrix)) {
+
+        float colorMatrix[16];
+        memcpy(colorMatrix, srcColorMatrix, 4 * sizeof(float));
+        memcpy(&colorMatrix[4], &srcColorMatrix[5], 4 * sizeof(float));
+        memcpy(&colorMatrix[8], &srcColorMatrix[10], 4 * sizeof(float));
+        memcpy(&colorMatrix[12], &srcColorMatrix[15], 4 * sizeof(float));
+
+        // Skia uses the range [0..255] for the addition vector, but we need
+        // the [0..1] range to apply the vector in GLSL
+        float colorVector[4];
+        colorVector[0] = srcColorMatrix[4] / 255.0f;
+        colorVector[1] = srcColorMatrix[9] / 255.0f;
+        colorVector[2] = srcColorMatrix[14] / 255.0f;
+        colorVector[3] = srcColorMatrix[19] / 255.0f;
+
+        glUniformMatrix4fv(mCaches.currentProgram->getUniform("colorMatrix"), 1,
+                GL_FALSE, colorMatrix);
+        glUniform4fv(mCaches.currentProgram->getUniform("colorMatrixVector"), 1, colorVector);
+        return;
+    }
+
+    // it is an error if we ever get here
 }
 
 void OpenGLRenderer::setupDrawTextGammaUniforms() {
@@ -1896,10 +1962,6 @@
 }
 
 void OpenGLRenderer::drawAlphaBitmap(Texture* texture, float left, float top, const SkPaint* paint) {
-    int alpha;
-    SkXfermode::Mode mode;
-    getAlphaAndMode(paint, &alpha, &mode);
-
     int color = paint != NULL ? paint->getColor() : 0;
 
     float x = left;
@@ -1921,7 +1983,7 @@
     // No need to check for a UV mapper on the texture object, only ARGB_8888
     // bitmaps get packed in the atlas
     drawAlpha8TextureMesh(x, y, x + texture->width, y + texture->height, texture->id,
-            paint != NULL, color, alpha, mode, (GLvoid*) NULL, (GLvoid*) gMeshTextureOffset,
+            paint, (GLvoid*) NULL, (GLvoid*) gMeshTextureOffset,
             GL_TRIANGLE_STRIP, gMeshCount, ignoreTransform);
 }
 
@@ -1939,26 +2001,19 @@
 
     const AutoTexture autoCleanup(texture);
 
-    int alpha;
-    SkXfermode::Mode mode;
-    getAlphaAndMode(paint, &alpha, &mode);
-
     texture->setWrap(GL_CLAMP_TO_EDGE, true);
     texture->setFilter(pureTranslate ? GL_NEAREST : FILTER(paint), true);
 
     const float x = (int) floorf(bounds.left + 0.5f);
     const float y = (int) floorf(bounds.top + 0.5f);
     if (CC_UNLIKELY(bitmap->config() == SkBitmap::kA8_Config)) {
-        int color = paint != NULL ? paint->getColor() : 0;
         drawAlpha8TextureMesh(x, y, x + bounds.getWidth(), y + bounds.getHeight(),
-                texture->id, paint != NULL, color, alpha, mode,
-                &vertices[0].x, &vertices[0].u,
+                texture->id, paint, &vertices[0].x, &vertices[0].u,
                 GL_TRIANGLES, bitmapCount * 6, true,
                 kModelViewMode_Translate, false);
     } else {
         drawTextureMesh(x, y, x + bounds.getWidth(), y + bounds.getHeight(),
-                texture->id, alpha / 255.0f, mode, texture->blend,
-                &vertices[0].x, &vertices[0].u,
+                texture->id, paint, texture->blend, &vertices[0].x, &vertices[0].u,
                 GL_TRIANGLES, bitmapCount * 6, false, true, 0,
                 kModelViewMode_Translate, false);
     }
@@ -2138,14 +2193,14 @@
     setupDraw();
     setupDrawWithTextureAndColor();
     setupDrawColor(a, a, a, a);
-    setupDrawColorFilter();
-    setupDrawBlending(true, mode, false);
+    setupDrawColorFilter(getColorFilter(paint));
+    setupDrawBlending(paint, true);
     setupDrawProgram();
     setupDrawDirtyRegionsDisabled();
     setupDrawModelView(kModelViewMode_TranslateAndScale, false, 0.0f, 0.0f, 1.0f, 1.0f);
     setupDrawTexture(texture->id);
     setupDrawPureColorUniforms();
-    setupDrawColorFilterUniforms();
+    setupDrawColorFilterUniforms(getColorFilter(paint));
     setupDrawMesh(&mesh[0].x, &mesh[0].u, &mesh[0].r);
 
     glDrawArrays(GL_TRIANGLES, 0, count);
@@ -2186,10 +2241,6 @@
     mCaches.unbindMeshBuffer();
     resetDrawTextureTexCoords(u1, v1, u2, v2);
 
-    int alpha;
-    SkXfermode::Mode mode;
-    getAlphaAndMode(paint, &alpha, &mode);
-
     texture->setWrap(GL_CLAMP_TO_EDGE, true);
 
     float scaleX = (dstRight - dstLeft) / (srcRight - srcLeft);
@@ -2231,14 +2282,13 @@
     }
 
     if (CC_UNLIKELY(bitmap->config() == SkBitmap::kA8_Config)) {
-        int color = paint ? paint->getColor() : 0;
         drawAlpha8TextureMesh(dstLeft, dstTop, dstRight, dstBottom,
-                texture->id, paint != NULL, color, alpha, mode,
+                texture->id, paint,
                 &mMeshVertices[0].x, &mMeshVertices[0].u,
                 GL_TRIANGLE_STRIP, gMeshCount, ignoreTransform);
     } else {
         drawTextureMesh(dstLeft, dstTop, dstRight, dstBottom,
-                texture->id, alpha / 255.0f, mode, texture->blend,
+                texture->id, paint, texture->blend,
                 &mMeshVertices[0].x, &mMeshVertices[0].u,
                 GL_TRIANGLE_STRIP, gMeshCount, false, ignoreTransform);
     }
@@ -2281,10 +2331,6 @@
         texture->setWrap(GL_CLAMP_TO_EDGE, true);
         texture->setFilter(GL_LINEAR, true);
 
-        int alpha;
-        SkXfermode::Mode mode;
-        getAlphaAndMode(paint, &alpha, &mode);
-
         const bool pureTranslate = currentTransform()->isPureTranslate();
         // Mark the current layer dirty where we are going to draw the patch
         if (hasLayer() && mesh->hasEmptyQuads) {
@@ -2315,8 +2361,8 @@
             top = y;
             ignoreTransform = true;
         }
-        drawIndexedTextureMesh(left, top, right, bottom, texture->id, alpha / 255.0f,
-                mode, texture->blend, (GLvoid*) mesh->offset, (GLvoid*) mesh->textureOffset,
+        drawIndexedTextureMesh(left, top, right, bottom, texture->id, paint,
+                texture->blend, (GLvoid*) mesh->offset, (GLvoid*) mesh->textureOffset,
                 GL_TRIANGLES, mesh->indexCount, false, ignoreTransform,
                 mCaches.patchCache.getMeshBuffer(), kModelViewMode_Translate, !mesh->hasEmptyQuads);
     }
@@ -2339,12 +2385,8 @@
     texture->setWrap(GL_CLAMP_TO_EDGE, true);
     texture->setFilter(GL_LINEAR, true);
 
-    int alpha;
-    SkXfermode::Mode mode;
-    getAlphaAndMode(paint, &alpha, &mode);
-
-    drawIndexedTextureMesh(0.0f, 0.0f, 1.0f, 1.0f, texture->id, alpha / 255.0f,
-            mode, texture->blend, &vertices[0].x, &vertices[0].u,
+    drawIndexedTextureMesh(0.0f, 0.0f, 1.0f, 1.0f, texture->id, paint,
+            texture->blend, &vertices[0].x, &vertices[0].u,
             GL_TRIANGLES, indexCount, false, true, 0, kModelViewMode_Translate, false);
 
     return DrawGlInfo::kStatusDrew;
@@ -2360,20 +2402,19 @@
     }
 
     int color = paint->getColor();
-    SkXfermode::Mode mode = getXfermode(paint->getXfermode());
     bool isAA = paint->isAntiAlias();
 
     setupDraw();
     setupDrawNoTexture();
     if (isAA) setupDrawAA();
     setupDrawColor(color, ((color >> 24) & 0xFF) * mSnapshot->alpha);
-    setupDrawColorFilter();
+    setupDrawColorFilter(getColorFilter(paint));
     setupDrawShader();
-    setupDrawBlending(isAA, mode);
+    setupDrawBlending(paint, isAA);
     setupDrawProgram();
     setupDrawModelView(kModelViewMode_Translate, useOffset, 0, 0, 0, 0);
     setupDrawColorUniforms();
-    setupDrawColorFilterUniforms();
+    setupDrawColorFilterUniforms(getColorFilter(paint));
     setupDrawShaderUniforms();
 
     const void* vertices = vertexBuffer.getBuffer();
@@ -2482,7 +2523,11 @@
     Rect clip(*currentClipRect());
     clip.snapToPixelBoundaries();
 
-    drawColorRect(clip.left, clip.top, clip.right, clip.bottom, color, mode, true);
+    SkPaint paint;
+    paint.setColor(color);
+    paint.setXfermodeMode(mode);
+
+    drawColorRect(clip.left, clip.top, clip.right, clip.bottom, &paint, true);
 
     return DrawGlInfo::kStatusDrew;
 }
@@ -2638,14 +2683,14 @@
         path.addRect(left, top, right, bottom);
         return drawConvexPath(path, p);
     } else {
-        drawColorRect(left, top, right, bottom, p->getColor(), getXfermode(p->getXfermode()));
+        drawColorRect(left, top, right, bottom, p);
         return DrawGlInfo::kStatusDrew;
     }
 }
 
 void OpenGLRenderer::drawTextShadow(const SkPaint* paint, const char* text,
         int bytesCount, int count, const float* positions,
-        FontRenderer& fontRenderer, int alpha, SkXfermode::Mode mode, float x, float y) {
+        FontRenderer& fontRenderer, int alpha, float x, float y) {
     mCaches.activeTexture(0);
 
     // NOTE: The drop shadow will not perform gamma correction
@@ -2670,15 +2715,15 @@
     setupDraw();
     setupDrawWithTexture(true);
     setupDrawAlpha8Color(shadowColor, shadowAlpha < 255 ? shadowAlpha : alpha);
-    setupDrawColorFilter();
+    setupDrawColorFilter(getColorFilter(paint));
     setupDrawShader();
-    setupDrawBlending(true, mode);
+    setupDrawBlending(paint, true);
     setupDrawProgram();
     setupDrawModelView(kModelViewMode_TranslateAndScale, false,
             sx, sy, sx + shadow->width, sy + shadow->height);
     setupDrawTexture(shadow->id);
     setupDrawPureColorUniforms();
-    setupDrawColorFilterUniforms();
+    setupDrawColorFilterUniforms(getColorFilter(paint));
     setupDrawShaderUniforms();
     setupDrawMesh(NULL, (GLvoid*) gMeshTextureOffset);
 
@@ -2720,7 +2765,7 @@
 
     if (CC_UNLIKELY(mDrawModifiers.mHasShadow)) {
         drawTextShadow(paint, text, bytesCount, count, positions, fontRenderer,
-                alpha, mode, 0.0f, 0.0f);
+                alpha, 0.0f, 0.0f);
     }
 
     // Pick the appropriate texture filtering
@@ -2798,7 +2843,7 @@
     if (CC_UNLIKELY(mDrawModifiers.mHasShadow)) {
         fontRenderer.setFont(paint, mat4::identity());
         drawTextShadow(paint, text, bytesCount, count, positions, fontRenderer,
-                alpha, mode, oldX, oldY);
+                alpha, oldX, oldY);
     }
 
     const bool hasActiveLayer = hasLayer();
@@ -2934,22 +2979,20 @@
     mCaches.activeTexture(0);
 
     if (CC_LIKELY(!layer->region.isEmpty())) {
-        SkiaColorFilter* oldFilter = mDrawModifiers.mColorFilter;
-        mDrawModifiers.mColorFilter = layer->getColorFilter();
-
         if (layer->region.isRect()) {
             DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate,
                     composeLayerRect(layer, layer->regionRect));
         } else if (layer->mesh) {
+
             const float a = getLayerAlpha(layer);
             setupDraw();
             setupDrawWithTexture();
             setupDrawColor(a, a, a, a);
-            setupDrawColorFilter();
-            setupDrawBlending(layer->isBlend() || a < 1.0f, layer->getMode(), false);
+            setupDrawColorFilter(layer->getColorFilter());
+            setupDrawBlending(layer);
             setupDrawProgram();
             setupDrawPureColorUniforms();
-            setupDrawColorFilterUniforms();
+            setupDrawColorFilterUniforms(layer->getColorFilter());
             setupDrawTexture(layer->getTexture());
             if (CC_LIKELY(currentTransform()->isPureTranslate())) {
                 int tx = (int) floorf(x + currentTransform()->getTranslateX() + 0.5f);
@@ -2985,12 +3028,12 @@
 #endif
         }
 
-        mDrawModifiers.mColorFilter = oldFilter;
-
         if (layer->debugDrawUpdate) {
             layer->debugDrawUpdate = false;
-            drawColorRect(x, y, x + layer->layer.getWidth(), y + layer->layer.getHeight(),
-                    0x7f00ff00, SkXfermode::kSrcOver_Mode);
+
+            SkPaint paint;
+            paint.setColor(0x7f00ff00);
+            drawColorRect(x, y, x + layer->layer.getWidth(), y + layer->layer.getHeight(), &paint);
         }
     }
     layer->hasDrawnSinceUpdate = true;
@@ -3018,18 +3061,6 @@
 }
 
 ///////////////////////////////////////////////////////////////////////////////
-// Color filters
-///////////////////////////////////////////////////////////////////////////////
-
-void OpenGLRenderer::resetColorFilter() {
-    mDrawModifiers.mColorFilter = NULL;
-}
-
-void OpenGLRenderer::setupColorFilter(SkiaColorFilter* filter) {
-    mDrawModifiers.mColorFilter = filter;
-}
-
-///////////////////////////////////////////////////////////////////////////////
 // Drop shadow
 ///////////////////////////////////////////////////////////////////////////////
 
@@ -3102,15 +3133,15 @@
     setupDraw();
     setupDrawWithTexture(true);
     setupDrawAlpha8Color(paint->getColor(), alpha);
-    setupDrawColorFilter();
+    setupDrawColorFilter(getColorFilter(paint));
     setupDrawShader();
-    setupDrawBlending(true, mode);
+    setupDrawBlending(paint, true);
     setupDrawProgram();
     setupDrawModelView(kModelViewMode_TranslateAndScale, false,
             x, y, x + texture->width, y + texture->height);
     setupDrawTexture(texture->id);
     setupDrawPureColorUniforms();
-    setupDrawColorFilterUniforms();
+    setupDrawColorFilterUniforms(getColorFilter(paint));
     setupDrawShaderUniforms();
     setupDrawMesh(NULL, (GLvoid*) gMeshTextureOffset);
 
@@ -3172,14 +3203,7 @@
         return DrawGlInfo::kStatusDone;
     }
 
-    int color = paint->getColor();
-    // If a shader is set, preserve only the alpha
-    if (mDrawModifiers.mShader) {
-        color |= 0x00ffffff;
-    }
-    SkXfermode::Mode mode = getXfermode(paint->getXfermode());
-
-    return drawColorRects(rects, count, color, mode);
+    return drawColorRects(rects, count, paint, false, true, true);
 }
 
 status_t OpenGLRenderer::drawShadow(const mat4& casterTransform, float casterAlpha,
@@ -3231,12 +3255,18 @@
     return DrawGlInfo::kStatusDrew;
 }
 
-status_t OpenGLRenderer::drawColorRects(const float* rects, int count, int color,
-        SkXfermode::Mode mode, bool ignoreTransform, bool dirty, bool clip) {
+status_t OpenGLRenderer::drawColorRects(const float* rects, int count, const SkPaint* paint,
+        bool ignoreTransform, bool dirty, bool clip) {
     if (count == 0) {
         return DrawGlInfo::kStatusDone;
     }
 
+    int color = paint->getColor();
+    // If a shader is set, preserve only the alpha
+    if (mDrawModifiers.mShader) {
+        color |= 0x00ffffff;
+    }
+
     float left = FLT_MAX;
     float top = FLT_MAX;
     float right = FLT_MIN;
@@ -3270,15 +3300,15 @@
     setupDrawNoTexture();
     setupDrawColor(color, ((color >> 24) & 0xFF) * currentSnapshot()->alpha);
     setupDrawShader();
-    setupDrawColorFilter();
-    setupDrawBlending(mode);
+    setupDrawColorFilter(getColorFilter(paint));
+    setupDrawBlending(paint);
     setupDrawProgram();
     setupDrawDirtyRegionsDisabled();
     setupDrawModelView(kModelViewMode_Translate, false,
             0.0f, 0.0f, 0.0f, 0.0f, ignoreTransform);
     setupDrawColorUniforms();
     setupDrawShaderUniforms();
-    setupDrawColorFilterUniforms();
+    setupDrawColorFilterUniforms(getColorFilter(paint));
 
     if (dirty && hasLayer()) {
         dirtyLayer(left, top, right, bottom, *currentTransform());
@@ -3290,7 +3320,8 @@
 }
 
 void OpenGLRenderer::drawColorRect(float left, float top, float right, float bottom,
-        int color, SkXfermode::Mode mode, bool ignoreTransform) {
+        const SkPaint* paint, bool ignoreTransform) {
+    int color = paint->getColor();
     // If a shader is set, preserve only the alpha
     if (mDrawModifiers.mShader) {
         color |= 0x00ffffff;
@@ -3300,14 +3331,14 @@
     setupDrawNoTexture();
     setupDrawColor(color, ((color >> 24) & 0xFF) * currentSnapshot()->alpha);
     setupDrawShader();
-    setupDrawColorFilter();
-    setupDrawBlending(mode);
+    setupDrawColorFilter(getColorFilter(paint));
+    setupDrawBlending(paint);
     setupDrawProgram();
     setupDrawModelView(kModelViewMode_TranslateAndScale, false,
             left, top, right, bottom, ignoreTransform);
     setupDrawColorUniforms();
     setupDrawShaderUniforms(ignoreTransform);
-    setupDrawColorFilterUniforms();
+    setupDrawColorFilterUniforms(getColorFilter(paint));
     setupDrawSimpleMesh();
 
     glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
@@ -3315,10 +3346,6 @@
 
 void OpenGLRenderer::drawTextureRect(float left, float top, float right, float bottom,
         Texture* texture, const SkPaint* paint) {
-    int alpha;
-    SkXfermode::Mode mode;
-    getAlphaAndMode(paint, &alpha, &mode);
-
     texture->setWrap(GL_CLAMP_TO_EDGE, true);
 
     GLvoid* vertices = (GLvoid*) NULL;
@@ -3340,11 +3367,11 @@
 
         texture->setFilter(GL_NEAREST, true);
         drawTextureMesh(x, y, x + texture->width, y + texture->height, texture->id,
-                alpha / 255.0f, mode, texture->blend, vertices, texCoords,
+                paint, texture->blend, vertices, texCoords,
                 GL_TRIANGLE_STRIP, gMeshCount, false, true);
     } else {
         texture->setFilter(FILTER(paint), true);
-        drawTextureMesh(left, top, right, bottom, texture->id, alpha / 255.0f, mode,
+        drawTextureMesh(left, top, right, bottom, texture->id, paint,
                 texture->blend, vertices, texCoords, GL_TRIANGLE_STRIP, gMeshCount);
     }
 
@@ -3353,75 +3380,84 @@
     }
 }
 
-void OpenGLRenderer::drawTextureRect(float left, float top, float right, float bottom,
-        GLuint texture, float alpha, SkXfermode::Mode mode, bool blend) {
-    drawTextureMesh(left, top, right, bottom, texture, alpha, mode, blend,
-            (GLvoid*) NULL, (GLvoid*) gMeshTextureOffset, GL_TRIANGLE_STRIP, gMeshCount);
-}
-
 void OpenGLRenderer::drawTextureMesh(float left, float top, float right, float bottom,
-        GLuint texture, float alpha, SkXfermode::Mode mode, bool blend,
+        GLuint texture, const SkPaint* paint, bool blend,
         GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount,
         bool swapSrcDst, bool ignoreTransform, GLuint vbo,
         ModelViewMode modelViewMode, bool dirty) {
 
+    int a;
+    SkXfermode::Mode mode;
+    getAlphaAndMode(paint, &a, &mode);
+    const float alpha = a / 255.0f;
+
     setupDraw();
     setupDrawWithTexture();
     setupDrawColor(alpha, alpha, alpha, alpha);
-    setupDrawColorFilter();
-    setupDrawBlending(blend, mode, swapSrcDst);
+    setupDrawColorFilter(getColorFilter(paint));
+    setupDrawBlending(paint, blend, swapSrcDst);
     setupDrawProgram();
     if (!dirty) setupDrawDirtyRegionsDisabled();
     setupDrawModelView(modelViewMode, false, left, top, right, bottom, ignoreTransform);
     setupDrawTexture(texture);
     setupDrawPureColorUniforms();
-    setupDrawColorFilterUniforms();
+    setupDrawColorFilterUniforms(getColorFilter(paint));
     setupDrawMesh(vertices, texCoords, vbo);
 
     glDrawArrays(drawMode, 0, elementsCount);
 }
 
 void OpenGLRenderer::drawIndexedTextureMesh(float left, float top, float right, float bottom,
-        GLuint texture, float alpha, SkXfermode::Mode mode, bool blend,
+        GLuint texture, const SkPaint* paint, bool blend,
         GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount,
         bool swapSrcDst, bool ignoreTransform, GLuint vbo,
         ModelViewMode modelViewMode, bool dirty) {
 
+    int a;
+    SkXfermode::Mode mode;
+    getAlphaAndMode(paint, &a, &mode);
+    const float alpha = a / 255.0f;
+
     setupDraw();
     setupDrawWithTexture();
     setupDrawColor(alpha, alpha, alpha, alpha);
-    setupDrawColorFilter();
-    setupDrawBlending(blend, mode, swapSrcDst);
+    setupDrawColorFilter(getColorFilter(paint));
+    setupDrawBlending(paint, blend, swapSrcDst);
     setupDrawProgram();
     if (!dirty) setupDrawDirtyRegionsDisabled();
     setupDrawModelView(modelViewMode, false, left, top, right, bottom, ignoreTransform);
     setupDrawTexture(texture);
     setupDrawPureColorUniforms();
-    setupDrawColorFilterUniforms();
+    setupDrawColorFilterUniforms(getColorFilter(paint));
     setupDrawMeshIndices(vertices, texCoords, vbo);
 
     glDrawElements(drawMode, elementsCount, GL_UNSIGNED_SHORT, NULL);
 }
 
 void OpenGLRenderer::drawAlpha8TextureMesh(float left, float top, float right, float bottom,
-        GLuint texture, bool hasColor, int color, int alpha, SkXfermode::Mode mode,
+        GLuint texture, const SkPaint* paint,
         GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount,
         bool ignoreTransform, ModelViewMode modelViewMode, bool dirty) {
 
+    int color = paint != NULL ? paint->getColor() : 0;
+    int alpha;
+    SkXfermode::Mode mode;
+    getAlphaAndMode(paint, &alpha, &mode);
+
     setupDraw();
     setupDrawWithTexture(true);
-    if (hasColor) {
+    if (paint != NULL) {
         setupDrawAlpha8Color(color, alpha);
     }
-    setupDrawColorFilter();
+    setupDrawColorFilter(getColorFilter(paint));
     setupDrawShader();
-    setupDrawBlending(true, mode);
+    setupDrawBlending(paint, true);
     setupDrawProgram();
     if (!dirty) setupDrawDirtyRegionsDisabled();
     setupDrawModelView(modelViewMode, false, left, top, right, bottom, ignoreTransform);
     setupDrawTexture(texture);
     setupDrawPureColorUniforms();
-    setupDrawColorFilterUniforms();
+    setupDrawColorFilterUniforms(getColorFilter(paint));
     setupDrawShaderUniforms(ignoreTransform);
     setupDrawMesh(vertices, texCoords);
 
@@ -3512,7 +3548,7 @@
     *alpha *= currentSnapshot()->alpha;
 }
 
-float OpenGLRenderer::getLayerAlpha(Layer* layer) const {
+float OpenGLRenderer::getLayerAlpha(const Layer* layer) const {
     float alpha;
     if (mDrawModifiers.mOverrideLayerAlpha < 1.0f) {
         alpha = mDrawModifiers.mOverrideLayerAlpha;
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index c8ecdda..e4d133d 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -21,6 +21,8 @@
 #include <GLES2/gl2ext.h>
 
 #include <SkBitmap.h>
+#include <SkCanvas.h>
+#include <SkColorFilter.h>
 #include <SkMatrix.h>
 #include <SkPaint.h>
 #include <SkRegion.h>
@@ -43,7 +45,6 @@
 #include "Rect.h"
 #include "Renderer.h"
 #include "StatefulBaseRenderer.h"
-#include "SkiaColorFilter.h"
 #include "Snapshot.h"
 #include "UvMapper.h"
 #include "Vertex.h"
@@ -68,7 +69,6 @@
     }
 
     SkiaShader* mShader;
-    SkiaColorFilter* mColorFilter;
     float mOverrideLayerAlpha;
 
     // Drop shadow
@@ -154,21 +154,11 @@
     ANDROID_API void clearLayerUpdates();
     ANDROID_API void flushLayerUpdates();
 
-    ANDROID_API int saveLayer(float left, float top, float right, float bottom,
-            SkPaint* paint, int flags) {
-        SkXfermode::Mode mode = SkXfermode::kSrcOver_Mode;
-        if (paint) mode = getXfermode(paint->getXfermode());
-        return saveLayer(left, top, right, bottom, paint ? paint->getAlpha() : 255, mode, flags);
-    }
-    ANDROID_API int saveLayerAlpha(float left, float top, float right, float bottom,
-            int alpha, int flags) {
-        return saveLayer(left, top, right, bottom, alpha, SkXfermode::kSrcOver_Mode, flags);
-    }
-    virtual int saveLayer(float left, float top, float right, float bottom,
-            int alpha, SkXfermode::Mode mode, int flags);
+    ANDROID_API virtual int saveLayer(float left, float top, float right, float bottom,
+            const SkPaint* paint, int flags);
 
     int saveLayerDeferred(float left, float top, float right, float bottom,
-            int alpha, SkXfermode::Mode mode, int flags);
+            const SkPaint* paint, int flags);
 
     virtual status_t drawDisplayList(DisplayList* displayList, Rect& dirty, int32_t replayFlags = 1);
     virtual status_t drawLayer(Layer* layer, float x, float y);
@@ -219,9 +209,6 @@
     virtual void resetShader();
     virtual void setupShader(SkiaShader* shader);
 
-    virtual void resetColorFilter();
-    virtual void setupColorFilter(SkiaColorFilter* filter);
-
     virtual void resetShadow();
     virtual void setupShadow(float radius, float dx, float dy, int color);
 
@@ -442,18 +429,14 @@
      *
      * @param layer The layer from which the alpha is extracted
      */
-    inline float getLayerAlpha(Layer* layer) const;
+    inline float getLayerAlpha(const Layer* layer) const;
 
     /**
-     * Safely retrieves the mode from the specified xfermode. If the specified
-     * xfermode is null, the mode is assumed to be SkXfermode::kSrcOver_Mode.
+     * Safely retrieves the ColorFilter from the given Paint. If the paint is
+     * null then null is returned.
      */
-    static inline SkXfermode::Mode getXfermode(SkXfermode* mode) {
-        SkXfermode::Mode resultMode;
-        if (!SkXfermode::AsMode(mode, &resultMode)) {
-            resultMode = SkXfermode::kSrcOver_Mode;
-        }
-        return resultMode;
+    static inline SkColorFilter* getColorFilter(const SkPaint* paint) {
+        return paint ? paint->getColorFilter() : NULL;
     }
 
     /**
@@ -538,7 +521,7 @@
      * @return True if the layer was successfully created, false otherwise
      */
     bool createLayer(float left, float top, float right, float bottom,
-            int alpha, SkXfermode::Mode mode, int flags);
+            const SkPaint* paint, int flags);
 
     /**
      * Creates a new layer stored in the specified snapshot as an FBO.
@@ -594,12 +577,11 @@
      * @param top The top coordinate of the rectangle
      * @param right The right coordinate of the rectangle
      * @param bottom The bottom coordinate of the rectangle
-     * @param color The rectangle's ARGB color, defined as a packed 32 bits word
-     * @param mode The Skia xfermode to use
+     * @param paint The paint containing the color, blending mode, etc.
      * @param ignoreTransform True if the current transform should be ignored
      */
     void drawColorRect(float left, float top, float right, float bottom,
-            int color, SkXfermode::Mode mode, bool ignoreTransform = false);
+            const SkPaint* paint, bool ignoreTransform = false);
 
     /**
      * Draws a series of colored rectangles with the specified color. The specified
@@ -608,15 +590,13 @@
      *
      * @param rects A list of rectangles, 4 floats (left, top, right, bottom)
      *              per rectangle
-     * @param color The rectangles' ARGB color, defined as a packed 32 bits word
-     * @param mode The Skia xfermode to use
+     * @param paint The paint containing the color, blending mode, etc.
      * @param ignoreTransform True if the current transform should be ignored
      * @param dirty True if calling this method should dirty the current layer
      * @param clip True if the rects should be clipped, false otherwise
      */
-    status_t drawColorRects(const float* rects, int count, int color,
-            SkXfermode::Mode mode, bool ignoreTransform = false,
-            bool dirty = true, bool clip = true);
+    status_t drawColorRects(const float* rects, int count, const SkPaint* paint,
+            bool ignoreTransform = false, bool dirty = true, bool clip = true);
 
     /**
      * Draws the shape represented by the specified path texture.
@@ -668,22 +648,6 @@
      * @param top The top coordinate of the rectangle
      * @param right The right coordinate of the rectangle
      * @param bottom The bottom coordinate of the rectangle
-     * @param texture The texture name to map onto the rectangle
-     * @param alpha An additional translucency parameter, between 0.0f and 1.0f
-     * @param mode The blending mode
-     * @param blend True if the texture contains an alpha channel
-     */
-    void drawTextureRect(float left, float top, float right, float bottom, GLuint texture,
-            float alpha, SkXfermode::Mode mode, bool blend);
-
-    /**
-     * Draws a textured rectangle with the specified texture. The specified coordinates
-     * are transformed by the current snapshot's transform matrix.
-     *
-     * @param left The left coordinate of the rectangle
-     * @param top The top coordinate of the rectangle
-     * @param right The right coordinate of the rectangle
-     * @param bottom The bottom coordinate of the rectangle
      * @param texture The texture to use
      * @param paint The paint containing the alpha, blending mode, etc.
      */
@@ -700,8 +664,7 @@
      * @param right The right coordinate of the rectangle
      * @param bottom The bottom coordinate of the rectangle
      * @param texture The texture name to map onto the rectangle
-     * @param alpha An additional translucency parameter, between 0.0f and 1.0f
-     * @param mode The blending mode
+     * @param paint The paint containing the alpha, blending mode, colorFilter, etc.
      * @param blend True if the texture contains an alpha channel
      * @param vertices The vertices that define the mesh
      * @param texCoords The texture coordinates of each vertex
@@ -713,19 +676,19 @@
      * @param dirty True if calling this method should dirty the current layer
      */
     void drawTextureMesh(float left, float top, float right, float bottom, GLuint texture,
-            float alpha, SkXfermode::Mode mode, bool blend,
+            const SkPaint* paint, bool blend,
             GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount,
             bool swapSrcDst = false, bool ignoreTransform = false, GLuint vbo = 0,
             ModelViewMode modelViewMode = kModelViewMode_TranslateAndScale, bool dirty = true);
 
     void drawIndexedTextureMesh(float left, float top, float right, float bottom, GLuint texture,
-            float alpha, SkXfermode::Mode mode, bool blend,
+            const SkPaint* paint, bool blend,
             GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount,
             bool swapSrcDst = false, bool ignoreTransform = false, GLuint vbo = 0,
             ModelViewMode modelViewMode = kModelViewMode_TranslateAndScale, bool dirty = true);
 
     void drawAlpha8TextureMesh(float left, float top, float right, float bottom,
-            GLuint texture, bool hasColor, int color, int alpha, SkXfermode::Mode mode,
+            GLuint texture, const SkPaint* paint,
             GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount,
             bool ignoreTransform, ModelViewMode modelViewMode = kModelViewMode_TranslateAndScale,
             bool dirty = true);
@@ -759,12 +722,11 @@
      * @param positions The x, y positions of individual glyphs (or NULL)
      * @param fontRenderer The font renderer object
      * @param alpha The alpha value for drawing the shadow
-     * @param mode The xfermode for drawing the shadow
      * @param x The x coordinate where the shadow will be drawn
      * @param y The y coordinate where the shadow will be drawn
      */
     void drawTextShadow(const SkPaint* paint, const char* text, int bytesCount, int count,
-            const float* positions, FontRenderer& fontRenderer, int alpha, SkXfermode::Mode mode,
+            const float* positions, FontRenderer& fontRenderer, int alpha,
             float x, float y);
 
     /**
@@ -849,11 +811,9 @@
     void setupDrawAlpha8Color(int color, int alpha);
     void setupDrawTextGamma(const SkPaint* paint);
     void setupDrawShader();
-    void setupDrawColorFilter();
-    void setupDrawBlending(SkXfermode::Mode mode = SkXfermode::kSrcOver_Mode,
-            bool swapSrcDst = false);
-    void setupDrawBlending(bool blend = true, SkXfermode::Mode mode = SkXfermode::kSrcOver_Mode,
-            bool swapSrcDst = false);
+    void setupDrawColorFilter(const SkColorFilter* filter);
+    void setupDrawBlending(const Layer* layer, bool swapSrcDst = false);
+    void setupDrawBlending(const SkPaint* paint, bool blend = true, bool swapSrcDst = false);
     void setupDrawProgram();
     void setupDrawDirtyRegionsDisabled();
 
@@ -877,7 +837,7 @@
     void setupDrawColorUniforms();
     void setupDrawPureColorUniforms();
     void setupDrawShaderUniforms(bool ignoreTransform = false);
-    void setupDrawColorFilterUniforms();
+    void setupDrawColorFilterUniforms(const SkColorFilter* paint);
     void setupDrawSimpleMesh();
     void setupDrawTexture(GLuint texture);
     void setupDrawExternalTexture(GLuint texture);
@@ -906,8 +866,7 @@
      * Renders the specified region as a series of rectangles. The region
      * must be in screen-space coordinates.
      */
-    void drawRegionRects(const SkRegion& region, int color, SkXfermode::Mode mode,
-            bool dirty = false);
+    void drawRegionRects(const SkRegion& region, const SkPaint& paint, bool dirty = false);
 
     /**
      * Draws the current clip region if any. Only when DEBUG_CLIP_REGIONS
diff --git a/libs/hwui/Program.h b/libs/hwui/Program.h
index 5dfb2fa..33c91b3 100644
--- a/libs/hwui/Program.h
+++ b/libs/hwui/Program.h
@@ -51,9 +51,8 @@
 #define PROGRAM_KEY_GRADIENT 0x8
 #define PROGRAM_KEY_BITMAP_FIRST 0x10
 #define PROGRAM_KEY_COLOR_MATRIX 0x20
-#define PROGRAM_KEY_COLOR_LIGHTING 0x40
-#define PROGRAM_KEY_COLOR_BLEND 0x80
-#define PROGRAM_KEY_BITMAP_NPOT 0x100
+#define PROGRAM_KEY_COLOR_BLEND 0x40
+#define PROGRAM_KEY_BITMAP_NPOT 0x80
 #define PROGRAM_KEY_SWAP_SRC_DST 0x2000
 
 #define PROGRAM_KEY_BITMAP_WRAPS_MASK 0x600
@@ -104,7 +103,6 @@
     enum ColorModifier {
         kColorNone = 0,
         kColorMatrix,
-        kColorLighting,
         kColorBlend
     };
 
@@ -248,9 +246,6 @@
             case kColorMatrix:
                 key |= PROGRAM_KEY_COLOR_MATRIX;
                 break;
-            case kColorLighting:
-                key |= PROGRAM_KEY_COLOR_LIGHTING;
-                break;
             case kColorBlend:
                 key |= PROGRAM_KEY_COLOR_BLEND;
                 key |= (colorMode & PROGRAM_MAX_XFERMODE) << PROGRAM_XFERMODE_COLOR_OP_SHIFT;
diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp
index a5ce6f6..6d50410 100644
--- a/libs/hwui/ProgramCache.cpp
+++ b/libs/hwui/ProgramCache.cpp
@@ -148,15 +148,12 @@
 };
 const char* gFS_Uniforms_BitmapSampler =
         "uniform sampler2D bitmapSampler;\n";
-const char* gFS_Uniforms_ColorOp[4] = {
+const char* gFS_Uniforms_ColorOp[3] = {
         // None
         "",
         // Matrix
         "uniform mat4 colorMatrix;\n"
         "uniform vec4 colorMatrixVector;\n",
-        // Lighting
-        "uniform vec4 lightingMul;\n"
-        "uniform vec4 lightingAdd;\n",
         // PorterDuff
         "uniform vec4 colorBlend;\n"
 };
@@ -311,17 +308,13 @@
         "    gl_FragColor = blendFramebuffer(fragColor, gl_LastFragColor);\n";
 const char* gFS_Main_FragColor_Blend_Swap =
         "    gl_FragColor = blendFramebuffer(gl_LastFragColor, fragColor);\n";
-const char* gFS_Main_ApplyColorOp[4] = {
+const char* gFS_Main_ApplyColorOp[3] = {
         // None
         "",
         // Matrix
         "    fragColor *= colorMatrix;\n"
         "    fragColor += colorMatrixVector;\n"
         "    fragColor.rgb *= fragColor.a;\n",
-        // Lighting
-        "    float lightingAlpha = fragColor.a;\n"
-        "    fragColor = min(fragColor * lightingMul + (lightingAdd * lightingAlpha), lightingAlpha);\n"
-        "    fragColor.a = lightingAlpha;\n",
         // PorterDuff
         "    fragColor = blendColors(colorBlend, fragColor);\n"
 };
diff --git a/libs/hwui/Renderer.h b/libs/hwui/Renderer.h
index 4799b32..4754bad 100644
--- a/libs/hwui/Renderer.h
+++ b/libs/hwui/Renderer.h
@@ -146,22 +146,15 @@
     virtual void restore() = 0;
     virtual void restoreToCount(int saveCount) = 0;
 
-    int saveLayer(float left, float top, float right, float bottom,
-            const SkPaint* paint, int flags) {
-        SkXfermode::Mode mode = SkXfermode::kSrcOver_Mode;
-        int alpha = 255;
-        if (paint) {
-            mode = getXfermode(paint->getXfermode());
-            alpha = paint->getAlpha();
-        }
-        return saveLayer(left, top, right, bottom, alpha, mode, flags);
-    }
+    virtual int saveLayer(float left, float top, float right, float bottom,
+            const SkPaint* paint, int flags) = 0;
+
     int saveLayerAlpha(float left, float top, float right, float bottom,
             int alpha, int flags) {
-        return saveLayer(left, top, right, bottom, alpha, SkXfermode::kSrcOver_Mode, flags);
+        SkPaint paint;
+        paint.setAlpha(alpha);
+        return saveLayer(left, top, right, bottom, &paint, flags);
     }
-    virtual int saveLayer(float left, float top, float right, float bottom,
-            int alpha, SkXfermode::Mode mode, int flags) = 0;
 
     // Matrix
     virtual void getMatrix(SkMatrix* outMatrix) const = 0;
@@ -185,9 +178,6 @@
     virtual void resetShader() = 0;
     virtual void setupShader(SkiaShader* shader) = 0;
 
-    virtual void resetColorFilter() = 0;
-    virtual void setupColorFilter(SkiaColorFilter* filter) = 0;
-
     virtual void resetShadow() = 0;
     virtual void setupShadow(float radius, float dx, float dy, int color) = 0;
 
diff --git a/libs/hwui/ResourceCache.cpp b/libs/hwui/ResourceCache.cpp
index e58857c..457cfa9 100644
--- a/libs/hwui/ResourceCache.cpp
+++ b/libs/hwui/ResourceCache.cpp
@@ -76,11 +76,6 @@
     incrementRefcount((void*) shaderResource, kShader);
 }
 
-void ResourceCache::incrementRefcount(SkiaColorFilter* filterResource) {
-    SkSafeRef(filterResource->getSkColorFilter());
-    incrementRefcount((void*) filterResource, kColorFilter);
-}
-
 void ResourceCache::incrementRefcount(const Res_png_9patch* patchResource) {
     incrementRefcount((void*) patchResource, kNinePatch);
 }
@@ -114,11 +109,6 @@
     incrementRefcountLocked((void*) shaderResource, kShader);
 }
 
-void ResourceCache::incrementRefcountLocked(SkiaColorFilter* filterResource) {
-    SkSafeRef(filterResource->getSkColorFilter());
-    incrementRefcountLocked((void*) filterResource, kColorFilter);
-}
-
 void ResourceCache::incrementRefcountLocked(const Res_png_9patch* patchResource) {
     incrementRefcountLocked((void*) patchResource, kNinePatch);
 }
@@ -147,11 +137,6 @@
     decrementRefcount((void*) shaderResource);
 }
 
-void ResourceCache::decrementRefcount(SkiaColorFilter* filterResource) {
-    SkSafeUnref(filterResource->getSkColorFilter());
-    decrementRefcount((void*) filterResource);
-}
-
 void ResourceCache::decrementRefcount(const Res_png_9patch* patchResource) {
     decrementRefcount((void*) patchResource);
 }
@@ -188,11 +173,6 @@
     decrementRefcountLocked((void*) shaderResource);
 }
 
-void ResourceCache::decrementRefcountLocked(SkiaColorFilter* filterResource) {
-    SkSafeUnref(filterResource->getSkColorFilter());
-    decrementRefcountLocked((void*) filterResource);
-}
-
 void ResourceCache::decrementRefcountLocked(const Res_png_9patch* patchResource) {
     decrementRefcountLocked((void*) patchResource);
 }
@@ -264,25 +244,6 @@
     }
 }
 
-void ResourceCache::destructor(SkiaColorFilter* resource) {
-    Mutex::Autolock _l(mLock);
-    destructorLocked(resource);
-}
-
-void ResourceCache::destructorLocked(SkiaColorFilter* resource) {
-    ssize_t index = mCache->indexOfKey(resource);
-    ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL;
-    if (ref == NULL) {
-        // If we're not tracking this resource, just delete it
-        delete resource;
-        return;
-    }
-    ref->destroyed = true;
-    if (ref->refCount == 0) {
-        deleteResourceReferenceLocked(resource, ref);
-    }
-}
-
 void ResourceCache::destructor(Res_png_9patch* resource) {
     Mutex::Autolock _l(mLock);
     destructorLocked(resource);
@@ -372,11 +333,6 @@
                 delete shader;
             }
             break;
-            case kColorFilter: {
-                SkiaColorFilter* filter = (SkiaColorFilter*) resource;
-                delete filter;
-            }
-            break;
             case kNinePatch: {
                 if (Caches::hasInstance()) {
                     Caches::getInstance().patchCache.removeDeferred((Res_png_9patch*) resource);
diff --git a/libs/hwui/ResourceCache.h b/libs/hwui/ResourceCache.h
index c06b09b..4097ba4 100644
--- a/libs/hwui/ResourceCache.h
+++ b/libs/hwui/ResourceCache.h
@@ -20,7 +20,6 @@
 #include <cutils/compiler.h>
 
 #include <SkBitmap.h>
-#include <SkiaColorFilter.h>
 #include <SkiaShader.h>
 
 #include <utils/KeyedVector.h>
@@ -38,7 +37,6 @@
 enum ResourceType {
     kBitmap,
     kShader,
-    kColorFilter,
     kNinePatch,
     kPath,
     kLayer
@@ -73,41 +71,35 @@
     void incrementRefcount(const SkPath* resource);
     void incrementRefcount(const SkBitmap* resource);
     void incrementRefcount(SkiaShader* resource);
-    void incrementRefcount(SkiaColorFilter* resource);
     void incrementRefcount(const Res_png_9patch* resource);
     void incrementRefcount(Layer* resource);
 
     void incrementRefcountLocked(const SkPath* resource);
     void incrementRefcountLocked(const SkBitmap* resource);
     void incrementRefcountLocked(SkiaShader* resource);
-    void incrementRefcountLocked(SkiaColorFilter* resource);
     void incrementRefcountLocked(const Res_png_9patch* resource);
     void incrementRefcountLocked(Layer* resource);
 
     void decrementRefcount(const SkBitmap* resource);
     void decrementRefcount(const SkPath* resource);
     void decrementRefcount(SkiaShader* resource);
-    void decrementRefcount(SkiaColorFilter* resource);
     void decrementRefcount(const Res_png_9patch* resource);
     void decrementRefcount(Layer* resource);
 
     void decrementRefcountLocked(const SkBitmap* resource);
     void decrementRefcountLocked(const SkPath* resource);
     void decrementRefcountLocked(SkiaShader* resource);
-    void decrementRefcountLocked(SkiaColorFilter* resource);
     void decrementRefcountLocked(const Res_png_9patch* resource);
     void decrementRefcountLocked(Layer* resource);
 
     void destructor(SkPath* resource);
     void destructor(const SkBitmap* resource);
     void destructor(SkiaShader* resource);
-    void destructor(SkiaColorFilter* resource);
     void destructor(Res_png_9patch* resource);
 
     void destructorLocked(SkPath* resource);
     void destructorLocked(const SkBitmap* resource);
     void destructorLocked(SkiaShader* resource);
-    void destructorLocked(SkiaColorFilter* resource);
     void destructorLocked(Res_png_9patch* resource);
 
     bool recycle(SkBitmap* resource);
diff --git a/libs/hwui/SkiaColorFilter.cpp b/libs/hwui/SkiaColorFilter.cpp
deleted file mode 100644
index df918be..0000000
--- a/libs/hwui/SkiaColorFilter.cpp
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "SkiaColorFilter.h"
-
-namespace android {
-namespace uirenderer {
-
-///////////////////////////////////////////////////////////////////////////////
-// Base color filter
-///////////////////////////////////////////////////////////////////////////////
-
-SkiaColorFilter::SkiaColorFilter(SkColorFilter *skFilter, Type type, bool blend):
-        mType(type), mBlend(blend), mSkFilter(skFilter) {
-}
-
-SkiaColorFilter::~SkiaColorFilter() {
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Color matrix filter
-///////////////////////////////////////////////////////////////////////////////
-
-SkiaColorMatrixFilter::SkiaColorMatrixFilter(SkColorFilter* skFilter, float* matrix, float* vector):
-        SkiaColorFilter(skFilter, kColorMatrix, true), mMatrix(matrix), mVector(vector) {
-    // Skia uses the range [0..255] for the addition vector, but we need
-    // the [0..1] range to apply the vector in GLSL
-    for (int i = 0; i < 4; i++) {
-        mVector[i] /= 255.0f;
-    }
-
-    // TODO: We should be smarter about this
-    mBlend = true;
-}
-
-SkiaColorMatrixFilter::~SkiaColorMatrixFilter() {
-    delete[] mMatrix;
-    delete[] mVector;
-}
-
-void SkiaColorMatrixFilter::describe(ProgramDescription& description,
-        const Extensions& extensions) {
-    description.colorOp = ProgramDescription::kColorMatrix;
-}
-
-void SkiaColorMatrixFilter::setupProgram(Program* program) {
-    glUniformMatrix4fv(program->getUniform("colorMatrix"), 1, GL_FALSE, &mMatrix[0]);
-    glUniform4fv(program->getUniform("colorMatrixVector"), 1, mVector);
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Lighting color filter
-///////////////////////////////////////////////////////////////////////////////
-
-SkiaLightingFilter::SkiaLightingFilter(SkColorFilter* skFilter, int multiply, int add):
-        SkiaColorFilter(skFilter, kLighting, true) {
-    mMulR = ((multiply >> 16) & 0xFF) / 255.0f;
-    mMulG = ((multiply >>  8) & 0xFF) / 255.0f;
-    mMulB = ((multiply      ) & 0xFF) / 255.0f;
-
-    mAddR = ((add >> 16) & 0xFF) / 255.0f;
-    mAddG = ((add >>  8) & 0xFF) / 255.0f;
-    mAddB = ((add      ) & 0xFF) / 255.0f;
-
-    // A lighting filter always ignores alpha
-    mBlend = false;
-}
-
-void SkiaLightingFilter::describe(ProgramDescription& description, const Extensions& extensions) {
-    description.colorOp = ProgramDescription::kColorLighting;
-}
-
-void SkiaLightingFilter::setupProgram(Program* program) {
-    glUniform4f(program->getUniform("lightingMul"), mMulR, mMulG, mMulB, 1.0f);
-    glUniform4f(program->getUniform("lightingAdd"), mAddR, mAddG, mAddB, 0.0f);
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Blend color filter
-///////////////////////////////////////////////////////////////////////////////
-
-SkiaBlendFilter::SkiaBlendFilter(SkColorFilter* skFilter, int color, SkXfermode::Mode mode):
-        SkiaColorFilter(skFilter, kBlend, true), mMode(mode) {
-    const int alpha = (color >> 24) & 0xFF;
-    mA = alpha / 255.0f;
-    mR = mA * ((color >> 16) & 0xFF) / 255.0f;
-    mG = mA * ((color >>  8) & 0xFF) / 255.0f;
-    mB = mA * ((color      ) & 0xFF) / 255.0f;
-
-    // TODO: We should do something smarter here
-    mBlend = true;
-}
-
-void SkiaBlendFilter::describe(ProgramDescription& description, const Extensions& extensions) {
-    description.colorOp = ProgramDescription::kColorBlend;
-    description.colorMode = mMode;
-}
-
-void SkiaBlendFilter::setupProgram(Program* program) {
-    glUniform4f(program->getUniform("colorBlend"), mR, mG, mB, mA);
-}
-
-}; // namespace uirenderer
-}; // namespace android
diff --git a/libs/hwui/SkiaColorFilter.h b/libs/hwui/SkiaColorFilter.h
deleted file mode 100644
index c222a2d..0000000
--- a/libs/hwui/SkiaColorFilter.h
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HWUI_SKIA_COLOR_FILTER_H
-#define ANDROID_HWUI_SKIA_COLOR_FILTER_H
-
-#include <GLES2/gl2.h>
-#include <SkColorFilter.h>
-
-#include <cutils/compiler.h>
-
-#include "ProgramCache.h"
-#include "Extensions.h"
-
-namespace android {
-namespace uirenderer {
-
-///////////////////////////////////////////////////////////////////////////////
-// Base color filter
-///////////////////////////////////////////////////////////////////////////////
-
-/**
- * Represents a Skia color filter. A color filter modifies a ProgramDescription
- * and sets uniforms on the resulting shaders.
- */
-class SkiaColorFilter {
-public:
-    /**
-     * Type of Skia color filter in use.
-     */
-    enum Type {
-        kNone,
-        kColorMatrix,
-        kLighting,
-        kBlend,
-    };
-
-    ANDROID_API SkiaColorFilter(SkColorFilter *skFilter, Type type, bool blend);
-    virtual ~SkiaColorFilter();
-
-    virtual void describe(ProgramDescription& description, const Extensions& extensions) = 0;
-    virtual void setupProgram(Program* program) = 0;
-
-    inline bool blend() const {
-        return mBlend;
-    }
-
-    Type type() const {
-        return mType;
-    }
-
-    SkColorFilter* getSkColorFilter() {
-        return mSkFilter;
-    }
-
-protected:
-    Type mType;
-    bool mBlend;
-
-private:
-    SkColorFilter *mSkFilter;
-}; // struct SkiaColorFilter
-
-///////////////////////////////////////////////////////////////////////////////
-// Implementations
-///////////////////////////////////////////////////////////////////////////////
-
-/**
- * A color filter that multiplies the source color with a matrix and adds a vector.
- */
-class SkiaColorMatrixFilter: public SkiaColorFilter {
-public:
-    ANDROID_API SkiaColorMatrixFilter(SkColorFilter *skFilter, float* matrix, float* vector);
-    ~SkiaColorMatrixFilter();
-
-    void describe(ProgramDescription& description, const Extensions& extensions);
-    void setupProgram(Program* program);
-
-private:
-    float* mMatrix;
-    float* mVector;
-}; // struct SkiaColorMatrixFilter
-
-/**
- * A color filters that multiplies the source color with a fixed value and adds
- * another fixed value. Ignores the alpha channel of both arguments.
- */
-class SkiaLightingFilter: public SkiaColorFilter {
-public:
-    ANDROID_API SkiaLightingFilter(SkColorFilter *skFilter, int multiply, int add);
-
-    void describe(ProgramDescription& description, const Extensions& extensions);
-    void setupProgram(Program* program);
-
-private:
-    GLfloat mMulR, mMulG, mMulB;
-    GLfloat mAddR, mAddG, mAddB;
-}; // struct SkiaLightingFilter
-
-/**
- * A color filters that blends the source color with a specified destination color
- * and PorterDuff blending mode.
- */
-class SkiaBlendFilter: public SkiaColorFilter {
-public:
-    ANDROID_API SkiaBlendFilter(SkColorFilter *skFilter, int color, SkXfermode::Mode mode);
-
-    void describe(ProgramDescription& description, const Extensions& extensions);
-    void setupProgram(Program* program);
-
-private:
-    SkXfermode::Mode mMode;
-    GLfloat mR, mG, mB, mA;
-}; // struct SkiaBlendFilter
-
-}; // namespace uirenderer
-}; // namespace android
-
-#endif // ANDROID_HWUI_SKIA_COLOR_FILTER_H
diff --git a/libs/hwui/Snapshot.cpp b/libs/hwui/Snapshot.cpp
index a6ec183..d26ee38 100644
--- a/libs/hwui/Snapshot.cpp
+++ b/libs/hwui/Snapshot.cpp
@@ -70,10 +70,6 @@
     } else {
         region = NULL;
     }
-
-    if (saveFlags & Snapshot::kFlagProjectionTarget) {
-        flags |= Snapshot::kFlagProjectionTarget;
-    }
 }
 
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/Snapshot.h b/libs/hwui/Snapshot.h
index d61d972..cc6d0cd 100644
--- a/libs/hwui/Snapshot.h
+++ b/libs/hwui/Snapshot.h
@@ -75,13 +75,7 @@
          * Indicates that this snapshot or an ancestor snapshot is
          * an FBO layer.
          */
-        kFlagFboTarget = 0x10,
-        /**
-         * Indicates that the save/restore pair encapsulates a
-         * projection target, and that after the restore any projected
-         * descendents should be drawn.
-         */
-        kFlagProjectionTarget = 0x20
+        kFlagFboTarget = 0x10
     };
 
     /**
diff --git a/libs/hwui/font/Font.cpp b/libs/hwui/font/Font.cpp
index b0945c6..5187f8f 100644
--- a/libs/hwui/font/Font.cpp
+++ b/libs/hwui/font/Font.cpp
@@ -405,10 +405,10 @@
         // If it's still not valid, we couldn't cache it, so we shouldn't
         // draw garbage; also skip empty glyphs (spaces)
         if (cachedGlyph->mIsValid && cachedGlyph->mCacheTexture) {
-            float penX = x + positions[(glyphsCount << 1)];
-            float penY = y + positions[(glyphsCount << 1) + 1];
+            int penX = x + (int) roundf(positions[(glyphsCount << 1)]);
+            int penY = y + (int) roundf(positions[(glyphsCount << 1) + 1]);
 
-            (*this.*render)(cachedGlyph, roundf(penX), roundf(penY),
+            (*this.*render)(cachedGlyph, penX, penY,
                     bitmap, bitmapW, bitmapH, bounds, positions);
         }
 
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index a848c8f..4e665d9 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -462,6 +462,16 @@
     mRenderThread.queueDelayed(&mInvokeFunctorsTask, delayMs);
 }
 
+void CanvasContext::runWithGlContext(RenderTask* task) {
+    if (mEglSurface != EGL_NO_SURFACE) {
+        mGlobalContext->makeCurrent(mEglSurface);
+    } else {
+        mGlobalContext->usePBufferSurface();
+    }
+
+    task->run();
+}
+
 } /* namespace renderthread */
 } /* namespace uirenderer */
 } /* namespace android */
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 2daa905..3197df3 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -65,6 +65,8 @@
     void attachFunctor(Functor* functor);
     void detachFunctor(Functor* functor);
 
+    void runWithGlContext(RenderTask* task);
+
 private:
     void setSurface(EGLNativeWindowType window);
     void swapBuffers();
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 25badac..34f1961 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -170,6 +170,18 @@
     post(task);
 }
 
+CREATE_BRIDGE2(runWithGlContext, CanvasContext* context, RenderTask* task) {
+    args->context->runWithGlContext(args->task);
+    return NULL;
+}
+
+void RenderProxy::runWithGlContext(RenderTask* gltask) {
+    SETUP_TASK(runWithGlContext);
+    args->context = mContext;
+    args->task = gltask;
+    postAndWait(task);
+}
+
 MethodInvokeRenderTask* RenderProxy::createTask(RunnableMethod method) {
     // TODO: Consider having a small pool of these to avoid alloc churn
     return new MethodInvokeRenderTask(method);
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index 113c5a8..1ad0c2d 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -62,6 +62,8 @@
     ANDROID_API void attachFunctor(Functor* functor);
     ANDROID_API void detachFunctor(Functor* functor);
 
+    ANDROID_API void runWithGlContext(RenderTask* task);
+
 private:
     RenderThread& mRenderThread;
     CanvasContext* mContext;
diff --git a/libs/hwui/utils/TinyHashMap.h b/libs/hwui/utils/TinyHashMap.h
index 8855140..4ff9a42 100644
--- a/libs/hwui/utils/TinyHashMap.h
+++ b/libs/hwui/utils/TinyHashMap.h
@@ -24,8 +24,6 @@
 
 /**
  * A very simple hash map that doesn't allow duplicate keys, overwriting the older entry.
- *
- * Currently, expects simple keys that are handled by hash_t()
  */
 template <typename TKey, typename TValue>
 class TinyHashMap {
@@ -36,7 +34,7 @@
      * Puts an entry in the hash, removing any existing entry with the same key
      */
     void put(TKey key, TValue value) {
-        hash_t hash = hash_t(key);
+        hash_t hash = android::hash_type(key);
 
         ssize_t index = mTable.find(-1, hash, key);
         if (index != -1) {
@@ -51,7 +49,7 @@
      * Return true if key is in the map, in which case stores the value in the output ref
      */
     bool get(TKey key, TValue& outValue) {
-        hash_t hash = hash_t(key);
+        hash_t hash = android::hash_type(key);
         ssize_t index = mTable.find(-1, hash, key);
         if (index == -1) {
             return false;
diff --git a/libs/input/Android.mk b/libs/input/Android.mk
index eb2bebe..6011ff0 100644
--- a/libs/input/Android.mk
+++ b/libs/input/Android.mk
@@ -17,30 +17,23 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:= \
-    EventHub.cpp \
-    InputApplication.cpp \
-    InputDispatcher.cpp \
-    InputListener.cpp \
-    InputManager.cpp \
-    InputReader.cpp \
-    InputWindow.cpp \
     PointerController.cpp \
     SpriteController.cpp
 
 LOCAL_SHARED_LIBRARIES := \
     libcutils \
     liblog \
-    libandroidfw \
     libutils \
-    libhardware \
-    libhardware_legacy \
     libskia \
     libgui \
     libui \
-    libinput
+	libinput \
+	libinputflinger
 
 LOCAL_C_INCLUDES := \
-    external/skia/include/core
+    external/skia/include/core \
+    frameworks/native/services
+
 
 LOCAL_CFLAGS += -Wno-unused-parameter
 
diff --git a/libs/input/EventHub.cpp b/libs/input/EventHub.cpp
deleted file mode 100644
index e2efd17..0000000
--- a/libs/input/EventHub.cpp
+++ /dev/null
@@ -1,1669 +0,0 @@
-/*
- * Copyright (C) 2005 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 "EventHub"
-
-// #define LOG_NDEBUG 0
-
-#include "EventHub.h"
-
-#include <hardware_legacy/power.h>
-
-#include <cutils/properties.h>
-#include <utils/Log.h>
-#include <utils/Timers.h>
-#include <utils/threads.h>
-#include <utils/Errors.h>
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <memory.h>
-#include <errno.h>
-#include <assert.h>
-
-#include <input/KeyLayoutMap.h>
-#include <input/KeyCharacterMap.h>
-#include <input/VirtualKeyMap.h>
-
-#include <string.h>
-#include <stdint.h>
-#include <dirent.h>
-
-#include <sys/inotify.h>
-#include <sys/epoll.h>
-#include <sys/ioctl.h>
-#include <sys/limits.h>
-#include <sys/sha1.h>
-#include <sys/utsname.h>
-
-/* this macro is used to tell if "bit" is set in "array"
- * it selects a byte from the array, and does a boolean AND
- * operation with a byte that only has the relevant bit set.
- * eg. to check for the 12th bit, we do (array[1] & 1<<4)
- */
-#define test_bit(bit, array)    (array[bit/8] & (1<<(bit%8)))
-
-/* this macro computes the number of bytes needed to represent a bit array of the specified size */
-#define sizeof_bit_array(bits)  ((bits + 7) / 8)
-
-#define INDENT "  "
-#define INDENT2 "    "
-#define INDENT3 "      "
-
-namespace android {
-
-static const char *WAKE_LOCK_ID = "KeyEvents";
-static const char *DEVICE_PATH = "/dev/input";
-
-/* return the larger integer */
-static inline int max(int v1, int v2)
-{
-    return (v1 > v2) ? v1 : v2;
-}
-
-static inline const char* toString(bool value) {
-    return value ? "true" : "false";
-}
-
-static String8 sha1(const String8& in) {
-    SHA1_CTX ctx;
-    SHA1Init(&ctx);
-    SHA1Update(&ctx, reinterpret_cast<const u_char*>(in.string()), in.size());
-    u_char digest[SHA1_DIGEST_LENGTH];
-    SHA1Final(digest, &ctx);
-
-    String8 out;
-    for (size_t i = 0; i < SHA1_DIGEST_LENGTH; i++) {
-        out.appendFormat("%02x", digest[i]);
-    }
-    return out;
-}
-
-static void getLinuxRelease(int* major, int* minor) {
-    struct utsname info;
-    if (uname(&info) || sscanf(info.release, "%d.%d", major, minor) <= 0) {
-        *major = 0, *minor = 0;
-        ALOGE("Could not get linux version: %s", strerror(errno));
-    }
-}
-
-// --- Global Functions ---
-
-uint32_t getAbsAxisUsage(int32_t axis, uint32_t deviceClasses) {
-    // Touch devices get dibs on touch-related axes.
-    if (deviceClasses & INPUT_DEVICE_CLASS_TOUCH) {
-        switch (axis) {
-        case ABS_X:
-        case ABS_Y:
-        case ABS_PRESSURE:
-        case ABS_TOOL_WIDTH:
-        case ABS_DISTANCE:
-        case ABS_TILT_X:
-        case ABS_TILT_Y:
-        case ABS_MT_SLOT:
-        case ABS_MT_TOUCH_MAJOR:
-        case ABS_MT_TOUCH_MINOR:
-        case ABS_MT_WIDTH_MAJOR:
-        case ABS_MT_WIDTH_MINOR:
-        case ABS_MT_ORIENTATION:
-        case ABS_MT_POSITION_X:
-        case ABS_MT_POSITION_Y:
-        case ABS_MT_TOOL_TYPE:
-        case ABS_MT_BLOB_ID:
-        case ABS_MT_TRACKING_ID:
-        case ABS_MT_PRESSURE:
-        case ABS_MT_DISTANCE:
-            return INPUT_DEVICE_CLASS_TOUCH;
-        }
-    }
-
-    // Joystick devices get the rest.
-    return deviceClasses & INPUT_DEVICE_CLASS_JOYSTICK;
-}
-
-// --- EventHub::Device ---
-
-EventHub::Device::Device(int fd, int32_t id, const String8& path,
-        const InputDeviceIdentifier& identifier) :
-        next(NULL),
-        fd(fd), id(id), path(path), identifier(identifier),
-        classes(0), configuration(NULL), virtualKeyMap(NULL),
-        ffEffectPlaying(false), ffEffectId(-1), controllerNumber(0),
-        timestampOverrideSec(0), timestampOverrideUsec(0) {
-    memset(keyBitmask, 0, sizeof(keyBitmask));
-    memset(absBitmask, 0, sizeof(absBitmask));
-    memset(relBitmask, 0, sizeof(relBitmask));
-    memset(swBitmask, 0, sizeof(swBitmask));
-    memset(ledBitmask, 0, sizeof(ledBitmask));
-    memset(ffBitmask, 0, sizeof(ffBitmask));
-    memset(propBitmask, 0, sizeof(propBitmask));
-}
-
-EventHub::Device::~Device() {
-    close();
-    delete configuration;
-    delete virtualKeyMap;
-}
-
-void EventHub::Device::close() {
-    if (fd >= 0) {
-        ::close(fd);
-        fd = -1;
-    }
-}
-
-
-// --- EventHub ---
-
-const uint32_t EventHub::EPOLL_ID_INOTIFY;
-const uint32_t EventHub::EPOLL_ID_WAKE;
-const int EventHub::EPOLL_SIZE_HINT;
-const int EventHub::EPOLL_MAX_EVENTS;
-
-EventHub::EventHub(void) :
-        mBuiltInKeyboardId(NO_BUILT_IN_KEYBOARD), mNextDeviceId(1), mControllerNumbers(),
-        mOpeningDevices(0), mClosingDevices(0),
-        mNeedToSendFinishedDeviceScan(false),
-        mNeedToReopenDevices(false), mNeedToScanDevices(true),
-        mPendingEventCount(0), mPendingEventIndex(0), mPendingINotify(false) {
-    acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
-
-    mEpollFd = epoll_create(EPOLL_SIZE_HINT);
-    LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance.  errno=%d", errno);
-
-    mINotifyFd = inotify_init();
-    int result = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE);
-    LOG_ALWAYS_FATAL_IF(result < 0, "Could not register INotify for %s.  errno=%d",
-            DEVICE_PATH, errno);
-
-    struct epoll_event eventItem;
-    memset(&eventItem, 0, sizeof(eventItem));
-    eventItem.events = EPOLLIN;
-    eventItem.data.u32 = EPOLL_ID_INOTIFY;
-    result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mINotifyFd, &eventItem);
-    LOG_ALWAYS_FATAL_IF(result != 0, "Could not add INotify to epoll instance.  errno=%d", errno);
-
-    int wakeFds[2];
-    result = pipe(wakeFds);
-    LOG_ALWAYS_FATAL_IF(result != 0, "Could not create wake pipe.  errno=%d", errno);
-
-    mWakeReadPipeFd = wakeFds[0];
-    mWakeWritePipeFd = wakeFds[1];
-
-    result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK);
-    LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake read pipe non-blocking.  errno=%d",
-            errno);
-
-    result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK);
-    LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake write pipe non-blocking.  errno=%d",
-            errno);
-
-    eventItem.data.u32 = EPOLL_ID_WAKE;
-    result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, &eventItem);
-    LOG_ALWAYS_FATAL_IF(result != 0, "Could not add wake read pipe to epoll instance.  errno=%d",
-            errno);
-
-    int major, minor;
-    getLinuxRelease(&major, &minor);
-    // EPOLLWAKEUP was introduced in kernel 3.5
-    mUsingEpollWakeup = major > 3 || (major == 3 && minor >= 5);
-}
-
-EventHub::~EventHub(void) {
-    closeAllDevicesLocked();
-
-    while (mClosingDevices) {
-        Device* device = mClosingDevices;
-        mClosingDevices = device->next;
-        delete device;
-    }
-
-    ::close(mEpollFd);
-    ::close(mINotifyFd);
-    ::close(mWakeReadPipeFd);
-    ::close(mWakeWritePipeFd);
-
-    release_wake_lock(WAKE_LOCK_ID);
-}
-
-InputDeviceIdentifier EventHub::getDeviceIdentifier(int32_t deviceId) const {
-    AutoMutex _l(mLock);
-    Device* device = getDeviceLocked(deviceId);
-    if (device == NULL) return InputDeviceIdentifier();
-    return device->identifier;
-}
-
-uint32_t EventHub::getDeviceClasses(int32_t deviceId) const {
-    AutoMutex _l(mLock);
-    Device* device = getDeviceLocked(deviceId);
-    if (device == NULL) return 0;
-    return device->classes;
-}
-
-int32_t EventHub::getDeviceControllerNumber(int32_t deviceId) const {
-    AutoMutex _l(mLock);
-    Device* device = getDeviceLocked(deviceId);
-    if (device == NULL) return 0;
-    return device->controllerNumber;
-}
-
-void EventHub::getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) const {
-    AutoMutex _l(mLock);
-    Device* device = getDeviceLocked(deviceId);
-    if (device && device->configuration) {
-        *outConfiguration = *device->configuration;
-    } else {
-        outConfiguration->clear();
-    }
-}
-
-status_t EventHub::getAbsoluteAxisInfo(int32_t deviceId, int axis,
-        RawAbsoluteAxisInfo* outAxisInfo) const {
-    outAxisInfo->clear();
-
-    if (axis >= 0 && axis <= ABS_MAX) {
-        AutoMutex _l(mLock);
-
-        Device* device = getDeviceLocked(deviceId);
-        if (device && !device->isVirtual() && test_bit(axis, device->absBitmask)) {
-            struct input_absinfo info;
-            if(ioctl(device->fd, EVIOCGABS(axis), &info)) {
-                ALOGW("Error reading absolute controller %d for device %s fd %d, errno=%d",
-                     axis, device->identifier.name.string(), device->fd, errno);
-                return -errno;
-            }
-
-            if (info.minimum != info.maximum) {
-                outAxisInfo->valid = true;
-                outAxisInfo->minValue = info.minimum;
-                outAxisInfo->maxValue = info.maximum;
-                outAxisInfo->flat = info.flat;
-                outAxisInfo->fuzz = info.fuzz;
-                outAxisInfo->resolution = info.resolution;
-            }
-            return OK;
-        }
-    }
-    return -1;
-}
-
-bool EventHub::hasRelativeAxis(int32_t deviceId, int axis) const {
-    if (axis >= 0 && axis <= REL_MAX) {
-        AutoMutex _l(mLock);
-
-        Device* device = getDeviceLocked(deviceId);
-        if (device) {
-            return test_bit(axis, device->relBitmask);
-        }
-    }
-    return false;
-}
-
-bool EventHub::hasInputProperty(int32_t deviceId, int property) const {
-    if (property >= 0 && property <= INPUT_PROP_MAX) {
-        AutoMutex _l(mLock);
-
-        Device* device = getDeviceLocked(deviceId);
-        if (device) {
-            return test_bit(property, device->propBitmask);
-        }
-    }
-    return false;
-}
-
-int32_t EventHub::getScanCodeState(int32_t deviceId, int32_t scanCode) const {
-    if (scanCode >= 0 && scanCode <= KEY_MAX) {
-        AutoMutex _l(mLock);
-
-        Device* device = getDeviceLocked(deviceId);
-        if (device && !device->isVirtual() && test_bit(scanCode, device->keyBitmask)) {
-            uint8_t keyState[sizeof_bit_array(KEY_MAX + 1)];
-            memset(keyState, 0, sizeof(keyState));
-            if (ioctl(device->fd, EVIOCGKEY(sizeof(keyState)), keyState) >= 0) {
-                return test_bit(scanCode, keyState) ? AKEY_STATE_DOWN : AKEY_STATE_UP;
-            }
-        }
-    }
-    return AKEY_STATE_UNKNOWN;
-}
-
-int32_t EventHub::getKeyCodeState(int32_t deviceId, int32_t keyCode) const {
-    AutoMutex _l(mLock);
-
-    Device* device = getDeviceLocked(deviceId);
-    if (device && !device->isVirtual() && device->keyMap.haveKeyLayout()) {
-        Vector<int32_t> scanCodes;
-        device->keyMap.keyLayoutMap->findScanCodesForKey(keyCode, &scanCodes);
-        if (scanCodes.size() != 0) {
-            uint8_t keyState[sizeof_bit_array(KEY_MAX + 1)];
-            memset(keyState, 0, sizeof(keyState));
-            if (ioctl(device->fd, EVIOCGKEY(sizeof(keyState)), keyState) >= 0) {
-                for (size_t i = 0; i < scanCodes.size(); i++) {
-                    int32_t sc = scanCodes.itemAt(i);
-                    if (sc >= 0 && sc <= KEY_MAX && test_bit(sc, keyState)) {
-                        return AKEY_STATE_DOWN;
-                    }
-                }
-                return AKEY_STATE_UP;
-            }
-        }
-    }
-    return AKEY_STATE_UNKNOWN;
-}
-
-int32_t EventHub::getSwitchState(int32_t deviceId, int32_t sw) const {
-    if (sw >= 0 && sw <= SW_MAX) {
-        AutoMutex _l(mLock);
-
-        Device* device = getDeviceLocked(deviceId);
-        if (device && !device->isVirtual() && test_bit(sw, device->swBitmask)) {
-            uint8_t swState[sizeof_bit_array(SW_MAX + 1)];
-            memset(swState, 0, sizeof(swState));
-            if (ioctl(device->fd, EVIOCGSW(sizeof(swState)), swState) >= 0) {
-                return test_bit(sw, swState) ? AKEY_STATE_DOWN : AKEY_STATE_UP;
-            }
-        }
-    }
-    return AKEY_STATE_UNKNOWN;
-}
-
-status_t EventHub::getAbsoluteAxisValue(int32_t deviceId, int32_t axis, int32_t* outValue) const {
-    *outValue = 0;
-
-    if (axis >= 0 && axis <= ABS_MAX) {
-        AutoMutex _l(mLock);
-
-        Device* device = getDeviceLocked(deviceId);
-        if (device && !device->isVirtual() && test_bit(axis, device->absBitmask)) {
-            struct input_absinfo info;
-            if(ioctl(device->fd, EVIOCGABS(axis), &info)) {
-                ALOGW("Error reading absolute controller %d for device %s fd %d, errno=%d",
-                     axis, device->identifier.name.string(), device->fd, errno);
-                return -errno;
-            }
-
-            *outValue = info.value;
-            return OK;
-        }
-    }
-    return -1;
-}
-
-bool EventHub::markSupportedKeyCodes(int32_t deviceId, size_t numCodes,
-        const int32_t* keyCodes, uint8_t* outFlags) const {
-    AutoMutex _l(mLock);
-
-    Device* device = getDeviceLocked(deviceId);
-    if (device && device->keyMap.haveKeyLayout()) {
-        Vector<int32_t> scanCodes;
-        for (size_t codeIndex = 0; codeIndex < numCodes; codeIndex++) {
-            scanCodes.clear();
-
-            status_t err = device->keyMap.keyLayoutMap->findScanCodesForKey(
-                    keyCodes[codeIndex], &scanCodes);
-            if (! err) {
-                // check the possible scan codes identified by the layout map against the
-                // map of codes actually emitted by the driver
-                for (size_t sc = 0; sc < scanCodes.size(); sc++) {
-                    if (test_bit(scanCodes[sc], device->keyBitmask)) {
-                        outFlags[codeIndex] = 1;
-                        break;
-                    }
-                }
-            }
-        }
-        return true;
-    }
-    return false;
-}
-
-status_t EventHub::mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode,
-        int32_t* outKeycode, uint32_t* outFlags) const {
-    AutoMutex _l(mLock);
-    Device* device = getDeviceLocked(deviceId);
-
-    if (device) {
-        // Check the key character map first.
-        sp<KeyCharacterMap> kcm = device->getKeyCharacterMap();
-        if (kcm != NULL) {
-            if (!kcm->mapKey(scanCode, usageCode, outKeycode)) {
-                *outFlags = 0;
-                return NO_ERROR;
-            }
-        }
-
-        // Check the key layout next.
-        if (device->keyMap.haveKeyLayout()) {
-            if (!device->keyMap.keyLayoutMap->mapKey(
-                    scanCode, usageCode, outKeycode, outFlags)) {
-                return NO_ERROR;
-            }
-        }
-    }
-
-    *outKeycode = 0;
-    *outFlags = 0;
-    return NAME_NOT_FOUND;
-}
-
-status_t EventHub::mapAxis(int32_t deviceId, int32_t scanCode, AxisInfo* outAxisInfo) const {
-    AutoMutex _l(mLock);
-    Device* device = getDeviceLocked(deviceId);
-
-    if (device && device->keyMap.haveKeyLayout()) {
-        status_t err = device->keyMap.keyLayoutMap->mapAxis(scanCode, outAxisInfo);
-        if (err == NO_ERROR) {
-            return NO_ERROR;
-        }
-    }
-
-    return NAME_NOT_FOUND;
-}
-
-void EventHub::setExcludedDevices(const Vector<String8>& devices) {
-    AutoMutex _l(mLock);
-
-    mExcludedDevices = devices;
-}
-
-bool EventHub::hasScanCode(int32_t deviceId, int32_t scanCode) const {
-    AutoMutex _l(mLock);
-    Device* device = getDeviceLocked(deviceId);
-    if (device && scanCode >= 0 && scanCode <= KEY_MAX) {
-        if (test_bit(scanCode, device->keyBitmask)) {
-            return true;
-        }
-    }
-    return false;
-}
-
-bool EventHub::hasLed(int32_t deviceId, int32_t led) const {
-    AutoMutex _l(mLock);
-    Device* device = getDeviceLocked(deviceId);
-    int32_t sc;
-    if (device && mapLed(device, led, &sc) == NO_ERROR) {
-        if (test_bit(sc, device->ledBitmask)) {
-            return true;
-        }
-    }
-    return false;
-}
-
-void EventHub::setLedState(int32_t deviceId, int32_t led, bool on) {
-    AutoMutex _l(mLock);
-    Device* device = getDeviceLocked(deviceId);
-    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 = sc;
-        ev.value = on ? 1 : 0;
-
-        ssize_t nWrite;
-        do {
-            nWrite = write(device->fd, &ev, sizeof(struct input_event));
-        } while (nWrite == -1 && errno == EINTR);
-    }
-}
-
-void EventHub::getVirtualKeyDefinitions(int32_t deviceId,
-        Vector<VirtualKeyDefinition>& outVirtualKeys) const {
-    outVirtualKeys.clear();
-
-    AutoMutex _l(mLock);
-    Device* device = getDeviceLocked(deviceId);
-    if (device && device->virtualKeyMap) {
-        outVirtualKeys.appendVector(device->virtualKeyMap->getVirtualKeys());
-    }
-}
-
-sp<KeyCharacterMap> EventHub::getKeyCharacterMap(int32_t deviceId) const {
-    AutoMutex _l(mLock);
-    Device* device = getDeviceLocked(deviceId);
-    if (device) {
-        return device->getKeyCharacterMap();
-    }
-    return NULL;
-}
-
-bool EventHub::setKeyboardLayoutOverlay(int32_t deviceId,
-        const sp<KeyCharacterMap>& map) {
-    AutoMutex _l(mLock);
-    Device* device = getDeviceLocked(deviceId);
-    if (device) {
-        if (map != device->overlayKeyMap) {
-            device->overlayKeyMap = map;
-            device->combinedKeyMap = KeyCharacterMap::combine(
-                    device->keyMap.keyCharacterMap, map);
-            return true;
-        }
-    }
-    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);
-    if (device && !device->isVirtual()) {
-        ff_effect effect;
-        memset(&effect, 0, sizeof(effect));
-        effect.type = FF_RUMBLE;
-        effect.id = device->ffEffectId;
-        effect.u.rumble.strong_magnitude = 0xc000;
-        effect.u.rumble.weak_magnitude = 0xc000;
-        effect.replay.length = (duration + 999999LL) / 1000000LL;
-        effect.replay.delay = 0;
-        if (ioctl(device->fd, EVIOCSFF, &effect)) {
-            ALOGW("Could not upload force feedback effect to device %s due to error %d.",
-                    device->identifier.name.string(), errno);
-            return;
-        }
-        device->ffEffectId = effect.id;
-
-        struct input_event ev;
-        ev.time.tv_sec = 0;
-        ev.time.tv_usec = 0;
-        ev.type = EV_FF;
-        ev.code = device->ffEffectId;
-        ev.value = 1;
-        if (write(device->fd, &ev, sizeof(ev)) != sizeof(ev)) {
-            ALOGW("Could not start force feedback effect on device %s due to error %d.",
-                    device->identifier.name.string(), errno);
-            return;
-        }
-        device->ffEffectPlaying = true;
-    }
-}
-
-void EventHub::cancelVibrate(int32_t deviceId) {
-    AutoMutex _l(mLock);
-    Device* device = getDeviceLocked(deviceId);
-    if (device && !device->isVirtual()) {
-        if (device->ffEffectPlaying) {
-            device->ffEffectPlaying = false;
-
-            struct input_event ev;
-            ev.time.tv_sec = 0;
-            ev.time.tv_usec = 0;
-            ev.type = EV_FF;
-            ev.code = device->ffEffectId;
-            ev.value = 0;
-            if (write(device->fd, &ev, sizeof(ev)) != sizeof(ev)) {
-                ALOGW("Could not stop force feedback effect on device %s due to error %d.",
-                        device->identifier.name.string(), errno);
-                return;
-            }
-        }
-    }
-}
-
-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;
-    }
-    ssize_t index = mDevices.indexOfKey(deviceId);
-    return index >= 0 ? mDevices.valueAt(index) : NULL;
-}
-
-EventHub::Device* EventHub::getDeviceByPathLocked(const char* devicePath) const {
-    for (size_t i = 0; i < mDevices.size(); i++) {
-        Device* device = mDevices.valueAt(i);
-        if (device->path == devicePath) {
-            return device;
-        }
-    }
-    return NULL;
-}
-
-size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
-    ALOG_ASSERT(bufferSize >= 1);
-
-    AutoMutex _l(mLock);
-
-    struct input_event readBuffer[bufferSize];
-
-    RawEvent* event = buffer;
-    size_t capacity = bufferSize;
-    bool awoken = false;
-    for (;;) {
-        nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
-
-        // Reopen input devices if needed.
-        if (mNeedToReopenDevices) {
-            mNeedToReopenDevices = false;
-
-            ALOGI("Reopening all input devices due to a configuration change.");
-
-            closeAllDevicesLocked();
-            mNeedToScanDevices = true;
-            break; // return to the caller before we actually rescan
-        }
-
-        // Report any devices that had last been added/removed.
-        while (mClosingDevices) {
-            Device* device = mClosingDevices;
-            ALOGV("Reporting device closed: id=%d, name=%s\n",
-                 device->id, device->path.string());
-            mClosingDevices = device->next;
-            event->when = now;
-            event->deviceId = device->id == mBuiltInKeyboardId ? BUILT_IN_KEYBOARD_ID : device->id;
-            event->type = DEVICE_REMOVED;
-            event += 1;
-            delete device;
-            mNeedToSendFinishedDeviceScan = true;
-            if (--capacity == 0) {
-                break;
-            }
-        }
-
-        if (mNeedToScanDevices) {
-            mNeedToScanDevices = false;
-            scanDevicesLocked();
-            mNeedToSendFinishedDeviceScan = true;
-        }
-
-        while (mOpeningDevices != NULL) {
-            Device* device = mOpeningDevices;
-            ALOGV("Reporting device opened: id=%d, name=%s\n",
-                 device->id, device->path.string());
-            mOpeningDevices = device->next;
-            event->when = now;
-            event->deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;
-            event->type = DEVICE_ADDED;
-            event += 1;
-            mNeedToSendFinishedDeviceScan = true;
-            if (--capacity == 0) {
-                break;
-            }
-        }
-
-        if (mNeedToSendFinishedDeviceScan) {
-            mNeedToSendFinishedDeviceScan = false;
-            event->when = now;
-            event->type = FINISHED_DEVICE_SCAN;
-            event += 1;
-            if (--capacity == 0) {
-                break;
-            }
-        }
-
-        // Grab the next input event.
-        bool deviceChanged = false;
-        while (mPendingEventIndex < mPendingEventCount) {
-            const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++];
-            if (eventItem.data.u32 == EPOLL_ID_INOTIFY) {
-                if (eventItem.events & EPOLLIN) {
-                    mPendingINotify = true;
-                } else {
-                    ALOGW("Received unexpected epoll event 0x%08x for INotify.", eventItem.events);
-                }
-                continue;
-            }
-
-            if (eventItem.data.u32 == EPOLL_ID_WAKE) {
-                if (eventItem.events & EPOLLIN) {
-                    ALOGV("awoken after wake()");
-                    awoken = true;
-                    char buffer[16];
-                    ssize_t nRead;
-                    do {
-                        nRead = read(mWakeReadPipeFd, buffer, sizeof(buffer));
-                    } while ((nRead == -1 && errno == EINTR) || nRead == sizeof(buffer));
-                } else {
-                    ALOGW("Received unexpected epoll event 0x%08x for wake read pipe.",
-                            eventItem.events);
-                }
-                continue;
-            }
-
-            ssize_t deviceIndex = mDevices.indexOfKey(eventItem.data.u32);
-            if (deviceIndex < 0) {
-                ALOGW("Received unexpected epoll event 0x%08x for unknown device id %d.",
-                        eventItem.events, eventItem.data.u32);
-                continue;
-            }
-
-            Device* device = mDevices.valueAt(deviceIndex);
-            if (eventItem.events & EPOLLIN) {
-                int32_t readSize = read(device->fd, readBuffer,
-                        sizeof(struct input_event) * capacity);
-                if (readSize == 0 || (readSize < 0 && errno == ENODEV)) {
-                    // Device was removed before INotify noticed.
-                    ALOGW("could not get event, removed? (fd: %d size: %d bufferSize: %d "
-                            "capacity: %d errno: %d)\n",
-                            device->fd, readSize, bufferSize, capacity, errno);
-                    deviceChanged = true;
-                    closeDeviceLocked(device);
-                } else if (readSize < 0) {
-                    if (errno != EAGAIN && errno != EINTR) {
-                        ALOGW("could not get event (errno=%d)", errno);
-                    }
-                } else if ((readSize % sizeof(struct input_event)) != 0) {
-                    ALOGE("could not get event (wrong size: %d)", readSize);
-                } else {
-                    int32_t deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;
-
-                    size_t count = size_t(readSize) / sizeof(struct input_event);
-                    for (size_t i = 0; i < count; i++) {
-                        struct input_event& iev = readBuffer[i];
-                        ALOGV("%s got: time=%d.%06d, type=%d, code=%d, value=%d",
-                                device->path.string(),
-                                (int) iev.time.tv_sec, (int) iev.time.tv_usec,
-                                iev.type, iev.code, iev.value);
-
-                        // Some input devices may have a better concept of the time
-                        // when an input event was actually generated than the kernel
-                        // which simply timestamps all events on entry to evdev.
-                        // This is a custom Android extension of the input protocol
-                        // mainly intended for use with uinput based device drivers.
-                        if (iev.type == EV_MSC) {
-                            if (iev.code == MSC_ANDROID_TIME_SEC) {
-                                device->timestampOverrideSec = iev.value;
-                                continue;
-                            } else if (iev.code == MSC_ANDROID_TIME_USEC) {
-                                device->timestampOverrideUsec = iev.value;
-                                continue;
-                            }
-                        }
-                        if (device->timestampOverrideSec || device->timestampOverrideUsec) {
-                            iev.time.tv_sec = device->timestampOverrideSec;
-                            iev.time.tv_usec = device->timestampOverrideUsec;
-                            if (iev.type == EV_SYN && iev.code == SYN_REPORT) {
-                                device->timestampOverrideSec = 0;
-                                device->timestampOverrideUsec = 0;
-                            }
-                            ALOGV("applied override time %d.%06d",
-                                    int(iev.time.tv_sec), int(iev.time.tv_usec));
-                        }
-
-#ifdef HAVE_POSIX_CLOCKS
-                        // Use the time specified in the event instead of the current time
-                        // so that downstream code can get more accurate estimates of
-                        // event dispatch latency from the time the event is enqueued onto
-                        // the evdev client buffer.
-                        //
-                        // The event's timestamp fortuitously uses the same monotonic clock
-                        // time base as the rest of Android.  The kernel event device driver
-                        // (drivers/input/evdev.c) obtains timestamps using ktime_get_ts().
-                        // The systemTime(SYSTEM_TIME_MONOTONIC) function we use everywhere
-                        // calls clock_gettime(CLOCK_MONOTONIC) which is implemented as a
-                        // system call that also queries ktime_get_ts().
-                        event->when = nsecs_t(iev.time.tv_sec) * 1000000000LL
-                                + nsecs_t(iev.time.tv_usec) * 1000LL;
-                        ALOGV("event time %lld, now %lld", event->when, now);
-
-                        // Bug 7291243: Add a guard in case the kernel generates timestamps
-                        // that appear to be far into the future because they were generated
-                        // using the wrong clock source.
-                        //
-                        // This can happen because when the input device is initially opened
-                        // it has a default clock source of CLOCK_REALTIME.  Any input events
-                        // enqueued right after the device is opened will have timestamps
-                        // generated using CLOCK_REALTIME.  We later set the clock source
-                        // to CLOCK_MONOTONIC but it is already too late.
-                        //
-                        // Invalid input event timestamps can result in ANRs, crashes and
-                        // and other issues that are hard to track down.  We must not let them
-                        // propagate through the system.
-                        //
-                        // Log a warning so that we notice the problem and recover gracefully.
-                        if (event->when >= now + 10 * 1000000000LL) {
-                            // Double-check.  Time may have moved on.
-                            nsecs_t time = systemTime(SYSTEM_TIME_MONOTONIC);
-                            if (event->when > time) {
-                                ALOGW("An input event from %s has a timestamp that appears to "
-                                        "have been generated using the wrong clock source "
-                                        "(expected CLOCK_MONOTONIC): "
-                                        "event time %lld, current time %lld, call time %lld.  "
-                                        "Using current time instead.",
-                                        device->path.string(), event->when, time, now);
-                                event->when = time;
-                            } else {
-                                ALOGV("Event time is ok but failed the fast path and required "
-                                        "an extra call to systemTime: "
-                                        "event time %lld, current time %lld, call time %lld.",
-                                        event->when, time, now);
-                            }
-                        }
-#else
-                        event->when = now;
-#endif
-                        event->deviceId = deviceId;
-                        event->type = iev.type;
-                        event->code = iev.code;
-                        event->value = iev.value;
-                        event += 1;
-                        capacity -= 1;
-                    }
-                    if (capacity == 0) {
-                        // The result buffer is full.  Reset the pending event index
-                        // so we will try to read the device again on the next iteration.
-                        mPendingEventIndex -= 1;
-                        break;
-                    }
-                }
-            } else if (eventItem.events & EPOLLHUP) {
-                ALOGI("Removing device %s due to epoll hang-up event.",
-                        device->identifier.name.string());
-                deviceChanged = true;
-                closeDeviceLocked(device);
-            } else {
-                ALOGW("Received unexpected epoll event 0x%08x for device %s.",
-                        eventItem.events, device->identifier.name.string());
-            }
-        }
-
-        // readNotify() will modify the list of devices so this must be done after
-        // processing all other events to ensure that we read all remaining events
-        // before closing the devices.
-        if (mPendingINotify && mPendingEventIndex >= mPendingEventCount) {
-            mPendingINotify = false;
-            readNotifyLocked();
-            deviceChanged = true;
-        }
-
-        // Report added or removed devices immediately.
-        if (deviceChanged) {
-            continue;
-        }
-
-        // Return now if we have collected any events or if we were explicitly awoken.
-        if (event != buffer || awoken) {
-            break;
-        }
-
-        // Poll for events.  Mind the wake lock dance!
-        // We hold a wake lock at all times except during epoll_wait().  This works due to some
-        // subtle choreography.  When a device driver has pending (unread) events, it acquires
-        // a kernel wake lock.  However, once the last pending event has been read, the device
-        // driver will release the kernel wake lock.  To prevent the system from going to sleep
-        // when this happens, the EventHub holds onto its own user wake lock while the client
-        // is processing events.  Thus the system can only sleep if there are no events
-        // pending or currently being processed.
-        //
-        // The timeout is advisory only.  If the device is asleep, it will not wake just to
-        // service the timeout.
-        mPendingEventIndex = 0;
-
-        mLock.unlock(); // release lock before poll, must be before release_wake_lock
-        release_wake_lock(WAKE_LOCK_ID);
-
-        int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis);
-
-        acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
-        mLock.lock(); // reacquire lock after poll, must be after acquire_wake_lock
-
-        if (pollResult == 0) {
-            // Timed out.
-            mPendingEventCount = 0;
-            break;
-        }
-
-        if (pollResult < 0) {
-            // An error occurred.
-            mPendingEventCount = 0;
-
-            // Sleep after errors to avoid locking up the system.
-            // Hopefully the error is transient.
-            if (errno != EINTR) {
-                ALOGW("poll failed (errno=%d)\n", errno);
-                usleep(100000);
-            }
-        } else {
-            // Some events occurred.
-            mPendingEventCount = size_t(pollResult);
-        }
-    }
-
-    // All done, return the number of events we read.
-    return event - buffer;
-}
-
-void EventHub::wake() {
-    ALOGV("wake() called");
-
-    ssize_t nWrite;
-    do {
-        nWrite = write(mWakeWritePipeFd, "W", 1);
-    } while (nWrite == -1 && errno == EINTR);
-
-    if (nWrite != 1 && errno != EAGAIN) {
-        ALOGW("Could not write wake signal, errno=%d", errno);
-    }
-}
-
-void EventHub::scanDevicesLocked() {
-    status_t res = scanDirLocked(DEVICE_PATH);
-    if(res < 0) {
-        ALOGE("scan dir failed for %s\n", DEVICE_PATH);
-    }
-    if (mDevices.indexOfKey(VIRTUAL_KEYBOARD_ID) < 0) {
-        createVirtualKeyboardLocked();
-    }
-}
-
-// ----------------------------------------------------------------------------
-
-static bool containsNonZeroByte(const uint8_t* array, uint32_t startIndex, uint32_t endIndex) {
-    const uint8_t* end = array + endIndex;
-    array += startIndex;
-    while (array != end) {
-        if (*(array++) != 0) {
-            return true;
-        }
-    }
-    return false;
-}
-
-static const int32_t GAMEPAD_KEYCODES[] = {
-        AKEYCODE_BUTTON_A, AKEYCODE_BUTTON_B, AKEYCODE_BUTTON_C,
-        AKEYCODE_BUTTON_X, AKEYCODE_BUTTON_Y, AKEYCODE_BUTTON_Z,
-        AKEYCODE_BUTTON_L1, AKEYCODE_BUTTON_R1,
-        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) {
-    char buffer[80];
-
-    ALOGV("Opening device: %s", devicePath);
-
-    int fd = open(devicePath, O_RDWR | O_CLOEXEC);
-    if(fd < 0) {
-        ALOGE("could not open %s, %s\n", devicePath, strerror(errno));
-        return -1;
-    }
-
-    InputDeviceIdentifier identifier;
-
-    // Get device name.
-    if(ioctl(fd, EVIOCGNAME(sizeof(buffer) - 1), &buffer) < 1) {
-        //fprintf(stderr, "could not get device name for %s, %s\n", devicePath, strerror(errno));
-    } else {
-        buffer[sizeof(buffer) - 1] = '\0';
-        identifier.name.setTo(buffer);
-    }
-
-    // Check to see if the device is on our excluded list
-    for (size_t i = 0; i < mExcludedDevices.size(); i++) {
-        const String8& item = mExcludedDevices.itemAt(i);
-        if (identifier.name == item) {
-            ALOGI("ignoring event id %s driver %s\n", devicePath, item.string());
-            close(fd);
-            return -1;
-        }
-    }
-
-    // Get device driver version.
-    int driverVersion;
-    if(ioctl(fd, EVIOCGVERSION, &driverVersion)) {
-        ALOGE("could not get driver version for %s, %s\n", devicePath, strerror(errno));
-        close(fd);
-        return -1;
-    }
-
-    // Get device identifier.
-    struct input_id inputId;
-    if(ioctl(fd, EVIOCGID, &inputId)) {
-        ALOGE("could not get device input id for %s, %s\n", devicePath, strerror(errno));
-        close(fd);
-        return -1;
-    }
-    identifier.bus = inputId.bustype;
-    identifier.product = inputId.product;
-    identifier.vendor = inputId.vendor;
-    identifier.version = inputId.version;
-
-    // Get device physical location.
-    if(ioctl(fd, EVIOCGPHYS(sizeof(buffer) - 1), &buffer) < 1) {
-        //fprintf(stderr, "could not get location for %s, %s\n", devicePath, strerror(errno));
-    } else {
-        buffer[sizeof(buffer) - 1] = '\0';
-        identifier.location.setTo(buffer);
-    }
-
-    // Get device unique id.
-    if(ioctl(fd, EVIOCGUNIQ(sizeof(buffer) - 1), &buffer) < 1) {
-        //fprintf(stderr, "could not get idstring for %s, %s\n", devicePath, strerror(errno));
-    } else {
-        buffer[sizeof(buffer) - 1] = '\0';
-        identifier.uniqueId.setTo(buffer);
-    }
-
-    // Fill in the descriptor.
-    assignDescriptorLocked(identifier);
-
-    // Make file descriptor non-blocking for use with poll().
-    if (fcntl(fd, F_SETFL, O_NONBLOCK)) {
-        ALOGE("Error %d making device file descriptor non-blocking.", errno);
-        close(fd);
-        return -1;
-    }
-
-    // Allocate device.  (The device object takes ownership of the fd at this point.)
-    int32_t deviceId = mNextDeviceId++;
-    Device* device = new Device(fd, deviceId, String8(devicePath), identifier);
-
-    ALOGV("add device %d: %s\n", deviceId, devicePath);
-    ALOGV("  bus:        %04x\n"
-         "  vendor      %04x\n"
-         "  product     %04x\n"
-         "  version     %04x\n",
-        identifier.bus, identifier.vendor, identifier.product, identifier.version);
-    ALOGV("  name:       \"%s\"\n", identifier.name.string());
-    ALOGV("  location:   \"%s\"\n", identifier.location.string());
-    ALOGV("  unique id:  \"%s\"\n", identifier.uniqueId.string());
-    ALOGV("  descriptor: \"%s\"\n", identifier.descriptor.string());
-    ALOGV("  driver:     v%d.%d.%d\n",
-        driverVersion >> 16, (driverVersion >> 8) & 0xff, driverVersion & 0xff);
-
-    // Load the configuration file for the device.
-    loadConfigurationLocked(device);
-
-    // Figure out the kinds of events the device reports.
-    ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(device->keyBitmask)), device->keyBitmask);
-    ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(device->absBitmask)), device->absBitmask);
-    ioctl(fd, EVIOCGBIT(EV_REL, sizeof(device->relBitmask)), device->relBitmask);
-    ioctl(fd, EVIOCGBIT(EV_SW, sizeof(device->swBitmask)), device->swBitmask);
-    ioctl(fd, EVIOCGBIT(EV_LED, sizeof(device->ledBitmask)), device->ledBitmask);
-    ioctl(fd, EVIOCGBIT(EV_FF, sizeof(device->ffBitmask)), device->ffBitmask);
-    ioctl(fd, EVIOCGPROP(sizeof(device->propBitmask)), device->propBitmask);
-
-    // See if this is a keyboard.  Ignore everything in the button range except for
-    // joystick and gamepad buttons which are handled like keyboards for the most part.
-    bool haveKeyboardKeys = containsNonZeroByte(device->keyBitmask, 0, sizeof_bit_array(BTN_MISC))
-            || containsNonZeroByte(device->keyBitmask, sizeof_bit_array(KEY_OK),
-                    sizeof_bit_array(KEY_MAX + 1));
-    bool haveGamepadButtons = containsNonZeroByte(device->keyBitmask, sizeof_bit_array(BTN_MISC),
-                    sizeof_bit_array(BTN_MOUSE))
-            || containsNonZeroByte(device->keyBitmask, sizeof_bit_array(BTN_JOYSTICK),
-                    sizeof_bit_array(BTN_DIGI));
-    if (haveKeyboardKeys || haveGamepadButtons) {
-        device->classes |= INPUT_DEVICE_CLASS_KEYBOARD;
-    }
-
-    // See if this is a cursor device such as a trackball or mouse.
-    if (test_bit(BTN_MOUSE, device->keyBitmask)
-            && test_bit(REL_X, device->relBitmask)
-            && test_bit(REL_Y, device->relBitmask)) {
-        device->classes |= INPUT_DEVICE_CLASS_CURSOR;
-    }
-
-    // See if this is a touch pad.
-    // Is this a new modern multi-touch driver?
-    if (test_bit(ABS_MT_POSITION_X, device->absBitmask)
-            && test_bit(ABS_MT_POSITION_Y, device->absBitmask)) {
-        // Some joysticks such as the PS3 controller report axes that conflict
-        // with the ABS_MT range.  Try to confirm that the device really is
-        // a touch screen.
-        if (test_bit(BTN_TOUCH, device->keyBitmask) || !haveGamepadButtons) {
-            device->classes |= INPUT_DEVICE_CLASS_TOUCH | INPUT_DEVICE_CLASS_TOUCH_MT;
-        }
-    // Is this an old style single-touch driver?
-    } else if (test_bit(BTN_TOUCH, device->keyBitmask)
-            && test_bit(ABS_X, device->absBitmask)
-            && test_bit(ABS_Y, device->absBitmask)) {
-        device->classes |= INPUT_DEVICE_CLASS_TOUCH;
-    }
-
-    // See if this device is a joystick.
-    // Assumes that joysticks always have gamepad buttons in order to distinguish them
-    // from other devices such as accelerometers that also have absolute axes.
-    if (haveGamepadButtons) {
-        uint32_t assumedClasses = device->classes | INPUT_DEVICE_CLASS_JOYSTICK;
-        for (int i = 0; i <= ABS_MAX; i++) {
-            if (test_bit(i, device->absBitmask)
-                    && (getAbsAxisUsage(i, assumedClasses) & INPUT_DEVICE_CLASS_JOYSTICK)) {
-                device->classes = assumedClasses;
-                break;
-            }
-        }
-    }
-
-    // Check whether this device has switches.
-    for (int i = 0; i <= SW_MAX; i++) {
-        if (test_bit(i, device->swBitmask)) {
-            device->classes |= INPUT_DEVICE_CLASS_SWITCH;
-            break;
-        }
-    }
-
-    // Check whether this device supports the vibrator.
-    if (test_bit(FF_RUMBLE, device->ffBitmask)) {
-        device->classes |= INPUT_DEVICE_CLASS_VIBRATOR;
-    }
-
-    // Configure virtual keys.
-    if ((device->classes & INPUT_DEVICE_CLASS_TOUCH)) {
-        // Load the virtual keys for the touch screen, if any.
-        // We do this now so that we can make sure to load the keymap if necessary.
-        status_t status = loadVirtualKeyMapLocked(device);
-        if (!status) {
-            device->classes |= INPUT_DEVICE_CLASS_KEYBOARD;
-        }
-    }
-
-    // Load the key map.
-    // We need to do this for joysticks too because the key layout may specify axes.
-    status_t keyMapStatus = NAME_NOT_FOUND;
-    if (device->classes & (INPUT_DEVICE_CLASS_KEYBOARD | INPUT_DEVICE_CLASS_JOYSTICK)) {
-        // Load the keymap for the device.
-        keyMapStatus = loadKeyMapLocked(device);
-    }
-
-    // Configure the keyboard, gamepad or virtual keyboard.
-    if (device->classes & INPUT_DEVICE_CLASS_KEYBOARD) {
-        // Register the keyboard as a built-in keyboard if it is eligible.
-        if (!keyMapStatus
-                && mBuiltInKeyboardId == NO_BUILT_IN_KEYBOARD
-                && isEligibleBuiltInKeyboard(device->identifier,
-                        device->configuration, &device->keyMap)) {
-            mBuiltInKeyboardId = device->id;
-        }
-
-        // 'Q' key support = cheap test of whether this is an alpha-capable kbd
-        if (hasKeycodeLocked(device, AKEYCODE_Q)) {
-            device->classes |= INPUT_DEVICE_CLASS_ALPHAKEY;
-        }
-
-        // See if this device has a DPAD.
-        if (hasKeycodeLocked(device, AKEYCODE_DPAD_UP) &&
-                hasKeycodeLocked(device, AKEYCODE_DPAD_DOWN) &&
-                hasKeycodeLocked(device, AKEYCODE_DPAD_LEFT) &&
-                hasKeycodeLocked(device, AKEYCODE_DPAD_RIGHT) &&
-                hasKeycodeLocked(device, AKEYCODE_DPAD_CENTER)) {
-            device->classes |= INPUT_DEVICE_CLASS_DPAD;
-        }
-
-        // See if this device has a gamepad.
-        for (size_t i = 0; i < sizeof(GAMEPAD_KEYCODES)/sizeof(GAMEPAD_KEYCODES[0]); i++) {
-            if (hasKeycodeLocked(device, GAMEPAD_KEYCODES[i])) {
-                device->classes |= INPUT_DEVICE_CLASS_GAMEPAD;
-                break;
-            }
-        }
-
-        // Disable kernel key repeat since we handle it ourselves
-        unsigned int repeatRate[] = {0,0};
-        if (ioctl(fd, EVIOCSREP, repeatRate)) {
-            ALOGW("Unable to disable kernel key repeat for %s: %s", devicePath, strerror(errno));
-        }
-    }
-
-    // If the device isn't recognized as something we handle, don't monitor it.
-    if (device->classes == 0) {
-        ALOGV("Dropping device: id=%d, path='%s', name='%s'",
-                deviceId, devicePath, device->identifier.name.string());
-        delete device;
-        return -1;
-    }
-
-    // Determine whether the device is external or internal.
-    if (isExternalDeviceLocked(device)) {
-        device->classes |= INPUT_DEVICE_CLASS_EXTERNAL;
-    }
-
-    if (device->classes & (INPUT_DEVICE_CLASS_JOYSTICK | INPUT_DEVICE_CLASS_GAMEPAD)) {
-        device->controllerNumber = getNextControllerNumberLocked(device);
-        setLedForController(device);
-    }
-
-    // Register with epoll.
-    struct epoll_event eventItem;
-    memset(&eventItem, 0, sizeof(eventItem));
-    eventItem.events = mUsingEpollWakeup ? EPOLLIN : EPOLLIN | EPOLLWAKEUP;
-    eventItem.data.u32 = deviceId;
-    if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, &eventItem)) {
-        ALOGE("Could not add device fd to epoll instance.  errno=%d", errno);
-        delete device;
-        return -1;
-    }
-
-    String8 wakeMechanism("EPOLLWAKEUP");
-    if (!mUsingEpollWakeup) {
-#ifndef EVIOCSSUSPENDBLOCK
-        // uapi headers don't include EVIOCSSUSPENDBLOCK, and future kernels
-        // will use an epoll flag instead, so as long as we want to support
-        // this feature, we need to be prepared to define the ioctl ourselves.
-#define EVIOCSSUSPENDBLOCK _IOW('E', 0x91, int)
-#endif
-        if (ioctl(fd, EVIOCSSUSPENDBLOCK, 1)) {
-            wakeMechanism = "<none>";
-        } else {
-            wakeMechanism = "EVIOCSSUSPENDBLOCK";
-        }
-    }
-
-    // Tell the kernel that we want to use the monotonic clock for reporting timestamps
-    // associated with input events.  This is important because the input system
-    // uses the timestamps extensively and assumes they were recorded using the monotonic
-    // clock.
-    //
-    // In older kernel, before Linux 3.4, there was no way to tell the kernel which
-    // clock to use to input event timestamps.  The standard kernel behavior was to
-    // record a real time timestamp, which isn't what we want.  Android kernels therefore
-    // contained a patch to the evdev_event() function in drivers/input/evdev.c to
-    // replace the call to do_gettimeofday() with ktime_get_ts() to cause the monotonic
-    // clock to be used instead of the real time clock.
-    //
-    // As of Linux 3.4, there is a new EVIOCSCLOCKID ioctl to set the desired clock.
-    // Therefore, we no longer require the Android-specific kernel patch described above
-    // as long as we make sure to set select the monotonic clock.  We do that here.
-    int clockId = CLOCK_MONOTONIC;
-    bool usingClockIoctl = !ioctl(fd, EVIOCSCLOCKID, &clockId);
-
-    ALOGI("New device: id=%d, fd=%d, path='%s', name='%s', classes=0x%x, "
-            "configuration='%s', keyLayout='%s', keyCharacterMap='%s', builtinKeyboard=%s, "
-            "wakeMechanism=%s, usingClockIoctl=%s",
-         deviceId, fd, devicePath, device->identifier.name.string(),
-         device->classes,
-         device->configurationFile.string(),
-         device->keyMap.keyLayoutFile.string(),
-         device->keyMap.keyCharacterMapFile.string(),
-         toString(mBuiltInKeyboardId == deviceId),
-         wakeMechanism.string(), toString(usingClockIoctl));
-
-    addDeviceLocked(device);
-    return 0;
-}
-
-void EventHub::createVirtualKeyboardLocked() {
-    InputDeviceIdentifier identifier;
-    identifier.name = "Virtual";
-    identifier.uniqueId = "<virtual>";
-    assignDescriptorLocked(identifier);
-
-    Device* device = new Device(-1, VIRTUAL_KEYBOARD_ID, String8("<virtual>"), identifier);
-    device->classes = INPUT_DEVICE_CLASS_KEYBOARD
-            | INPUT_DEVICE_CLASS_ALPHAKEY
-            | INPUT_DEVICE_CLASS_DPAD
-            | INPUT_DEVICE_CLASS_VIRTUAL;
-    loadKeyMapLocked(device);
-    addDeviceLocked(device);
-}
-
-void EventHub::addDeviceLocked(Device* device) {
-    mDevices.add(device->id, device);
-    device->next = mOpeningDevices;
-    mOpeningDevices = device;
-}
-
-void EventHub::loadConfigurationLocked(Device* device) {
-    device->configurationFile = getInputDeviceConfigurationFilePathByDeviceIdentifier(
-            device->identifier, INPUT_DEVICE_CONFIGURATION_FILE_TYPE_CONFIGURATION);
-    if (device->configurationFile.isEmpty()) {
-        ALOGD("No input device configuration file found for device '%s'.",
-                device->identifier.name.string());
-    } else {
-        status_t status = PropertyMap::load(device->configurationFile,
-                &device->configuration);
-        if (status) {
-            ALOGE("Error loading input device configuration file for device '%s'.  "
-                    "Using default configuration.",
-                    device->identifier.name.string());
-        }
-    }
-}
-
-status_t EventHub::loadVirtualKeyMapLocked(Device* device) {
-    // The virtual key map is supplied by the kernel as a system board property file.
-    String8 path;
-    path.append("/sys/board_properties/virtualkeys.");
-    path.append(device->identifier.name);
-    if (access(path.string(), R_OK)) {
-        return NAME_NOT_FOUND;
-    }
-    return VirtualKeyMap::load(path, &device->virtualKeyMap);
-}
-
-status_t EventHub::loadKeyMapLocked(Device* device) {
-    return device->keyMap.load(device->identifier, device->configuration);
-}
-
-bool EventHub::isExternalDeviceLocked(Device* device) {
-    if (device->configuration) {
-        bool value;
-        if (device->configuration->tryGetProperty(String8("device.internal"), value)) {
-            return !value;
-        }
-    }
-    return device->identifier.bus == BUS_USB || device->identifier.bus == BUS_BLUETOOTH;
-}
-
-int32_t EventHub::getNextControllerNumberLocked(Device* device) {
-    if (mControllerNumbers.isFull()) {
-        ALOGI("Maximum number of controllers reached, assigning controller number 0 to device %s",
-                device->identifier.name.string());
-        return 0;
-    }
-    // Since the controller number 0 is reserved for non-controllers, translate all numbers up by
-    // one
-    return static_cast<int32_t>(mControllerNumbers.markFirstUnmarkedBit() + 1);
-}
-
-void EventHub::releaseControllerNumberLocked(Device* device) {
-    int32_t num = device->controllerNumber;
-    device->controllerNumber= 0;
-    if (num == 0) {
-        return;
-    }
-    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) {
-        return false;
-    }
-    
-    Vector<int32_t> scanCodes;
-    device->keyMap.keyLayoutMap->findScanCodesForKey(keycode, &scanCodes);
-    const size_t N = scanCodes.size();
-    for (size_t i=0; i<N && i<=KEY_MAX; i++) {
-        int32_t sc = scanCodes.itemAt(i);
-        if (sc >= 0 && sc <= KEY_MAX && test_bit(sc, device->keyBitmask)) {
-            return true;
-        }
-    }
-    
-    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) {
-        closeDeviceLocked(device);
-        return 0;
-    }
-    ALOGV("Remove device: %s not found, device may already have been removed.", devicePath);
-    return -1;
-}
-
-void EventHub::closeAllDevicesLocked() {
-    while (mDevices.size() > 0) {
-        closeDeviceLocked(mDevices.valueAt(mDevices.size() - 1));
-    }
-}
-
-void EventHub::closeDeviceLocked(Device* device) {
-    ALOGI("Removed device: path=%s name=%s id=%d fd=%d classes=0x%x\n",
-         device->path.string(), device->identifier.name.string(), device->id,
-         device->fd, device->classes);
-
-    if (device->id == mBuiltInKeyboardId) {
-        ALOGW("built-in keyboard device %s (id=%d) is closing! the apps will not like this",
-                device->path.string(), mBuiltInKeyboardId);
-        mBuiltInKeyboardId = NO_BUILT_IN_KEYBOARD;
-    }
-
-    if (!device->isVirtual()) {
-        if (epoll_ctl(mEpollFd, EPOLL_CTL_DEL, device->fd, NULL)) {
-            ALOGW("Could not remove device fd from epoll instance.  errno=%d", errno);
-        }
-    }
-
-    releaseControllerNumberLocked(device);
-
-    mDevices.removeItem(device->id);
-    device->close();
-
-    // Unlink for opening devices list if it is present.
-    Device* pred = NULL;
-    bool found = false;
-    for (Device* entry = mOpeningDevices; entry != NULL; ) {
-        if (entry == device) {
-            found = true;
-            break;
-        }
-        pred = entry;
-        entry = entry->next;
-    }
-    if (found) {
-        // Unlink the device from the opening devices list then delete it.
-        // We don't need to tell the client that the device was closed because
-        // it does not even know it was opened in the first place.
-        ALOGI("Device %s was immediately closed after opening.", device->path.string());
-        if (pred) {
-            pred->next = device->next;
-        } else {
-            mOpeningDevices = device->next;
-        }
-        delete device;
-    } else {
-        // Link into closing devices list.
-        // The device will be deleted later after we have informed the client.
-        device->next = mClosingDevices;
-        mClosingDevices = device;
-    }
-}
-
-status_t EventHub::readNotifyLocked() {
-    int res;
-    char devname[PATH_MAX];
-    char *filename;
-    char event_buf[512];
-    int event_size;
-    int event_pos = 0;
-    struct inotify_event *event;
-
-    ALOGV("EventHub::readNotify nfd: %d\n", mINotifyFd);
-    res = read(mINotifyFd, event_buf, sizeof(event_buf));
-    if(res < (int)sizeof(*event)) {
-        if(errno == EINTR)
-            return 0;
-        ALOGW("could not get event, %s\n", strerror(errno));
-        return -1;
-    }
-    //printf("got %d bytes of event information\n", res);
-
-    strcpy(devname, DEVICE_PATH);
-    filename = devname + strlen(devname);
-    *filename++ = '/';
-
-    while(res >= (int)sizeof(*event)) {
-        event = (struct inotify_event *)(event_buf + event_pos);
-        //printf("%d: %08x \"%s\"\n", event->wd, event->mask, event->len ? event->name : "");
-        if(event->len) {
-            strcpy(filename, event->name);
-            if(event->mask & IN_CREATE) {
-                openDeviceLocked(devname);
-            } else {
-                ALOGI("Removing device '%s' due to inotify event\n", devname);
-                closeDeviceByPathLocked(devname);
-            }
-        }
-        event_size = sizeof(*event) + event->len;
-        res -= event_size;
-        event_pos += event_size;
-    }
-    return 0;
-}
-
-status_t EventHub::scanDirLocked(const char *dirname)
-{
-    char devname[PATH_MAX];
-    char *filename;
-    DIR *dir;
-    struct dirent *de;
-    dir = opendir(dirname);
-    if(dir == NULL)
-        return -1;
-    strcpy(devname, dirname);
-    filename = devname + strlen(devname);
-    *filename++ = '/';
-    while((de = readdir(dir))) {
-        if(de->d_name[0] == '.' &&
-           (de->d_name[1] == '\0' ||
-            (de->d_name[1] == '.' && de->d_name[2] == '\0')))
-            continue;
-        strcpy(filename, de->d_name);
-        openDeviceLocked(devname);
-    }
-    closedir(dir);
-    return 0;
-}
-
-void EventHub::requestReopenDevices() {
-    ALOGV("requestReopenDevices() called");
-
-    AutoMutex _l(mLock);
-    mNeedToReopenDevices = true;
-}
-
-void EventHub::dump(String8& dump) {
-    dump.append("Event Hub State:\n");
-
-    { // acquire lock
-        AutoMutex _l(mLock);
-
-        dump.appendFormat(INDENT "BuiltInKeyboardId: %d\n", mBuiltInKeyboardId);
-
-        dump.append(INDENT "Devices:\n");
-
-        for (size_t i = 0; i < mDevices.size(); i++) {
-            const Device* device = mDevices.valueAt(i);
-            if (mBuiltInKeyboardId == device->id) {
-                dump.appendFormat(INDENT2 "%d: %s (aka device 0 - built-in keyboard)\n",
-                        device->id, device->identifier.name.string());
-            } else {
-                dump.appendFormat(INDENT2 "%d: %s\n", device->id,
-                        device->identifier.name.string());
-            }
-            dump.appendFormat(INDENT3 "Classes: 0x%08x\n", device->classes);
-            dump.appendFormat(INDENT3 "Path: %s\n", device->path.string());
-            dump.appendFormat(INDENT3 "Descriptor: %s\n", device->identifier.descriptor.string());
-            dump.appendFormat(INDENT3 "Location: %s\n", device->identifier.location.string());
-            dump.appendFormat(INDENT3 "ControllerNumber: %d\n", device->controllerNumber);
-            dump.appendFormat(INDENT3 "UniqueId: %s\n", device->identifier.uniqueId.string());
-            dump.appendFormat(INDENT3 "Identifier: bus=0x%04x, vendor=0x%04x, "
-                    "product=0x%04x, version=0x%04x\n",
-                    device->identifier.bus, device->identifier.vendor,
-                    device->identifier.product, device->identifier.version);
-            dump.appendFormat(INDENT3 "KeyLayoutFile: %s\n",
-                    device->keyMap.keyLayoutFile.string());
-            dump.appendFormat(INDENT3 "KeyCharacterMapFile: %s\n",
-                    device->keyMap.keyCharacterMapFile.string());
-            dump.appendFormat(INDENT3 "ConfigurationFile: %s\n",
-                    device->configurationFile.string());
-            dump.appendFormat(INDENT3 "HaveKeyboardLayoutOverlay: %s\n",
-                    toString(device->overlayKeyMap != NULL));
-        }
-    } // release lock
-}
-
-void EventHub::monitor() {
-    // Acquire and release the lock to ensure that the event hub has not deadlocked.
-    mLock.lock();
-    mLock.unlock();
-}
-
-
-}; // namespace android
diff --git a/libs/input/EventHub.h b/libs/input/EventHub.h
deleted file mode 100644
index 20179ae..0000000
--- a/libs/input/EventHub.h
+++ /dev/null
@@ -1,457 +0,0 @@
-/*
- * Copyright (C) 2005 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//
-#ifndef _RUNTIME_EVENT_HUB_H
-#define _RUNTIME_EVENT_HUB_H
-
-#include <input/Input.h>
-#include <input/InputDevice.h>
-#include <input/Keyboard.h>
-#include <input/KeyLayoutMap.h>
-#include <input/KeyCharacterMap.h>
-#include <input/VirtualKeyMap.h>
-#include <utils/String8.h>
-#include <utils/threads.h>
-#include <utils/Log.h>
-#include <utils/threads.h>
-#include <utils/List.h>
-#include <utils/Errors.h>
-#include <utils/PropertyMap.h>
-#include <utils/Vector.h>
-#include <utils/KeyedVector.h>
-#include <utils/BitSet.h>
-
-#include <linux/input.h>
-#include <sys/epoll.h>
-
-/* Convenience constants. */
-
-#define BTN_FIRST 0x100  // first button code
-#define BTN_LAST 0x15f   // last button code
-
-/*
- * These constants are used privately in Android to pass raw timestamps
- * through evdev from uinput device drivers because there is currently no
- * other way to transfer this information.  The evdev driver automatically
- * timestamps all input events with the time they were posted and clobbers
- * whatever information was passed in.
- *
- * For the purposes of this hack, the timestamp is specified in the
- * CLOCK_MONOTONIC timebase and is split into two EV_MSC events specifying
- * seconds and microseconds.
- */
-#define MSC_ANDROID_TIME_SEC 0x6
-#define MSC_ANDROID_TIME_USEC 0x7
-
-namespace android {
-
-enum {
-    // Device id of a special "virtual" keyboard that is always present.
-    VIRTUAL_KEYBOARD_ID = -1,
-    // Device id of the "built-in" keyboard if there is one.
-    BUILT_IN_KEYBOARD_ID = 0,
-};
-
-/*
- * A raw event as retrieved from the EventHub.
- */
-struct RawEvent {
-    nsecs_t when;
-    int32_t deviceId;
-    int32_t type;
-    int32_t code;
-    int32_t value;
-};
-
-/* Describes an absolute axis. */
-struct RawAbsoluteAxisInfo {
-    bool valid; // true if the information is valid, false otherwise
-
-    int32_t minValue;  // minimum value
-    int32_t maxValue;  // maximum value
-    int32_t flat;      // center flat position, eg. flat == 8 means center is between -8 and 8
-    int32_t fuzz;      // error tolerance, eg. fuzz == 4 means value is +/- 4 due to noise
-    int32_t resolution; // resolution in units per mm or radians per mm
-
-    inline void clear() {
-        valid = false;
-        minValue = 0;
-        maxValue = 0;
-        flat = 0;
-        fuzz = 0;
-        resolution = 0;
-    }
-};
-
-/*
- * Input device classes.
- */
-enum {
-    /* The input device is a keyboard or has buttons. */
-    INPUT_DEVICE_CLASS_KEYBOARD      = 0x00000001,
-
-    /* The input device is an alpha-numeric keyboard (not just a dial pad). */
-    INPUT_DEVICE_CLASS_ALPHAKEY      = 0x00000002,
-
-    /* The input device is a touchscreen or a touchpad (either single-touch or multi-touch). */
-    INPUT_DEVICE_CLASS_TOUCH         = 0x00000004,
-
-    /* The input device is a cursor device such as a trackball or mouse. */
-    INPUT_DEVICE_CLASS_CURSOR        = 0x00000008,
-
-    /* The input device is a multi-touch touchscreen. */
-    INPUT_DEVICE_CLASS_TOUCH_MT      = 0x00000010,
-
-    /* The input device is a directional pad (implies keyboard, has DPAD keys). */
-    INPUT_DEVICE_CLASS_DPAD          = 0x00000020,
-
-    /* The input device is a gamepad (implies keyboard, has BUTTON keys). */
-    INPUT_DEVICE_CLASS_GAMEPAD       = 0x00000040,
-
-    /* The input device has switches. */
-    INPUT_DEVICE_CLASS_SWITCH        = 0x00000080,
-
-    /* The input device is a joystick (implies gamepad, has joystick absolute axes). */
-    INPUT_DEVICE_CLASS_JOYSTICK      = 0x00000100,
-
-    /* The input device has a vibrator (supports FF_RUMBLE). */
-    INPUT_DEVICE_CLASS_VIBRATOR      = 0x00000200,
-
-    /* The input device is virtual (not a real device, not part of UI configuration). */
-    INPUT_DEVICE_CLASS_VIRTUAL       = 0x40000000,
-
-    /* The input device is external (not built-in). */
-    INPUT_DEVICE_CLASS_EXTERNAL      = 0x80000000,
-};
-
-/*
- * Gets the class that owns an axis, in cases where multiple classes might claim
- * the same axis for different purposes.
- */
-extern uint32_t getAbsAxisUsage(int32_t axis, uint32_t deviceClasses);
-
-/*
- * Grand Central Station for events.
- *
- * The event hub aggregates input events received across all known input
- * devices on the system, including devices that may be emulated by the simulator
- * environment.  In addition, the event hub generates fake input events to indicate
- * when devices are added or removed.
- *
- * The event hub provides a stream of input events (via the getEvent function).
- * It also supports querying the current actual state of input devices such as identifying
- * which keys are currently down.  Finally, the event hub keeps track of the capabilities of
- * individual input devices, such as their class and the set of key codes that they support.
- */
-class EventHubInterface : public virtual RefBase {
-protected:
-    EventHubInterface() { }
-    virtual ~EventHubInterface() { }
-
-public:
-    // Synthetic raw event type codes produced when devices are added or removed.
-    enum {
-        // Sent when a device is added.
-        DEVICE_ADDED = 0x10000000,
-        // Sent when a device is removed.
-        DEVICE_REMOVED = 0x20000000,
-        // Sent when all added/removed devices from the most recent scan have been reported.
-        // This event is always sent at least once.
-        FINISHED_DEVICE_SCAN = 0x30000000,
-
-        FIRST_SYNTHETIC_EVENT = DEVICE_ADDED,
-    };
-
-    virtual uint32_t getDeviceClasses(int32_t deviceId) const = 0;
-
-    virtual InputDeviceIdentifier getDeviceIdentifier(int32_t deviceId) const = 0;
-
-    virtual int32_t getDeviceControllerNumber(int32_t deviceId) const = 0;
-
-    virtual void getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) const = 0;
-
-    virtual status_t getAbsoluteAxisInfo(int32_t deviceId, int axis,
-            RawAbsoluteAxisInfo* outAxisInfo) const = 0;
-
-    virtual bool hasRelativeAxis(int32_t deviceId, int axis) const = 0;
-
-    virtual bool hasInputProperty(int32_t deviceId, int property) const = 0;
-
-    virtual status_t mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode,
-            int32_t* outKeycode, uint32_t* outFlags) const = 0;
-
-    virtual status_t mapAxis(int32_t deviceId, int32_t scanCode,
-            AxisInfo* outAxisInfo) const = 0;
-
-    // Sets devices that are excluded from opening.
-    // This can be used to ignore input devices for sensors.
-    virtual void setExcludedDevices(const Vector<String8>& devices) = 0;
-
-    /*
-     * Wait for events to become available and returns them.
-     * After returning, the EventHub holds onto a wake lock until the next call to getEvent.
-     * This ensures that the device will not go to sleep while the event is being processed.
-     * If the device needs to remain awake longer than that, then the caller is responsible
-     * for taking care of it (say, by poking the power manager user activity timer).
-     *
-     * The timeout is advisory only.  If the device is asleep, it will not wake just to
-     * service the timeout.
-     *
-     * Returns the number of events obtained, or 0 if the timeout expired.
-     */
-    virtual size_t getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) = 0;
-
-    /*
-     * Query current input state.
-     */
-    virtual int32_t getScanCodeState(int32_t deviceId, int32_t scanCode) const = 0;
-    virtual int32_t getKeyCodeState(int32_t deviceId, int32_t keyCode) const = 0;
-    virtual int32_t getSwitchState(int32_t deviceId, int32_t sw) const = 0;
-    virtual status_t getAbsoluteAxisValue(int32_t deviceId, int32_t axis,
-            int32_t* outValue) const = 0;
-
-    /*
-     * Examine key input devices for specific framework keycode support
-     */
-    virtual bool markSupportedKeyCodes(int32_t deviceId, size_t numCodes, const int32_t* keyCodes,
-            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;
-
-    virtual void getVirtualKeyDefinitions(int32_t deviceId,
-            Vector<VirtualKeyDefinition>& outVirtualKeys) const = 0;
-
-    virtual sp<KeyCharacterMap> getKeyCharacterMap(int32_t deviceId) const = 0;
-    virtual bool setKeyboardLayoutOverlay(int32_t deviceId, const sp<KeyCharacterMap>& map) = 0;
-
-    /* Control the vibrator. */
-    virtual void vibrate(int32_t deviceId, nsecs_t duration) = 0;
-    virtual void cancelVibrate(int32_t deviceId) = 0;
-
-    /* Requests the EventHub to reopen all input devices on the next call to getEvents(). */
-    virtual void requestReopenDevices() = 0;
-
-    /* Wakes up getEvents() if it is blocked on a read. */
-    virtual void wake() = 0;
-
-    /* Dump EventHub state to a string. */
-    virtual void dump(String8& dump) = 0;
-
-    /* Called by the heatbeat to ensures that the reader has not deadlocked. */
-    virtual void monitor() = 0;
-};
-
-class EventHub : public EventHubInterface
-{
-public:
-    EventHub();
-
-    virtual uint32_t getDeviceClasses(int32_t deviceId) const;
-
-    virtual InputDeviceIdentifier getDeviceIdentifier(int32_t deviceId) const;
-
-    virtual int32_t getDeviceControllerNumber(int32_t deviceId) const;
-
-    virtual void getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) const;
-
-    virtual status_t getAbsoluteAxisInfo(int32_t deviceId, int axis,
-            RawAbsoluteAxisInfo* outAxisInfo) const;
-
-    virtual bool hasRelativeAxis(int32_t deviceId, int axis) const;
-
-    virtual bool hasInputProperty(int32_t deviceId, int property) const;
-
-    virtual status_t mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode,
-            int32_t* outKeycode, uint32_t* outFlags) const;
-
-    virtual status_t mapAxis(int32_t deviceId, int32_t scanCode,
-            AxisInfo* outAxisInfo) const;
-
-    virtual void setExcludedDevices(const Vector<String8>& devices);
-
-    virtual int32_t getScanCodeState(int32_t deviceId, int32_t scanCode) const;
-    virtual int32_t getKeyCodeState(int32_t deviceId, int32_t keyCode) const;
-    virtual int32_t getSwitchState(int32_t deviceId, int32_t sw) const;
-    virtual status_t getAbsoluteAxisValue(int32_t deviceId, int32_t axis, int32_t* outValue) const;
-
-    virtual bool markSupportedKeyCodes(int32_t deviceId, size_t numCodes,
-            const int32_t* keyCodes, uint8_t* outFlags) const;
-
-    virtual size_t getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize);
-
-    virtual bool hasScanCode(int32_t deviceId, int32_t scanCode) const;
-    virtual bool hasLed(int32_t deviceId, int32_t led) const;
-    virtual void setLedState(int32_t deviceId, int32_t led, bool on);
-
-    virtual void getVirtualKeyDefinitions(int32_t deviceId,
-            Vector<VirtualKeyDefinition>& outVirtualKeys) const;
-
-    virtual sp<KeyCharacterMap> getKeyCharacterMap(int32_t deviceId) const;
-    virtual bool setKeyboardLayoutOverlay(int32_t deviceId, const sp<KeyCharacterMap>& map);
-
-    virtual void vibrate(int32_t deviceId, nsecs_t duration);
-    virtual void cancelVibrate(int32_t deviceId);
-
-    virtual void requestReopenDevices();
-
-    virtual void wake();
-
-    virtual void dump(String8& dump);
-    virtual void monitor();
-
-protected:
-    virtual ~EventHub();
-
-private:
-    struct Device {
-        Device* next;
-
-        int fd; // may be -1 if device is virtual
-        const int32_t id;
-        const String8 path;
-        const InputDeviceIdentifier identifier;
-
-        uint32_t classes;
-
-        uint8_t keyBitmask[(KEY_MAX + 1) / 8];
-        uint8_t absBitmask[(ABS_MAX + 1) / 8];
-        uint8_t relBitmask[(REL_MAX + 1) / 8];
-        uint8_t swBitmask[(SW_MAX + 1) / 8];
-        uint8_t ledBitmask[(LED_MAX + 1) / 8];
-        uint8_t ffBitmask[(FF_MAX + 1) / 8];
-        uint8_t propBitmask[(INPUT_PROP_MAX + 1) / 8];
-
-        String8 configurationFile;
-        PropertyMap* configuration;
-        VirtualKeyMap* virtualKeyMap;
-        KeyMap keyMap;
-
-        sp<KeyCharacterMap> overlayKeyMap;
-        sp<KeyCharacterMap> combinedKeyMap;
-
-        bool ffEffectPlaying;
-        int16_t ffEffectId; // initially -1
-
-        int32_t controllerNumber;
-
-        int32_t timestampOverrideSec;
-        int32_t timestampOverrideUsec;
-
-        Device(int fd, int32_t id, const String8& path, const InputDeviceIdentifier& identifier);
-        ~Device();
-
-        void close();
-
-        inline bool isVirtual() const { return fd < 0; }
-
-        const sp<KeyCharacterMap>& getKeyCharacterMap() const {
-            if (combinedKeyMap != NULL) {
-                return combinedKeyMap;
-            }
-            return keyMap.keyCharacterMap;
-        }
-    };
-
-    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);
-    void closeAllDevicesLocked();
-
-    status_t scanDirLocked(const char *dirname);
-    void scanDevicesLocked();
-    status_t readNotifyLocked();
-
-    Device* getDeviceByDescriptorLocked(String8& descriptor) const;
-    Device* getDeviceLocked(int32_t deviceId) const;
-    Device* getDeviceByPathLocked(const char* devicePath) const;
-
-    bool hasKeycodeLocked(Device* device, int keycode) const;
-
-    void loadConfigurationLocked(Device* device);
-    status_t loadVirtualKeyMapLocked(Device* device);
-    status_t loadKeyMapLocked(Device* device);
-
-    bool isExternalDeviceLocked(Device* device);
-
-    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;
-
-    // The actual id of the built-in keyboard, or NO_BUILT_IN_KEYBOARD if none.
-    // EventHub remaps the built-in keyboard to id 0 externally as required by the API.
-    enum {
-        // Must not conflict with any other assigned device ids, including
-        // the virtual keyboard id (-1).
-        NO_BUILT_IN_KEYBOARD = -2,
-    };
-    int32_t mBuiltInKeyboardId;
-
-    int32_t mNextDeviceId;
-
-    BitSet32 mControllerNumbers;
-
-    KeyedVector<int32_t, Device*> mDevices;
-
-    Device *mOpeningDevices;
-    Device *mClosingDevices;
-
-    bool mNeedToSendFinishedDeviceScan;
-    bool mNeedToReopenDevices;
-    bool mNeedToScanDevices;
-    Vector<String8> mExcludedDevices;
-
-    int mEpollFd;
-    int mINotifyFd;
-    int mWakeReadPipeFd;
-    int mWakeWritePipeFd;
-
-    // Ids used for epoll notifications not associated with devices.
-    static const uint32_t EPOLL_ID_INOTIFY = 0x80000001;
-    static const uint32_t EPOLL_ID_WAKE = 0x80000002;
-
-    // Epoll FD list size hint.
-    static const int EPOLL_SIZE_HINT = 8;
-
-    // Maximum number of signalled FDs to handle at a time.
-    static const int EPOLL_MAX_EVENTS = 16;
-
-    // The array of pending epoll events and the index of the next event to be handled.
-    struct epoll_event mPendingEventItems[EPOLL_MAX_EVENTS];
-    size_t mPendingEventCount;
-    size_t mPendingEventIndex;
-    bool mPendingINotify;
-
-    bool mUsingEpollWakeup;
-};
-
-}; // namespace android
-
-#endif // _RUNTIME_EVENT_HUB_H
diff --git a/libs/input/InputApplication.cpp b/libs/input/InputApplication.cpp
deleted file mode 100644
index a99e637..0000000
--- a/libs/input/InputApplication.cpp
+++ /dev/null
@@ -1,42 +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.
- */
-
-#define LOG_TAG "InputApplication"
-
-#include "InputApplication.h"
-
-#include <cutils/log.h>
-
-namespace android {
-
-// --- InputApplicationHandle ---
-
-InputApplicationHandle::InputApplicationHandle() :
-    mInfo(NULL) {
-}
-
-InputApplicationHandle::~InputApplicationHandle() {
-    delete mInfo;
-}
-
-void InputApplicationHandle::releaseInfo() {
-    if (mInfo) {
-        delete mInfo;
-        mInfo = NULL;
-    }
-}
-
-} // namespace android
diff --git a/libs/input/InputApplication.h b/libs/input/InputApplication.h
deleted file mode 100644
index 1f5504c..0000000
--- a/libs/input/InputApplication.h
+++ /dev/null
@@ -1,83 +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.
- */
-
-#ifndef _UI_INPUT_APPLICATION_H
-#define _UI_INPUT_APPLICATION_H
-
-#include <input/Input.h>
-
-#include <utils/RefBase.h>
-#include <utils/Timers.h>
-#include <utils/String8.h>
-
-namespace android {
-
-/*
- * Describes the properties of an application that can receive input.
- */
-struct InputApplicationInfo {
-    String8 name;
-    nsecs_t dispatchingTimeout;
-};
-
-
-/*
- * Handle for an application that can receive input.
- *
- * Used by the native input dispatcher as a handle for the window manager objects
- * that describe an application.
- */
-class InputApplicationHandle : public RefBase {
-public:
-    inline const InputApplicationInfo* getInfo() const {
-        return mInfo;
-    }
-
-    inline String8 getName() const {
-        return mInfo ? mInfo->name : String8("<invalid>");
-    }
-
-    inline nsecs_t getDispatchingTimeout(nsecs_t defaultValue) const {
-        return mInfo ? mInfo->dispatchingTimeout : defaultValue;
-    }
-
-    /**
-     * Requests that the state of this object be updated to reflect
-     * the most current available information about the application.
-     *
-     * This method should only be called from within the input dispatcher's
-     * critical section.
-     *
-     * Returns true on success, or false if the handle is no longer valid.
-     */
-    virtual bool updateInfo() = 0;
-
-    /**
-     * Releases the storage used by the associated information when it is
-     * no longer needed.
-     */
-    void releaseInfo();
-
-protected:
-    InputApplicationHandle();
-    virtual ~InputApplicationHandle();
-
-    InputApplicationInfo* mInfo;
-};
-
-} // namespace android
-
-#endif // _UI_INPUT_APPLICATION_H
diff --git a/libs/input/InputDispatcher.cpp b/libs/input/InputDispatcher.cpp
deleted file mode 100644
index 10a639e..0000000
--- a/libs/input/InputDispatcher.cpp
+++ /dev/null
@@ -1,4470 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 "InputDispatcher"
-#define ATRACE_TAG ATRACE_TAG_INPUT
-
-//#define LOG_NDEBUG 0
-
-// Log detailed debug messages about each inbound event notification to the dispatcher.
-#define DEBUG_INBOUND_EVENT_DETAILS 0
-
-// Log detailed debug messages about each outbound event processed by the dispatcher.
-#define DEBUG_OUTBOUND_EVENT_DETAILS 0
-
-// Log debug messages about the dispatch cycle.
-#define DEBUG_DISPATCH_CYCLE 0
-
-// Log debug messages about registrations.
-#define DEBUG_REGISTRATION 0
-
-// Log debug messages about input event injection.
-#define DEBUG_INJECTION 0
-
-// Log debug messages about input focus tracking.
-#define DEBUG_FOCUS 0
-
-// Log debug messages about the app switch latency optimization.
-#define DEBUG_APP_SWITCH 0
-
-// Log debug messages about hover events.
-#define DEBUG_HOVER 0
-
-#include "InputDispatcher.h"
-
-#include <utils/Trace.h>
-#include <cutils/log.h>
-#include <androidfw/PowerManager.h>
-
-#include <stddef.h>
-#include <unistd.h>
-#include <errno.h>
-#include <limits.h>
-#include <time.h>
-
-#define INDENT "  "
-#define INDENT2 "    "
-#define INDENT3 "      "
-#define INDENT4 "        "
-
-namespace android {
-
-// Default input dispatching timeout if there is no focused application or paused window
-// from which to determine an appropriate dispatching timeout.
-const nsecs_t DEFAULT_INPUT_DISPATCHING_TIMEOUT = 5000 * 1000000LL; // 5 sec
-
-// Amount of time to allow for all pending events to be processed when an app switch
-// key is on the way.  This is used to preempt input dispatch and drop input events
-// when an application takes too long to respond and the user has pressed an app switch key.
-const nsecs_t APP_SWITCH_TIMEOUT = 500 * 1000000LL; // 0.5sec
-
-// Amount of time to allow for an event to be dispatched (measured since its eventTime)
-// before considering it stale and dropping it.
-const nsecs_t STALE_EVENT_TIMEOUT = 10000 * 1000000LL; // 10sec
-
-// Amount of time to allow touch events to be streamed out to a connection before requiring
-// that the first event be finished.  This value extends the ANR timeout by the specified
-// amount.  For example, if streaming is allowed to get ahead by one second relative to the
-// queue of waiting unfinished events, then ANRs will similarly be delayed by one second.
-const nsecs_t STREAM_AHEAD_EVENT_TIMEOUT = 500 * 1000000LL; // 0.5sec
-
-// Log a warning when an event takes longer than this to process, even if an ANR does not occur.
-const nsecs_t SLOW_EVENT_PROCESSING_WARNING_TIMEOUT = 2000 * 1000000LL; // 2sec
-
-// Number of recent events to keep for debugging purposes.
-const size_t RECENT_QUEUE_MAX_SIZE = 10;
-
-static inline nsecs_t now() {
-    return systemTime(SYSTEM_TIME_MONOTONIC);
-}
-
-static inline const char* toString(bool value) {
-    return value ? "true" : "false";
-}
-
-static inline int32_t getMotionEventActionPointerIndex(int32_t action) {
-    return (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK)
-            >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
-}
-
-static bool isValidKeyAction(int32_t action) {
-    switch (action) {
-    case AKEY_EVENT_ACTION_DOWN:
-    case AKEY_EVENT_ACTION_UP:
-        return true;
-    default:
-        return false;
-    }
-}
-
-static bool validateKeyEvent(int32_t action) {
-    if (! isValidKeyAction(action)) {
-        ALOGE("Key event has invalid action code 0x%x", action);
-        return false;
-    }
-    return true;
-}
-
-static bool isValidMotionAction(int32_t action, size_t pointerCount) {
-    switch (action & AMOTION_EVENT_ACTION_MASK) {
-    case AMOTION_EVENT_ACTION_DOWN:
-    case AMOTION_EVENT_ACTION_UP:
-    case AMOTION_EVENT_ACTION_CANCEL:
-    case AMOTION_EVENT_ACTION_MOVE:
-    case AMOTION_EVENT_ACTION_OUTSIDE:
-    case AMOTION_EVENT_ACTION_HOVER_ENTER:
-    case AMOTION_EVENT_ACTION_HOVER_MOVE:
-    case AMOTION_EVENT_ACTION_HOVER_EXIT:
-    case AMOTION_EVENT_ACTION_SCROLL:
-        return true;
-    case AMOTION_EVENT_ACTION_POINTER_DOWN:
-    case AMOTION_EVENT_ACTION_POINTER_UP: {
-        int32_t index = getMotionEventActionPointerIndex(action);
-        return index >= 0 && size_t(index) < pointerCount;
-    }
-    default:
-        return false;
-    }
-}
-
-static bool validateMotionEvent(int32_t action, size_t pointerCount,
-        const PointerProperties* pointerProperties) {
-    if (! isValidMotionAction(action, pointerCount)) {
-        ALOGE("Motion event has invalid action code 0x%x", action);
-        return false;
-    }
-    if (pointerCount < 1 || pointerCount > MAX_POINTERS) {
-        ALOGE("Motion event has invalid pointer count %d; value must be between 1 and %d.",
-                pointerCount, MAX_POINTERS);
-        return false;
-    }
-    BitSet32 pointerIdBits;
-    for (size_t i = 0; i < pointerCount; i++) {
-        int32_t id = pointerProperties[i].id;
-        if (id < 0 || id > MAX_POINTER_ID) {
-            ALOGE("Motion event has invalid pointer id %d; value must be between 0 and %d",
-                    id, MAX_POINTER_ID);
-            return false;
-        }
-        if (pointerIdBits.hasBit(id)) {
-            ALOGE("Motion event has duplicate pointer id %d", id);
-            return false;
-        }
-        pointerIdBits.markBit(id);
-    }
-    return true;
-}
-
-static bool isMainDisplay(int32_t displayId) {
-    return displayId == ADISPLAY_ID_DEFAULT || displayId == ADISPLAY_ID_NONE;
-}
-
-static void dumpRegion(String8& dump, const SkRegion& region) {
-    if (region.isEmpty()) {
-        dump.append("<empty>");
-        return;
-    }
-
-    bool first = true;
-    for (SkRegion::Iterator it(region); !it.done(); it.next()) {
-        if (first) {
-            first = false;
-        } else {
-            dump.append("|");
-        }
-        const SkIRect& rect = it.rect();
-        dump.appendFormat("[%d,%d][%d,%d]", rect.fLeft, rect.fTop, rect.fRight, rect.fBottom);
-    }
-}
-
-
-// --- InputDispatcher ---
-
-InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy) :
-    mPolicy(policy),
-    mPendingEvent(NULL), mAppSwitchSawKeyDown(false), mAppSwitchDueTime(LONG_LONG_MAX),
-    mNextUnblockedEvent(NULL),
-    mDispatchEnabled(false), mDispatchFrozen(false), mInputFilterEnabled(false),
-    mInputTargetWaitCause(INPUT_TARGET_WAIT_CAUSE_NONE) {
-    mLooper = new Looper(false);
-
-    mKeyRepeatState.lastKeyEntry = NULL;
-
-    policy->getDispatcherConfiguration(&mConfig);
-}
-
-InputDispatcher::~InputDispatcher() {
-    { // acquire lock
-        AutoMutex _l(mLock);
-
-        resetKeyRepeatLocked();
-        releasePendingEventLocked();
-        drainInboundQueueLocked();
-    }
-
-    while (mConnectionsByFd.size() != 0) {
-        unregisterInputChannel(mConnectionsByFd.valueAt(0)->inputChannel);
-    }
-}
-
-void InputDispatcher::dispatchOnce() {
-    nsecs_t nextWakeupTime = LONG_LONG_MAX;
-    { // acquire lock
-        AutoMutex _l(mLock);
-        mDispatcherIsAliveCondition.broadcast();
-
-        // Run a dispatch loop if there are no pending commands.
-        // The dispatch loop might enqueue commands to run afterwards.
-        if (!haveCommandsLocked()) {
-            dispatchOnceInnerLocked(&nextWakeupTime);
-        }
-
-        // Run all pending commands if there are any.
-        // If any commands were run then force the next poll to wake up immediately.
-        if (runCommandsLockedInterruptible()) {
-            nextWakeupTime = LONG_LONG_MIN;
-        }
-    } // release lock
-
-    // Wait for callback or timeout or wake.  (make sure we round up, not down)
-    nsecs_t currentTime = now();
-    int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime);
-    mLooper->pollOnce(timeoutMillis);
-}
-
-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()) {
-        resetKeyRepeatLocked();
-    }
-
-    // If dispatching is frozen, do not process timeouts or try to deliver any new events.
-    if (mDispatchFrozen) {
-#if DEBUG_FOCUS
-        ALOGD("Dispatch frozen.  Waiting some more.");
-#endif
-        return;
-    }
-
-    // Optimize latency of app switches.
-    // Essentially we start a short timeout when an app switch key (HOME / ENDCALL) has
-    // been pressed.  When it expires, we preempt dispatch and drop all other pending events.
-    bool isAppSwitchDue = mAppSwitchDueTime <= currentTime;
-    if (mAppSwitchDueTime < *nextWakeupTime) {
-        *nextWakeupTime = mAppSwitchDueTime;
-    }
-
-    // Ready to start a new event.
-    // If we don't already have a pending event, go grab one.
-    if (! mPendingEvent) {
-        if (mInboundQueue.isEmpty()) {
-            if (isAppSwitchDue) {
-                // The inbound queue is empty so the app switch key we were waiting
-                // for will never arrive.  Stop waiting for it.
-                resetPendingAppSwitchLocked(false);
-                isAppSwitchDue = false;
-            }
-
-            // Synthesize a key repeat if appropriate.
-            if (mKeyRepeatState.lastKeyEntry) {
-                if (currentTime >= mKeyRepeatState.nextRepeatTime) {
-                    mPendingEvent = synthesizeKeyRepeatLocked(currentTime);
-                } else {
-                    if (mKeyRepeatState.nextRepeatTime < *nextWakeupTime) {
-                        *nextWakeupTime = mKeyRepeatState.nextRepeatTime;
-                    }
-                }
-            }
-
-            // Nothing to do if there is no pending event.
-            if (!mPendingEvent) {
-                return;
-            }
-        } else {
-            // Inbound queue has at least one entry.
-            mPendingEvent = mInboundQueue.dequeueAtHead();
-            traceInboundQueueLengthLocked();
-        }
-
-        // Poke user activity for this event.
-        if (mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER) {
-            pokeUserActivityLocked(mPendingEvent);
-        }
-
-        // Get ready to dispatch the event.
-        resetANRTimeoutsLocked();
-    }
-
-    // Now we have an event to dispatch.
-    // All events are eventually dequeued and processed this way, even if we intend to drop them.
-    ALOG_ASSERT(mPendingEvent != NULL);
-    bool done = false;
-    DropReason dropReason = DROP_REASON_NOT_DROPPED;
-    if (!(mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER)) {
-        dropReason = DROP_REASON_POLICY;
-    } else if (!mDispatchEnabled) {
-        dropReason = DROP_REASON_DISABLED;
-    }
-
-    if (mNextUnblockedEvent == mPendingEvent) {
-        mNextUnblockedEvent = NULL;
-    }
-
-    switch (mPendingEvent->type) {
-    case EventEntry::TYPE_CONFIGURATION_CHANGED: {
-        ConfigurationChangedEntry* typedEntry =
-                static_cast<ConfigurationChangedEntry*>(mPendingEvent);
-        done = dispatchConfigurationChangedLocked(currentTime, typedEntry);
-        dropReason = DROP_REASON_NOT_DROPPED; // configuration changes are never dropped
-        break;
-    }
-
-    case EventEntry::TYPE_DEVICE_RESET: {
-        DeviceResetEntry* typedEntry =
-                static_cast<DeviceResetEntry*>(mPendingEvent);
-        done = dispatchDeviceResetLocked(currentTime, typedEntry);
-        dropReason = DROP_REASON_NOT_DROPPED; // device resets are never dropped
-        break;
-    }
-
-    case EventEntry::TYPE_KEY: {
-        KeyEntry* typedEntry = static_cast<KeyEntry*>(mPendingEvent);
-        if (isAppSwitchDue) {
-            if (isAppSwitchKeyEventLocked(typedEntry)) {
-                resetPendingAppSwitchLocked(true);
-                isAppSwitchDue = false;
-            } else if (dropReason == DROP_REASON_NOT_DROPPED) {
-                dropReason = DROP_REASON_APP_SWITCH;
-            }
-        }
-        if (dropReason == DROP_REASON_NOT_DROPPED
-                && isStaleEventLocked(currentTime, typedEntry)) {
-            dropReason = DROP_REASON_STALE;
-        }
-        if (dropReason == DROP_REASON_NOT_DROPPED && mNextUnblockedEvent) {
-            dropReason = DROP_REASON_BLOCKED;
-        }
-        done = dispatchKeyLocked(currentTime, typedEntry, &dropReason, nextWakeupTime);
-        break;
-    }
-
-    case EventEntry::TYPE_MOTION: {
-        MotionEntry* typedEntry = static_cast<MotionEntry*>(mPendingEvent);
-        if (dropReason == DROP_REASON_NOT_DROPPED && isAppSwitchDue) {
-            dropReason = DROP_REASON_APP_SWITCH;
-        }
-        if (dropReason == DROP_REASON_NOT_DROPPED
-                && isStaleEventLocked(currentTime, typedEntry)) {
-            dropReason = DROP_REASON_STALE;
-        }
-        if (dropReason == DROP_REASON_NOT_DROPPED && mNextUnblockedEvent) {
-            dropReason = DROP_REASON_BLOCKED;
-        }
-        done = dispatchMotionLocked(currentTime, typedEntry,
-                &dropReason, nextWakeupTime);
-        break;
-    }
-
-    default:
-        ALOG_ASSERT(false);
-        break;
-    }
-
-    if (done) {
-        if (dropReason != DROP_REASON_NOT_DROPPED) {
-            dropInboundEventLocked(mPendingEvent, dropReason);
-        }
-
-        releasePendingEventLocked();
-        *nextWakeupTime = LONG_LONG_MIN;  // force next poll to wake up immediately
-    }
-}
-
-bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) {
-    bool needWake = mInboundQueue.isEmpty();
-    mInboundQueue.enqueueAtTail(entry);
-    traceInboundQueueLengthLocked();
-
-    switch (entry->type) {
-    case EventEntry::TYPE_KEY: {
-        // Optimize app switch latency.
-        // If the application takes too long to catch up then we drop all events preceding
-        // the app switch key.
-        KeyEntry* keyEntry = static_cast<KeyEntry*>(entry);
-        if (isAppSwitchKeyEventLocked(keyEntry)) {
-            if (keyEntry->action == AKEY_EVENT_ACTION_DOWN) {
-                mAppSwitchSawKeyDown = true;
-            } else if (keyEntry->action == AKEY_EVENT_ACTION_UP) {
-                if (mAppSwitchSawKeyDown) {
-#if DEBUG_APP_SWITCH
-                    ALOGD("App switch is pending!");
-#endif
-                    mAppSwitchDueTime = keyEntry->eventTime + APP_SWITCH_TIMEOUT;
-                    mAppSwitchSawKeyDown = false;
-                    needWake = true;
-                }
-            }
-        }
-        break;
-    }
-
-    case EventEntry::TYPE_MOTION: {
-        // Optimize case where the current application is unresponsive and the user
-        // decides to touch a window in a different application.
-        // If the application takes too long to catch up then we drop all events preceding
-        // the touch into the other window.
-        MotionEntry* motionEntry = static_cast<MotionEntry*>(entry);
-        if (motionEntry->action == AMOTION_EVENT_ACTION_DOWN
-                && (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER)
-                && mInputTargetWaitCause == INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY
-                && mInputTargetWaitApplicationHandle != NULL) {
-            int32_t displayId = motionEntry->displayId;
-            int32_t x = int32_t(motionEntry->pointerCoords[0].
-                    getAxisValue(AMOTION_EVENT_AXIS_X));
-            int32_t y = int32_t(motionEntry->pointerCoords[0].
-                    getAxisValue(AMOTION_EVENT_AXIS_Y));
-            sp<InputWindowHandle> touchedWindowHandle = findTouchedWindowAtLocked(displayId, x, y);
-            if (touchedWindowHandle != NULL
-                    && touchedWindowHandle->inputApplicationHandle
-                            != mInputTargetWaitApplicationHandle) {
-                // User touched a different application than the one we are waiting on.
-                // Flag the event, and start pruning the input queue.
-                mNextUnblockedEvent = motionEntry;
-                needWake = true;
-            }
-        }
-        break;
-    }
-    }
-
-    return needWake;
-}
-
-void InputDispatcher::addRecentEventLocked(EventEntry* entry) {
-    entry->refCount += 1;
-    mRecentQueue.enqueueAtTail(entry);
-    if (mRecentQueue.count() > RECENT_QUEUE_MAX_SIZE) {
-        mRecentQueue.dequeueAtHead()->release();
-    }
-}
-
-sp<InputWindowHandle> InputDispatcher::findTouchedWindowAtLocked(int32_t displayId,
-        int32_t x, int32_t y) {
-    // Traverse windows from front to back to find touched window.
-    size_t numWindows = mWindowHandles.size();
-    for (size_t i = 0; i < numWindows; i++) {
-        sp<InputWindowHandle> windowHandle = mWindowHandles.itemAt(i);
-        const InputWindowInfo* windowInfo = windowHandle->getInfo();
-        if (windowInfo->displayId == displayId) {
-            int32_t flags = windowInfo->layoutParamsFlags;
-            int32_t privateFlags = windowInfo->layoutParamsPrivateFlags;
-
-            if (windowInfo->visible) {
-                if (!(flags & InputWindowInfo::FLAG_NOT_TOUCHABLE)) {
-                    bool isTouchModal = (flags & (InputWindowInfo::FLAG_NOT_FOCUSABLE
-                            | InputWindowInfo::FLAG_NOT_TOUCH_MODAL)) == 0;
-                    if (isTouchModal || windowInfo->touchableRegionContainsPoint(x, y)) {
-                        // Found window.
-                        return windowHandle;
-                    }
-                }
-            }
-
-            if (privateFlags & InputWindowInfo::PRIVATE_FLAG_SYSTEM_ERROR) {
-                // Error window is on top but not visible, so touch is dropped.
-                return NULL;
-            }
-        }
-    }
-    return NULL;
-}
-
-void InputDispatcher::dropInboundEventLocked(EventEntry* entry, DropReason dropReason) {
-    const char* reason;
-    switch (dropReason) {
-    case DROP_REASON_POLICY:
-#if DEBUG_INBOUND_EVENT_DETAILS
-        ALOGD("Dropped event because policy consumed it.");
-#endif
-        reason = "inbound event was dropped because the policy consumed it";
-        break;
-    case DROP_REASON_DISABLED:
-        ALOGI("Dropped event because input dispatch is disabled.");
-        reason = "inbound event was dropped because input dispatch is disabled";
-        break;
-    case DROP_REASON_APP_SWITCH:
-        ALOGI("Dropped event because of pending overdue app switch.");
-        reason = "inbound event was dropped because of pending overdue app switch";
-        break;
-    case DROP_REASON_BLOCKED:
-        ALOGI("Dropped event because the current application is not responding and the user "
-                "has started interacting with a different application.");
-        reason = "inbound event was dropped because the current application is not responding "
-                "and the user has started interacting with a different application";
-        break;
-    case DROP_REASON_STALE:
-        ALOGI("Dropped event because it is stale.");
-        reason = "inbound event was dropped because it is stale";
-        break;
-    default:
-        ALOG_ASSERT(false);
-        return;
-    }
-
-    switch (entry->type) {
-    case EventEntry::TYPE_KEY: {
-        CancelationOptions options(CancelationOptions::CANCEL_NON_POINTER_EVENTS, reason);
-        synthesizeCancelationEventsForAllConnectionsLocked(options);
-        break;
-    }
-    case EventEntry::TYPE_MOTION: {
-        MotionEntry* motionEntry = static_cast<MotionEntry*>(entry);
-        if (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER) {
-            CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS, reason);
-            synthesizeCancelationEventsForAllConnectionsLocked(options);
-        } else {
-            CancelationOptions options(CancelationOptions::CANCEL_NON_POINTER_EVENTS, reason);
-            synthesizeCancelationEventsForAllConnectionsLocked(options);
-        }
-        break;
-    }
-    }
-}
-
-bool InputDispatcher::isAppSwitchKeyCode(int32_t keyCode) {
-    return keyCode == AKEYCODE_HOME
-            || keyCode == AKEYCODE_ENDCALL
-            || keyCode == AKEYCODE_APP_SWITCH;
-}
-
-bool InputDispatcher::isAppSwitchKeyEventLocked(KeyEntry* keyEntry) {
-    return ! (keyEntry->flags & AKEY_EVENT_FLAG_CANCELED)
-            && isAppSwitchKeyCode(keyEntry->keyCode)
-            && (keyEntry->policyFlags & POLICY_FLAG_TRUSTED)
-            && (keyEntry->policyFlags & POLICY_FLAG_PASS_TO_USER);
-}
-
-bool InputDispatcher::isAppSwitchPendingLocked() {
-    return mAppSwitchDueTime != LONG_LONG_MAX;
-}
-
-void InputDispatcher::resetPendingAppSwitchLocked(bool handled) {
-    mAppSwitchDueTime = LONG_LONG_MAX;
-
-#if DEBUG_APP_SWITCH
-    if (handled) {
-        ALOGD("App switch has arrived.");
-    } else {
-        ALOGD("App switch was abandoned.");
-    }
-#endif
-}
-
-bool InputDispatcher::isStaleEventLocked(nsecs_t currentTime, EventEntry* entry) {
-    return currentTime - entry->eventTime >= STALE_EVENT_TIMEOUT;
-}
-
-bool InputDispatcher::haveCommandsLocked() const {
-    return !mCommandQueue.isEmpty();
-}
-
-bool InputDispatcher::runCommandsLockedInterruptible() {
-    if (mCommandQueue.isEmpty()) {
-        return false;
-    }
-
-    do {
-        CommandEntry* commandEntry = mCommandQueue.dequeueAtHead();
-
-        Command command = commandEntry->command;
-        (this->*command)(commandEntry); // commands are implicitly 'LockedInterruptible'
-
-        commandEntry->connection.clear();
-        delete commandEntry;
-    } while (! mCommandQueue.isEmpty());
-    return true;
-}
-
-InputDispatcher::CommandEntry* InputDispatcher::postCommandLocked(Command command) {
-    CommandEntry* commandEntry = new CommandEntry(command);
-    mCommandQueue.enqueueAtTail(commandEntry);
-    return commandEntry;
-}
-
-void InputDispatcher::drainInboundQueueLocked() {
-    while (! mInboundQueue.isEmpty()) {
-        EventEntry* entry = mInboundQueue.dequeueAtHead();
-        releaseInboundEventLocked(entry);
-    }
-    traceInboundQueueLengthLocked();
-}
-
-void InputDispatcher::releasePendingEventLocked() {
-    if (mPendingEvent) {
-        resetANRTimeoutsLocked();
-        releaseInboundEventLocked(mPendingEvent);
-        mPendingEvent = NULL;
-    }
-}
-
-void InputDispatcher::releaseInboundEventLocked(EventEntry* entry) {
-    InjectionState* injectionState = entry->injectionState;
-    if (injectionState && injectionState->injectionResult == INPUT_EVENT_INJECTION_PENDING) {
-#if DEBUG_DISPATCH_CYCLE
-        ALOGD("Injected inbound event was dropped.");
-#endif
-        setInjectionResultLocked(entry, INPUT_EVENT_INJECTION_FAILED);
-    }
-    if (entry == mNextUnblockedEvent) {
-        mNextUnblockedEvent = NULL;
-    }
-    addRecentEventLocked(entry);
-    entry->release();
-}
-
-void InputDispatcher::resetKeyRepeatLocked() {
-    if (mKeyRepeatState.lastKeyEntry) {
-        mKeyRepeatState.lastKeyEntry->release();
-        mKeyRepeatState.lastKeyEntry = NULL;
-    }
-}
-
-InputDispatcher::KeyEntry* InputDispatcher::synthesizeKeyRepeatLocked(nsecs_t currentTime) {
-    KeyEntry* entry = mKeyRepeatState.lastKeyEntry;
-
-    // Reuse the repeated key entry if it is otherwise unreferenced.
-    uint32_t policyFlags = (entry->policyFlags & POLICY_FLAG_RAW_MASK)
-            | POLICY_FLAG_PASS_TO_USER | POLICY_FLAG_TRUSTED;
-    if (entry->refCount == 1) {
-        entry->recycle();
-        entry->eventTime = currentTime;
-        entry->policyFlags = policyFlags;
-        entry->repeatCount += 1;
-    } else {
-        KeyEntry* newEntry = new KeyEntry(currentTime,
-                entry->deviceId, entry->source, policyFlags,
-                entry->action, entry->flags, entry->keyCode, entry->scanCode,
-                entry->metaState, entry->repeatCount + 1, entry->downTime);
-
-        mKeyRepeatState.lastKeyEntry = newEntry;
-        entry->release();
-
-        entry = newEntry;
-    }
-    entry->syntheticRepeat = true;
-
-    // Increment reference count since we keep a reference to the event in
-    // mKeyRepeatState.lastKeyEntry in addition to the one we return.
-    entry->refCount += 1;
-
-    mKeyRepeatState.nextRepeatTime = currentTime + mConfig.keyRepeatDelay;
-    return entry;
-}
-
-bool InputDispatcher::dispatchConfigurationChangedLocked(
-        nsecs_t currentTime, ConfigurationChangedEntry* entry) {
-#if DEBUG_OUTBOUND_EVENT_DETAILS
-    ALOGD("dispatchConfigurationChanged - eventTime=%lld", entry->eventTime);
-#endif
-
-    // Reset key repeating in case a keyboard device was added or removed or something.
-    resetKeyRepeatLocked();
-
-    // Enqueue a command to run outside the lock to tell the policy that the configuration changed.
-    CommandEntry* commandEntry = postCommandLocked(
-            & InputDispatcher::doNotifyConfigurationChangedInterruptible);
-    commandEntry->eventTime = entry->eventTime;
-    return true;
-}
-
-bool InputDispatcher::dispatchDeviceResetLocked(
-        nsecs_t currentTime, DeviceResetEntry* entry) {
-#if DEBUG_OUTBOUND_EVENT_DETAILS
-    ALOGD("dispatchDeviceReset - eventTime=%lld, deviceId=%d", entry->eventTime, entry->deviceId);
-#endif
-
-    CancelationOptions options(CancelationOptions::CANCEL_ALL_EVENTS,
-            "device was reset");
-    options.deviceId = entry->deviceId;
-    synthesizeCancelationEventsForAllConnectionsLocked(options);
-    return true;
-}
-
-bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry,
-        DropReason* dropReason, nsecs_t* nextWakeupTime) {
-    // Preprocessing.
-    if (! entry->dispatchInProgress) {
-        if (entry->repeatCount == 0
-                && entry->action == AKEY_EVENT_ACTION_DOWN
-                && (entry->policyFlags & POLICY_FLAG_TRUSTED)
-                && (!(entry->policyFlags & POLICY_FLAG_DISABLE_KEY_REPEAT))) {
-            if (mKeyRepeatState.lastKeyEntry
-                    && mKeyRepeatState.lastKeyEntry->keyCode == entry->keyCode) {
-                // We have seen two identical key downs in a row which indicates that the device
-                // driver is automatically generating key repeats itself.  We take note of the
-                // repeat here, but we disable our own next key repeat timer since it is clear that
-                // we will not need to synthesize key repeats ourselves.
-                entry->repeatCount = mKeyRepeatState.lastKeyEntry->repeatCount + 1;
-                resetKeyRepeatLocked();
-                mKeyRepeatState.nextRepeatTime = LONG_LONG_MAX; // don't generate repeats ourselves
-            } else {
-                // Not a repeat.  Save key down state in case we do see a repeat later.
-                resetKeyRepeatLocked();
-                mKeyRepeatState.nextRepeatTime = entry->eventTime + mConfig.keyRepeatTimeout;
-            }
-            mKeyRepeatState.lastKeyEntry = entry;
-            entry->refCount += 1;
-        } else if (! entry->syntheticRepeat) {
-            resetKeyRepeatLocked();
-        }
-
-        if (entry->repeatCount == 1) {
-            entry->flags |= AKEY_EVENT_FLAG_LONG_PRESS;
-        } else {
-            entry->flags &= ~AKEY_EVENT_FLAG_LONG_PRESS;
-        }
-
-        entry->dispatchInProgress = true;
-
-        logOutboundKeyDetailsLocked("dispatchKey - ", entry);
-    }
-
-    // Handle case where the policy asked us to try again later last time.
-    if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER) {
-        if (currentTime < entry->interceptKeyWakeupTime) {
-            if (entry->interceptKeyWakeupTime < *nextWakeupTime) {
-                *nextWakeupTime = entry->interceptKeyWakeupTime;
-            }
-            return false; // wait until next wakeup
-        }
-        entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN;
-        entry->interceptKeyWakeupTime = 0;
-    }
-
-    // Give the policy a chance to intercept the key.
-    if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN) {
-        if (entry->policyFlags & POLICY_FLAG_PASS_TO_USER) {
-            CommandEntry* commandEntry = postCommandLocked(
-                    & InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible);
-            if (mFocusedWindowHandle != NULL) {
-                commandEntry->inputWindowHandle = mFocusedWindowHandle;
-            }
-            commandEntry->keyEntry = entry;
-            entry->refCount += 1;
-            return false; // wait for the command to run
-        } else {
-            entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_CONTINUE;
-        }
-    } else if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_SKIP) {
-        if (*dropReason == DROP_REASON_NOT_DROPPED) {
-            *dropReason = DROP_REASON_POLICY;
-        }
-    }
-
-    // Clean up if dropping the event.
-    if (*dropReason != DROP_REASON_NOT_DROPPED) {
-        setInjectionResultLocked(entry, *dropReason == DROP_REASON_POLICY
-                ? INPUT_EVENT_INJECTION_SUCCEEDED : INPUT_EVENT_INJECTION_FAILED);
-        return true;
-    }
-
-    // Identify targets.
-    Vector<InputTarget> inputTargets;
-    int32_t injectionResult = findFocusedWindowTargetsLocked(currentTime,
-            entry, inputTargets, nextWakeupTime);
-    if (injectionResult == INPUT_EVENT_INJECTION_PENDING) {
-        return false;
-    }
-
-    setInjectionResultLocked(entry, injectionResult);
-    if (injectionResult != INPUT_EVENT_INJECTION_SUCCEEDED) {
-        return true;
-    }
-
-    addMonitoringTargetsLocked(inputTargets);
-
-    // Dispatch the key.
-    dispatchEventLocked(currentTime, entry, inputTargets);
-    return true;
-}
-
-void InputDispatcher::logOutboundKeyDetailsLocked(const char* prefix, const KeyEntry* entry) {
-#if DEBUG_OUTBOUND_EVENT_DETAILS
-    ALOGD("%seventTime=%lld, deviceId=%d, source=0x%x, policyFlags=0x%x, "
-            "action=0x%x, flags=0x%x, keyCode=0x%x, scanCode=0x%x, metaState=0x%x, "
-            "repeatCount=%d, downTime=%lld",
-            prefix,
-            entry->eventTime, entry->deviceId, entry->source, entry->policyFlags,
-            entry->action, entry->flags, entry->keyCode, entry->scanCode, entry->metaState,
-            entry->repeatCount, entry->downTime);
-#endif
-}
-
-bool InputDispatcher::dispatchMotionLocked(
-        nsecs_t currentTime, MotionEntry* entry, DropReason* dropReason, nsecs_t* nextWakeupTime) {
-    // Preprocessing.
-    if (! entry->dispatchInProgress) {
-        entry->dispatchInProgress = true;
-
-        logOutboundMotionDetailsLocked("dispatchMotion - ", entry);
-    }
-
-    // Clean up if dropping the event.
-    if (*dropReason != DROP_REASON_NOT_DROPPED) {
-        setInjectionResultLocked(entry, *dropReason == DROP_REASON_POLICY
-                ? INPUT_EVENT_INJECTION_SUCCEEDED : INPUT_EVENT_INJECTION_FAILED);
-        return true;
-    }
-
-    bool isPointerEvent = entry->source & AINPUT_SOURCE_CLASS_POINTER;
-
-    // Identify targets.
-    Vector<InputTarget> inputTargets;
-
-    bool conflictingPointerActions = false;
-    int32_t injectionResult;
-    if (isPointerEvent) {
-        // Pointer event.  (eg. touchscreen)
-        injectionResult = findTouchedWindowTargetsLocked(currentTime,
-                entry, inputTargets, nextWakeupTime, &conflictingPointerActions);
-    } else {
-        // Non touch event.  (eg. trackball)
-        injectionResult = findFocusedWindowTargetsLocked(currentTime,
-                entry, inputTargets, nextWakeupTime);
-    }
-    if (injectionResult == INPUT_EVENT_INJECTION_PENDING) {
-        return false;
-    }
-
-    setInjectionResultLocked(entry, injectionResult);
-    if (injectionResult != INPUT_EVENT_INJECTION_SUCCEEDED) {
-        return true;
-    }
-
-    // TODO: support sending secondary display events to input monitors
-    if (isMainDisplay(entry->displayId)) {
-        addMonitoringTargetsLocked(inputTargets);
-    }
-
-    // Dispatch the motion.
-    if (conflictingPointerActions) {
-        CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS,
-                "conflicting pointer actions");
-        synthesizeCancelationEventsForAllConnectionsLocked(options);
-    }
-    dispatchEventLocked(currentTime, entry, inputTargets);
-    return true;
-}
-
-
-void InputDispatcher::logOutboundMotionDetailsLocked(const char* prefix, const MotionEntry* entry) {
-#if DEBUG_OUTBOUND_EVENT_DETAILS
-    ALOGD("%seventTime=%lld, deviceId=%d, source=0x%x, policyFlags=0x%x, "
-            "action=0x%x, flags=0x%x, "
-            "metaState=0x%x, buttonState=0x%x, "
-            "edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%lld",
-            prefix,
-            entry->eventTime, entry->deviceId, entry->source, entry->policyFlags,
-            entry->action, entry->flags,
-            entry->metaState, entry->buttonState,
-            entry->edgeFlags, entry->xPrecision, entry->yPrecision,
-            entry->downTime);
-
-    for (uint32_t i = 0; i < entry->pointerCount; i++) {
-        ALOGD("  Pointer %d: id=%d, toolType=%d, "
-                "x=%f, y=%f, pressure=%f, size=%f, "
-                "touchMajor=%f, touchMinor=%f, toolMajor=%f, toolMinor=%f, "
-                "orientation=%f",
-                i, entry->pointerProperties[i].id,
-                entry->pointerProperties[i].toolType,
-                entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X),
-                entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y),
-                entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE),
-                entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_SIZE),
-                entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR),
-                entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR),
-                entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR),
-                entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR),
-                entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION));
-    }
-#endif
-}
-
-void InputDispatcher::dispatchEventLocked(nsecs_t currentTime,
-        EventEntry* eventEntry, const Vector<InputTarget>& inputTargets) {
-#if DEBUG_DISPATCH_CYCLE
-    ALOGD("dispatchEventToCurrentInputTargets");
-#endif
-
-    ALOG_ASSERT(eventEntry->dispatchInProgress); // should already have been set to true
-
-    pokeUserActivityLocked(eventEntry);
-
-    for (size_t i = 0; i < inputTargets.size(); i++) {
-        const InputTarget& inputTarget = inputTargets.itemAt(i);
-
-        ssize_t connectionIndex = getConnectionIndexLocked(inputTarget.inputChannel);
-        if (connectionIndex >= 0) {
-            sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
-            prepareDispatchCycleLocked(currentTime, connection, eventEntry, &inputTarget);
-        } else {
-#if DEBUG_FOCUS
-            ALOGD("Dropping event delivery to target with channel '%s' because it "
-                    "is no longer registered with the input dispatcher.",
-                    inputTarget.inputChannel->getName().string());
-#endif
-        }
-    }
-}
-
-int32_t InputDispatcher::handleTargetsNotReadyLocked(nsecs_t currentTime,
-        const EventEntry* entry,
-        const sp<InputApplicationHandle>& applicationHandle,
-        const sp<InputWindowHandle>& windowHandle,
-        nsecs_t* nextWakeupTime, const char* reason) {
-    if (applicationHandle == NULL && windowHandle == NULL) {
-        if (mInputTargetWaitCause != INPUT_TARGET_WAIT_CAUSE_SYSTEM_NOT_READY) {
-#if DEBUG_FOCUS
-            ALOGD("Waiting for system to become ready for input.  Reason: %s", reason);
-#endif
-            mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_SYSTEM_NOT_READY;
-            mInputTargetWaitStartTime = currentTime;
-            mInputTargetWaitTimeoutTime = LONG_LONG_MAX;
-            mInputTargetWaitTimeoutExpired = false;
-            mInputTargetWaitApplicationHandle.clear();
-        }
-    } else {
-        if (mInputTargetWaitCause != INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY) {
-#if DEBUG_FOCUS
-            ALOGD("Waiting for application to become ready for input: %s.  Reason: %s",
-                    getApplicationWindowLabelLocked(applicationHandle, windowHandle).string(),
-                    reason);
-#endif
-            nsecs_t timeout;
-            if (windowHandle != NULL) {
-                timeout = windowHandle->getDispatchingTimeout(DEFAULT_INPUT_DISPATCHING_TIMEOUT);
-            } else if (applicationHandle != NULL) {
-                timeout = applicationHandle->getDispatchingTimeout(
-                        DEFAULT_INPUT_DISPATCHING_TIMEOUT);
-            } else {
-                timeout = DEFAULT_INPUT_DISPATCHING_TIMEOUT;
-            }
-
-            mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY;
-            mInputTargetWaitStartTime = currentTime;
-            mInputTargetWaitTimeoutTime = currentTime + timeout;
-            mInputTargetWaitTimeoutExpired = false;
-            mInputTargetWaitApplicationHandle.clear();
-
-            if (windowHandle != NULL) {
-                mInputTargetWaitApplicationHandle = windowHandle->inputApplicationHandle;
-            }
-            if (mInputTargetWaitApplicationHandle == NULL && applicationHandle != NULL) {
-                mInputTargetWaitApplicationHandle = applicationHandle;
-            }
-        }
-    }
-
-    if (mInputTargetWaitTimeoutExpired) {
-        return INPUT_EVENT_INJECTION_TIMED_OUT;
-    }
-
-    if (currentTime >= mInputTargetWaitTimeoutTime) {
-        onANRLocked(currentTime, applicationHandle, windowHandle,
-                entry->eventTime, mInputTargetWaitStartTime, reason);
-
-        // Force poll loop to wake up immediately on next iteration once we get the
-        // ANR response back from the policy.
-        *nextWakeupTime = LONG_LONG_MIN;
-        return INPUT_EVENT_INJECTION_PENDING;
-    } else {
-        // Force poll loop to wake up when timeout is due.
-        if (mInputTargetWaitTimeoutTime < *nextWakeupTime) {
-            *nextWakeupTime = mInputTargetWaitTimeoutTime;
-        }
-        return INPUT_EVENT_INJECTION_PENDING;
-    }
-}
-
-void InputDispatcher::resumeAfterTargetsNotReadyTimeoutLocked(nsecs_t newTimeout,
-        const sp<InputChannel>& inputChannel) {
-    if (newTimeout > 0) {
-        // Extend the timeout.
-        mInputTargetWaitTimeoutTime = now() + newTimeout;
-    } else {
-        // Give up.
-        mInputTargetWaitTimeoutExpired = true;
-
-        // Input state will not be realistic.  Mark it out of sync.
-        if (inputChannel.get()) {
-            ssize_t connectionIndex = getConnectionIndexLocked(inputChannel);
-            if (connectionIndex >= 0) {
-                sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
-                sp<InputWindowHandle> windowHandle = connection->inputWindowHandle;
-
-                if (windowHandle != NULL) {
-                    mTouchState.removeWindow(windowHandle);
-                }
-
-                if (connection->status == Connection::STATUS_NORMAL) {
-                    CancelationOptions options(CancelationOptions::CANCEL_ALL_EVENTS,
-                            "application not responding");
-                    synthesizeCancelationEventsForConnectionLocked(connection, options);
-                }
-            }
-        }
-    }
-}
-
-nsecs_t InputDispatcher::getTimeSpentWaitingForApplicationLocked(
-        nsecs_t currentTime) {
-    if (mInputTargetWaitCause == INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY) {
-        return currentTime - mInputTargetWaitStartTime;
-    }
-    return 0;
-}
-
-void InputDispatcher::resetANRTimeoutsLocked() {
-#if DEBUG_FOCUS
-        ALOGD("Resetting ANR timeouts.");
-#endif
-
-    // Reset input target wait timeout.
-    mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_NONE;
-    mInputTargetWaitApplicationHandle.clear();
-}
-
-int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime,
-        const EventEntry* entry, Vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime) {
-    int32_t injectionResult;
-
-    // If there is no currently focused window and no focused application
-    // then drop the event.
-    if (mFocusedWindowHandle == NULL) {
-        if (mFocusedApplicationHandle != NULL) {
-            injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
-                    mFocusedApplicationHandle, NULL, nextWakeupTime,
-                    "Waiting because no window has focus but there is a "
-                    "focused application that may eventually add a window "
-                    "when it finishes starting up.");
-            goto Unresponsive;
-        }
-
-        ALOGI("Dropping event because there is no focused window or focused application.");
-        injectionResult = INPUT_EVENT_INJECTION_FAILED;
-        goto Failed;
-    }
-
-    // Check permissions.
-    if (! checkInjectionPermission(mFocusedWindowHandle, entry->injectionState)) {
-        injectionResult = INPUT_EVENT_INJECTION_PERMISSION_DENIED;
-        goto Failed;
-    }
-
-    // If the currently focused window is paused then keep waiting.
-    if (mFocusedWindowHandle->getInfo()->paused) {
-        injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
-                mFocusedApplicationHandle, mFocusedWindowHandle, nextWakeupTime,
-                "Waiting because the focused window is paused.");
-        goto Unresponsive;
-    }
-
-    // If the currently focused window is still working on previous events then keep waiting.
-    if (!isWindowReadyForMoreInputLocked(currentTime, mFocusedWindowHandle, entry)) {
-        injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
-                mFocusedApplicationHandle, mFocusedWindowHandle, nextWakeupTime,
-                "Waiting because the focused window has not finished "
-                "processing the input events that were previously delivered to it.");
-        goto Unresponsive;
-    }
-
-    // Success!  Output targets.
-    injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED;
-    addWindowTargetLocked(mFocusedWindowHandle,
-            InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS, BitSet32(0),
-            inputTargets);
-
-    // Done.
-Failed:
-Unresponsive:
-    nsecs_t timeSpentWaitingForApplication = getTimeSpentWaitingForApplicationLocked(currentTime);
-    updateDispatchStatisticsLocked(currentTime, entry,
-            injectionResult, timeSpentWaitingForApplication);
-#if DEBUG_FOCUS
-    ALOGD("findFocusedWindow finished: injectionResult=%d, "
-            "timeSpentWaitingForApplication=%0.1fms",
-            injectionResult, timeSpentWaitingForApplication / 1000000.0);
-#endif
-    return injectionResult;
-}
-
-int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime,
-        const MotionEntry* entry, Vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime,
-        bool* outConflictingPointerActions) {
-    enum InjectionPermission {
-        INJECTION_PERMISSION_UNKNOWN,
-        INJECTION_PERMISSION_GRANTED,
-        INJECTION_PERMISSION_DENIED
-    };
-
-    nsecs_t startTime = now();
-
-    // 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;
-
-    // Update the touch state as needed based on the properties of the touch event.
-    int32_t injectionResult = INPUT_EVENT_INJECTION_PENDING;
-    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);
-    bool isHoverAction = (maskedAction == AMOTION_EVENT_ACTION_HOVER_MOVE
-            || maskedAction == AMOTION_EVENT_ACTION_HOVER_ENTER
-            || maskedAction == AMOTION_EVENT_ACTION_HOVER_EXIT);
-    bool newGesture = (maskedAction == AMOTION_EVENT_ACTION_DOWN
-            || maskedAction == AMOTION_EVENT_ACTION_SCROLL
-            || isHoverAction);
-    bool wrongDevice = false;
-    if (newGesture) {
-        bool down = maskedAction == AMOTION_EVENT_ACTION_DOWN;
-        if (switchedDevice && mTouchState.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;
-            goto Failed;
-        }
-        mTempTouchState.reset();
-        mTempTouchState.down = down;
-        mTempTouchState.deviceId = entry->deviceId;
-        mTempTouchState.source = entry->source;
-        mTempTouchState.displayId = displayId;
-        isSplit = false;
-    } else {
-        mTempTouchState.copyFrom(mTouchState);
-    }
-
-    if (newGesture || (isSplit && maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN)) {
-        /* Case 1: New splittable pointer going down, or need target for hover or scroll. */
-
-        int32_t pointerIndex = getMotionEventActionPointerIndex(action);
-        int32_t x = int32_t(entry->pointerCoords[pointerIndex].
-                getAxisValue(AMOTION_EVENT_AXIS_X));
-        int32_t y = int32_t(entry->pointerCoords[pointerIndex].
-                getAxisValue(AMOTION_EVENT_AXIS_Y));
-        sp<InputWindowHandle> newTouchedWindowHandle;
-        sp<InputWindowHandle> topErrorWindowHandle;
-        bool isTouchModal = false;
-
-        // Traverse windows from front to back to find touched window and outside targets.
-        size_t numWindows = mWindowHandles.size();
-        for (size_t i = 0; i < numWindows; i++) {
-            sp<InputWindowHandle> windowHandle = mWindowHandles.itemAt(i);
-            const InputWindowInfo* windowInfo = windowHandle->getInfo();
-            if (windowInfo->displayId != displayId) {
-                continue; // wrong display
-            }
-
-            int32_t privateFlags = windowInfo->layoutParamsPrivateFlags;
-            if (privateFlags & InputWindowInfo::PRIVATE_FLAG_SYSTEM_ERROR) {
-                if (topErrorWindowHandle == NULL) {
-                    topErrorWindowHandle = windowHandle;
-                }
-            }
-
-            int32_t flags = windowInfo->layoutParamsFlags;
-            if (windowInfo->visible) {
-                if (! (flags & InputWindowInfo::FLAG_NOT_TOUCHABLE)) {
-                    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;
-                        }
-                        break; // found touched window, exit window loop
-                    }
-                }
-
-                if (maskedAction == AMOTION_EVENT_ACTION_DOWN
-                        && (flags & InputWindowInfo::FLAG_WATCH_OUTSIDE_TOUCH)) {
-                    int32_t outsideTargetFlags = InputTarget::FLAG_DISPATCH_AS_OUTSIDE;
-                    if (isWindowObscuredAtPointLocked(windowHandle, x, y)) {
-                        outsideTargetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED;
-                    }
-
-                    mTempTouchState.addOrUpdateWindow(
-                            windowHandle, outsideTargetFlags, BitSet32(0));
-                }
-            }
-        }
-
-        // If there is an error window but it is not taking focus (typically because
-        // it is invisible) then wait for it.  Any other focused window may in
-        // fact be in ANR state.
-        if (topErrorWindowHandle != NULL && newTouchedWindowHandle != topErrorWindowHandle) {
-            injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
-                    NULL, NULL, nextWakeupTime,
-                    "Waiting because a system error window is about to be displayed.");
-            injectionPermission = INJECTION_PERMISSION_UNKNOWN;
-            goto Unresponsive;
-        }
-
-        // Figure out whether splitting will be allowed for this window.
-        if (newTouchedWindowHandle != NULL
-                && newTouchedWindowHandle->getInfo()->supportsSplitTouch()) {
-            // New window supports splitting.
-            isSplit = true;
-        } else if (isSplit) {
-            // New window does not support splitting but we have already split events.
-            // Ignore the new window.
-            newTouchedWindowHandle = NULL;
-        }
-
-        // Handle the case where we did not find a window.
-        if (newTouchedWindowHandle == NULL) {
-            // Try to assign the pointer to the first foreground window we find, if there is one.
-            newTouchedWindowHandle = mTempTouchState.getFirstForegroundWindowHandle();
-            if (newTouchedWindowHandle == NULL) {
-                ALOGI("Dropping event because there is no touchable window at (%d, %d).", x, y);
-                injectionResult = INPUT_EVENT_INJECTION_FAILED;
-                goto Failed;
-            }
-        }
-
-        // Set target flags.
-        int32_t targetFlags = InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS;
-        if (isSplit) {
-            targetFlags |= InputTarget::FLAG_SPLIT;
-        }
-        if (isWindowObscuredAtPointLocked(newTouchedWindowHandle, x, y)) {
-            targetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED;
-        }
-
-        // Update hover state.
-        if (isHoverAction) {
-            newHoverWindowHandle = newTouchedWindowHandle;
-        } else if (maskedAction == AMOTION_EVENT_ACTION_SCROLL) {
-            newHoverWindowHandle = mLastHoverWindowHandle;
-        }
-
-        // Update the temporary touch state.
-        BitSet32 pointerIds;
-        if (isSplit) {
-            uint32_t pointerId = entry->pointerProperties[pointerIndex].id;
-            pointerIds.markBit(pointerId);
-        }
-        mTempTouchState.addOrUpdateWindow(newTouchedWindowHandle, targetFlags, pointerIds);
-    } else {
-        /* Case 2: Pointer move, up, cancel or non-splittable pointer down. */
-
-        // If the pointer is not currently down, then ignore the event.
-        if (! mTempTouchState.down) {
-#if DEBUG_FOCUS
-            ALOGD("Dropping event because the pointer is not down or we previously "
-                    "dropped the pointer down event.");
-#endif
-            injectionResult = INPUT_EVENT_INJECTION_FAILED;
-            goto Failed;
-        }
-
-        // Check whether touches should slip outside of the current foreground window.
-        if (maskedAction == AMOTION_EVENT_ACTION_MOVE
-                && entry->pointerCount == 1
-                && mTempTouchState.isSlippery()) {
-            int32_t x = int32_t(entry->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X));
-            int32_t y = int32_t(entry->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y));
-
-            sp<InputWindowHandle> oldTouchedWindowHandle =
-                    mTempTouchState.getFirstForegroundWindowHandle();
-            sp<InputWindowHandle> newTouchedWindowHandle =
-                    findTouchedWindowAtLocked(displayId, x, y);
-            if (oldTouchedWindowHandle != newTouchedWindowHandle
-                    && newTouchedWindowHandle != NULL) {
-#if DEBUG_FOCUS
-                ALOGD("Touch is slipping out of window %s into window %s.",
-                        oldTouchedWindowHandle->getName().string(),
-                        newTouchedWindowHandle->getName().string());
-#endif
-                // Make a slippery exit from the old window.
-                mTempTouchState.addOrUpdateWindow(oldTouchedWindowHandle,
-                        InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT, BitSet32(0));
-
-                // Make a slippery entrance into the new window.
-                if (newTouchedWindowHandle->getInfo()->supportsSplitTouch()) {
-                    isSplit = true;
-                }
-
-                int32_t targetFlags = InputTarget::FLAG_FOREGROUND
-                        | InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER;
-                if (isSplit) {
-                    targetFlags |= InputTarget::FLAG_SPLIT;
-                }
-                if (isWindowObscuredAtPointLocked(newTouchedWindowHandle, x, y)) {
-                    targetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED;
-                }
-
-                BitSet32 pointerIds;
-                if (isSplit) {
-                    pointerIds.markBit(entry->pointerProperties[0].id);
-                }
-                mTempTouchState.addOrUpdateWindow(newTouchedWindowHandle, targetFlags, pointerIds);
-            }
-        }
-    }
-
-    if (newHoverWindowHandle != mLastHoverWindowHandle) {
-        // Let the previous window know that the hover sequence is over.
-        if (mLastHoverWindowHandle != NULL) {
-#if DEBUG_HOVER
-            ALOGD("Sending hover exit event to window %s.",
-                    mLastHoverWindowHandle->getName().string());
-#endif
-            mTempTouchState.addOrUpdateWindow(mLastHoverWindowHandle,
-                    InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT, BitSet32(0));
-        }
-
-        // Let the new window know that the hover sequence is starting.
-        if (newHoverWindowHandle != NULL) {
-#if DEBUG_HOVER
-            ALOGD("Sending hover enter event to window %s.",
-                    newHoverWindowHandle->getName().string());
-#endif
-            mTempTouchState.addOrUpdateWindow(newHoverWindowHandle,
-                    InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER, BitSet32(0));
-        }
-    }
-
-    // Check permission to inject into all touched foreground windows and ensure there
-    // is at least one touched foreground window.
-    {
-        bool haveForegroundWindow = false;
-        for (size_t i = 0; i < mTempTouchState.windows.size(); i++) {
-            const TouchedWindow& touchedWindow = mTempTouchState.windows[i];
-            if (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) {
-                haveForegroundWindow = true;
-                if (! checkInjectionPermission(touchedWindow.windowHandle,
-                        entry->injectionState)) {
-                    injectionResult = INPUT_EVENT_INJECTION_PERMISSION_DENIED;
-                    injectionPermission = INJECTION_PERMISSION_DENIED;
-                    goto Failed;
-                }
-            }
-        }
-        if (! haveForegroundWindow) {
-#if DEBUG_FOCUS
-            ALOGD("Dropping event because there is no touched foreground window to receive it.");
-#endif
-            injectionResult = INPUT_EVENT_INJECTION_FAILED;
-            goto Failed;
-        }
-
-        // Permission granted to injection into all touched foreground windows.
-        injectionPermission = INJECTION_PERMISSION_GRANTED;
-    }
-
-    // Check whether windows listening for outside touches are owned by the same UID. If it is
-    // set the policy flag that we will not reveal coordinate information to this window.
-    if (maskedAction == AMOTION_EVENT_ACTION_DOWN) {
-        sp<InputWindowHandle> foregroundWindowHandle =
-                mTempTouchState.getFirstForegroundWindowHandle();
-        const int32_t foregroundWindowUid = foregroundWindowHandle->getInfo()->ownerUid;
-        for (size_t i = 0; i < mTempTouchState.windows.size(); i++) {
-            const TouchedWindow& touchedWindow = mTempTouchState.windows[i];
-            if (touchedWindow.targetFlags & InputTarget::FLAG_DISPATCH_AS_OUTSIDE) {
-                sp<InputWindowHandle> inputWindowHandle = touchedWindow.windowHandle;
-                if (inputWindowHandle->getInfo()->ownerUid != foregroundWindowUid) {
-                    mTempTouchState.addOrUpdateWindow(inputWindowHandle,
-                            InputTarget::FLAG_ZERO_COORDS, BitSet32(0));
-                }
-            }
-        }
-    }
-
-    // Ensure all touched foreground windows are ready for new input.
-    for (size_t i = 0; i < mTempTouchState.windows.size(); i++) {
-        const TouchedWindow& touchedWindow = mTempTouchState.windows[i];
-        if (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) {
-            // If the touched window is paused then keep waiting.
-            if (touchedWindow.windowHandle->getInfo()->paused) {
-                injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
-                        NULL, touchedWindow.windowHandle, nextWakeupTime,
-                        "Waiting because the touched window is paused.");
-                goto Unresponsive;
-            }
-
-            // If the touched window is still working on previous events then keep waiting.
-            if (!isWindowReadyForMoreInputLocked(currentTime, touchedWindow.windowHandle, entry)) {
-                injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
-                        NULL, touchedWindow.windowHandle, nextWakeupTime,
-                        "Waiting because the touched window has not finished "
-                        "processing the input events that were previously delivered to it.");
-                goto Unresponsive;
-            }
-        }
-    }
-
-    // If this is the first pointer going down and the touched window has a wallpaper
-    // then also add the touched wallpaper windows so they are locked in for the duration
-    // of the touch gesture.
-    // We do not collect wallpapers during HOVER_MOVE or SCROLL because the wallpaper
-    // engine only supports touch events.  We would need to add a mechanism similar
-    // to View.onGenericMotionEvent to enable wallpapers to handle these events.
-    if (maskedAction == AMOTION_EVENT_ACTION_DOWN) {
-        sp<InputWindowHandle> foregroundWindowHandle =
-                mTempTouchState.getFirstForegroundWindowHandle();
-        if (foregroundWindowHandle->getInfo()->hasWallpaper) {
-            for (size_t i = 0; i < mWindowHandles.size(); i++) {
-                sp<InputWindowHandle> windowHandle = mWindowHandles.itemAt(i);
-                const InputWindowInfo* info = windowHandle->getInfo();
-                if (info->displayId == displayId
-                        && windowHandle->getInfo()->layoutParamsType
-                                == InputWindowInfo::TYPE_WALLPAPER) {
-                    mTempTouchState.addOrUpdateWindow(windowHandle,
-                            InputTarget::FLAG_WINDOW_IS_OBSCURED
-                                    | InputTarget::FLAG_DISPATCH_AS_IS,
-                            BitSet32(0));
-                }
-            }
-        }
-    }
-
-    // Success!  Output targets.
-    injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED;
-
-    for (size_t i = 0; i < mTempTouchState.windows.size(); i++) {
-        const TouchedWindow& touchedWindow = mTempTouchState.windows.itemAt(i);
-        addWindowTargetLocked(touchedWindow.windowHandle, touchedWindow.targetFlags,
-                touchedWindow.pointerIds, inputTargets);
-    }
-
-    // Drop the outside or hover touch windows since we will not care about them
-    // in the next iteration.
-    mTempTouchState.filterNonAsIsTouchWindows();
-
-Failed:
-    // Check injection permission once and for all.
-    if (injectionPermission == INJECTION_PERMISSION_UNKNOWN) {
-        if (checkInjectionPermission(NULL, entry->injectionState)) {
-            injectionPermission = INJECTION_PERMISSION_GRANTED;
-        } else {
-            injectionPermission = INJECTION_PERMISSION_DENIED;
-        }
-    }
-
-    // Update final pieces of touch state if the injector had permission.
-    if (injectionPermission == INJECTION_PERMISSION_GRANTED) {
-        if (!wrongDevice) {
-            if (switchedDevice) {
-#if DEBUG_FOCUS
-                ALOGD("Conflicting pointer actions: Switched to a different device.");
-#endif
-                *outConflictingPointerActions = true;
-            }
-
-            if (isHoverAction) {
-                // Started hovering, therefore no longer down.
-                if (mTouchState.down) {
-#if DEBUG_FOCUS
-                    ALOGD("Conflicting pointer actions: Hover received while pointer was down.");
-#endif
-                    *outConflictingPointerActions = true;
-                }
-                mTouchState.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;
-                }
-            } else if (maskedAction == AMOTION_EVENT_ACTION_UP
-                    || maskedAction == AMOTION_EVENT_ACTION_CANCEL) {
-                // All pointers up or canceled.
-                mTouchState.reset();
-            } else if (maskedAction == AMOTION_EVENT_ACTION_DOWN) {
-                // First pointer went down.
-                if (mTouchState.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) {
-                    int32_t pointerIndex = getMotionEventActionPointerIndex(action);
-                    uint32_t pointerId = entry->pointerProperties[pointerIndex].id;
-
-                    for (size_t i = 0; i < mTempTouchState.windows.size(); ) {
-                        TouchedWindow& touchedWindow = mTempTouchState.windows.editItemAt(i);
-                        if (touchedWindow.targetFlags & InputTarget::FLAG_SPLIT) {
-                            touchedWindow.pointerIds.clearBit(pointerId);
-                            if (touchedWindow.pointerIds.isEmpty()) {
-                                mTempTouchState.windows.removeAt(i);
-                                continue;
-                            }
-                        }
-                        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);
-            }
-
-            // Update hover state.
-            mLastHoverWindowHandle = newHoverWindowHandle;
-        }
-    } else {
-#if DEBUG_FOCUS
-        ALOGD("Not updating touch focus because injection was denied.");
-#endif
-    }
-
-Unresponsive:
-    // Reset temporary touch state to ensure we release unnecessary references to input channels.
-    mTempTouchState.reset();
-
-    nsecs_t timeSpentWaitingForApplication = getTimeSpentWaitingForApplicationLocked(currentTime);
-    updateDispatchStatisticsLocked(currentTime, entry,
-            injectionResult, timeSpentWaitingForApplication);
-#if DEBUG_FOCUS
-    ALOGD("findTouchedWindow finished: injectionResult=%d, injectionPermission=%d, "
-            "timeSpentWaitingForApplication=%0.1fms",
-            injectionResult, injectionPermission, timeSpentWaitingForApplication / 1000000.0);
-#endif
-    return injectionResult;
-}
-
-void InputDispatcher::addWindowTargetLocked(const sp<InputWindowHandle>& windowHandle,
-        int32_t targetFlags, BitSet32 pointerIds, Vector<InputTarget>& inputTargets) {
-    inputTargets.push();
-
-    const InputWindowInfo* windowInfo = windowHandle->getInfo();
-    InputTarget& target = inputTargets.editTop();
-    target.inputChannel = windowInfo->inputChannel;
-    target.flags = targetFlags;
-    target.xOffset = - windowInfo->frameLeft;
-    target.yOffset = - windowInfo->frameTop;
-    target.scaleFactor = windowInfo->scaleFactor;
-    target.pointerIds = pointerIds;
-}
-
-void InputDispatcher::addMonitoringTargetsLocked(Vector<InputTarget>& inputTargets) {
-    for (size_t i = 0; i < mMonitoringChannels.size(); i++) {
-        inputTargets.push();
-
-        InputTarget& target = inputTargets.editTop();
-        target.inputChannel = mMonitoringChannels[i];
-        target.flags = InputTarget::FLAG_DISPATCH_AS_IS;
-        target.xOffset = 0;
-        target.yOffset = 0;
-        target.pointerIds.clear();
-        target.scaleFactor = 1.0f;
-    }
-}
-
-bool InputDispatcher::checkInjectionPermission(const sp<InputWindowHandle>& windowHandle,
-        const InjectionState* injectionState) {
-    if (injectionState
-            && (windowHandle == NULL
-                    || windowHandle->getInfo()->ownerUid != injectionState->injectorUid)
-            && !hasInjectionPermission(injectionState->injectorPid, injectionState->injectorUid)) {
-        if (windowHandle != NULL) {
-            ALOGW("Permission denied: injecting event from pid %d uid %d to window %s "
-                    "owned by uid %d",
-                    injectionState->injectorPid, injectionState->injectorUid,
-                    windowHandle->getName().string(),
-                    windowHandle->getInfo()->ownerUid);
-        } else {
-            ALOGW("Permission denied: injecting event from pid %d uid %d",
-                    injectionState->injectorPid, injectionState->injectorUid);
-        }
-        return false;
-    }
-    return true;
-}
-
-bool InputDispatcher::isWindowObscuredAtPointLocked(
-        const sp<InputWindowHandle>& windowHandle, int32_t x, int32_t y) const {
-    int32_t displayId = windowHandle->getInfo()->displayId;
-    size_t numWindows = mWindowHandles.size();
-    for (size_t i = 0; i < numWindows; i++) {
-        sp<InputWindowHandle> otherHandle = mWindowHandles.itemAt(i);
-        if (otherHandle == windowHandle) {
-            break;
-        }
-
-        const InputWindowInfo* otherInfo = otherHandle->getInfo();
-        if (otherInfo->displayId == displayId
-                && otherInfo->visible && !otherInfo->isTrustedOverlay()
-                && otherInfo->frameContainsPoint(x, y)) {
-            return true;
-        }
-    }
-    return false;
-}
-
-bool InputDispatcher::isWindowReadyForMoreInputLocked(nsecs_t currentTime,
-        const sp<InputWindowHandle>& windowHandle, const EventEntry* eventEntry) {
-    ssize_t connectionIndex = getConnectionIndexLocked(windowHandle->getInputChannel());
-    if (connectionIndex >= 0) {
-        sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
-        if (connection->inputPublisherBlocked) {
-            return false;
-        }
-        if (eventEntry->type == EventEntry::TYPE_KEY) {
-            // If the event is a key event, then we must wait for all previous events to
-            // complete before delivering it because previous events may have the
-            // side-effect of transferring focus to a different window and we want to
-            // ensure that the following keys are sent to the new window.
-            //
-            // Suppose the user touches a button in a window then immediately presses "A".
-            // If the button causes a pop-up window to appear then we want to ensure that
-            // the "A" key is delivered to the new pop-up window.  This is because users
-            // often anticipate pending UI changes when typing on a keyboard.
-            // To obtain this behavior, we must serialize key events with respect to all
-            // prior input events.
-            return connection->outboundQueue.isEmpty()
-                    && connection->waitQueue.isEmpty();
-        }
-        // Touch events can always be sent to a window immediately because the user intended
-        // to touch whatever was visible at the time.  Even if focus changes or a new
-        // window appears moments later, the touch event was meant to be delivered to
-        // whatever window happened to be on screen at the time.
-        //
-        // Generic motion events, such as trackball or joystick events are a little trickier.
-        // Like key events, generic motion events are delivered to the focused window.
-        // Unlike key events, generic motion events don't tend to transfer focus to other
-        // windows and it is not important for them to be serialized.  So we prefer to deliver
-        // generic motion events as soon as possible to improve efficiency and reduce lag
-        // through batching.
-        //
-        // The one case where we pause input event delivery is when the wait queue is piling
-        // up with lots of events because the application is not responding.
-        // This condition ensures that ANRs are detected reliably.
-        if (!connection->waitQueue.isEmpty()
-                && currentTime >= connection->waitQueue.head->deliveryTime
-                        + STREAM_AHEAD_EVENT_TIMEOUT) {
-            return false;
-        }
-    }
-    return true;
-}
-
-String8 InputDispatcher::getApplicationWindowLabelLocked(
-        const sp<InputApplicationHandle>& applicationHandle,
-        const sp<InputWindowHandle>& windowHandle) {
-    if (applicationHandle != NULL) {
-        if (windowHandle != NULL) {
-            String8 label(applicationHandle->getName());
-            label.append(" - ");
-            label.append(windowHandle->getName());
-            return label;
-        } else {
-            return applicationHandle->getName();
-        }
-    } else if (windowHandle != NULL) {
-        return windowHandle->getName();
-    } else {
-        return String8("<unknown application or window>");
-    }
-}
-
-void InputDispatcher::pokeUserActivityLocked(const EventEntry* eventEntry) {
-    if (mFocusedWindowHandle != NULL) {
-        const InputWindowInfo* info = mFocusedWindowHandle->getInfo();
-        if (info->inputFeatures & InputWindowInfo::INPUT_FEATURE_DISABLE_USER_ACTIVITY) {
-#if DEBUG_DISPATCH_CYCLE
-            ALOGD("Not poking user activity: disabled by window '%s'.", info->name.string());
-#endif
-            return;
-        }
-    }
-
-    int32_t eventType = USER_ACTIVITY_EVENT_OTHER;
-    switch (eventEntry->type) {
-    case EventEntry::TYPE_MOTION: {
-        const MotionEntry* motionEntry = static_cast<const MotionEntry*>(eventEntry);
-        if (motionEntry->action == AMOTION_EVENT_ACTION_CANCEL) {
-            return;
-        }
-
-        if (MotionEvent::isTouchEvent(motionEntry->source, motionEntry->action)) {
-            eventType = USER_ACTIVITY_EVENT_TOUCH;
-        }
-        break;
-    }
-    case EventEntry::TYPE_KEY: {
-        const KeyEntry* keyEntry = static_cast<const KeyEntry*>(eventEntry);
-        if (keyEntry->flags & AKEY_EVENT_FLAG_CANCELED) {
-            return;
-        }
-        eventType = USER_ACTIVITY_EVENT_BUTTON;
-        break;
-    }
-    }
-
-    CommandEntry* commandEntry = postCommandLocked(
-            & InputDispatcher::doPokeUserActivityLockedInterruptible);
-    commandEntry->eventTime = eventEntry->eventTime;
-    commandEntry->userActivityEventType = eventType;
-}
-
-void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,
-        const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget) {
-#if DEBUG_DISPATCH_CYCLE
-    ALOGD("channel '%s' ~ prepareDispatchCycle - flags=0x%08x, "
-            "xOffset=%f, yOffset=%f, scaleFactor=%f, "
-            "pointerIds=0x%x",
-            connection->getInputChannelName(), inputTarget->flags,
-            inputTarget->xOffset, inputTarget->yOffset,
-            inputTarget->scaleFactor, inputTarget->pointerIds.value);
-#endif
-
-    // Skip this event if the connection status is not normal.
-    // We don't want to enqueue additional outbound events if the connection is broken.
-    if (connection->status != Connection::STATUS_NORMAL) {
-#if DEBUG_DISPATCH_CYCLE
-        ALOGD("channel '%s' ~ Dropping event because the channel status is %s",
-                connection->getInputChannelName(), connection->getStatusLabel());
-#endif
-        return;
-    }
-
-    // Split a motion event if needed.
-    if (inputTarget->flags & InputTarget::FLAG_SPLIT) {
-        ALOG_ASSERT(eventEntry->type == EventEntry::TYPE_MOTION);
-
-        MotionEntry* originalMotionEntry = static_cast<MotionEntry*>(eventEntry);
-        if (inputTarget->pointerIds.count() != originalMotionEntry->pointerCount) {
-            MotionEntry* splitMotionEntry = splitMotionEvent(
-                    originalMotionEntry, inputTarget->pointerIds);
-            if (!splitMotionEntry) {
-                return; // split event was dropped
-            }
-#if DEBUG_FOCUS
-            ALOGD("channel '%s' ~ Split motion event.",
-                    connection->getInputChannelName());
-            logOutboundMotionDetailsLocked("  ", splitMotionEntry);
-#endif
-            enqueueDispatchEntriesLocked(currentTime, connection,
-                    splitMotionEntry, inputTarget);
-            splitMotionEntry->release();
-            return;
-        }
-    }
-
-    // Not splitting.  Enqueue dispatch entries for the event as is.
-    enqueueDispatchEntriesLocked(currentTime, connection, eventEntry, inputTarget);
-}
-
-void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime,
-        const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget) {
-    bool wasEmpty = connection->outboundQueue.isEmpty();
-
-    // Enqueue dispatch entries for the requested modes.
-    enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
-            InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT);
-    enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
-            InputTarget::FLAG_DISPATCH_AS_OUTSIDE);
-    enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
-            InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER);
-    enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
-            InputTarget::FLAG_DISPATCH_AS_IS);
-    enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
-            InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT);
-    enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
-            InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER);
-
-    // If the outbound queue was previously empty, start the dispatch cycle going.
-    if (wasEmpty && !connection->outboundQueue.isEmpty()) {
-        startDispatchCycleLocked(currentTime, connection);
-    }
-}
-
-void InputDispatcher::enqueueDispatchEntryLocked(
-        const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget,
-        int32_t dispatchMode) {
-    int32_t inputTargetFlags = inputTarget->flags;
-    if (!(inputTargetFlags & dispatchMode)) {
-        return;
-    }
-    inputTargetFlags = (inputTargetFlags & ~InputTarget::FLAG_DISPATCH_MASK) | dispatchMode;
-
-    // This is a new event.
-    // Enqueue a new dispatch entry onto the outbound queue for this connection.
-    DispatchEntry* dispatchEntry = new DispatchEntry(eventEntry, // increments ref
-            inputTargetFlags, inputTarget->xOffset, inputTarget->yOffset,
-            inputTarget->scaleFactor);
-
-    // Apply target flags and update the connection's input state.
-    switch (eventEntry->type) {
-    case EventEntry::TYPE_KEY: {
-        KeyEntry* keyEntry = static_cast<KeyEntry*>(eventEntry);
-        dispatchEntry->resolvedAction = keyEntry->action;
-        dispatchEntry->resolvedFlags = keyEntry->flags;
-
-        if (!connection->inputState.trackKey(keyEntry,
-                dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags)) {
-#if DEBUG_DISPATCH_CYCLE
-            ALOGD("channel '%s' ~ enqueueDispatchEntryLocked: skipping inconsistent key event",
-                    connection->getInputChannelName());
-#endif
-            delete dispatchEntry;
-            return; // skip the inconsistent event
-        }
-        break;
-    }
-
-    case EventEntry::TYPE_MOTION: {
-        MotionEntry* motionEntry = static_cast<MotionEntry*>(eventEntry);
-        if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_OUTSIDE) {
-            dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_OUTSIDE;
-        } else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT) {
-            dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_HOVER_EXIT;
-        } else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER) {
-            dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_HOVER_ENTER;
-        } else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT) {
-            dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_CANCEL;
-        } else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER) {
-            dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_DOWN;
-        } else {
-            dispatchEntry->resolvedAction = motionEntry->action;
-        }
-        if (dispatchEntry->resolvedAction == AMOTION_EVENT_ACTION_HOVER_MOVE
-                && !connection->inputState.isHovering(
-                        motionEntry->deviceId, motionEntry->source, motionEntry->displayId)) {
-#if DEBUG_DISPATCH_CYCLE
-        ALOGD("channel '%s' ~ enqueueDispatchEntryLocked: filling in missing hover enter event",
-                connection->getInputChannelName());
-#endif
-            dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_HOVER_ENTER;
-        }
-
-        dispatchEntry->resolvedFlags = motionEntry->flags;
-        if (dispatchEntry->targetFlags & InputTarget::FLAG_WINDOW_IS_OBSCURED) {
-            dispatchEntry->resolvedFlags |= AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED;
-        }
-
-        if (!connection->inputState.trackMotion(motionEntry,
-                dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags)) {
-#if DEBUG_DISPATCH_CYCLE
-            ALOGD("channel '%s' ~ enqueueDispatchEntryLocked: skipping inconsistent motion event",
-                    connection->getInputChannelName());
-#endif
-            delete dispatchEntry;
-            return; // skip the inconsistent event
-        }
-        break;
-    }
-    }
-
-    // Remember that we are waiting for this dispatch to complete.
-    if (dispatchEntry->hasForegroundTarget()) {
-        incrementPendingForegroundDispatchesLocked(eventEntry);
-    }
-
-    // Enqueue the dispatch entry.
-    connection->outboundQueue.enqueueAtTail(dispatchEntry);
-    traceOutboundQueueLengthLocked(connection);
-}
-
-void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
-        const sp<Connection>& connection) {
-#if DEBUG_DISPATCH_CYCLE
-    ALOGD("channel '%s' ~ startDispatchCycle",
-            connection->getInputChannelName());
-#endif
-
-    while (connection->status == Connection::STATUS_NORMAL
-            && !connection->outboundQueue.isEmpty()) {
-        DispatchEntry* dispatchEntry = connection->outboundQueue.head;
-        dispatchEntry->deliveryTime = currentTime;
-
-        // Publish the event.
-        status_t status;
-        EventEntry* eventEntry = dispatchEntry->eventEntry;
-        switch (eventEntry->type) {
-        case EventEntry::TYPE_KEY: {
-            KeyEntry* keyEntry = static_cast<KeyEntry*>(eventEntry);
-
-            // Publish the key event.
-            status = connection->inputPublisher.publishKeyEvent(dispatchEntry->seq,
-                    keyEntry->deviceId, keyEntry->source,
-                    dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags,
-                    keyEntry->keyCode, keyEntry->scanCode,
-                    keyEntry->metaState, keyEntry->repeatCount, keyEntry->downTime,
-                    keyEntry->eventTime);
-            break;
-        }
-
-        case EventEntry::TYPE_MOTION: {
-            MotionEntry* motionEntry = static_cast<MotionEntry*>(eventEntry);
-
-            PointerCoords scaledCoords[MAX_POINTERS];
-            const PointerCoords* usingCoords = motionEntry->pointerCoords;
-
-            // Set the X and Y offset depending on the input source.
-            float xOffset, yOffset, scaleFactor;
-            if ((motionEntry->source & AINPUT_SOURCE_CLASS_POINTER)
-                    && !(dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS)) {
-                scaleFactor = dispatchEntry->scaleFactor;
-                xOffset = dispatchEntry->xOffset * scaleFactor;
-                yOffset = dispatchEntry->yOffset * scaleFactor;
-                if (scaleFactor != 1.0f) {
-                    for (size_t i = 0; i < motionEntry->pointerCount; i++) {
-                        scaledCoords[i] = motionEntry->pointerCoords[i];
-                        scaledCoords[i].scale(scaleFactor);
-                    }
-                    usingCoords = scaledCoords;
-                }
-            } else {
-                xOffset = 0.0f;
-                yOffset = 0.0f;
-                scaleFactor = 1.0f;
-
-                // We don't want the dispatch target to know.
-                if (dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS) {
-                    for (size_t i = 0; i < motionEntry->pointerCount; i++) {
-                        scaledCoords[i].clear();
-                    }
-                    usingCoords = scaledCoords;
-                }
-            }
-
-            // Publish the motion event.
-            status = connection->inputPublisher.publishMotionEvent(dispatchEntry->seq,
-                    motionEntry->deviceId, motionEntry->source,
-                    dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags,
-                    motionEntry->edgeFlags, motionEntry->metaState, motionEntry->buttonState,
-                    xOffset, yOffset,
-                    motionEntry->xPrecision, motionEntry->yPrecision,
-                    motionEntry->downTime, motionEntry->eventTime,
-                    motionEntry->pointerCount, motionEntry->pointerProperties,
-                    usingCoords);
-            break;
-        }
-
-        default:
-            ALOG_ASSERT(false);
-            return;
-        }
-
-        // Check the result.
-        if (status) {
-            if (status == WOULD_BLOCK) {
-                if (connection->waitQueue.isEmpty()) {
-                    ALOGE("channel '%s' ~ Could not publish event because the pipe is full. "
-                            "This is unexpected because the wait queue is empty, so the pipe "
-                            "should be empty and we shouldn't have any problems writing an "
-                            "event to it, status=%d", connection->getInputChannelName(), status);
-                    abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/);
-                } else {
-                    // Pipe is full and we are waiting for the app to finish process some events
-                    // before sending more events to it.
-#if DEBUG_DISPATCH_CYCLE
-                    ALOGD("channel '%s' ~ Could not publish event because the pipe is full, "
-                            "waiting for the application to catch up",
-                            connection->getInputChannelName());
-#endif
-                    connection->inputPublisherBlocked = true;
-                }
-            } else {
-                ALOGE("channel '%s' ~ Could not publish event due to an unexpected error, "
-                        "status=%d", connection->getInputChannelName(), status);
-                abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/);
-            }
-            return;
-        }
-
-        // Re-enqueue the event on the wait queue.
-        connection->outboundQueue.dequeue(dispatchEntry);
-        traceOutboundQueueLengthLocked(connection);
-        connection->waitQueue.enqueueAtTail(dispatchEntry);
-        traceWaitQueueLengthLocked(connection);
-    }
-}
-
-void InputDispatcher::finishDispatchCycleLocked(nsecs_t currentTime,
-        const sp<Connection>& connection, uint32_t seq, bool handled) {
-#if DEBUG_DISPATCH_CYCLE
-    ALOGD("channel '%s' ~ finishDispatchCycle - seq=%u, handled=%s",
-            connection->getInputChannelName(), seq, toString(handled));
-#endif
-
-    connection->inputPublisherBlocked = false;
-
-    if (connection->status == Connection::STATUS_BROKEN
-            || connection->status == Connection::STATUS_ZOMBIE) {
-        return;
-    }
-
-    // Notify other system components and prepare to start the next dispatch cycle.
-    onDispatchCycleFinishedLocked(currentTime, connection, seq, handled);
-}
-
-void InputDispatcher::abortBrokenDispatchCycleLocked(nsecs_t currentTime,
-        const sp<Connection>& connection, bool notify) {
-#if DEBUG_DISPATCH_CYCLE
-    ALOGD("channel '%s' ~ abortBrokenDispatchCycle - notify=%s",
-            connection->getInputChannelName(), toString(notify));
-#endif
-
-    // Clear the dispatch queues.
-    drainDispatchQueueLocked(&connection->outboundQueue);
-    traceOutboundQueueLengthLocked(connection);
-    drainDispatchQueueLocked(&connection->waitQueue);
-    traceWaitQueueLengthLocked(connection);
-
-    // The connection appears to be unrecoverably broken.
-    // Ignore already broken or zombie connections.
-    if (connection->status == Connection::STATUS_NORMAL) {
-        connection->status = Connection::STATUS_BROKEN;
-
-        if (notify) {
-            // Notify other system components.
-            onDispatchCycleBrokenLocked(currentTime, connection);
-        }
-    }
-}
-
-void InputDispatcher::drainDispatchQueueLocked(Queue<DispatchEntry>* queue) {
-    while (!queue->isEmpty()) {
-        DispatchEntry* dispatchEntry = queue->dequeueAtHead();
-        releaseDispatchEntryLocked(dispatchEntry);
-    }
-}
-
-void InputDispatcher::releaseDispatchEntryLocked(DispatchEntry* dispatchEntry) {
-    if (dispatchEntry->hasForegroundTarget()) {
-        decrementPendingForegroundDispatchesLocked(dispatchEntry->eventEntry);
-    }
-    delete dispatchEntry;
-}
-
-int InputDispatcher::handleReceiveCallback(int fd, int events, void* data) {
-    InputDispatcher* d = static_cast<InputDispatcher*>(data);
-
-    { // acquire lock
-        AutoMutex _l(d->mLock);
-
-        ssize_t connectionIndex = d->mConnectionsByFd.indexOfKey(fd);
-        if (connectionIndex < 0) {
-            ALOGE("Received spurious receive callback for unknown input channel.  "
-                    "fd=%d, events=0x%x", fd, events);
-            return 0; // remove the callback
-        }
-
-        bool notify;
-        sp<Connection> connection = d->mConnectionsByFd.valueAt(connectionIndex);
-        if (!(events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP))) {
-            if (!(events & ALOOPER_EVENT_INPUT)) {
-                ALOGW("channel '%s' ~ Received spurious callback for unhandled poll event.  "
-                        "events=0x%x", connection->getInputChannelName(), events);
-                return 1;
-            }
-
-            nsecs_t currentTime = now();
-            bool gotOne = false;
-            status_t status;
-            for (;;) {
-                uint32_t seq;
-                bool handled;
-                status = connection->inputPublisher.receiveFinishedSignal(&seq, &handled);
-                if (status) {
-                    break;
-                }
-                d->finishDispatchCycleLocked(currentTime, connection, seq, handled);
-                gotOne = true;
-            }
-            if (gotOne) {
-                d->runCommandsLockedInterruptible();
-                if (status == WOULD_BLOCK) {
-                    return 1;
-                }
-            }
-
-            notify = status != DEAD_OBJECT || !connection->monitor;
-            if (notify) {
-                ALOGE("channel '%s' ~ Failed to receive finished signal.  status=%d",
-                        connection->getInputChannelName(), status);
-            }
-        } else {
-            // Monitor channels are never explicitly unregistered.
-            // We do it automatically when the remote endpoint is closed so don't warn
-            // about them.
-            notify = !connection->monitor;
-            if (notify) {
-                ALOGW("channel '%s' ~ Consumer closed input channel or an error occurred.  "
-                        "events=0x%x", connection->getInputChannelName(), events);
-            }
-        }
-
-        // Unregister the channel.
-        d->unregisterInputChannelLocked(connection->inputChannel, notify);
-        return 0; // remove the callback
-    } // release lock
-}
-
-void InputDispatcher::synthesizeCancelationEventsForAllConnectionsLocked(
-        const CancelationOptions& options) {
-    for (size_t i = 0; i < mConnectionsByFd.size(); i++) {
-        synthesizeCancelationEventsForConnectionLocked(
-                mConnectionsByFd.valueAt(i), options);
-    }
-}
-
-void InputDispatcher::synthesizeCancelationEventsForInputChannelLocked(
-        const sp<InputChannel>& channel, const CancelationOptions& options) {
-    ssize_t index = getConnectionIndexLocked(channel);
-    if (index >= 0) {
-        synthesizeCancelationEventsForConnectionLocked(
-                mConnectionsByFd.valueAt(index), options);
-    }
-}
-
-void InputDispatcher::synthesizeCancelationEventsForConnectionLocked(
-        const sp<Connection>& connection, const CancelationOptions& options) {
-    if (connection->status == Connection::STATUS_BROKEN) {
-        return;
-    }
-
-    nsecs_t currentTime = now();
-
-    Vector<EventEntry*> cancelationEvents;
-    connection->inputState.synthesizeCancelationEvents(currentTime,
-            cancelationEvents, options);
-
-    if (!cancelationEvents.isEmpty()) {
-#if DEBUG_OUTBOUND_EVENT_DETAILS
-        ALOGD("channel '%s' ~ Synthesized %d cancelation events to bring channel back in sync "
-                "with reality: %s, mode=%d.",
-                connection->getInputChannelName(), cancelationEvents.size(),
-                options.reason, options.mode);
-#endif
-        for (size_t i = 0; i < cancelationEvents.size(); i++) {
-            EventEntry* cancelationEventEntry = cancelationEvents.itemAt(i);
-            switch (cancelationEventEntry->type) {
-            case EventEntry::TYPE_KEY:
-                logOutboundKeyDetailsLocked("cancel - ",
-                        static_cast<KeyEntry*>(cancelationEventEntry));
-                break;
-            case EventEntry::TYPE_MOTION:
-                logOutboundMotionDetailsLocked("cancel - ",
-                        static_cast<MotionEntry*>(cancelationEventEntry));
-                break;
-            }
-
-            InputTarget target;
-            sp<InputWindowHandle> windowHandle = getWindowHandleLocked(connection->inputChannel);
-            if (windowHandle != NULL) {
-                const InputWindowInfo* windowInfo = windowHandle->getInfo();
-                target.xOffset = -windowInfo->frameLeft;
-                target.yOffset = -windowInfo->frameTop;
-                target.scaleFactor = windowInfo->scaleFactor;
-            } else {
-                target.xOffset = 0;
-                target.yOffset = 0;
-                target.scaleFactor = 1.0f;
-            }
-            target.inputChannel = connection->inputChannel;
-            target.flags = InputTarget::FLAG_DISPATCH_AS_IS;
-
-            enqueueDispatchEntryLocked(connection, cancelationEventEntry, // increments ref
-                    &target, InputTarget::FLAG_DISPATCH_AS_IS);
-
-            cancelationEventEntry->release();
-        }
-
-        startDispatchCycleLocked(currentTime, connection);
-    }
-}
-
-InputDispatcher::MotionEntry*
-InputDispatcher::splitMotionEvent(const MotionEntry* originalMotionEntry, BitSet32 pointerIds) {
-    ALOG_ASSERT(pointerIds.value != 0);
-
-    uint32_t splitPointerIndexMap[MAX_POINTERS];
-    PointerProperties splitPointerProperties[MAX_POINTERS];
-    PointerCoords splitPointerCoords[MAX_POINTERS];
-
-    uint32_t originalPointerCount = originalMotionEntry->pointerCount;
-    uint32_t splitPointerCount = 0;
-
-    for (uint32_t originalPointerIndex = 0; originalPointerIndex < originalPointerCount;
-            originalPointerIndex++) {
-        const PointerProperties& pointerProperties =
-                originalMotionEntry->pointerProperties[originalPointerIndex];
-        uint32_t pointerId = uint32_t(pointerProperties.id);
-        if (pointerIds.hasBit(pointerId)) {
-            splitPointerIndexMap[splitPointerCount] = originalPointerIndex;
-            splitPointerProperties[splitPointerCount].copyFrom(pointerProperties);
-            splitPointerCoords[splitPointerCount].copyFrom(
-                    originalMotionEntry->pointerCoords[originalPointerIndex]);
-            splitPointerCount += 1;
-        }
-    }
-
-    if (splitPointerCount != pointerIds.count()) {
-        // This is bad.  We are missing some of the pointers that we expected to deliver.
-        // Most likely this indicates that we received an ACTION_MOVE events that has
-        // different pointer ids than we expected based on the previous ACTION_DOWN
-        // or ACTION_POINTER_DOWN events that caused us to decide to split the pointers
-        // in this way.
-        ALOGW("Dropping split motion event because the pointer count is %d but "
-                "we expected there to be %d pointers.  This probably means we received "
-                "a broken sequence of pointer ids from the input device.",
-                splitPointerCount, pointerIds.count());
-        return NULL;
-    }
-
-    int32_t action = originalMotionEntry->action;
-    int32_t maskedAction = action & AMOTION_EVENT_ACTION_MASK;
-    if (maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN
-            || maskedAction == AMOTION_EVENT_ACTION_POINTER_UP) {
-        int32_t originalPointerIndex = getMotionEventActionPointerIndex(action);
-        const PointerProperties& pointerProperties =
-                originalMotionEntry->pointerProperties[originalPointerIndex];
-        uint32_t pointerId = uint32_t(pointerProperties.id);
-        if (pointerIds.hasBit(pointerId)) {
-            if (pointerIds.count() == 1) {
-                // The first/last pointer went down/up.
-                action = maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN
-                        ? AMOTION_EVENT_ACTION_DOWN : AMOTION_EVENT_ACTION_UP;
-            } else {
-                // A secondary pointer went down/up.
-                uint32_t splitPointerIndex = 0;
-                while (pointerId != uint32_t(splitPointerProperties[splitPointerIndex].id)) {
-                    splitPointerIndex += 1;
-                }
-                action = maskedAction | (splitPointerIndex
-                        << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
-            }
-        } else {
-            // An unrelated pointer changed.
-            action = AMOTION_EVENT_ACTION_MOVE;
-        }
-    }
-
-    MotionEntry* splitMotionEntry = new MotionEntry(
-            originalMotionEntry->eventTime,
-            originalMotionEntry->deviceId,
-            originalMotionEntry->source,
-            originalMotionEntry->policyFlags,
-            action,
-            originalMotionEntry->flags,
-            originalMotionEntry->metaState,
-            originalMotionEntry->buttonState,
-            originalMotionEntry->edgeFlags,
-            originalMotionEntry->xPrecision,
-            originalMotionEntry->yPrecision,
-            originalMotionEntry->downTime,
-            originalMotionEntry->displayId,
-            splitPointerCount, splitPointerProperties, splitPointerCoords);
-
-    if (originalMotionEntry->injectionState) {
-        splitMotionEntry->injectionState = originalMotionEntry->injectionState;
-        splitMotionEntry->injectionState->refCount += 1;
-    }
-
-    return splitMotionEntry;
-}
-
-void InputDispatcher::notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) {
-#if DEBUG_INBOUND_EVENT_DETAILS
-    ALOGD("notifyConfigurationChanged - eventTime=%lld", args->eventTime);
-#endif
-
-    bool needWake;
-    { // acquire lock
-        AutoMutex _l(mLock);
-
-        ConfigurationChangedEntry* newEntry = new ConfigurationChangedEntry(args->eventTime);
-        needWake = enqueueInboundEventLocked(newEntry);
-    } // release lock
-
-    if (needWake) {
-        mLooper->wake();
-    }
-}
-
-void InputDispatcher::notifyKey(const NotifyKeyArgs* args) {
-#if DEBUG_INBOUND_EVENT_DETAILS
-    ALOGD("notifyKey - eventTime=%lld, deviceId=%d, source=0x%x, policyFlags=0x%x, action=0x%x, "
-            "flags=0x%x, keyCode=0x%x, scanCode=0x%x, metaState=0x%x, downTime=%lld",
-            args->eventTime, args->deviceId, args->source, args->policyFlags,
-            args->action, args->flags, args->keyCode, args->scanCode,
-            args->metaState, args->downTime);
-#endif
-    if (!validateKeyEvent(args->action)) {
-        return;
-    }
-
-    uint32_t policyFlags = args->policyFlags;
-    int32_t flags = args->flags;
-    int32_t metaState = args->metaState;
-    if ((policyFlags & POLICY_FLAG_VIRTUAL) || (flags & AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY)) {
-        policyFlags |= POLICY_FLAG_VIRTUAL;
-        flags |= AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY;
-    }
-    if (policyFlags & POLICY_FLAG_ALT) {
-        metaState |= AMETA_ALT_ON | AMETA_ALT_LEFT_ON;
-    }
-    if (policyFlags & POLICY_FLAG_ALT_GR) {
-        metaState |= AMETA_ALT_ON | AMETA_ALT_RIGHT_ON;
-    }
-    if (policyFlags & POLICY_FLAG_SHIFT) {
-        metaState |= AMETA_SHIFT_ON | AMETA_SHIFT_LEFT_ON;
-    }
-    if (policyFlags & POLICY_FLAG_CAPS_LOCK) {
-        metaState |= AMETA_CAPS_LOCK_ON;
-    }
-    if (policyFlags & POLICY_FLAG_FUNCTION) {
-        metaState |= AMETA_FUNCTION_ON;
-    }
-
-    policyFlags |= POLICY_FLAG_TRUSTED;
-
-    KeyEvent event;
-    event.initialize(args->deviceId, args->source, args->action,
-            flags, args->keyCode, args->scanCode, metaState, 0,
-            args->downTime, args->eventTime);
-
-    mPolicy->interceptKeyBeforeQueueing(&event, /*byref*/ policyFlags);
-
-    if (policyFlags & POLICY_FLAG_WOKE_HERE) {
-        flags |= AKEY_EVENT_FLAG_WOKE_HERE;
-    }
-
-    bool needWake;
-    { // acquire lock
-        mLock.lock();
-
-        if (shouldSendKeyToInputFilterLocked(args)) {
-            mLock.unlock();
-
-            policyFlags |= POLICY_FLAG_FILTERED;
-            if (!mPolicy->filterInputEvent(&event, policyFlags)) {
-                return; // event was consumed by the filter
-            }
-
-            mLock.lock();
-        }
-
-        int32_t repeatCount = 0;
-        KeyEntry* newEntry = new KeyEntry(args->eventTime,
-                args->deviceId, args->source, policyFlags,
-                args->action, flags, args->keyCode, args->scanCode,
-                metaState, repeatCount, args->downTime);
-
-        needWake = enqueueInboundEventLocked(newEntry);
-        mLock.unlock();
-    } // release lock
-
-    if (needWake) {
-        mLooper->wake();
-    }
-}
-
-bool InputDispatcher::shouldSendKeyToInputFilterLocked(const NotifyKeyArgs* args) {
-    return mInputFilterEnabled;
-}
-
-void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) {
-#if DEBUG_INBOUND_EVENT_DETAILS
-    ALOGD("notifyMotion - eventTime=%lld, deviceId=%d, source=0x%x, policyFlags=0x%x, "
-            "action=0x%x, flags=0x%x, metaState=0x%x, buttonState=0x%x, edgeFlags=0x%x, "
-            "xPrecision=%f, yPrecision=%f, downTime=%lld",
-            args->eventTime, args->deviceId, args->source, args->policyFlags,
-            args->action, args->flags, args->metaState, args->buttonState,
-            args->edgeFlags, args->xPrecision, args->yPrecision, args->downTime);
-    for (uint32_t i = 0; i < args->pointerCount; i++) {
-        ALOGD("  Pointer %d: id=%d, toolType=%d, "
-                "x=%f, y=%f, pressure=%f, size=%f, "
-                "touchMajor=%f, touchMinor=%f, toolMajor=%f, toolMinor=%f, "
-                "orientation=%f",
-                i, args->pointerProperties[i].id,
-                args->pointerProperties[i].toolType,
-                args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X),
-                args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y),
-                args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE),
-                args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_SIZE),
-                args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR),
-                args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR),
-                args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR),
-                args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR),
-                args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION));
-    }
-#endif
-    if (!validateMotionEvent(args->action, args->pointerCount, args->pointerProperties)) {
-        return;
-    }
-
-    uint32_t policyFlags = args->policyFlags;
-    policyFlags |= POLICY_FLAG_TRUSTED;
-    mPolicy->interceptMotionBeforeQueueing(args->eventTime, /*byref*/ policyFlags);
-
-    bool needWake;
-    { // acquire lock
-        mLock.lock();
-
-        if (shouldSendMotionToInputFilterLocked(args)) {
-            mLock.unlock();
-
-            MotionEvent event;
-            event.initialize(args->deviceId, args->source, args->action, args->flags,
-                    args->edgeFlags, args->metaState, args->buttonState, 0, 0,
-                    args->xPrecision, args->yPrecision,
-                    args->downTime, args->eventTime,
-                    args->pointerCount, args->pointerProperties, args->pointerCoords);
-
-            policyFlags |= POLICY_FLAG_FILTERED;
-            if (!mPolicy->filterInputEvent(&event, policyFlags)) {
-                return; // event was consumed by the filter
-            }
-
-            mLock.lock();
-        }
-
-        // Just enqueue a new motion event.
-        MotionEntry* newEntry = new MotionEntry(args->eventTime,
-                args->deviceId, args->source, policyFlags,
-                args->action, args->flags, args->metaState, args->buttonState,
-                args->edgeFlags, args->xPrecision, args->yPrecision, args->downTime,
-                args->displayId,
-                args->pointerCount, args->pointerProperties, args->pointerCoords);
-
-        needWake = enqueueInboundEventLocked(newEntry);
-        mLock.unlock();
-    } // release lock
-
-    if (needWake) {
-        mLooper->wake();
-    }
-}
-
-bool InputDispatcher::shouldSendMotionToInputFilterLocked(const NotifyMotionArgs* args) {
-    // TODO: support sending secondary display events to input filter
-    return mInputFilterEnabled && isMainDisplay(args->displayId);
-}
-
-void InputDispatcher::notifySwitch(const NotifySwitchArgs* args) {
-#if DEBUG_INBOUND_EVENT_DETAILS
-    ALOGD("notifySwitch - eventTime=%lld, policyFlags=0x%x, switchValues=0x%08x, switchMask=0x%08x",
-            args->eventTime, args->policyFlags,
-            args->switchValues, args->switchMask);
-#endif
-
-    uint32_t policyFlags = args->policyFlags;
-    policyFlags |= POLICY_FLAG_TRUSTED;
-    mPolicy->notifySwitch(args->eventTime,
-            args->switchValues, args->switchMask, policyFlags);
-}
-
-void InputDispatcher::notifyDeviceReset(const NotifyDeviceResetArgs* args) {
-#if DEBUG_INBOUND_EVENT_DETAILS
-    ALOGD("notifyDeviceReset - eventTime=%lld, deviceId=%d",
-            args->eventTime, args->deviceId);
-#endif
-
-    bool needWake;
-    { // acquire lock
-        AutoMutex _l(mLock);
-
-        DeviceResetEntry* newEntry = new DeviceResetEntry(args->eventTime, args->deviceId);
-        needWake = enqueueInboundEventLocked(newEntry);
-    } // release lock
-
-    if (needWake) {
-        mLooper->wake();
-    }
-}
-
-int32_t InputDispatcher::injectInputEvent(const InputEvent* event,
-        int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis,
-        uint32_t policyFlags) {
-#if DEBUG_INBOUND_EVENT_DETAILS
-    ALOGD("injectInputEvent - eventType=%d, injectorPid=%d, injectorUid=%d, "
-            "syncMode=%d, timeoutMillis=%d, policyFlags=0x%08x",
-            event->getType(), injectorPid, injectorUid, syncMode, timeoutMillis, policyFlags);
-#endif
-
-    nsecs_t endTime = now() + milliseconds_to_nanoseconds(timeoutMillis);
-
-    policyFlags |= POLICY_FLAG_INJECTED;
-    if (hasInjectionPermission(injectorPid, injectorUid)) {
-        policyFlags |= POLICY_FLAG_TRUSTED;
-    }
-
-    EventEntry* firstInjectedEntry;
-    EventEntry* lastInjectedEntry;
-    switch (event->getType()) {
-    case AINPUT_EVENT_TYPE_KEY: {
-        const KeyEvent* keyEvent = static_cast<const KeyEvent*>(event);
-        int32_t action = keyEvent->getAction();
-        if (! validateKeyEvent(action)) {
-            return INPUT_EVENT_INJECTION_FAILED;
-        }
-
-        int32_t flags = keyEvent->getFlags();
-        if (flags & AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY) {
-            policyFlags |= POLICY_FLAG_VIRTUAL;
-        }
-
-        if (!(policyFlags & POLICY_FLAG_FILTERED)) {
-            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(),
-                policyFlags, action, flags,
-                keyEvent->getKeyCode(), keyEvent->getScanCode(), keyEvent->getMetaState(),
-                keyEvent->getRepeatCount(), keyEvent->getDownTime());
-        lastInjectedEntry = firstInjectedEntry;
-        break;
-    }
-
-    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();
-        if (! validateMotionEvent(action, pointerCount, pointerProperties)) {
-            return INPUT_EVENT_INJECTION_FAILED;
-        }
-
-        if (!(policyFlags & POLICY_FLAG_FILTERED)) {
-            nsecs_t eventTime = motionEvent->getEventTime();
-            mPolicy->interceptMotionBeforeQueueing(eventTime, /*byref*/ policyFlags);
-        }
-
-        mLock.lock();
-        const nsecs_t* sampleEventTimes = motionEvent->getSampleEventTimes();
-        const PointerCoords* samplePointerCoords = motionEvent->getSamplePointerCoords();
-        firstInjectedEntry = new MotionEntry(*sampleEventTimes,
-                motionEvent->getDeviceId(), motionEvent->getSource(), policyFlags,
-                action, motionEvent->getFlags(),
-                motionEvent->getMetaState(), motionEvent->getButtonState(),
-                motionEvent->getEdgeFlags(),
-                motionEvent->getXPrecision(), motionEvent->getYPrecision(),
-                motionEvent->getDownTime(), displayId,
-                uint32_t(pointerCount), pointerProperties, samplePointerCoords);
-        lastInjectedEntry = firstInjectedEntry;
-        for (size_t i = motionEvent->getHistorySize(); i > 0; i--) {
-            sampleEventTimes += 1;
-            samplePointerCoords += pointerCount;
-            MotionEntry* nextInjectedEntry = new MotionEntry(*sampleEventTimes,
-                    motionEvent->getDeviceId(), motionEvent->getSource(), policyFlags,
-                    action, motionEvent->getFlags(),
-                    motionEvent->getMetaState(), motionEvent->getButtonState(),
-                    motionEvent->getEdgeFlags(),
-                    motionEvent->getXPrecision(), motionEvent->getYPrecision(),
-                    motionEvent->getDownTime(), displayId,
-                    uint32_t(pointerCount), pointerProperties, samplePointerCoords);
-            lastInjectedEntry->next = nextInjectedEntry;
-            lastInjectedEntry = nextInjectedEntry;
-        }
-        break;
-    }
-
-    default:
-        ALOGW("Cannot inject event of type %d", event->getType());
-        return INPUT_EVENT_INJECTION_FAILED;
-    }
-
-    InjectionState* injectionState = new InjectionState(injectorPid, injectorUid);
-    if (syncMode == INPUT_EVENT_INJECTION_SYNC_NONE) {
-        injectionState->injectionIsAsync = true;
-    }
-
-    injectionState->refCount += 1;
-    lastInjectedEntry->injectionState = injectionState;
-
-    bool needWake = false;
-    for (EventEntry* entry = firstInjectedEntry; entry != NULL; ) {
-        EventEntry* nextEntry = entry->next;
-        needWake |= enqueueInboundEventLocked(entry);
-        entry = nextEntry;
-    }
-
-    mLock.unlock();
-
-    if (needWake) {
-        mLooper->wake();
-    }
-
-    int32_t injectionResult;
-    { // acquire lock
-        AutoMutex _l(mLock);
-
-        if (syncMode == INPUT_EVENT_INJECTION_SYNC_NONE) {
-            injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED;
-        } else {
-            for (;;) {
-                injectionResult = injectionState->injectionResult;
-                if (injectionResult != INPUT_EVENT_INJECTION_PENDING) {
-                    break;
-                }
-
-                nsecs_t remainingTimeout = endTime - now();
-                if (remainingTimeout <= 0) {
-#if DEBUG_INJECTION
-                    ALOGD("injectInputEvent - Timed out waiting for injection result "
-                            "to become available.");
-#endif
-                    injectionResult = INPUT_EVENT_INJECTION_TIMED_OUT;
-                    break;
-                }
-
-                mInjectionResultAvailableCondition.waitRelative(mLock, remainingTimeout);
-            }
-
-            if (injectionResult == INPUT_EVENT_INJECTION_SUCCEEDED
-                    && syncMode == INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_FINISHED) {
-                while (injectionState->pendingForegroundDispatches != 0) {
-#if DEBUG_INJECTION
-                    ALOGD("injectInputEvent - Waiting for %d pending foreground dispatches.",
-                            injectionState->pendingForegroundDispatches);
-#endif
-                    nsecs_t remainingTimeout = endTime - now();
-                    if (remainingTimeout <= 0) {
-#if DEBUG_INJECTION
-                    ALOGD("injectInputEvent - Timed out waiting for pending foreground "
-                            "dispatches to finish.");
-#endif
-                        injectionResult = INPUT_EVENT_INJECTION_TIMED_OUT;
-                        break;
-                    }
-
-                    mInjectionSyncFinishedCondition.waitRelative(mLock, remainingTimeout);
-                }
-            }
-        }
-
-        injectionState->release();
-    } // release lock
-
-#if DEBUG_INJECTION
-    ALOGD("injectInputEvent - Finished with result %d.  "
-            "injectorPid=%d, injectorUid=%d",
-            injectionResult, injectorPid, injectorUid);
-#endif
-
-    return injectionResult;
-}
-
-bool InputDispatcher::hasInjectionPermission(int32_t injectorPid, int32_t injectorUid) {
-    return injectorUid == 0
-            || mPolicy->checkInjectEventsPermissionNonReentrant(injectorPid, injectorUid);
-}
-
-void InputDispatcher::setInjectionResultLocked(EventEntry* entry, int32_t injectionResult) {
-    InjectionState* injectionState = entry->injectionState;
-    if (injectionState) {
-#if DEBUG_INJECTION
-        ALOGD("Setting input event injection result to %d.  "
-                "injectorPid=%d, injectorUid=%d",
-                 injectionResult, injectionState->injectorPid, injectionState->injectorUid);
-#endif
-
-        if (injectionState->injectionIsAsync
-                && !(entry->policyFlags & POLICY_FLAG_FILTERED)) {
-            // Log the outcome since the injector did not wait for the injection result.
-            switch (injectionResult) {
-            case INPUT_EVENT_INJECTION_SUCCEEDED:
-                ALOGV("Asynchronous input event injection succeeded.");
-                break;
-            case INPUT_EVENT_INJECTION_FAILED:
-                ALOGW("Asynchronous input event injection failed.");
-                break;
-            case INPUT_EVENT_INJECTION_PERMISSION_DENIED:
-                ALOGW("Asynchronous input event injection permission denied.");
-                break;
-            case INPUT_EVENT_INJECTION_TIMED_OUT:
-                ALOGW("Asynchronous input event injection timed out.");
-                break;
-            }
-        }
-
-        injectionState->injectionResult = injectionResult;
-        mInjectionResultAvailableCondition.broadcast();
-    }
-}
-
-void InputDispatcher::incrementPendingForegroundDispatchesLocked(EventEntry* entry) {
-    InjectionState* injectionState = entry->injectionState;
-    if (injectionState) {
-        injectionState->pendingForegroundDispatches += 1;
-    }
-}
-
-void InputDispatcher::decrementPendingForegroundDispatchesLocked(EventEntry* entry) {
-    InjectionState* injectionState = entry->injectionState;
-    if (injectionState) {
-        injectionState->pendingForegroundDispatches -= 1;
-
-        if (injectionState->pendingForegroundDispatches == 0) {
-            mInjectionSyncFinishedCondition.broadcast();
-        }
-    }
-}
-
-sp<InputWindowHandle> InputDispatcher::getWindowHandleLocked(
-        const sp<InputChannel>& inputChannel) const {
-    size_t numWindows = mWindowHandles.size();
-    for (size_t i = 0; i < numWindows; i++) {
-        const sp<InputWindowHandle>& windowHandle = mWindowHandles.itemAt(i);
-        if (windowHandle->getInputChannel() == inputChannel) {
-            return windowHandle;
-        }
-    }
-    return NULL;
-}
-
-bool InputDispatcher::hasWindowHandleLocked(
-        const sp<InputWindowHandle>& windowHandle) const {
-    size_t numWindows = mWindowHandles.size();
-    for (size_t i = 0; i < numWindows; i++) {
-        if (mWindowHandles.itemAt(i) == windowHandle) {
-            return true;
-        }
-    }
-    return false;
-}
-
-void InputDispatcher::setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles) {
-#if DEBUG_FOCUS
-    ALOGD("setInputWindows");
-#endif
-    { // acquire lock
-        AutoMutex _l(mLock);
-
-        Vector<sp<InputWindowHandle> > oldWindowHandles = mWindowHandles;
-        mWindowHandles = inputWindowHandles;
-
-        sp<InputWindowHandle> newFocusedWindowHandle;
-        bool foundHoveredWindow = false;
-        for (size_t i = 0; i < mWindowHandles.size(); i++) {
-            const sp<InputWindowHandle>& windowHandle = mWindowHandles.itemAt(i);
-            if (!windowHandle->updateInfo() || windowHandle->getInputChannel() == NULL) {
-                mWindowHandles.removeAt(i--);
-                continue;
-            }
-            if (windowHandle->getInfo()->hasFocus) {
-                newFocusedWindowHandle = windowHandle;
-            }
-            if (windowHandle == mLastHoverWindowHandle) {
-                foundHoveredWindow = true;
-            }
-        }
-
-        if (!foundHoveredWindow) {
-            mLastHoverWindowHandle = NULL;
-        }
-
-        if (mFocusedWindowHandle != newFocusedWindowHandle) {
-            if (mFocusedWindowHandle != NULL) {
-#if DEBUG_FOCUS
-                ALOGD("Focus left window: %s",
-                        mFocusedWindowHandle->getName().string());
-#endif
-                sp<InputChannel> focusedInputChannel = mFocusedWindowHandle->getInputChannel();
-                if (focusedInputChannel != NULL) {
-                    CancelationOptions options(CancelationOptions::CANCEL_NON_POINTER_EVENTS,
-                            "focus left window");
-                    synthesizeCancelationEventsForInputChannelLocked(
-                            focusedInputChannel, options);
-                }
-            }
-            if (newFocusedWindowHandle != NULL) {
-#if DEBUG_FOCUS
-                ALOGD("Focus entered window: %s",
-                        newFocusedWindowHandle->getName().string());
-#endif
-            }
-            mFocusedWindowHandle = newFocusedWindowHandle;
-        }
-
-        for (size_t i = 0; i < mTouchState.windows.size(); i++) {
-            TouchedWindow& touchedWindow = mTouchState.windows.editItemAt(i);
-            if (!hasWindowHandleLocked(touchedWindow.windowHandle)) {
-#if DEBUG_FOCUS
-                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);
-                }
-                mTouchState.windows.removeAt(i--);
-            }
-        }
-
-        // Release information for windows that are no longer present.
-        // This ensures that unused input channels are released promptly.
-        // Otherwise, they might stick around until the window handle is destroyed
-        // which might not happen until the next GC.
-        for (size_t i = 0; i < oldWindowHandles.size(); i++) {
-            const sp<InputWindowHandle>& oldWindowHandle = oldWindowHandles.itemAt(i);
-            if (!hasWindowHandleLocked(oldWindowHandle)) {
-#if DEBUG_FOCUS
-                ALOGD("Window went away: %s", oldWindowHandle->getName().string());
-#endif
-                oldWindowHandle->releaseInfo();
-            }
-        }
-    } // release lock
-
-    // Wake up poll loop since it may need to make new input dispatching choices.
-    mLooper->wake();
-}
-
-void InputDispatcher::setFocusedApplication(
-        const sp<InputApplicationHandle>& inputApplicationHandle) {
-#if DEBUG_FOCUS
-    ALOGD("setFocusedApplication");
-#endif
-    { // acquire lock
-        AutoMutex _l(mLock);
-
-        if (inputApplicationHandle != NULL && inputApplicationHandle->updateInfo()) {
-            if (mFocusedApplicationHandle != inputApplicationHandle) {
-                if (mFocusedApplicationHandle != NULL) {
-                    resetANRTimeoutsLocked();
-                    mFocusedApplicationHandle->releaseInfo();
-                }
-                mFocusedApplicationHandle = inputApplicationHandle;
-            }
-        } else if (mFocusedApplicationHandle != NULL) {
-            resetANRTimeoutsLocked();
-            mFocusedApplicationHandle->releaseInfo();
-            mFocusedApplicationHandle.clear();
-        }
-
-#if DEBUG_FOCUS
-        //logDispatchStateLocked();
-#endif
-    } // release lock
-
-    // Wake up poll loop since it may need to make new input dispatching choices.
-    mLooper->wake();
-}
-
-void InputDispatcher::setInputDispatchMode(bool enabled, bool frozen) {
-#if DEBUG_FOCUS
-    ALOGD("setInputDispatchMode: enabled=%d, frozen=%d", enabled, frozen);
-#endif
-
-    bool changed;
-    { // acquire lock
-        AutoMutex _l(mLock);
-
-        if (mDispatchEnabled != enabled || mDispatchFrozen != frozen) {
-            if (mDispatchFrozen && !frozen) {
-                resetANRTimeoutsLocked();
-            }
-
-            if (mDispatchEnabled && !enabled) {
-                resetAndDropEverythingLocked("dispatcher is being disabled");
-            }
-
-            mDispatchEnabled = enabled;
-            mDispatchFrozen = frozen;
-            changed = true;
-        } else {
-            changed = false;
-        }
-
-#if DEBUG_FOCUS
-        //logDispatchStateLocked();
-#endif
-    } // release lock
-
-    if (changed) {
-        // Wake up poll loop since it may need to make new input dispatching choices.
-        mLooper->wake();
-    }
-}
-
-void InputDispatcher::setInputFilterEnabled(bool enabled) {
-#if DEBUG_FOCUS
-    ALOGD("setInputFilterEnabled: enabled=%d", enabled);
-#endif
-
-    { // acquire lock
-        AutoMutex _l(mLock);
-
-        if (mInputFilterEnabled == enabled) {
-            return;
-        }
-
-        mInputFilterEnabled = enabled;
-        resetAndDropEverythingLocked("input filter is being enabled or disabled");
-    } // release lock
-
-    // Wake up poll loop since there might be work to do to drop everything.
-    mLooper->wake();
-}
-
-bool InputDispatcher::transferTouchFocus(const sp<InputChannel>& fromChannel,
-        const sp<InputChannel>& toChannel) {
-#if DEBUG_FOCUS
-    ALOGD("transferTouchFocus: fromChannel=%s, toChannel=%s",
-            fromChannel->getName().string(), toChannel->getName().string());
-#endif
-    { // acquire lock
-        AutoMutex _l(mLock);
-
-        sp<InputWindowHandle> fromWindowHandle = getWindowHandleLocked(fromChannel);
-        sp<InputWindowHandle> toWindowHandle = getWindowHandleLocked(toChannel);
-        if (fromWindowHandle == NULL || toWindowHandle == NULL) {
-#if DEBUG_FOCUS
-            ALOGD("Cannot transfer focus because from or to window not found.");
-#endif
-            return false;
-        }
-        if (fromWindowHandle == toWindowHandle) {
-#if DEBUG_FOCUS
-            ALOGD("Trivial transfer to same window.");
-#endif
-            return true;
-        }
-        if (fromWindowHandle->getInfo()->displayId != toWindowHandle->getInfo()->displayId) {
-#if DEBUG_FOCUS
-            ALOGD("Cannot transfer focus because windows are on different displays.");
-#endif
-            return false;
-        }
-
-        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;
-
-                mTouchState.windows.removeAt(i);
-
-                int32_t newTargetFlags = oldTargetFlags
-                        & (InputTarget::FLAG_FOREGROUND
-                                | InputTarget::FLAG_SPLIT | InputTarget::FLAG_DISPATCH_AS_IS);
-                mTouchState.addOrUpdateWindow(toWindowHandle, newTargetFlags, pointerIds);
-
-                found = true;
-                break;
-            }
-        }
-
-        if (! found) {
-#if DEBUG_FOCUS
-            ALOGD("Focus transfer failed because from window did not have focus.");
-#endif
-            return false;
-        }
-
-        ssize_t fromConnectionIndex = getConnectionIndexLocked(fromChannel);
-        ssize_t toConnectionIndex = getConnectionIndexLocked(toChannel);
-        if (fromConnectionIndex >= 0 && toConnectionIndex >= 0) {
-            sp<Connection> fromConnection = mConnectionsByFd.valueAt(fromConnectionIndex);
-            sp<Connection> toConnection = mConnectionsByFd.valueAt(toConnectionIndex);
-
-            fromConnection->inputState.copyPointerStateTo(toConnection->inputState);
-            CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS,
-                    "transferring touch focus from this window to another window");
-            synthesizeCancelationEventsForConnectionLocked(fromConnection, options);
-        }
-
-#if DEBUG_FOCUS
-        logDispatchStateLocked();
-#endif
-    } // release lock
-
-    // Wake up poll loop since it may need to make new input dispatching choices.
-    mLooper->wake();
-    return true;
-}
-
-void InputDispatcher::resetAndDropEverythingLocked(const char* reason) {
-#if DEBUG_FOCUS
-    ALOGD("Resetting and dropping all events (%s).", reason);
-#endif
-
-    CancelationOptions options(CancelationOptions::CANCEL_ALL_EVENTS, reason);
-    synthesizeCancelationEventsForAllConnectionsLocked(options);
-
-    resetKeyRepeatLocked();
-    releasePendingEventLocked();
-    drainInboundQueueLocked();
-    resetANRTimeoutsLocked();
-
-    mTouchState.reset();
-    mLastHoverWindowHandle.clear();
-}
-
-void InputDispatcher::logDispatchStateLocked() {
-    String8 dump;
-    dumpDispatchStateLocked(dump);
-
-    char* text = dump.lockBuffer(dump.size());
-    char* start = text;
-    while (*start != '\0') {
-        char* end = strchr(start, '\n');
-        if (*end == '\n') {
-            *(end++) = '\0';
-        }
-        ALOGD("%s", start);
-        start = end;
-    }
-}
-
-void InputDispatcher::dumpDispatchStateLocked(String8& dump) {
-    dump.appendFormat(INDENT "DispatchEnabled: %d\n", mDispatchEnabled);
-    dump.appendFormat(INDENT "DispatchFrozen: %d\n", mDispatchFrozen);
-
-    if (mFocusedApplicationHandle != NULL) {
-        dump.appendFormat(INDENT "FocusedApplication: name='%s', dispatchingTimeout=%0.3fms\n",
-                mFocusedApplicationHandle->getName().string(),
-                mFocusedApplicationHandle->getDispatchingTimeout(
-                        DEFAULT_INPUT_DISPATCHING_TIMEOUT) / 1000000.0);
-    } else {
-        dump.append(INDENT "FocusedApplication: <null>\n");
-    }
-    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 "%d: name='%s', pointerIds=0x%0x, targetFlags=0x%x\n",
-                    i, touchedWindow.windowHandle->getName().string(),
-                    touchedWindow.pointerIds.value,
-                    touchedWindow.targetFlags);
-        }
-    } else {
-        dump.append(INDENT "TouchedWindows: <none>\n");
-    }
-
-    if (!mWindowHandles.isEmpty()) {
-        dump.append(INDENT "Windows:\n");
-        for (size_t i = 0; i < mWindowHandles.size(); i++) {
-            const sp<InputWindowHandle>& windowHandle = mWindowHandles.itemAt(i);
-            const InputWindowInfo* windowInfo = windowHandle->getInfo();
-
-            dump.appendFormat(INDENT2 "%d: name='%s', displayId=%d, "
-                    "paused=%s, hasFocus=%s, hasWallpaper=%s, "
-                    "visible=%s, canReceiveKeys=%s, flags=0x%08x, type=0x%08x, layer=%d, "
-                    "frame=[%d,%d][%d,%d], scale=%f, "
-                    "touchableRegion=",
-                    i, windowInfo->name.string(), windowInfo->displayId,
-                    toString(windowInfo->paused),
-                    toString(windowInfo->hasFocus),
-                    toString(windowInfo->hasWallpaper),
-                    toString(windowInfo->visible),
-                    toString(windowInfo->canReceiveKeys),
-                    windowInfo->layoutParamsFlags, windowInfo->layoutParamsType,
-                    windowInfo->layer,
-                    windowInfo->frameLeft, windowInfo->frameTop,
-                    windowInfo->frameRight, windowInfo->frameBottom,
-                    windowInfo->scaleFactor);
-            dumpRegion(dump, windowInfo->touchableRegion);
-            dump.appendFormat(", inputFeatures=0x%08x", windowInfo->inputFeatures);
-            dump.appendFormat(", ownerPid=%d, ownerUid=%d, dispatchingTimeout=%0.3fms\n",
-                    windowInfo->ownerPid, windowInfo->ownerUid,
-                    windowInfo->dispatchingTimeout / 1000000.0);
-        }
-    } else {
-        dump.append(INDENT "Windows: <none>\n");
-    }
-
-    if (!mMonitoringChannels.isEmpty()) {
-        dump.append(INDENT "MonitoringChannels:\n");
-        for (size_t i = 0; i < mMonitoringChannels.size(); i++) {
-            const sp<InputChannel>& channel = mMonitoringChannels[i];
-            dump.appendFormat(INDENT2 "%d: '%s'\n", i, channel->getName().string());
-        }
-    } else {
-        dump.append(INDENT "MonitoringChannels: <none>\n");
-    }
-
-    nsecs_t currentTime = now();
-
-    // Dump recently dispatched or dropped events from oldest to newest.
-    if (!mRecentQueue.isEmpty()) {
-        dump.appendFormat(INDENT "RecentQueue: length=%u\n", mRecentQueue.count());
-        for (EventEntry* entry = mRecentQueue.head; entry; entry = entry->next) {
-            dump.append(INDENT2);
-            entry->appendDescription(dump);
-            dump.appendFormat(", age=%0.1fms\n",
-                    (currentTime - entry->eventTime) * 0.000001f);
-        }
-    } else {
-        dump.append(INDENT "RecentQueue: <empty>\n");
-    }
-
-    // Dump event currently being dispatched.
-    if (mPendingEvent) {
-        dump.append(INDENT "PendingEvent:\n");
-        dump.append(INDENT2);
-        mPendingEvent->appendDescription(dump);
-        dump.appendFormat(", age=%0.1fms\n",
-                (currentTime - mPendingEvent->eventTime) * 0.000001f);
-    } else {
-        dump.append(INDENT "PendingEvent: <none>\n");
-    }
-
-    // Dump inbound events from oldest to newest.
-    if (!mInboundQueue.isEmpty()) {
-        dump.appendFormat(INDENT "InboundQueue: length=%u\n", mInboundQueue.count());
-        for (EventEntry* entry = mInboundQueue.head; entry; entry = entry->next) {
-            dump.append(INDENT2);
-            entry->appendDescription(dump);
-            dump.appendFormat(", age=%0.1fms\n",
-                    (currentTime - entry->eventTime) * 0.000001f);
-        }
-    } else {
-        dump.append(INDENT "InboundQueue: <empty>\n");
-    }
-
-    if (!mConnectionsByFd.isEmpty()) {
-        dump.append(INDENT "Connections:\n");
-        for (size_t i = 0; i < mConnectionsByFd.size(); i++) {
-            const sp<Connection>& connection = mConnectionsByFd.valueAt(i);
-            dump.appendFormat(INDENT2 "%d: channelName='%s', windowName='%s', "
-                    "status=%s, monitor=%s, inputPublisherBlocked=%s\n",
-                    i, connection->getInputChannelName(), connection->getWindowName(),
-                    connection->getStatusLabel(), toString(connection->monitor),
-                    toString(connection->inputPublisherBlocked));
-
-            if (!connection->outboundQueue.isEmpty()) {
-                dump.appendFormat(INDENT3 "OutboundQueue: length=%u\n",
-                        connection->outboundQueue.count());
-                for (DispatchEntry* entry = connection->outboundQueue.head; entry;
-                        entry = entry->next) {
-                    dump.append(INDENT4);
-                    entry->eventEntry->appendDescription(dump);
-                    dump.appendFormat(", targetFlags=0x%08x, resolvedAction=%d, age=%0.1fms\n",
-                            entry->targetFlags, entry->resolvedAction,
-                            (currentTime - entry->eventEntry->eventTime) * 0.000001f);
-                }
-            } else {
-                dump.append(INDENT3 "OutboundQueue: <empty>\n");
-            }
-
-            if (!connection->waitQueue.isEmpty()) {
-                dump.appendFormat(INDENT3 "WaitQueue: length=%u\n",
-                        connection->waitQueue.count());
-                for (DispatchEntry* entry = connection->waitQueue.head; entry;
-                        entry = entry->next) {
-                    dump.append(INDENT4);
-                    entry->eventEntry->appendDescription(dump);
-                    dump.appendFormat(", targetFlags=0x%08x, resolvedAction=%d, "
-                            "age=%0.1fms, wait=%0.1fms\n",
-                            entry->targetFlags, entry->resolvedAction,
-                            (currentTime - entry->eventEntry->eventTime) * 0.000001f,
-                            (currentTime - entry->deliveryTime) * 0.000001f);
-                }
-            } else {
-                dump.append(INDENT3 "WaitQueue: <empty>\n");
-            }
-        }
-    } else {
-        dump.append(INDENT "Connections: <none>\n");
-    }
-
-    if (isAppSwitchPendingLocked()) {
-        dump.appendFormat(INDENT "AppSwitch: pending, due in %0.1fms\n",
-                (mAppSwitchDueTime - now()) / 1000000.0);
-    } else {
-        dump.append(INDENT "AppSwitch: not pending\n");
-    }
-
-    dump.append(INDENT "Configuration:\n");
-    dump.appendFormat(INDENT2 "KeyRepeatDelay: %0.1fms\n",
-            mConfig.keyRepeatDelay * 0.000001f);
-    dump.appendFormat(INDENT2 "KeyRepeatTimeout: %0.1fms\n",
-            mConfig.keyRepeatTimeout * 0.000001f);
-}
-
-status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel,
-        const sp<InputWindowHandle>& inputWindowHandle, bool monitor) {
-#if DEBUG_REGISTRATION
-    ALOGD("channel '%s' ~ registerInputChannel - monitor=%s", inputChannel->getName().string(),
-            toString(monitor));
-#endif
-
-    { // acquire lock
-        AutoMutex _l(mLock);
-
-        if (getConnectionIndexLocked(inputChannel) >= 0) {
-            ALOGW("Attempted to register already registered input channel '%s'",
-                    inputChannel->getName().string());
-            return BAD_VALUE;
-        }
-
-        sp<Connection> connection = new Connection(inputChannel, inputWindowHandle, monitor);
-
-        int fd = inputChannel->getFd();
-        mConnectionsByFd.add(fd, connection);
-
-        if (monitor) {
-            mMonitoringChannels.push(inputChannel);
-        }
-
-        mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
-    } // release lock
-
-    // Wake the looper because some connections have changed.
-    mLooper->wake();
-    return OK;
-}
-
-status_t InputDispatcher::unregisterInputChannel(const sp<InputChannel>& inputChannel) {
-#if DEBUG_REGISTRATION
-    ALOGD("channel '%s' ~ unregisterInputChannel", inputChannel->getName().string());
-#endif
-
-    { // acquire lock
-        AutoMutex _l(mLock);
-
-        status_t status = unregisterInputChannelLocked(inputChannel, false /*notify*/);
-        if (status) {
-            return status;
-        }
-    } // release lock
-
-    // Wake the poll loop because removing the connection may have changed the current
-    // synchronization state.
-    mLooper->wake();
-    return OK;
-}
-
-status_t InputDispatcher::unregisterInputChannelLocked(const sp<InputChannel>& inputChannel,
-        bool notify) {
-    ssize_t connectionIndex = getConnectionIndexLocked(inputChannel);
-    if (connectionIndex < 0) {
-        ALOGW("Attempted to unregister already unregistered input channel '%s'",
-                inputChannel->getName().string());
-        return BAD_VALUE;
-    }
-
-    sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
-    mConnectionsByFd.removeItemsAt(connectionIndex);
-
-    if (connection->monitor) {
-        removeMonitorChannelLocked(inputChannel);
-    }
-
-    mLooper->removeFd(inputChannel->getFd());
-
-    nsecs_t currentTime = now();
-    abortBrokenDispatchCycleLocked(currentTime, connection, notify);
-
-    connection->status = Connection::STATUS_ZOMBIE;
-    return OK;
-}
-
-void InputDispatcher::removeMonitorChannelLocked(const sp<InputChannel>& inputChannel) {
-    for (size_t i = 0; i < mMonitoringChannels.size(); i++) {
-         if (mMonitoringChannels[i] == inputChannel) {
-             mMonitoringChannels.removeAt(i);
-             break;
-         }
-    }
-}
-
-ssize_t InputDispatcher::getConnectionIndexLocked(const sp<InputChannel>& inputChannel) {
-    ssize_t connectionIndex = mConnectionsByFd.indexOfKey(inputChannel->getFd());
-    if (connectionIndex >= 0) {
-        sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
-        if (connection->inputChannel.get() == inputChannel.get()) {
-            return connectionIndex;
-        }
-    }
-
-    return -1;
-}
-
-void InputDispatcher::onDispatchCycleFinishedLocked(
-        nsecs_t currentTime, const sp<Connection>& connection, uint32_t seq, bool handled) {
-    CommandEntry* commandEntry = postCommandLocked(
-            & InputDispatcher::doDispatchCycleFinishedLockedInterruptible);
-    commandEntry->connection = connection;
-    commandEntry->eventTime = currentTime;
-    commandEntry->seq = seq;
-    commandEntry->handled = handled;
-}
-
-void InputDispatcher::onDispatchCycleBrokenLocked(
-        nsecs_t currentTime, const sp<Connection>& connection) {
-    ALOGE("channel '%s' ~ Channel is unrecoverably broken and will be disposed!",
-            connection->getInputChannelName());
-
-    CommandEntry* commandEntry = postCommandLocked(
-            & InputDispatcher::doNotifyInputChannelBrokenLockedInterruptible);
-    commandEntry->connection = connection;
-}
-
-void InputDispatcher::onANRLocked(
-        nsecs_t currentTime, const sp<InputApplicationHandle>& applicationHandle,
-        const sp<InputWindowHandle>& windowHandle,
-        nsecs_t eventTime, nsecs_t waitStartTime, const char* reason) {
-    float dispatchLatency = (currentTime - eventTime) * 0.000001f;
-    float waitDuration = (currentTime - waitStartTime) * 0.000001f;
-    ALOGI("Application is not responding: %s.  "
-            "It has been %0.1fms since event, %0.1fms since wait started.  Reason: %s",
-            getApplicationWindowLabelLocked(applicationHandle, windowHandle).string(),
-            dispatchLatency, waitDuration, reason);
-
-    // Capture a record of the InputDispatcher state at the time of the ANR.
-    time_t t = time(NULL);
-    struct tm tm;
-    localtime_r(&t, &tm);
-    char timestr[64];
-    strftime(timestr, sizeof(timestr), "%F %T", &tm);
-    mLastANRState.clear();
-    mLastANRState.append(INDENT "ANR:\n");
-    mLastANRState.appendFormat(INDENT2 "Time: %s\n", timestr);
-    mLastANRState.appendFormat(INDENT2 "Window: %s\n",
-            getApplicationWindowLabelLocked(applicationHandle, windowHandle).string());
-    mLastANRState.appendFormat(INDENT2 "DispatchLatency: %0.1fms\n", dispatchLatency);
-    mLastANRState.appendFormat(INDENT2 "WaitDuration: %0.1fms\n", waitDuration);
-    mLastANRState.appendFormat(INDENT2 "Reason: %s\n", reason);
-    dumpDispatchStateLocked(mLastANRState);
-
-    CommandEntry* commandEntry = postCommandLocked(
-            & InputDispatcher::doNotifyANRLockedInterruptible);
-    commandEntry->inputApplicationHandle = applicationHandle;
-    commandEntry->inputWindowHandle = windowHandle;
-    commandEntry->reason = reason;
-}
-
-void InputDispatcher::doNotifyConfigurationChangedInterruptible(
-        CommandEntry* commandEntry) {
-    mLock.unlock();
-
-    mPolicy->notifyConfigurationChanged(commandEntry->eventTime);
-
-    mLock.lock();
-}
-
-void InputDispatcher::doNotifyInputChannelBrokenLockedInterruptible(
-        CommandEntry* commandEntry) {
-    sp<Connection> connection = commandEntry->connection;
-
-    if (connection->status != Connection::STATUS_ZOMBIE) {
-        mLock.unlock();
-
-        mPolicy->notifyInputChannelBroken(connection->inputWindowHandle);
-
-        mLock.lock();
-    }
-}
-
-void InputDispatcher::doNotifyANRLockedInterruptible(
-        CommandEntry* commandEntry) {
-    mLock.unlock();
-
-    nsecs_t newTimeout = mPolicy->notifyANR(
-            commandEntry->inputApplicationHandle, commandEntry->inputWindowHandle,
-            commandEntry->reason);
-
-    mLock.lock();
-
-    resumeAfterTargetsNotReadyTimeoutLocked(newTimeout,
-            commandEntry->inputWindowHandle != NULL
-                    ? commandEntry->inputWindowHandle->getInputChannel() : NULL);
-}
-
-void InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible(
-        CommandEntry* commandEntry) {
-    KeyEntry* entry = commandEntry->keyEntry;
-
-    KeyEvent event;
-    initializeKeyEvent(&event, entry);
-
-    mLock.unlock();
-
-    nsecs_t delay = mPolicy->interceptKeyBeforeDispatching(commandEntry->inputWindowHandle,
-            &event, entry->policyFlags);
-
-    mLock.lock();
-
-    if (delay < 0) {
-        entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_SKIP;
-    } else if (!delay) {
-        entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_CONTINUE;
-    } else {
-        entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER;
-        entry->interceptKeyWakeupTime = now() + delay;
-    }
-    entry->release();
-}
-
-void InputDispatcher::doDispatchCycleFinishedLockedInterruptible(
-        CommandEntry* commandEntry) {
-    sp<Connection> connection = commandEntry->connection;
-    nsecs_t finishTime = commandEntry->eventTime;
-    uint32_t seq = commandEntry->seq;
-    bool handled = commandEntry->handled;
-
-    // Handle post-event policy actions.
-    DispatchEntry* dispatchEntry = connection->findWaitQueueEntry(seq);
-    if (dispatchEntry) {
-        nsecs_t eventDuration = finishTime - dispatchEntry->deliveryTime;
-        if (eventDuration > SLOW_EVENT_PROCESSING_WARNING_TIMEOUT) {
-            String8 msg;
-            msg.appendFormat("Window '%s' spent %0.1fms processing the last input event: ",
-                    connection->getWindowName(), eventDuration * 0.000001f);
-            dispatchEntry->eventEntry->appendDescription(msg);
-            ALOGI("%s", msg.string());
-        }
-
-        bool restartEvent;
-        if (dispatchEntry->eventEntry->type == EventEntry::TYPE_KEY) {
-            KeyEntry* keyEntry = static_cast<KeyEntry*>(dispatchEntry->eventEntry);
-            restartEvent = afterKeyEventLockedInterruptible(connection,
-                    dispatchEntry, keyEntry, handled);
-        } else if (dispatchEntry->eventEntry->type == EventEntry::TYPE_MOTION) {
-            MotionEntry* motionEntry = static_cast<MotionEntry*>(dispatchEntry->eventEntry);
-            restartEvent = afterMotionEventLockedInterruptible(connection,
-                    dispatchEntry, motionEntry, handled);
-        } else {
-            restartEvent = false;
-        }
-
-        // Dequeue the event and start the next cycle.
-        // Note that because the lock might have been released, it is possible that the
-        // contents of the wait queue to have been drained, so we need to double-check
-        // a few things.
-        if (dispatchEntry == connection->findWaitQueueEntry(seq)) {
-            connection->waitQueue.dequeue(dispatchEntry);
-            traceWaitQueueLengthLocked(connection);
-            if (restartEvent && connection->status == Connection::STATUS_NORMAL) {
-                connection->outboundQueue.enqueueAtHead(dispatchEntry);
-                traceOutboundQueueLengthLocked(connection);
-            } else {
-                releaseDispatchEntryLocked(dispatchEntry);
-            }
-        }
-
-        // Start the next dispatch cycle for this connection.
-        startDispatchCycleLocked(now(), connection);
-    }
-}
-
-bool InputDispatcher::afterKeyEventLockedInterruptible(const sp<Connection>& connection,
-        DispatchEntry* dispatchEntry, KeyEntry* keyEntry, bool handled) {
-    if (!(keyEntry->flags & AKEY_EVENT_FLAG_FALLBACK)) {
-        // Get the fallback key state.
-        // Clear it out after dispatching the UP.
-        int32_t originalKeyCode = keyEntry->keyCode;
-        int32_t fallbackKeyCode = connection->inputState.getFallbackKey(originalKeyCode);
-        if (keyEntry->action == AKEY_EVENT_ACTION_UP) {
-            connection->inputState.removeFallbackKey(originalKeyCode);
-        }
-
-        if (handled || !dispatchEntry->hasForegroundTarget()) {
-            // If the application handles the original key for which we previously
-            // generated a fallback or if the window is not a foreground window,
-            // then cancel the associated fallback key, if any.
-            if (fallbackKeyCode != -1) {
-                // Dispatch the unhandled key to the policy with the cancel flag.
-#if DEBUG_OUTBOUND_EVENT_DETAILS
-                ALOGD("Unhandled key event: Asking policy to cancel fallback action.  "
-                        "keyCode=%d, action=%d, repeatCount=%d, policyFlags=0x%08x",
-                        keyEntry->keyCode, keyEntry->action, keyEntry->repeatCount,
-                        keyEntry->policyFlags);
-#endif
-                KeyEvent event;
-                initializeKeyEvent(&event, keyEntry);
-                event.setFlags(event.getFlags() | AKEY_EVENT_FLAG_CANCELED);
-
-                mLock.unlock();
-
-                mPolicy->dispatchUnhandledKey(connection->inputWindowHandle,
-                        &event, keyEntry->policyFlags, &event);
-
-                mLock.lock();
-
-                // Cancel the fallback key.
-                if (fallbackKeyCode != AKEYCODE_UNKNOWN) {
-                    CancelationOptions options(CancelationOptions::CANCEL_FALLBACK_EVENTS,
-                            "application handled the original non-fallback key "
-                            "or is no longer a foreground target, "
-                            "canceling previously dispatched fallback key");
-                    options.keyCode = fallbackKeyCode;
-                    synthesizeCancelationEventsForConnectionLocked(connection, options);
-                }
-                connection->inputState.removeFallbackKey(originalKeyCode);
-            }
-        } else {
-            // If the application did not handle a non-fallback key, first check
-            // that we are in a good state to perform unhandled key event processing
-            // Then ask the policy what to do with it.
-            bool initialDown = keyEntry->action == AKEY_EVENT_ACTION_DOWN
-                    && keyEntry->repeatCount == 0;
-            if (fallbackKeyCode == -1 && !initialDown) {
-#if DEBUG_OUTBOUND_EVENT_DETAILS
-                ALOGD("Unhandled key event: Skipping unhandled key event processing "
-                        "since this is not an initial down.  "
-                        "keyCode=%d, action=%d, repeatCount=%d, policyFlags=0x%08x",
-                        originalKeyCode, keyEntry->action, keyEntry->repeatCount,
-                        keyEntry->policyFlags);
-#endif
-                return false;
-            }
-
-            // Dispatch the unhandled key to the policy.
-#if DEBUG_OUTBOUND_EVENT_DETAILS
-            ALOGD("Unhandled key event: Asking policy to perform fallback action.  "
-                    "keyCode=%d, action=%d, repeatCount=%d, policyFlags=0x%08x",
-                    keyEntry->keyCode, keyEntry->action, keyEntry->repeatCount,
-                    keyEntry->policyFlags);
-#endif
-            KeyEvent event;
-            initializeKeyEvent(&event, keyEntry);
-
-            mLock.unlock();
-
-            bool fallback = mPolicy->dispatchUnhandledKey(connection->inputWindowHandle,
-                    &event, keyEntry->policyFlags, &event);
-
-            mLock.lock();
-
-            if (connection->status != Connection::STATUS_NORMAL) {
-                connection->inputState.removeFallbackKey(originalKeyCode);
-                return false;
-            }
-
-            // Latch the fallback keycode for this key on an initial down.
-            // The fallback keycode cannot change at any other point in the lifecycle.
-            if (initialDown) {
-                if (fallback) {
-                    fallbackKeyCode = event.getKeyCode();
-                } else {
-                    fallbackKeyCode = AKEYCODE_UNKNOWN;
-                }
-                connection->inputState.setFallbackKey(originalKeyCode, fallbackKeyCode);
-            }
-
-            ALOG_ASSERT(fallbackKeyCode != -1);
-
-            // Cancel the fallback key if the policy decides not to send it anymore.
-            // We will continue to dispatch the key to the policy but we will no
-            // longer dispatch a fallback key to the application.
-            if (fallbackKeyCode != AKEYCODE_UNKNOWN
-                    && (!fallback || fallbackKeyCode != event.getKeyCode())) {
-#if DEBUG_OUTBOUND_EVENT_DETAILS
-                if (fallback) {
-                    ALOGD("Unhandled key event: Policy requested to send key %d"
-                            "as a fallback for %d, but on the DOWN it had requested "
-                            "to send %d instead.  Fallback canceled.",
-                            event.getKeyCode(), originalKeyCode, fallbackKeyCode);
-                } else {
-                    ALOGD("Unhandled key event: Policy did not request fallback for %d, "
-                            "but on the DOWN it had requested to send %d.  "
-                            "Fallback canceled.",
-                            originalKeyCode, fallbackKeyCode);
-                }
-#endif
-
-                CancelationOptions options(CancelationOptions::CANCEL_FALLBACK_EVENTS,
-                        "canceling fallback, policy no longer desires it");
-                options.keyCode = fallbackKeyCode;
-                synthesizeCancelationEventsForConnectionLocked(connection, options);
-
-                fallback = false;
-                fallbackKeyCode = AKEYCODE_UNKNOWN;
-                if (keyEntry->action != AKEY_EVENT_ACTION_UP) {
-                    connection->inputState.setFallbackKey(originalKeyCode,
-                            fallbackKeyCode);
-                }
-            }
-
-#if DEBUG_OUTBOUND_EVENT_DETAILS
-            {
-                String8 msg;
-                const KeyedVector<int32_t, int32_t>& fallbackKeys =
-                        connection->inputState.getFallbackKeys();
-                for (size_t i = 0; i < fallbackKeys.size(); i++) {
-                    msg.appendFormat(", %d->%d", fallbackKeys.keyAt(i),
-                            fallbackKeys.valueAt(i));
-                }
-                ALOGD("Unhandled key event: %d currently tracked fallback keys%s.",
-                        fallbackKeys.size(), msg.string());
-            }
-#endif
-
-            if (fallback) {
-                // Restart the dispatch cycle using the fallback key.
-                keyEntry->eventTime = event.getEventTime();
-                keyEntry->deviceId = event.getDeviceId();
-                keyEntry->source = event.getSource();
-                keyEntry->flags = event.getFlags() | AKEY_EVENT_FLAG_FALLBACK;
-                keyEntry->keyCode = fallbackKeyCode;
-                keyEntry->scanCode = event.getScanCode();
-                keyEntry->metaState = event.getMetaState();
-                keyEntry->repeatCount = event.getRepeatCount();
-                keyEntry->downTime = event.getDownTime();
-                keyEntry->syntheticRepeat = false;
-
-#if DEBUG_OUTBOUND_EVENT_DETAILS
-                ALOGD("Unhandled key event: Dispatching fallback key.  "
-                        "originalKeyCode=%d, fallbackKeyCode=%d, fallbackMetaState=%08x",
-                        originalKeyCode, fallbackKeyCode, keyEntry->metaState);
-#endif
-                return true; // restart the event
-            } else {
-#if DEBUG_OUTBOUND_EVENT_DETAILS
-                ALOGD("Unhandled key event: No fallback key.");
-#endif
-            }
-        }
-    }
-    return false;
-}
-
-bool InputDispatcher::afterMotionEventLockedInterruptible(const sp<Connection>& connection,
-        DispatchEntry* dispatchEntry, MotionEntry* motionEntry, bool handled) {
-    return false;
-}
-
-void InputDispatcher::doPokeUserActivityLockedInterruptible(CommandEntry* commandEntry) {
-    mLock.unlock();
-
-    mPolicy->pokeUserActivity(commandEntry->eventTime, commandEntry->userActivityEventType);
-
-    mLock.lock();
-}
-
-void InputDispatcher::initializeKeyEvent(KeyEvent* event, const KeyEntry* entry) {
-    event->initialize(entry->deviceId, entry->source, entry->action, entry->flags,
-            entry->keyCode, entry->scanCode, entry->metaState, entry->repeatCount,
-            entry->downTime, entry->eventTime);
-}
-
-void InputDispatcher::updateDispatchStatisticsLocked(nsecs_t currentTime, const EventEntry* entry,
-        int32_t injectionResult, nsecs_t timeSpentWaitingForApplication) {
-    // TODO Write some statistics about how long we spend waiting.
-}
-
-void InputDispatcher::traceInboundQueueLengthLocked() {
-    if (ATRACE_ENABLED()) {
-        ATRACE_INT("iq", mInboundQueue.count());
-    }
-}
-
-void InputDispatcher::traceOutboundQueueLengthLocked(const sp<Connection>& connection) {
-    if (ATRACE_ENABLED()) {
-        char counterName[40];
-        snprintf(counterName, sizeof(counterName), "oq:%s", connection->getWindowName());
-        ATRACE_INT(counterName, connection->outboundQueue.count());
-    }
-}
-
-void InputDispatcher::traceWaitQueueLengthLocked(const sp<Connection>& connection) {
-    if (ATRACE_ENABLED()) {
-        char counterName[40];
-        snprintf(counterName, sizeof(counterName), "wq:%s", connection->getWindowName());
-        ATRACE_INT(counterName, connection->waitQueue.count());
-    }
-}
-
-void InputDispatcher::dump(String8& dump) {
-    AutoMutex _l(mLock);
-
-    dump.append("Input Dispatcher State:\n");
-    dumpDispatchStateLocked(dump);
-
-    if (!mLastANRState.isEmpty()) {
-        dump.append("\nInput Dispatcher State at time of last ANR:\n");
-        dump.append(mLastANRState);
-    }
-}
-
-void InputDispatcher::monitor() {
-    // Acquire and release the lock to ensure that the dispatcher has not deadlocked.
-    mLock.lock();
-    mLooper->wake();
-    mDispatcherIsAliveCondition.wait(mLock);
-    mLock.unlock();
-}
-
-
-// --- InputDispatcher::Queue ---
-
-template <typename T>
-uint32_t InputDispatcher::Queue<T>::count() const {
-    uint32_t result = 0;
-    for (const T* entry = head; entry; entry = entry->next) {
-        result += 1;
-    }
-    return result;
-}
-
-
-// --- InputDispatcher::InjectionState ---
-
-InputDispatcher::InjectionState::InjectionState(int32_t injectorPid, int32_t injectorUid) :
-        refCount(1),
-        injectorPid(injectorPid), injectorUid(injectorUid),
-        injectionResult(INPUT_EVENT_INJECTION_PENDING), injectionIsAsync(false),
-        pendingForegroundDispatches(0) {
-}
-
-InputDispatcher::InjectionState::~InjectionState() {
-}
-
-void InputDispatcher::InjectionState::release() {
-    refCount -= 1;
-    if (refCount == 0) {
-        delete this;
-    } else {
-        ALOG_ASSERT(refCount > 0);
-    }
-}
-
-
-// --- InputDispatcher::EventEntry ---
-
-InputDispatcher::EventEntry::EventEntry(int32_t type, nsecs_t eventTime, uint32_t policyFlags) :
-        refCount(1), type(type), eventTime(eventTime), policyFlags(policyFlags),
-        injectionState(NULL), dispatchInProgress(false) {
-}
-
-InputDispatcher::EventEntry::~EventEntry() {
-    releaseInjectionState();
-}
-
-void InputDispatcher::EventEntry::release() {
-    refCount -= 1;
-    if (refCount == 0) {
-        delete this;
-    } else {
-        ALOG_ASSERT(refCount > 0);
-    }
-}
-
-void InputDispatcher::EventEntry::releaseInjectionState() {
-    if (injectionState) {
-        injectionState->release();
-        injectionState = NULL;
-    }
-}
-
-
-// --- InputDispatcher::ConfigurationChangedEntry ---
-
-InputDispatcher::ConfigurationChangedEntry::ConfigurationChangedEntry(nsecs_t eventTime) :
-        EventEntry(TYPE_CONFIGURATION_CHANGED, eventTime, 0) {
-}
-
-InputDispatcher::ConfigurationChangedEntry::~ConfigurationChangedEntry() {
-}
-
-void InputDispatcher::ConfigurationChangedEntry::appendDescription(String8& msg) const {
-    msg.append("ConfigurationChangedEvent(), policyFlags=0x%08x",
-            policyFlags);
-}
-
-
-// --- InputDispatcher::DeviceResetEntry ---
-
-InputDispatcher::DeviceResetEntry::DeviceResetEntry(nsecs_t eventTime, int32_t deviceId) :
-        EventEntry(TYPE_DEVICE_RESET, eventTime, 0),
-        deviceId(deviceId) {
-}
-
-InputDispatcher::DeviceResetEntry::~DeviceResetEntry() {
-}
-
-void InputDispatcher::DeviceResetEntry::appendDescription(String8& msg) const {
-    msg.appendFormat("DeviceResetEvent(deviceId=%d), policyFlags=0x%08x",
-            deviceId, policyFlags);
-}
-
-
-// --- InputDispatcher::KeyEntry ---
-
-InputDispatcher::KeyEntry::KeyEntry(nsecs_t eventTime,
-        int32_t deviceId, uint32_t source, uint32_t policyFlags, int32_t action,
-        int32_t flags, int32_t keyCode, int32_t scanCode, int32_t metaState,
-        int32_t repeatCount, nsecs_t downTime) :
-        EventEntry(TYPE_KEY, eventTime, policyFlags),
-        deviceId(deviceId), source(source), action(action), flags(flags),
-        keyCode(keyCode), scanCode(scanCode), metaState(metaState),
-        repeatCount(repeatCount), downTime(downTime),
-        syntheticRepeat(false), interceptKeyResult(KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN),
-        interceptKeyWakeupTime(0) {
-}
-
-InputDispatcher::KeyEntry::~KeyEntry() {
-}
-
-void InputDispatcher::KeyEntry::appendDescription(String8& msg) const {
-    msg.appendFormat("KeyEvent(deviceId=%d, source=0x%08x, action=%d, "
-            "flags=0x%08x, keyCode=%d, scanCode=%d, metaState=0x%08x, "
-            "repeatCount=%d), policyFlags=0x%08x",
-            deviceId, source, action, flags, keyCode, scanCode, metaState,
-            repeatCount, policyFlags);
-}
-
-void InputDispatcher::KeyEntry::recycle() {
-    releaseInjectionState();
-
-    dispatchInProgress = false;
-    syntheticRepeat = false;
-    interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN;
-    interceptKeyWakeupTime = 0;
-}
-
-
-// --- InputDispatcher::MotionEntry ---
-
-InputDispatcher::MotionEntry::MotionEntry(nsecs_t eventTime,
-        int32_t deviceId, uint32_t source, uint32_t policyFlags, int32_t action, int32_t flags,
-        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) :
-        EventEntry(TYPE_MOTION, eventTime, policyFlags),
-        eventTime(eventTime),
-        deviceId(deviceId), source(source), action(action), flags(flags),
-        metaState(metaState), buttonState(buttonState), edgeFlags(edgeFlags),
-        xPrecision(xPrecision), yPrecision(yPrecision),
-        downTime(downTime), displayId(displayId), pointerCount(pointerCount) {
-    for (uint32_t i = 0; i < pointerCount; i++) {
-        this->pointerProperties[i].copyFrom(pointerProperties[i]);
-        this->pointerCoords[i].copyFrom(pointerCoords[i]);
-    }
-}
-
-InputDispatcher::MotionEntry::~MotionEntry() {
-}
-
-void InputDispatcher::MotionEntry::appendDescription(String8& msg) const {
-    msg.appendFormat("MotionEvent(deviceId=%d, source=0x%08x, action=%d, "
-            "flags=0x%08x, metaState=0x%08x, buttonState=0x%08x, edgeFlags=0x%08x, "
-            "xPrecision=%.1f, yPrecision=%.1f, displayId=%d, pointers=[",
-            deviceId, source, action, flags, metaState, buttonState, edgeFlags,
-            xPrecision, yPrecision, displayId);
-    for (uint32_t i = 0; i < pointerCount; i++) {
-        if (i) {
-            msg.append(", ");
-        }
-        msg.appendFormat("%d: (%.1f, %.1f)", pointerProperties[i].id,
-                pointerCoords[i].getX(), pointerCoords[i].getY());
-    }
-    msg.appendFormat("]), policyFlags=0x%08x", policyFlags);
-}
-
-
-// --- InputDispatcher::DispatchEntry ---
-
-volatile int32_t InputDispatcher::DispatchEntry::sNextSeqAtomic;
-
-InputDispatcher::DispatchEntry::DispatchEntry(EventEntry* eventEntry,
-        int32_t targetFlags, float xOffset, float yOffset, float scaleFactor) :
-        seq(nextSeq()),
-        eventEntry(eventEntry), targetFlags(targetFlags),
-        xOffset(xOffset), yOffset(yOffset), scaleFactor(scaleFactor),
-        deliveryTime(0), resolvedAction(0), resolvedFlags(0) {
-    eventEntry->refCount += 1;
-}
-
-InputDispatcher::DispatchEntry::~DispatchEntry() {
-    eventEntry->release();
-}
-
-uint32_t InputDispatcher::DispatchEntry::nextSeq() {
-    // Sequence number 0 is reserved and will never be returned.
-    uint32_t seq;
-    do {
-        seq = android_atomic_inc(&sNextSeqAtomic);
-    } while (!seq);
-    return seq;
-}
-
-
-// --- InputDispatcher::InputState ---
-
-InputDispatcher::InputState::InputState() {
-}
-
-InputDispatcher::InputState::~InputState() {
-}
-
-bool InputDispatcher::InputState::isNeutral() const {
-    return mKeyMementos.isEmpty() && mMotionMementos.isEmpty();
-}
-
-bool InputDispatcher::InputState::isHovering(int32_t deviceId, uint32_t source,
-        int32_t displayId) const {
-    for (size_t i = 0; i < mMotionMementos.size(); i++) {
-        const MotionMemento& memento = mMotionMementos.itemAt(i);
-        if (memento.deviceId == deviceId
-                && memento.source == source
-                && memento.displayId == displayId
-                && memento.hovering) {
-            return true;
-        }
-    }
-    return false;
-}
-
-bool InputDispatcher::InputState::trackKey(const KeyEntry* entry,
-        int32_t action, int32_t flags) {
-    switch (action) {
-    case AKEY_EVENT_ACTION_UP: {
-        if (entry->flags & AKEY_EVENT_FLAG_FALLBACK) {
-            for (size_t i = 0; i < mFallbackKeys.size(); ) {
-                if (mFallbackKeys.valueAt(i) == entry->keyCode) {
-                    mFallbackKeys.removeItemsAt(i);
-                } else {
-                    i += 1;
-                }
-            }
-        }
-        ssize_t index = findKeyMemento(entry);
-        if (index >= 0) {
-            mKeyMementos.removeAt(index);
-            return true;
-        }
-        /* FIXME: We can't just drop the key up event because that prevents creating
-         * popup windows that are automatically shown when a key is held and then
-         * dismissed when the key is released.  The problem is that the popup will
-         * not have received the original key down, so the key up will be considered
-         * to be inconsistent with its observed state.  We could perhaps handle this
-         * by synthesizing a key down but that will cause other problems.
-         *
-         * So for now, allow inconsistent key up events to be dispatched.
-         *
-#if DEBUG_OUTBOUND_EVENT_DETAILS
-        ALOGD("Dropping inconsistent key up event: deviceId=%d, source=%08x, "
-                "keyCode=%d, scanCode=%d",
-                entry->deviceId, entry->source, entry->keyCode, entry->scanCode);
-#endif
-        return false;
-        */
-        return true;
-    }
-
-    case AKEY_EVENT_ACTION_DOWN: {
-        ssize_t index = findKeyMemento(entry);
-        if (index >= 0) {
-            mKeyMementos.removeAt(index);
-        }
-        addKeyMemento(entry, flags);
-        return true;
-    }
-
-    default:
-        return true;
-    }
-}
-
-bool InputDispatcher::InputState::trackMotion(const MotionEntry* entry,
-        int32_t action, int32_t flags) {
-    int32_t actionMasked = action & AMOTION_EVENT_ACTION_MASK;
-    switch (actionMasked) {
-    case AMOTION_EVENT_ACTION_UP:
-    case AMOTION_EVENT_ACTION_CANCEL: {
-        ssize_t index = findMotionMemento(entry, false /*hovering*/);
-        if (index >= 0) {
-            mMotionMementos.removeAt(index);
-            return true;
-        }
-#if DEBUG_OUTBOUND_EVENT_DETAILS
-        ALOGD("Dropping inconsistent motion up or cancel event: deviceId=%d, source=%08x, "
-                "actionMasked=%d",
-                entry->deviceId, entry->source, actionMasked);
-#endif
-        return false;
-    }
-
-    case AMOTION_EVENT_ACTION_DOWN: {
-        ssize_t index = findMotionMemento(entry, false /*hovering*/);
-        if (index >= 0) {
-            mMotionMementos.removeAt(index);
-        }
-        addMotionMemento(entry, flags, false /*hovering*/);
-        return true;
-    }
-
-    case AMOTION_EVENT_ACTION_POINTER_UP:
-    case AMOTION_EVENT_ACTION_POINTER_DOWN:
-    case AMOTION_EVENT_ACTION_MOVE: {
-        ssize_t index = findMotionMemento(entry, false /*hovering*/);
-        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",
-                entry->deviceId, entry->source, actionMasked);
-#endif
-        return false;
-    }
-
-    case AMOTION_EVENT_ACTION_HOVER_EXIT: {
-        ssize_t index = findMotionMemento(entry, true /*hovering*/);
-        if (index >= 0) {
-            mMotionMementos.removeAt(index);
-            return true;
-        }
-#if DEBUG_OUTBOUND_EVENT_DETAILS
-        ALOGD("Dropping inconsistent motion hover exit event: deviceId=%d, source=%08x",
-                entry->deviceId, entry->source);
-#endif
-        return false;
-    }
-
-    case AMOTION_EVENT_ACTION_HOVER_ENTER:
-    case AMOTION_EVENT_ACTION_HOVER_MOVE: {
-        ssize_t index = findMotionMemento(entry, true /*hovering*/);
-        if (index >= 0) {
-            mMotionMementos.removeAt(index);
-        }
-        addMotionMemento(entry, flags, true /*hovering*/);
-        return true;
-    }
-
-    default:
-        return true;
-    }
-}
-
-ssize_t InputDispatcher::InputState::findKeyMemento(const KeyEntry* entry) const {
-    for (size_t i = 0; i < mKeyMementos.size(); i++) {
-        const KeyMemento& memento = mKeyMementos.itemAt(i);
-        if (memento.deviceId == entry->deviceId
-                && memento.source == entry->source
-                && memento.keyCode == entry->keyCode
-                && memento.scanCode == entry->scanCode) {
-            return i;
-        }
-    }
-    return -1;
-}
-
-ssize_t InputDispatcher::InputState::findMotionMemento(const MotionEntry* entry,
-        bool hovering) const {
-    for (size_t i = 0; i < mMotionMementos.size(); i++) {
-        const MotionMemento& memento = mMotionMementos.itemAt(i);
-        if (memento.deviceId == entry->deviceId
-                && memento.source == entry->source
-                && memento.displayId == entry->displayId
-                && memento.hovering == hovering) {
-            return i;
-        }
-    }
-    return -1;
-}
-
-void InputDispatcher::InputState::addKeyMemento(const KeyEntry* entry, int32_t flags) {
-    mKeyMementos.push();
-    KeyMemento& memento = mKeyMementos.editTop();
-    memento.deviceId = entry->deviceId;
-    memento.source = entry->source;
-    memento.keyCode = entry->keyCode;
-    memento.scanCode = entry->scanCode;
-    memento.metaState = entry->metaState;
-    memento.flags = flags;
-    memento.downTime = entry->downTime;
-    memento.policyFlags = entry->policyFlags;
-}
-
-void InputDispatcher::InputState::addMotionMemento(const MotionEntry* entry,
-        int32_t flags, bool hovering) {
-    mMotionMementos.push();
-    MotionMemento& memento = mMotionMementos.editTop();
-    memento.deviceId = entry->deviceId;
-    memento.source = entry->source;
-    memento.flags = flags;
-    memento.xPrecision = entry->xPrecision;
-    memento.yPrecision = entry->yPrecision;
-    memento.downTime = entry->downTime;
-    memento.displayId = entry->displayId;
-    memento.setPointers(entry);
-    memento.hovering = hovering;
-    memento.policyFlags = entry->policyFlags;
-}
-
-void InputDispatcher::InputState::MotionMemento::setPointers(const MotionEntry* entry) {
-    pointerCount = entry->pointerCount;
-    for (uint32_t i = 0; i < entry->pointerCount; i++) {
-        pointerProperties[i].copyFrom(entry->pointerProperties[i]);
-        pointerCoords[i].copyFrom(entry->pointerCoords[i]);
-    }
-}
-
-void InputDispatcher::InputState::synthesizeCancelationEvents(nsecs_t currentTime,
-        Vector<EventEntry*>& outEvents, const CancelationOptions& options) {
-    for (size_t i = 0; i < mKeyMementos.size(); i++) {
-        const KeyMemento& memento = mKeyMementos.itemAt(i);
-        if (shouldCancelKey(memento, options)) {
-            outEvents.push(new KeyEntry(currentTime,
-                    memento.deviceId, memento.source, memento.policyFlags,
-                    AKEY_EVENT_ACTION_UP, memento.flags | AKEY_EVENT_FLAG_CANCELED,
-                    memento.keyCode, memento.scanCode, memento.metaState, 0, memento.downTime));
-        }
-    }
-
-    for (size_t i = 0; i < mMotionMementos.size(); i++) {
-        const MotionMemento& memento = mMotionMementos.itemAt(i);
-        if (shouldCancelMotion(memento, options)) {
-            outEvents.push(new MotionEntry(currentTime,
-                    memento.deviceId, memento.source, memento.policyFlags,
-                    memento.hovering
-                            ? AMOTION_EVENT_ACTION_HOVER_EXIT
-                            : AMOTION_EVENT_ACTION_CANCEL,
-                    memento.flags, 0, 0, 0,
-                    memento.xPrecision, memento.yPrecision, memento.downTime,
-                    memento.displayId,
-                    memento.pointerCount, memento.pointerProperties, memento.pointerCoords));
-        }
-    }
-}
-
-void InputDispatcher::InputState::clear() {
-    mKeyMementos.clear();
-    mMotionMementos.clear();
-    mFallbackKeys.clear();
-}
-
-void InputDispatcher::InputState::copyPointerStateTo(InputState& other) const {
-    for (size_t i = 0; i < mMotionMementos.size(); i++) {
-        const MotionMemento& memento = mMotionMementos.itemAt(i);
-        if (memento.source & AINPUT_SOURCE_CLASS_POINTER) {
-            for (size_t j = 0; j < other.mMotionMementos.size(); ) {
-                const MotionMemento& otherMemento = other.mMotionMementos.itemAt(j);
-                if (memento.deviceId == otherMemento.deviceId
-                        && memento.source == otherMemento.source
-                        && memento.displayId == otherMemento.displayId) {
-                    other.mMotionMementos.removeAt(j);
-                } else {
-                    j += 1;
-                }
-            }
-            other.mMotionMementos.push(memento);
-        }
-    }
-}
-
-int32_t InputDispatcher::InputState::getFallbackKey(int32_t originalKeyCode) {
-    ssize_t index = mFallbackKeys.indexOfKey(originalKeyCode);
-    return index >= 0 ? mFallbackKeys.valueAt(index) : -1;
-}
-
-void InputDispatcher::InputState::setFallbackKey(int32_t originalKeyCode,
-        int32_t fallbackKeyCode) {
-    ssize_t index = mFallbackKeys.indexOfKey(originalKeyCode);
-    if (index >= 0) {
-        mFallbackKeys.replaceValueAt(index, fallbackKeyCode);
-    } else {
-        mFallbackKeys.add(originalKeyCode, fallbackKeyCode);
-    }
-}
-
-void InputDispatcher::InputState::removeFallbackKey(int32_t originalKeyCode) {
-    mFallbackKeys.removeItem(originalKeyCode);
-}
-
-bool InputDispatcher::InputState::shouldCancelKey(const KeyMemento& memento,
-        const CancelationOptions& options) {
-    if (options.keyCode != -1 && memento.keyCode != options.keyCode) {
-        return false;
-    }
-
-    if (options.deviceId != -1 && memento.deviceId != options.deviceId) {
-        return false;
-    }
-
-    switch (options.mode) {
-    case CancelationOptions::CANCEL_ALL_EVENTS:
-    case CancelationOptions::CANCEL_NON_POINTER_EVENTS:
-        return true;
-    case CancelationOptions::CANCEL_FALLBACK_EVENTS:
-        return memento.flags & AKEY_EVENT_FLAG_FALLBACK;
-    default:
-        return false;
-    }
-}
-
-bool InputDispatcher::InputState::shouldCancelMotion(const MotionMemento& memento,
-        const CancelationOptions& options) {
-    if (options.deviceId != -1 && memento.deviceId != options.deviceId) {
-        return false;
-    }
-
-    switch (options.mode) {
-    case CancelationOptions::CANCEL_ALL_EVENTS:
-        return true;
-    case CancelationOptions::CANCEL_POINTER_EVENTS:
-        return memento.source & AINPUT_SOURCE_CLASS_POINTER;
-    case CancelationOptions::CANCEL_NON_POINTER_EVENTS:
-        return !(memento.source & AINPUT_SOURCE_CLASS_POINTER);
-    default:
-        return false;
-    }
-}
-
-
-// --- InputDispatcher::Connection ---
-
-InputDispatcher::Connection::Connection(const sp<InputChannel>& inputChannel,
-        const sp<InputWindowHandle>& inputWindowHandle, bool monitor) :
-        status(STATUS_NORMAL), inputChannel(inputChannel), inputWindowHandle(inputWindowHandle),
-        monitor(monitor),
-        inputPublisher(inputChannel), inputPublisherBlocked(false) {
-}
-
-InputDispatcher::Connection::~Connection() {
-}
-
-const char* InputDispatcher::Connection::getWindowName() const {
-    if (inputWindowHandle != NULL) {
-        return inputWindowHandle->getName().string();
-    }
-    if (monitor) {
-        return "monitor";
-    }
-    return "?";
-}
-
-const char* InputDispatcher::Connection::getStatusLabel() const {
-    switch (status) {
-    case STATUS_NORMAL:
-        return "NORMAL";
-
-    case STATUS_BROKEN:
-        return "BROKEN";
-
-    case STATUS_ZOMBIE:
-        return "ZOMBIE";
-
-    default:
-        return "UNKNOWN";
-    }
-}
-
-InputDispatcher::DispatchEntry* InputDispatcher::Connection::findWaitQueueEntry(uint32_t seq) {
-    for (DispatchEntry* entry = waitQueue.head; entry != NULL; entry = entry->next) {
-        if (entry->seq == seq) {
-            return entry;
-        }
-    }
-    return NULL;
-}
-
-
-// --- InputDispatcher::CommandEntry ---
-
-InputDispatcher::CommandEntry::CommandEntry(Command command) :
-    command(command), eventTime(0), keyEntry(NULL), userActivityEventType(0),
-    seq(0), handled(false) {
-}
-
-InputDispatcher::CommandEntry::~CommandEntry() {
-}
-
-
-// --- InputDispatcher::TouchState ---
-
-InputDispatcher::TouchState::TouchState() :
-    down(false), split(false), deviceId(-1), source(0), displayId(-1) {
-}
-
-InputDispatcher::TouchState::~TouchState() {
-}
-
-void InputDispatcher::TouchState::reset() {
-    down = false;
-    split = false;
-    deviceId = -1;
-    source = 0;
-    displayId = -1;
-    windows.clear();
-}
-
-void InputDispatcher::TouchState::copyFrom(const TouchState& other) {
-    down = other.down;
-    split = other.split;
-    deviceId = other.deviceId;
-    source = other.source;
-    displayId = other.displayId;
-    windows = other.windows;
-}
-
-void InputDispatcher::TouchState::addOrUpdateWindow(const sp<InputWindowHandle>& windowHandle,
-        int32_t targetFlags, BitSet32 pointerIds) {
-    if (targetFlags & InputTarget::FLAG_SPLIT) {
-        split = true;
-    }
-
-    for (size_t i = 0; i < windows.size(); i++) {
-        TouchedWindow& touchedWindow = windows.editItemAt(i);
-        if (touchedWindow.windowHandle == windowHandle) {
-            touchedWindow.targetFlags |= targetFlags;
-            if (targetFlags & InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT) {
-                touchedWindow.targetFlags &= ~InputTarget::FLAG_DISPATCH_AS_IS;
-            }
-            touchedWindow.pointerIds.value |= pointerIds.value;
-            return;
-        }
-    }
-
-    windows.push();
-
-    TouchedWindow& touchedWindow = windows.editTop();
-    touchedWindow.windowHandle = windowHandle;
-    touchedWindow.targetFlags = targetFlags;
-    touchedWindow.pointerIds = pointerIds;
-}
-
-void InputDispatcher::TouchState::removeWindow(const sp<InputWindowHandle>& windowHandle) {
-    for (size_t i = 0; i < windows.size(); i++) {
-        if (windows.itemAt(i).windowHandle == windowHandle) {
-            windows.removeAt(i);
-            return;
-        }
-    }
-}
-
-void InputDispatcher::TouchState::filterNonAsIsTouchWindows() {
-    for (size_t i = 0 ; i < windows.size(); ) {
-        TouchedWindow& window = windows.editItemAt(i);
-        if (window.targetFlags & (InputTarget::FLAG_DISPATCH_AS_IS
-                | InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER)) {
-            window.targetFlags &= ~InputTarget::FLAG_DISPATCH_MASK;
-            window.targetFlags |= InputTarget::FLAG_DISPATCH_AS_IS;
-            i += 1;
-        } else {
-            windows.removeAt(i);
-        }
-    }
-}
-
-sp<InputWindowHandle> InputDispatcher::TouchState::getFirstForegroundWindowHandle() const {
-    for (size_t i = 0; i < windows.size(); i++) {
-        const TouchedWindow& window = windows.itemAt(i);
-        if (window.targetFlags & InputTarget::FLAG_FOREGROUND) {
-            return window.windowHandle;
-        }
-    }
-    return NULL;
-}
-
-bool InputDispatcher::TouchState::isSlippery() const {
-    // Must have exactly one foreground window.
-    bool haveSlipperyForegroundWindow = false;
-    for (size_t i = 0; i < windows.size(); i++) {
-        const TouchedWindow& window = windows.itemAt(i);
-        if (window.targetFlags & InputTarget::FLAG_FOREGROUND) {
-            if (haveSlipperyForegroundWindow
-                    || !(window.windowHandle->getInfo()->layoutParamsFlags
-                            & InputWindowInfo::FLAG_SLIPPERY)) {
-                return false;
-            }
-            haveSlipperyForegroundWindow = true;
-        }
-    }
-    return haveSlipperyForegroundWindow;
-}
-
-
-// --- InputDispatcherThread ---
-
-InputDispatcherThread::InputDispatcherThread(const sp<InputDispatcherInterface>& dispatcher) :
-        Thread(/*canCallJava*/ true), mDispatcher(dispatcher) {
-}
-
-InputDispatcherThread::~InputDispatcherThread() {
-}
-
-bool InputDispatcherThread::threadLoop() {
-    mDispatcher->dispatchOnce();
-    return true;
-}
-
-} // namespace android
diff --git a/libs/input/InputDispatcher.h b/libs/input/InputDispatcher.h
deleted file mode 100644
index 190e7b2..0000000
--- a/libs/input/InputDispatcher.h
+++ /dev/null
@@ -1,1123 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _UI_INPUT_DISPATCHER_H
-#define _UI_INPUT_DISPATCHER_H
-
-#include <input/Input.h>
-#include <input/InputTransport.h>
-#include <utils/KeyedVector.h>
-#include <utils/Vector.h>
-#include <utils/threads.h>
-#include <utils/Timers.h>
-#include <utils/RefBase.h>
-#include <utils/String8.h>
-#include <utils/Looper.h>
-#include <utils/BitSet.h>
-#include <cutils/atomic.h>
-
-#include <stddef.h>
-#include <unistd.h>
-#include <limits.h>
-
-#include "InputWindow.h"
-#include "InputApplication.h"
-#include "InputListener.h"
-
-
-namespace android {
-
-/*
- * Constants used to report the outcome of input event injection.
- */
-enum {
-    /* (INTERNAL USE ONLY) Specifies that injection is pending and its outcome is unknown. */
-    INPUT_EVENT_INJECTION_PENDING = -1,
-
-    /* Injection succeeded. */
-    INPUT_EVENT_INJECTION_SUCCEEDED = 0,
-
-    /* Injection failed because the injector did not have permission to inject
-     * into the application with input focus. */
-    INPUT_EVENT_INJECTION_PERMISSION_DENIED = 1,
-
-    /* Injection failed because there were no available input targets. */
-    INPUT_EVENT_INJECTION_FAILED = 2,
-
-    /* Injection failed due to a timeout. */
-    INPUT_EVENT_INJECTION_TIMED_OUT = 3
-};
-
-/*
- * Constants used to determine the input event injection synchronization mode.
- */
-enum {
-    /* Injection is asynchronous and is assumed always to be successful. */
-    INPUT_EVENT_INJECTION_SYNC_NONE = 0,
-
-    /* Waits for previous events to be dispatched so that the input dispatcher can determine
-     * whether input event injection willbe permitted based on the current input focus.
-     * Does not wait for the input event to finish processing. */
-    INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_RESULT = 1,
-
-    /* Waits for the input event to be completely processed. */
-    INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_FINISHED = 2,
-};
-
-
-/*
- * An input target specifies how an input event is to be dispatched to a particular window
- * including the window's input channel, control flags, a timeout, and an X / Y offset to
- * be added to input event coordinates to compensate for the absolute position of the
- * window area.
- */
-struct InputTarget {
-    enum {
-        /* This flag indicates that the event is being delivered to a foreground application. */
-        FLAG_FOREGROUND = 1 << 0,
-
-        /* This flag indicates that the target of a MotionEvent is partly or wholly
-         * obscured by another visible window above it.  The motion event should be
-         * delivered with flag AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED. */
-        FLAG_WINDOW_IS_OBSCURED = 1 << 1,
-
-        /* This flag indicates that a motion event is being split across multiple windows. */
-        FLAG_SPLIT = 1 << 2,
-
-        /* This flag indicates that the pointer coordinates dispatched to the application
-         * will be zeroed out to avoid revealing information to an application. This is
-         * used in conjunction with FLAG_DISPATCH_AS_OUTSIDE to prevent apps not sharing
-         * the same UID from watching all touches. */
-        FLAG_ZERO_COORDS = 1 << 3,
-
-        /* This flag indicates that the event should be sent as is.
-         * Should always be set unless the event is to be transmuted. */
-        FLAG_DISPATCH_AS_IS = 1 << 8,
-
-        /* This flag indicates that a MotionEvent with AMOTION_EVENT_ACTION_DOWN falls outside
-         * of the area of this target and so should instead be delivered as an
-         * AMOTION_EVENT_ACTION_OUTSIDE to this target. */
-        FLAG_DISPATCH_AS_OUTSIDE = 1 << 9,
-
-        /* This flag indicates that a hover sequence is starting in the given window.
-         * The event is transmuted into ACTION_HOVER_ENTER. */
-        FLAG_DISPATCH_AS_HOVER_ENTER = 1 << 10,
-
-        /* This flag indicates that a hover event happened outside of a window which handled
-         * previous hover events, signifying the end of the current hover sequence for that
-         * window.
-         * The event is transmuted into ACTION_HOVER_ENTER. */
-        FLAG_DISPATCH_AS_HOVER_EXIT = 1 << 11,
-
-        /* This flag indicates that the event should be canceled.
-         * It is used to transmute ACTION_MOVE into ACTION_CANCEL when a touch slips
-         * outside of a window. */
-        FLAG_DISPATCH_AS_SLIPPERY_EXIT = 1 << 12,
-
-        /* This flag indicates that the event should be dispatched as an initial down.
-         * It is used to transmute ACTION_MOVE into ACTION_DOWN when a touch slips
-         * into a new window. */
-        FLAG_DISPATCH_AS_SLIPPERY_ENTER = 1 << 13,
-
-        /* Mask for all dispatch modes. */
-        FLAG_DISPATCH_MASK = FLAG_DISPATCH_AS_IS
-                | FLAG_DISPATCH_AS_OUTSIDE
-                | FLAG_DISPATCH_AS_HOVER_ENTER
-                | FLAG_DISPATCH_AS_HOVER_EXIT
-                | FLAG_DISPATCH_AS_SLIPPERY_EXIT
-                | FLAG_DISPATCH_AS_SLIPPERY_ENTER,
-    };
-
-    // The input channel to be targeted.
-    sp<InputChannel> inputChannel;
-
-    // Flags for the input target.
-    int32_t flags;
-
-    // The x and y offset to add to a MotionEvent as it is delivered.
-    // (ignored for KeyEvents)
-    float xOffset, yOffset;
-
-    // Scaling factor to apply to MotionEvent as it is delivered.
-    // (ignored for KeyEvents)
-    float scaleFactor;
-
-    // The subset of pointer ids to include in motion events dispatched to this input target
-    // if FLAG_SPLIT is set.
-    BitSet32 pointerIds;
-};
-
-
-/*
- * Input dispatcher configuration.
- *
- * Specifies various options that modify the behavior of the input dispatcher.
- * The values provided here are merely defaults. The actual values will come from ViewConfiguration
- * and are passed into the dispatcher during initialization.
- */
-struct InputDispatcherConfiguration {
-    // The key repeat initial timeout.
-    nsecs_t keyRepeatTimeout;
-
-    // The key repeat inter-key delay.
-    nsecs_t keyRepeatDelay;
-
-    InputDispatcherConfiguration() :
-            keyRepeatTimeout(500 * 1000000LL),
-            keyRepeatDelay(50 * 1000000LL) { }
-};
-
-
-/*
- * Input dispatcher policy interface.
- *
- * The input reader policy is used by the input reader to interact with the Window Manager
- * and other system components.
- *
- * The actual implementation is partially supported by callbacks into the DVM
- * via JNI.  This interface is also mocked in the unit tests.
- */
-class InputDispatcherPolicyInterface : public virtual RefBase {
-protected:
-    InputDispatcherPolicyInterface() { }
-    virtual ~InputDispatcherPolicyInterface() { }
-
-public:
-    /* Notifies the system that a configuration change has occurred. */
-    virtual void notifyConfigurationChanged(nsecs_t when) = 0;
-
-    /* Notifies the system that an application is not responding.
-     * Returns a new timeout to continue waiting, or 0 to abort dispatch. */
-    virtual nsecs_t notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle,
-            const sp<InputWindowHandle>& inputWindowHandle,
-            const String8& reason) = 0;
-
-    /* Notifies the system that an input channel is unrecoverably broken. */
-    virtual void notifyInputChannelBroken(const sp<InputWindowHandle>& inputWindowHandle) = 0;
-
-    /* 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
-     * to injectInputEvent.
-     */
-    virtual bool filterInputEvent(const InputEvent* inputEvent, uint32_t policyFlags) = 0;
-
-    /* Intercepts a key event immediately before queueing it.
-     * The policy can use this method as an opportunity to perform power management functions
-     * and early event preprocessing such as updating policy flags.
-     *
-     * This method is expected to set the POLICY_FLAG_PASS_TO_USER policy flag if the event
-     * should be dispatched to applications.
-     */
-    virtual void interceptKeyBeforeQueueing(const KeyEvent* keyEvent, uint32_t& policyFlags) = 0;
-
-    /* Intercepts a touch, trackball or other motion event before queueing it.
-     * The policy can use this method as an opportunity to perform power management functions
-     * and early event preprocessing such as updating policy flags.
-     *
-     * This method is expected to set the POLICY_FLAG_PASS_TO_USER policy flag if the event
-     * should be dispatched to applications.
-     */
-    virtual void interceptMotionBeforeQueueing(nsecs_t when, uint32_t& policyFlags) = 0;
-
-    /* Allows the policy a chance to intercept a key before dispatching. */
-    virtual nsecs_t interceptKeyBeforeDispatching(const sp<InputWindowHandle>& inputWindowHandle,
-            const KeyEvent* keyEvent, uint32_t policyFlags) = 0;
-
-    /* Allows the policy a chance to perform default processing for an unhandled key.
-     * Returns an alternate keycode to redispatch as a fallback, or 0 to give up. */
-    virtual bool dispatchUnhandledKey(const sp<InputWindowHandle>& inputWindowHandle,
-            const KeyEvent* keyEvent, uint32_t policyFlags, KeyEvent* outFallbackKeyEvent) = 0;
-
-    /* Notifies the policy about switch events.
-     */
-    virtual void notifySwitch(nsecs_t when,
-            uint32_t switchValues, uint32_t switchMask, uint32_t policyFlags) = 0;
-
-    /* Poke user activity for an event dispatched to a window. */
-    virtual void pokeUserActivity(nsecs_t eventTime, int32_t eventType) = 0;
-
-    /* Checks whether a given application pid/uid has permission to inject input events
-     * into other applications.
-     *
-     * This method is special in that its implementation promises to be non-reentrant and
-     * is safe to call while holding other locks.  (Most other methods make no such guarantees!)
-     */
-    virtual bool checkInjectEventsPermissionNonReentrant(
-            int32_t injectorPid, int32_t injectorUid) = 0;
-};
-
-
-/* Notifies the system about input events generated by the input reader.
- * The dispatcher is expected to be mostly asynchronous. */
-class InputDispatcherInterface : public virtual RefBase, public InputListenerInterface {
-protected:
-    InputDispatcherInterface() { }
-    virtual ~InputDispatcherInterface() { }
-
-public:
-    /* Dumps the state of the input dispatcher.
-     *
-     * This method may be called on any thread (usually by the input manager). */
-    virtual void dump(String8& dump) = 0;
-
-    /* Called by the heatbeat to ensures that the dispatcher has not deadlocked. */
-    virtual void monitor() = 0;
-
-    /* Runs a single iteration of the dispatch loop.
-     * Nominally processes one queued event, a timeout, or a response from an input consumer.
-     *
-     * This method should only be called on the input dispatcher thread.
-     */
-    virtual void dispatchOnce() = 0;
-
-    /* Injects an input event and optionally waits for sync.
-     * The synchronization mode determines whether the method blocks while waiting for
-     * input injection to proceed.
-     * Returns one of the INPUT_EVENT_INJECTION_XXX constants.
-     *
-     * This method may be called on any thread (usually by the input manager).
-     */
-    virtual int32_t injectInputEvent(const InputEvent* event,
-            int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis,
-            uint32_t policyFlags) = 0;
-
-    /* Sets the list of input windows.
-     *
-     * This method may be called on any thread (usually by the input manager).
-     */
-    virtual void setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles) = 0;
-
-    /* Sets the focused application.
-     *
-     * This method may be called on any thread (usually by the input manager).
-     */
-    virtual void setFocusedApplication(
-            const sp<InputApplicationHandle>& inputApplicationHandle) = 0;
-
-    /* Sets the input dispatching mode.
-     *
-     * This method may be called on any thread (usually by the input manager).
-     */
-    virtual void setInputDispatchMode(bool enabled, bool frozen) = 0;
-
-    /* Sets whether input event filtering is enabled.
-     * When enabled, incoming input events are sent to the policy's filterInputEvent
-     * method instead of being dispatched.  The filter is expected to use
-     * injectInputEvent to inject the events it would like to have dispatched.
-     * It should include POLICY_FLAG_FILTERED in the policy flags during injection.
-     */
-    virtual void setInputFilterEnabled(bool enabled) = 0;
-
-    /* Transfers touch focus from the window associated with one channel to the
-     * window associated with the other channel.
-     *
-     * Returns true on success.  False if the window did not actually have touch focus.
-     */
-    virtual bool transferTouchFocus(const sp<InputChannel>& fromChannel,
-            const sp<InputChannel>& toChannel) = 0;
-
-    /* Registers or unregister input channels that may be used as targets for input events.
-     * If monitor is true, the channel will receive a copy of all input events.
-     *
-     * These methods may be called on any thread (usually by the input manager).
-     */
-    virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel,
-            const sp<InputWindowHandle>& inputWindowHandle, bool monitor) = 0;
-    virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel) = 0;
-};
-
-/* Dispatches events to input targets.  Some functions of the input dispatcher, such as
- * identifying input targets, are controlled by a separate policy object.
- *
- * IMPORTANT INVARIANT:
- *     Because the policy can potentially block or cause re-entrance into the input dispatcher,
- *     the input dispatcher never calls into the policy while holding its internal locks.
- *     The implementation is also carefully designed to recover from scenarios such as an
- *     input channel becoming unregistered while identifying input targets or processing timeouts.
- *
- *     Methods marked 'Locked' must be called with the lock acquired.
- *
- *     Methods marked 'LockedInterruptible' must be called with the lock acquired but
- *     may during the course of their execution release the lock, call into the policy, and
- *     then reacquire the lock.  The caller is responsible for recovering gracefully.
- *
- *     A 'LockedInterruptible' method may called a 'Locked' method, but NOT vice-versa.
- */
-class InputDispatcher : public InputDispatcherInterface {
-protected:
-    virtual ~InputDispatcher();
-
-public:
-    explicit InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy);
-
-    virtual void dump(String8& dump);
-    virtual void monitor();
-
-    virtual void dispatchOnce();
-
-    virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args);
-    virtual void notifyKey(const NotifyKeyArgs* args);
-    virtual void notifyMotion(const NotifyMotionArgs* args);
-    virtual void notifySwitch(const NotifySwitchArgs* args);
-    virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args);
-
-    virtual int32_t injectInputEvent(const InputEvent* event,
-            int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis,
-            uint32_t policyFlags);
-
-    virtual void setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles);
-    virtual void setFocusedApplication(const sp<InputApplicationHandle>& inputApplicationHandle);
-    virtual void setInputDispatchMode(bool enabled, bool frozen);
-    virtual void setInputFilterEnabled(bool enabled);
-
-    virtual bool transferTouchFocus(const sp<InputChannel>& fromChannel,
-            const sp<InputChannel>& toChannel);
-
-    virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel,
-            const sp<InputWindowHandle>& inputWindowHandle, bool monitor);
-    virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel);
-
-private:
-    template <typename T>
-    struct Link {
-        T* next;
-        T* prev;
-
-    protected:
-        inline Link() : next(NULL), prev(NULL) { }
-    };
-
-    struct InjectionState {
-        mutable int32_t refCount;
-
-        int32_t injectorPid;
-        int32_t injectorUid;
-        int32_t injectionResult;  // initially INPUT_EVENT_INJECTION_PENDING
-        bool injectionIsAsync; // set to true if injection is not waiting for the result
-        int32_t pendingForegroundDispatches; // the number of foreground dispatches in progress
-
-        InjectionState(int32_t injectorPid, int32_t injectorUid);
-        void release();
-
-    private:
-        ~InjectionState();
-    };
-
-    struct EventEntry : Link<EventEntry> {
-        enum {
-            TYPE_CONFIGURATION_CHANGED,
-            TYPE_DEVICE_RESET,
-            TYPE_KEY,
-            TYPE_MOTION
-        };
-
-        mutable int32_t refCount;
-        int32_t type;
-        nsecs_t eventTime;
-        uint32_t policyFlags;
-        InjectionState* injectionState;
-
-        bool dispatchInProgress; // initially false, set to true while dispatching
-
-        inline bool isInjected() const { return injectionState != NULL; }
-
-        void release();
-
-        virtual void appendDescription(String8& msg) const = 0;
-
-    protected:
-        EventEntry(int32_t type, nsecs_t eventTime, uint32_t policyFlags);
-        virtual ~EventEntry();
-        void releaseInjectionState();
-    };
-
-    struct ConfigurationChangedEntry : EventEntry {
-        ConfigurationChangedEntry(nsecs_t eventTime);
-        virtual void appendDescription(String8& msg) const;
-
-    protected:
-        virtual ~ConfigurationChangedEntry();
-    };
-
-    struct DeviceResetEntry : EventEntry {
-        int32_t deviceId;
-
-        DeviceResetEntry(nsecs_t eventTime, int32_t deviceId);
-        virtual void appendDescription(String8& msg) const;
-
-    protected:
-        virtual ~DeviceResetEntry();
-    };
-
-    struct KeyEntry : EventEntry {
-        int32_t deviceId;
-        uint32_t source;
-        int32_t action;
-        int32_t flags;
-        int32_t keyCode;
-        int32_t scanCode;
-        int32_t metaState;
-        int32_t repeatCount;
-        nsecs_t downTime;
-
-        bool syntheticRepeat; // set to true for synthetic key repeats
-
-        enum InterceptKeyResult {
-            INTERCEPT_KEY_RESULT_UNKNOWN,
-            INTERCEPT_KEY_RESULT_SKIP,
-            INTERCEPT_KEY_RESULT_CONTINUE,
-            INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER,
-        };
-        InterceptKeyResult interceptKeyResult; // set based on the interception result
-        nsecs_t interceptKeyWakeupTime; // used with INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER
-
-        KeyEntry(nsecs_t eventTime,
-                int32_t deviceId, uint32_t source, uint32_t policyFlags, int32_t action,
-                int32_t flags, int32_t keyCode, int32_t scanCode, int32_t metaState,
-                int32_t repeatCount, nsecs_t downTime);
-        virtual void appendDescription(String8& msg) const;
-        void recycle();
-
-    protected:
-        virtual ~KeyEntry();
-    };
-
-    struct MotionEntry : EventEntry {
-        nsecs_t eventTime;
-        int32_t deviceId;
-        uint32_t source;
-        int32_t action;
-        int32_t flags;
-        int32_t metaState;
-        int32_t buttonState;
-        int32_t edgeFlags;
-        float xPrecision;
-        float yPrecision;
-        nsecs_t downTime;
-        int32_t displayId;
-        uint32_t pointerCount;
-        PointerProperties pointerProperties[MAX_POINTERS];
-        PointerCoords pointerCoords[MAX_POINTERS];
-
-        MotionEntry(nsecs_t eventTime,
-                int32_t deviceId, uint32_t source, uint32_t policyFlags,
-                int32_t action, int32_t flags,
-                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);
-        virtual void appendDescription(String8& msg) const;
-
-    protected:
-        virtual ~MotionEntry();
-    };
-
-    // Tracks the progress of dispatching a particular event to a particular connection.
-    struct DispatchEntry : Link<DispatchEntry> {
-        const uint32_t seq; // unique sequence number, never 0
-
-        EventEntry* eventEntry; // the event to dispatch
-        int32_t targetFlags;
-        float xOffset;
-        float yOffset;
-        float scaleFactor;
-        nsecs_t deliveryTime; // time when the event was actually delivered
-
-        // Set to the resolved action and flags when the event is enqueued.
-        int32_t resolvedAction;
-        int32_t resolvedFlags;
-
-        DispatchEntry(EventEntry* eventEntry,
-                int32_t targetFlags, float xOffset, float yOffset, float scaleFactor);
-        ~DispatchEntry();
-
-        inline bool hasForegroundTarget() const {
-            return targetFlags & InputTarget::FLAG_FOREGROUND;
-        }
-
-        inline bool isSplit() const {
-            return targetFlags & InputTarget::FLAG_SPLIT;
-        }
-
-    private:
-        static volatile int32_t sNextSeqAtomic;
-
-        static uint32_t nextSeq();
-    };
-
-    // A command entry captures state and behavior for an action to be performed in the
-    // dispatch loop after the initial processing has taken place.  It is essentially
-    // a kind of continuation used to postpone sensitive policy interactions to a point
-    // in the dispatch loop where it is safe to release the lock (generally after finishing
-    // the critical parts of the dispatch cycle).
-    //
-    // The special thing about commands is that they can voluntarily release and reacquire
-    // the dispatcher lock at will.  Initially when the command starts running, the
-    // dispatcher lock is held.  However, if the command needs to call into the policy to
-    // do some work, it can release the lock, do the work, then reacquire the lock again
-    // before returning.
-    //
-    // This mechanism is a bit clunky but it helps to preserve the invariant that the dispatch
-    // never calls into the policy while holding its lock.
-    //
-    // Commands are implicitly 'LockedInterruptible'.
-    struct CommandEntry;
-    typedef void (InputDispatcher::*Command)(CommandEntry* commandEntry);
-
-    class Connection;
-    struct CommandEntry : Link<CommandEntry> {
-        CommandEntry(Command command);
-        ~CommandEntry();
-
-        Command command;
-
-        // parameters for the command (usage varies by command)
-        sp<Connection> connection;
-        nsecs_t eventTime;
-        KeyEntry* keyEntry;
-        sp<InputApplicationHandle> inputApplicationHandle;
-        sp<InputWindowHandle> inputWindowHandle;
-        String8 reason;
-        int32_t userActivityEventType;
-        uint32_t seq;
-        bool handled;
-    };
-
-    // Generic queue implementation.
-    template <typename T>
-    struct Queue {
-        T* head;
-        T* tail;
-
-        inline Queue() : head(NULL), tail(NULL) {
-        }
-
-        inline bool isEmpty() const {
-            return !head;
-        }
-
-        inline void enqueueAtTail(T* entry) {
-            entry->prev = tail;
-            if (tail) {
-                tail->next = entry;
-            } else {
-                head = entry;
-            }
-            entry->next = NULL;
-            tail = entry;
-        }
-
-        inline void enqueueAtHead(T* entry) {
-            entry->next = head;
-            if (head) {
-                head->prev = entry;
-            } else {
-                tail = entry;
-            }
-            entry->prev = NULL;
-            head = entry;
-        }
-
-        inline void dequeue(T* entry) {
-            if (entry->prev) {
-                entry->prev->next = entry->next;
-            } else {
-                head = entry->next;
-            }
-            if (entry->next) {
-                entry->next->prev = entry->prev;
-            } else {
-                tail = entry->prev;
-            }
-        }
-
-        inline T* dequeueAtHead() {
-            T* entry = head;
-            head = entry->next;
-            if (head) {
-                head->prev = NULL;
-            } else {
-                tail = NULL;
-            }
-            return entry;
-        }
-
-        uint32_t count() const;
-    };
-
-    /* Specifies which events are to be canceled and why. */
-    struct CancelationOptions {
-        enum Mode {
-            CANCEL_ALL_EVENTS = 0,
-            CANCEL_POINTER_EVENTS = 1,
-            CANCEL_NON_POINTER_EVENTS = 2,
-            CANCEL_FALLBACK_EVENTS = 3,
-        };
-
-        // The criterion to use to determine which events should be canceled.
-        Mode mode;
-
-        // Descriptive reason for the cancelation.
-        const char* reason;
-
-        // The specific keycode of the key event to cancel, or -1 to cancel any key event.
-        int32_t keyCode;
-
-        // The specific device id of events to cancel, or -1 to cancel events from any device.
-        int32_t deviceId;
-
-        CancelationOptions(Mode mode, const char* reason) :
-                mode(mode), reason(reason), keyCode(-1), deviceId(-1) { }
-    };
-
-    /* Tracks dispatched key and motion event state so that cancelation events can be
-     * synthesized when events are dropped. */
-    class InputState {
-    public:
-        InputState();
-        ~InputState();
-
-        // Returns true if there is no state to be canceled.
-        bool isNeutral() const;
-
-        // Returns true if the specified source is known to have received a hover enter
-        // motion event.
-        bool isHovering(int32_t deviceId, uint32_t source, int32_t displayId) const;
-
-        // Records tracking information for a key event that has just been published.
-        // Returns true if the event should be delivered, false if it is inconsistent
-        // and should be skipped.
-        bool trackKey(const KeyEntry* entry, int32_t action, int32_t flags);
-
-        // Records tracking information for a motion event that has just been published.
-        // Returns true if the event should be delivered, false if it is inconsistent
-        // and should be skipped.
-        bool trackMotion(const MotionEntry* entry, int32_t action, int32_t flags);
-
-        // Synthesizes cancelation events for the current state and resets the tracked state.
-        void synthesizeCancelationEvents(nsecs_t currentTime,
-                Vector<EventEntry*>& outEvents, const CancelationOptions& options);
-
-        // Clears the current state.
-        void clear();
-
-        // Copies pointer-related parts of the input state to another instance.
-        void copyPointerStateTo(InputState& other) const;
-
-        // Gets the fallback key associated with a keycode.
-        // Returns -1 if none.
-        // Returns AKEYCODE_UNKNOWN if we are only dispatching the unhandled key to the policy.
-        int32_t getFallbackKey(int32_t originalKeyCode);
-
-        // Sets the fallback key for a particular keycode.
-        void setFallbackKey(int32_t originalKeyCode, int32_t fallbackKeyCode);
-
-        // Removes the fallback key for a particular keycode.
-        void removeFallbackKey(int32_t originalKeyCode);
-
-        inline const KeyedVector<int32_t, int32_t>& getFallbackKeys() const {
-            return mFallbackKeys;
-        }
-
-    private:
-        struct KeyMemento {
-            int32_t deviceId;
-            uint32_t source;
-            int32_t keyCode;
-            int32_t scanCode;
-            int32_t metaState;
-            int32_t flags;
-            nsecs_t downTime;
-            uint32_t policyFlags;
-        };
-
-        struct MotionMemento {
-            int32_t deviceId;
-            uint32_t source;
-            int32_t flags;
-            float xPrecision;
-            float yPrecision;
-            nsecs_t downTime;
-            int32_t displayId;
-            uint32_t pointerCount;
-            PointerProperties pointerProperties[MAX_POINTERS];
-            PointerCoords pointerCoords[MAX_POINTERS];
-            bool hovering;
-            uint32_t policyFlags;
-
-            void setPointers(const MotionEntry* entry);
-        };
-
-        Vector<KeyMemento> mKeyMementos;
-        Vector<MotionMemento> mMotionMementos;
-        KeyedVector<int32_t, int32_t> mFallbackKeys;
-
-        ssize_t findKeyMemento(const KeyEntry* entry) const;
-        ssize_t findMotionMemento(const MotionEntry* entry, bool hovering) const;
-
-        void addKeyMemento(const KeyEntry* entry, int32_t flags);
-        void addMotionMemento(const MotionEntry* entry, int32_t flags, bool hovering);
-
-        static bool shouldCancelKey(const KeyMemento& memento,
-                const CancelationOptions& options);
-        static bool shouldCancelMotion(const MotionMemento& memento,
-                const CancelationOptions& options);
-    };
-
-    /* Manages the dispatch state associated with a single input channel. */
-    class Connection : public RefBase {
-    protected:
-        virtual ~Connection();
-
-    public:
-        enum Status {
-            // Everything is peachy.
-            STATUS_NORMAL,
-            // An unrecoverable communication error has occurred.
-            STATUS_BROKEN,
-            // The input channel has been unregistered.
-            STATUS_ZOMBIE
-        };
-
-        Status status;
-        sp<InputChannel> inputChannel; // never null
-        sp<InputWindowHandle> inputWindowHandle; // may be null
-        bool monitor;
-        InputPublisher inputPublisher;
-        InputState inputState;
-
-        // True if the socket is full and no further events can be published until
-        // the application consumes some of the input.
-        bool inputPublisherBlocked;
-
-        // Queue of events that need to be published to the connection.
-        Queue<DispatchEntry> outboundQueue;
-
-        // Queue of events that have been published to the connection but that have not
-        // yet received a "finished" response from the application.
-        Queue<DispatchEntry> waitQueue;
-
-        explicit Connection(const sp<InputChannel>& inputChannel,
-                const sp<InputWindowHandle>& inputWindowHandle, bool monitor);
-
-        inline const char* getInputChannelName() const { return inputChannel->getName().string(); }
-
-        const char* getWindowName() const;
-        const char* getStatusLabel() const;
-
-        DispatchEntry* findWaitQueueEntry(uint32_t seq);
-    };
-
-    enum DropReason {
-        DROP_REASON_NOT_DROPPED = 0,
-        DROP_REASON_POLICY = 1,
-        DROP_REASON_APP_SWITCH = 2,
-        DROP_REASON_DISABLED = 3,
-        DROP_REASON_BLOCKED = 4,
-        DROP_REASON_STALE = 5,
-    };
-
-    sp<InputDispatcherPolicyInterface> mPolicy;
-    InputDispatcherConfiguration mConfig;
-
-    Mutex mLock;
-
-    Condition mDispatcherIsAliveCondition;
-
-    sp<Looper> mLooper;
-
-    EventEntry* mPendingEvent;
-    Queue<EventEntry> mInboundQueue;
-    Queue<EventEntry> mRecentQueue;
-    Queue<CommandEntry> mCommandQueue;
-
-    void dispatchOnceInnerLocked(nsecs_t* nextWakeupTime);
-
-    // Enqueues an inbound event.  Returns true if mLooper->wake() should be called.
-    bool enqueueInboundEventLocked(EventEntry* entry);
-
-    // Cleans up input state when dropping an inbound event.
-    void dropInboundEventLocked(EventEntry* entry, DropReason dropReason);
-
-    // Adds an event to a queue of recent events for debugging purposes.
-    void addRecentEventLocked(EventEntry* entry);
-
-    // App switch latency optimization.
-    bool mAppSwitchSawKeyDown;
-    nsecs_t mAppSwitchDueTime;
-
-    static bool isAppSwitchKeyCode(int32_t keyCode);
-    bool isAppSwitchKeyEventLocked(KeyEntry* keyEntry);
-    bool isAppSwitchPendingLocked();
-    void resetPendingAppSwitchLocked(bool handled);
-
-    // Stale event latency optimization.
-    static bool isStaleEventLocked(nsecs_t currentTime, EventEntry* entry);
-
-    // Blocked event latency optimization.  Drops old events when the user intends
-    // to transfer focus to a new application.
-    EventEntry* mNextUnblockedEvent;
-
-    sp<InputWindowHandle> findTouchedWindowAtLocked(int32_t displayId, int32_t x, int32_t y);
-
-    // All registered connections mapped by channel file descriptor.
-    KeyedVector<int, sp<Connection> > mConnectionsByFd;
-
-    ssize_t getConnectionIndexLocked(const sp<InputChannel>& inputChannel);
-
-    // Input channels that will receive a copy of all input events.
-    Vector<sp<InputChannel> > mMonitoringChannels;
-
-    // Event injection and synchronization.
-    Condition mInjectionResultAvailableCondition;
-    bool hasInjectionPermission(int32_t injectorPid, int32_t injectorUid);
-    void setInjectionResultLocked(EventEntry* entry, int32_t injectionResult);
-
-    Condition mInjectionSyncFinishedCondition;
-    void incrementPendingForegroundDispatchesLocked(EventEntry* entry);
-    void decrementPendingForegroundDispatchesLocked(EventEntry* entry);
-
-    // Key repeat tracking.
-    struct KeyRepeatState {
-        KeyEntry* lastKeyEntry; // or null if no repeat
-        nsecs_t nextRepeatTime;
-    } mKeyRepeatState;
-
-    void resetKeyRepeatLocked();
-    KeyEntry* synthesizeKeyRepeatLocked(nsecs_t currentTime);
-
-    // Deferred command processing.
-    bool haveCommandsLocked() const;
-    bool runCommandsLockedInterruptible();
-    CommandEntry* postCommandLocked(Command command);
-
-    // Input filter processing.
-    bool shouldSendKeyToInputFilterLocked(const NotifyKeyArgs* args);
-    bool shouldSendMotionToInputFilterLocked(const NotifyMotionArgs* args);
-
-    // Inbound event processing.
-    void drainInboundQueueLocked();
-    void releasePendingEventLocked();
-    void releaseInboundEventLocked(EventEntry* entry);
-
-    // Dispatch state.
-    bool mDispatchEnabled;
-    bool mDispatchFrozen;
-    bool mInputFilterEnabled;
-
-    Vector<sp<InputWindowHandle> > mWindowHandles;
-
-    sp<InputWindowHandle> getWindowHandleLocked(const sp<InputChannel>& inputChannel) const;
-    bool hasWindowHandleLocked(const sp<InputWindowHandle>& windowHandle) const;
-
-    // Focus tracking for keys, trackball, etc.
-    sp<InputWindowHandle> mFocusedWindowHandle;
-
-    // Focus tracking for touch.
-    struct TouchedWindow {
-        sp<InputWindowHandle> windowHandle;
-        int32_t targetFlags;
-        BitSet32 pointerIds;        // zero unless target flag FLAG_SPLIT is set
-    };
-    struct TouchState {
-        bool down;
-        bool split;
-        int32_t deviceId; // id of the device that is currently down, others are rejected
-        uint32_t source;  // source of the device that is current down, others are rejected
-        int32_t displayId; // id to the display that currently has a touch, others are rejected
-        Vector<TouchedWindow> windows;
-
-        TouchState();
-        ~TouchState();
-        void reset();
-        void copyFrom(const TouchState& other);
-        void addOrUpdateWindow(const sp<InputWindowHandle>& windowHandle,
-                int32_t targetFlags, BitSet32 pointerIds);
-        void removeWindow(const sp<InputWindowHandle>& windowHandle);
-        void filterNonAsIsTouchWindows();
-        sp<InputWindowHandle> getFirstForegroundWindowHandle() const;
-        bool isSlippery() const;
-    };
-
-    TouchState mTouchState;
-    TouchState mTempTouchState;
-
-    // Focused application.
-    sp<InputApplicationHandle> mFocusedApplicationHandle;
-
-    // Dispatcher state at time of last ANR.
-    String8 mLastANRState;
-
-    // Dispatch inbound events.
-    bool dispatchConfigurationChangedLocked(
-            nsecs_t currentTime, ConfigurationChangedEntry* entry);
-    bool dispatchDeviceResetLocked(
-            nsecs_t currentTime, DeviceResetEntry* entry);
-    bool dispatchKeyLocked(
-            nsecs_t currentTime, KeyEntry* entry,
-            DropReason* dropReason, nsecs_t* nextWakeupTime);
-    bool dispatchMotionLocked(
-            nsecs_t currentTime, MotionEntry* entry,
-            DropReason* dropReason, nsecs_t* nextWakeupTime);
-    void dispatchEventLocked(nsecs_t currentTime, EventEntry* entry,
-            const Vector<InputTarget>& inputTargets);
-
-    void logOutboundKeyDetailsLocked(const char* prefix, const KeyEntry* entry);
-    void logOutboundMotionDetailsLocked(const char* prefix, const MotionEntry* entry);
-
-    // Keeping track of ANR timeouts.
-    enum InputTargetWaitCause {
-        INPUT_TARGET_WAIT_CAUSE_NONE,
-        INPUT_TARGET_WAIT_CAUSE_SYSTEM_NOT_READY,
-        INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY,
-    };
-
-    InputTargetWaitCause mInputTargetWaitCause;
-    nsecs_t mInputTargetWaitStartTime;
-    nsecs_t mInputTargetWaitTimeoutTime;
-    bool mInputTargetWaitTimeoutExpired;
-    sp<InputApplicationHandle> mInputTargetWaitApplicationHandle;
-
-    // Contains the last window which received a hover event.
-    sp<InputWindowHandle> mLastHoverWindowHandle;
-
-    // Finding targets for input events.
-    int32_t handleTargetsNotReadyLocked(nsecs_t currentTime, const EventEntry* entry,
-            const sp<InputApplicationHandle>& applicationHandle,
-            const sp<InputWindowHandle>& windowHandle,
-            nsecs_t* nextWakeupTime, const char* reason);
-    void resumeAfterTargetsNotReadyTimeoutLocked(nsecs_t newTimeout,
-            const sp<InputChannel>& inputChannel);
-    nsecs_t getTimeSpentWaitingForApplicationLocked(nsecs_t currentTime);
-    void resetANRTimeoutsLocked();
-
-    int32_t findFocusedWindowTargetsLocked(nsecs_t currentTime, const EventEntry* entry,
-            Vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime);
-    int32_t findTouchedWindowTargetsLocked(nsecs_t currentTime, const MotionEntry* entry,
-            Vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime,
-            bool* outConflictingPointerActions);
-
-    void addWindowTargetLocked(const sp<InputWindowHandle>& windowHandle,
-            int32_t targetFlags, BitSet32 pointerIds, Vector<InputTarget>& inputTargets);
-    void addMonitoringTargetsLocked(Vector<InputTarget>& inputTargets);
-
-    void pokeUserActivityLocked(const EventEntry* eventEntry);
-    bool checkInjectionPermission(const sp<InputWindowHandle>& windowHandle,
-            const InjectionState* injectionState);
-    bool isWindowObscuredAtPointLocked(const sp<InputWindowHandle>& windowHandle,
-            int32_t x, int32_t y) const;
-    bool isWindowReadyForMoreInputLocked(nsecs_t currentTime,
-            const sp<InputWindowHandle>& windowHandle, const EventEntry* eventEntry);
-    String8 getApplicationWindowLabelLocked(const sp<InputApplicationHandle>& applicationHandle,
-            const sp<InputWindowHandle>& windowHandle);
-
-    // Manage the dispatch cycle for a single connection.
-    // These methods are deliberately not Interruptible because doing all of the work
-    // with the mutex held makes it easier to ensure that connection invariants are maintained.
-    // If needed, the methods post commands to run later once the critical bits are done.
-    void prepareDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection,
-            EventEntry* eventEntry, const InputTarget* inputTarget);
-    void enqueueDispatchEntriesLocked(nsecs_t currentTime, const sp<Connection>& connection,
-            EventEntry* eventEntry, const InputTarget* inputTarget);
-    void enqueueDispatchEntryLocked(const sp<Connection>& connection,
-            EventEntry* eventEntry, const InputTarget* inputTarget, int32_t dispatchMode);
-    void startDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection);
-    void finishDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection,
-            uint32_t seq, bool handled);
-    void abortBrokenDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection,
-            bool notify);
-    void drainDispatchQueueLocked(Queue<DispatchEntry>* queue);
-    void releaseDispatchEntryLocked(DispatchEntry* dispatchEntry);
-    static int handleReceiveCallback(int fd, int events, void* data);
-
-    void synthesizeCancelationEventsForAllConnectionsLocked(
-            const CancelationOptions& options);
-    void synthesizeCancelationEventsForInputChannelLocked(const sp<InputChannel>& channel,
-            const CancelationOptions& options);
-    void synthesizeCancelationEventsForConnectionLocked(const sp<Connection>& connection,
-            const CancelationOptions& options);
-
-    // Splitting motion events across windows.
-    MotionEntry* splitMotionEvent(const MotionEntry* originalMotionEntry, BitSet32 pointerIds);
-
-    // Reset and drop everything the dispatcher is doing.
-    void resetAndDropEverythingLocked(const char* reason);
-
-    // Dump state.
-    void dumpDispatchStateLocked(String8& dump);
-    void logDispatchStateLocked();
-
-    // Registration.
-    void removeMonitorChannelLocked(const sp<InputChannel>& inputChannel);
-    status_t unregisterInputChannelLocked(const sp<InputChannel>& inputChannel, bool notify);
-
-    // Add or remove a connection to the mActiveConnections vector.
-    void activateConnectionLocked(Connection* connection);
-    void deactivateConnectionLocked(Connection* connection);
-
-    // Interesting events that we might like to log or tell the framework about.
-    void onDispatchCycleFinishedLocked(
-            nsecs_t currentTime, const sp<Connection>& connection, uint32_t seq, bool handled);
-    void onDispatchCycleBrokenLocked(
-            nsecs_t currentTime, const sp<Connection>& connection);
-    void onANRLocked(
-            nsecs_t currentTime, const sp<InputApplicationHandle>& applicationHandle,
-            const sp<InputWindowHandle>& windowHandle,
-            nsecs_t eventTime, nsecs_t waitStartTime, const char* reason);
-
-    // Outbound policy interactions.
-    void doNotifyConfigurationChangedInterruptible(CommandEntry* commandEntry);
-    void doNotifyInputChannelBrokenLockedInterruptible(CommandEntry* commandEntry);
-    void doNotifyANRLockedInterruptible(CommandEntry* commandEntry);
-    void doInterceptKeyBeforeDispatchingLockedInterruptible(CommandEntry* commandEntry);
-    void doDispatchCycleFinishedLockedInterruptible(CommandEntry* commandEntry);
-    bool afterKeyEventLockedInterruptible(const sp<Connection>& connection,
-            DispatchEntry* dispatchEntry, KeyEntry* keyEntry, bool handled);
-    bool afterMotionEventLockedInterruptible(const sp<Connection>& connection,
-            DispatchEntry* dispatchEntry, MotionEntry* motionEntry, bool handled);
-    void doPokeUserActivityLockedInterruptible(CommandEntry* commandEntry);
-    void initializeKeyEvent(KeyEvent* event, const KeyEntry* entry);
-
-    // Statistics gathering.
-    void updateDispatchStatisticsLocked(nsecs_t currentTime, const EventEntry* entry,
-            int32_t injectionResult, nsecs_t timeSpentWaitingForApplication);
-    void traceInboundQueueLengthLocked();
-    void traceOutboundQueueLengthLocked(const sp<Connection>& connection);
-    void traceWaitQueueLengthLocked(const sp<Connection>& connection);
-};
-
-/* Enqueues and dispatches input events, endlessly. */
-class InputDispatcherThread : public Thread {
-public:
-    explicit InputDispatcherThread(const sp<InputDispatcherInterface>& dispatcher);
-    ~InputDispatcherThread();
-
-private:
-    virtual bool threadLoop();
-
-    sp<InputDispatcherInterface> mDispatcher;
-};
-
-} // namespace android
-
-#endif // _UI_INPUT_DISPATCHER_H
diff --git a/libs/input/InputListener.cpp b/libs/input/InputListener.cpp
deleted file mode 100644
index 85bb0ed..0000000
--- a/libs/input/InputListener.cpp
+++ /dev/null
@@ -1,182 +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.
- */
-
-#define LOG_TAG "InputListener"
-
-//#define LOG_NDEBUG 0
-
-#include "InputListener.h"
-
-#include <cutils/log.h>
-
-namespace android {
-
-// --- NotifyConfigurationChangedArgs ---
-
-NotifyConfigurationChangedArgs::NotifyConfigurationChangedArgs(nsecs_t eventTime) :
-        eventTime(eventTime) {
-}
-
-NotifyConfigurationChangedArgs::NotifyConfigurationChangedArgs(
-        const NotifyConfigurationChangedArgs& other) :
-        eventTime(other.eventTime) {
-}
-
-void NotifyConfigurationChangedArgs::notify(const sp<InputListenerInterface>& listener) const {
-    listener->notifyConfigurationChanged(this);
-}
-
-
-// --- NotifyKeyArgs ---
-
-NotifyKeyArgs::NotifyKeyArgs(nsecs_t eventTime, int32_t deviceId, uint32_t source,
-        uint32_t policyFlags,
-        int32_t action, int32_t flags, int32_t keyCode, int32_t scanCode,
-        int32_t metaState, nsecs_t downTime) :
-        eventTime(eventTime), deviceId(deviceId), source(source), policyFlags(policyFlags),
-        action(action), flags(flags), keyCode(keyCode), scanCode(scanCode),
-        metaState(metaState), downTime(downTime) {
-}
-
-NotifyKeyArgs::NotifyKeyArgs(const NotifyKeyArgs& other) :
-        eventTime(other.eventTime), deviceId(other.deviceId), source(other.source),
-        policyFlags(other.policyFlags),
-        action(other.action), flags(other.flags),
-        keyCode(other.keyCode), scanCode(other.scanCode),
-        metaState(other.metaState), downTime(other.downTime) {
-}
-
-void NotifyKeyArgs::notify(const sp<InputListenerInterface>& listener) const {
-    listener->notifyKey(this);
-}
-
-
-// --- NotifyMotionArgs ---
-
-NotifyMotionArgs::NotifyMotionArgs(nsecs_t eventTime, int32_t deviceId, uint32_t source,
-        uint32_t policyFlags,
-        int32_t action, int32_t flags, int32_t metaState, int32_t buttonState,
-        int32_t edgeFlags, int32_t displayId, uint32_t pointerCount,
-        const PointerProperties* pointerProperties, const PointerCoords* pointerCoords,
-        float xPrecision, float yPrecision, nsecs_t downTime) :
-        eventTime(eventTime), deviceId(deviceId), source(source), policyFlags(policyFlags),
-        action(action), flags(flags), metaState(metaState), buttonState(buttonState),
-        edgeFlags(edgeFlags), displayId(displayId), pointerCount(pointerCount),
-        xPrecision(xPrecision), yPrecision(yPrecision), downTime(downTime) {
-    for (uint32_t i = 0; i < pointerCount; i++) {
-        this->pointerProperties[i].copyFrom(pointerProperties[i]);
-        this->pointerCoords[i].copyFrom(pointerCoords[i]);
-    }
-}
-
-NotifyMotionArgs::NotifyMotionArgs(const NotifyMotionArgs& other) :
-        eventTime(other.eventTime), deviceId(other.deviceId), source(other.source),
-        policyFlags(other.policyFlags),
-        action(other.action), flags(other.flags),
-        metaState(other.metaState), buttonState(other.buttonState),
-        edgeFlags(other.edgeFlags), displayId(other.displayId),
-        pointerCount(other.pointerCount),
-        xPrecision(other.xPrecision), yPrecision(other.yPrecision), downTime(other.downTime) {
-    for (uint32_t i = 0; i < pointerCount; i++) {
-        pointerProperties[i].copyFrom(other.pointerProperties[i]);
-        pointerCoords[i].copyFrom(other.pointerCoords[i]);
-    }
-}
-
-void NotifyMotionArgs::notify(const sp<InputListenerInterface>& listener) const {
-    listener->notifyMotion(this);
-}
-
-
-// --- NotifySwitchArgs ---
-
-NotifySwitchArgs::NotifySwitchArgs(nsecs_t eventTime, uint32_t policyFlags,
-        uint32_t switchValues, uint32_t switchMask) :
-        eventTime(eventTime), policyFlags(policyFlags),
-        switchValues(switchValues), switchMask(switchMask) {
-}
-
-NotifySwitchArgs::NotifySwitchArgs(const NotifySwitchArgs& other) :
-        eventTime(other.eventTime), policyFlags(other.policyFlags),
-        switchValues(other.switchValues), switchMask(other.switchMask) {
-}
-
-void NotifySwitchArgs::notify(const sp<InputListenerInterface>& listener) const {
-    listener->notifySwitch(this);
-}
-
-
-// --- NotifyDeviceResetArgs ---
-
-NotifyDeviceResetArgs::NotifyDeviceResetArgs(nsecs_t eventTime, int32_t deviceId) :
-        eventTime(eventTime), deviceId(deviceId) {
-}
-
-NotifyDeviceResetArgs::NotifyDeviceResetArgs(const NotifyDeviceResetArgs& other) :
-        eventTime(other.eventTime), deviceId(other.deviceId) {
-}
-
-void NotifyDeviceResetArgs::notify(const sp<InputListenerInterface>& listener) const {
-    listener->notifyDeviceReset(this);
-}
-
-
-// --- QueuedInputListener ---
-
-QueuedInputListener::QueuedInputListener(const sp<InputListenerInterface>& innerListener) :
-        mInnerListener(innerListener) {
-}
-
-QueuedInputListener::~QueuedInputListener() {
-    size_t count = mArgsQueue.size();
-    for (size_t i = 0; i < count; i++) {
-        delete mArgsQueue[i];
-    }
-}
-
-void QueuedInputListener::notifyConfigurationChanged(
-        const NotifyConfigurationChangedArgs* args) {
-    mArgsQueue.push(new NotifyConfigurationChangedArgs(*args));
-}
-
-void QueuedInputListener::notifyKey(const NotifyKeyArgs* args) {
-    mArgsQueue.push(new NotifyKeyArgs(*args));
-}
-
-void QueuedInputListener::notifyMotion(const NotifyMotionArgs* args) {
-    mArgsQueue.push(new NotifyMotionArgs(*args));
-}
-
-void QueuedInputListener::notifySwitch(const NotifySwitchArgs* args) {
-    mArgsQueue.push(new NotifySwitchArgs(*args));
-}
-
-void QueuedInputListener::notifyDeviceReset(const NotifyDeviceResetArgs* args) {
-    mArgsQueue.push(new NotifyDeviceResetArgs(*args));
-}
-
-void QueuedInputListener::flush() {
-    size_t count = mArgsQueue.size();
-    for (size_t i = 0; i < count; i++) {
-        NotifyArgs* args = mArgsQueue[i];
-        args->notify(mInnerListener);
-        delete args;
-    }
-    mArgsQueue.clear();
-}
-
-
-} // namespace android
diff --git a/libs/input/InputListener.h b/libs/input/InputListener.h
deleted file mode 100644
index 78ae10f..0000000
--- a/libs/input/InputListener.h
+++ /dev/null
@@ -1,196 +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.
- */
-
-#ifndef _UI_INPUT_LISTENER_H
-#define _UI_INPUT_LISTENER_H
-
-#include <input/Input.h>
-#include <utils/RefBase.h>
-#include <utils/Vector.h>
-
-namespace android {
-
-class InputListenerInterface;
-
-
-/* Superclass of all input event argument objects */
-struct NotifyArgs {
-    virtual ~NotifyArgs() { }
-
-    virtual void notify(const sp<InputListenerInterface>& listener) const = 0;
-};
-
-
-/* Describes a configuration change event. */
-struct NotifyConfigurationChangedArgs : public NotifyArgs {
-    nsecs_t eventTime;
-
-    inline NotifyConfigurationChangedArgs() { }
-
-    NotifyConfigurationChangedArgs(nsecs_t eventTime);
-
-    NotifyConfigurationChangedArgs(const NotifyConfigurationChangedArgs& other);
-
-    virtual ~NotifyConfigurationChangedArgs() { }
-
-    virtual void notify(const sp<InputListenerInterface>& listener) const;
-};
-
-
-/* Describes a key event. */
-struct NotifyKeyArgs : public NotifyArgs {
-    nsecs_t eventTime;
-    int32_t deviceId;
-    uint32_t source;
-    uint32_t policyFlags;
-    int32_t action;
-    int32_t flags;
-    int32_t keyCode;
-    int32_t scanCode;
-    int32_t metaState;
-    nsecs_t downTime;
-
-    inline NotifyKeyArgs() { }
-
-    NotifyKeyArgs(nsecs_t eventTime, int32_t deviceId, uint32_t source, uint32_t policyFlags,
-            int32_t action, int32_t flags, int32_t keyCode, int32_t scanCode,
-            int32_t metaState, nsecs_t downTime);
-
-    NotifyKeyArgs(const NotifyKeyArgs& other);
-
-    virtual ~NotifyKeyArgs() { }
-
-    virtual void notify(const sp<InputListenerInterface>& listener) const;
-};
-
-
-/* Describes a motion event. */
-struct NotifyMotionArgs : public NotifyArgs {
-    nsecs_t eventTime;
-    int32_t deviceId;
-    uint32_t source;
-    uint32_t policyFlags;
-    int32_t action;
-    int32_t flags;
-    int32_t metaState;
-    int32_t buttonState;
-    int32_t edgeFlags;
-    int32_t displayId;
-    uint32_t pointerCount;
-    PointerProperties pointerProperties[MAX_POINTERS];
-    PointerCoords pointerCoords[MAX_POINTERS];
-    float xPrecision;
-    float yPrecision;
-    nsecs_t downTime;
-
-    inline NotifyMotionArgs() { }
-
-    NotifyMotionArgs(nsecs_t eventTime, int32_t deviceId, uint32_t source, uint32_t policyFlags,
-            int32_t action, int32_t flags, int32_t metaState, int32_t buttonState,
-            int32_t edgeFlags, int32_t displayId, uint32_t pointerCount,
-            const PointerProperties* pointerProperties, const PointerCoords* pointerCoords,
-            float xPrecision, float yPrecision, nsecs_t downTime);
-
-    NotifyMotionArgs(const NotifyMotionArgs& other);
-
-    virtual ~NotifyMotionArgs() { }
-
-    virtual void notify(const sp<InputListenerInterface>& listener) const;
-};
-
-
-/* Describes a switch event. */
-struct NotifySwitchArgs : public NotifyArgs {
-    nsecs_t eventTime;
-    uint32_t policyFlags;
-    uint32_t switchValues;
-    uint32_t switchMask;
-
-    inline NotifySwitchArgs() { }
-
-    NotifySwitchArgs(nsecs_t eventTime, uint32_t policyFlags,
-            uint32_t switchValues, uint32_t switchMask);
-
-    NotifySwitchArgs(const NotifySwitchArgs& other);
-
-    virtual ~NotifySwitchArgs() { }
-
-    virtual void notify(const sp<InputListenerInterface>& listener) const;
-};
-
-
-/* Describes a device reset event, such as when a device is added,
- * reconfigured, or removed. */
-struct NotifyDeviceResetArgs : public NotifyArgs {
-    nsecs_t eventTime;
-    int32_t deviceId;
-
-    inline NotifyDeviceResetArgs() { }
-
-    NotifyDeviceResetArgs(nsecs_t eventTime, int32_t deviceId);
-
-    NotifyDeviceResetArgs(const NotifyDeviceResetArgs& other);
-
-    virtual ~NotifyDeviceResetArgs() { }
-
-    virtual void notify(const sp<InputListenerInterface>& listener) const;
-};
-
-
-/*
- * The interface used by the InputReader to notify the InputListener about input events.
- */
-class InputListenerInterface : public virtual RefBase {
-protected:
-    InputListenerInterface() { }
-    virtual ~InputListenerInterface() { }
-
-public:
-    virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) = 0;
-    virtual void notifyKey(const NotifyKeyArgs* args) = 0;
-    virtual void notifyMotion(const NotifyMotionArgs* args) = 0;
-    virtual void notifySwitch(const NotifySwitchArgs* args) = 0;
-    virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args) = 0;
-};
-
-
-/*
- * An implementation of the listener interface that queues up and defers dispatch
- * of decoded events until flushed.
- */
-class QueuedInputListener : public InputListenerInterface {
-protected:
-    virtual ~QueuedInputListener();
-
-public:
-    QueuedInputListener(const sp<InputListenerInterface>& innerListener);
-
-    virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args);
-    virtual void notifyKey(const NotifyKeyArgs* args);
-    virtual void notifyMotion(const NotifyMotionArgs* args);
-    virtual void notifySwitch(const NotifySwitchArgs* args);
-    virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args);
-
-    void flush();
-
-private:
-    sp<InputListenerInterface> mInnerListener;
-    Vector<NotifyArgs*> mArgsQueue;
-};
-
-} // namespace android
-
-#endif // _UI_INPUT_LISTENER_H
diff --git a/libs/input/InputManager.cpp b/libs/input/InputManager.cpp
deleted file mode 100644
index 6a6547b..0000000
--- a/libs/input/InputManager.cpp
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 "InputManager"
-
-//#define LOG_NDEBUG 0
-
-#include "InputManager.h"
-
-#include <cutils/log.h>
-
-namespace android {
-
-InputManager::InputManager(
-        const sp<EventHubInterface>& eventHub,
-        const sp<InputReaderPolicyInterface>& readerPolicy,
-        const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
-    mDispatcher = new InputDispatcher(dispatcherPolicy);
-    mReader = new InputReader(eventHub, readerPolicy, mDispatcher);
-    initialize();
-}
-
-InputManager::InputManager(
-        const sp<InputReaderInterface>& reader,
-        const sp<InputDispatcherInterface>& dispatcher) :
-        mReader(reader),
-        mDispatcher(dispatcher) {
-    initialize();
-}
-
-InputManager::~InputManager() {
-    stop();
-}
-
-void InputManager::initialize() {
-    mReaderThread = new InputReaderThread(mReader);
-    mDispatcherThread = new InputDispatcherThread(mDispatcher);
-}
-
-status_t InputManager::start() {
-    status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);
-    if (result) {
-        ALOGE("Could not start InputDispatcher thread due to error %d.", result);
-        return result;
-    }
-
-    result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);
-    if (result) {
-        ALOGE("Could not start InputReader thread due to error %d.", result);
-
-        mDispatcherThread->requestExit();
-        return result;
-    }
-
-    return OK;
-}
-
-status_t InputManager::stop() {
-    status_t result = mReaderThread->requestExitAndWait();
-    if (result) {
-        ALOGW("Could not stop InputReader thread due to error %d.", result);
-    }
-
-    result = mDispatcherThread->requestExitAndWait();
-    if (result) {
-        ALOGW("Could not stop InputDispatcher thread due to error %d.", result);
-    }
-
-    return OK;
-}
-
-sp<InputReaderInterface> InputManager::getReader() {
-    return mReader;
-}
-
-sp<InputDispatcherInterface> InputManager::getDispatcher() {
-    return mDispatcher;
-}
-
-} // namespace android
diff --git a/libs/input/InputManager.h b/libs/input/InputManager.h
deleted file mode 100644
index a213b2d..0000000
--- a/libs/input/InputManager.h
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _UI_INPUT_MANAGER_H
-#define _UI_INPUT_MANAGER_H
-
-/**
- * Native input manager.
- */
-
-#include "EventHub.h"
-#include "InputReader.h"
-#include "InputDispatcher.h"
-
-#include <input/Input.h>
-#include <input/InputTransport.h>
-#include <utils/Errors.h>
-#include <utils/Vector.h>
-#include <utils/Timers.h>
-#include <utils/RefBase.h>
-#include <utils/String8.h>
-
-namespace android {
-
-/*
- * The input manager is the core of the system event processing.
- *
- * The input manager uses two threads.
- *
- * 1. The InputReaderThread (called "InputReader") reads and preprocesses raw input events,
- *    applies policy, and posts messages to a queue managed by the DispatcherThread.
- * 2. The InputDispatcherThread (called "InputDispatcher") thread waits for new events on the
- *    queue and asynchronously dispatches them to applications.
- *
- * By design, the InputReaderThread class and InputDispatcherThread class do not share any
- * internal state.  Moreover, all communication is done one way from the InputReaderThread
- * into the InputDispatcherThread and never the reverse.  Both classes may interact with the
- * InputDispatchPolicy, however.
- *
- * The InputManager class never makes any calls into Java itself.  Instead, the
- * InputDispatchPolicy is responsible for performing all external interactions with the
- * system, including calling DVM services.
- */
-class InputManagerInterface : public virtual RefBase {
-protected:
-    InputManagerInterface() { }
-    virtual ~InputManagerInterface() { }
-
-public:
-    /* Starts the input manager threads. */
-    virtual status_t start() = 0;
-
-    /* Stops the input manager threads and waits for them to exit. */
-    virtual status_t stop() = 0;
-
-    /* Gets the input reader. */
-    virtual sp<InputReaderInterface> getReader() = 0;
-
-    /* Gets the input dispatcher. */
-    virtual sp<InputDispatcherInterface> getDispatcher() = 0;
-};
-
-class InputManager : public InputManagerInterface {
-protected:
-    virtual ~InputManager();
-
-public:
-    InputManager(
-            const sp<EventHubInterface>& eventHub,
-            const sp<InputReaderPolicyInterface>& readerPolicy,
-            const sp<InputDispatcherPolicyInterface>& dispatcherPolicy);
-
-    // (used for testing purposes)
-    InputManager(
-            const sp<InputReaderInterface>& reader,
-            const sp<InputDispatcherInterface>& dispatcher);
-
-    virtual status_t start();
-    virtual status_t stop();
-
-    virtual sp<InputReaderInterface> getReader();
-    virtual sp<InputDispatcherInterface> getDispatcher();
-
-private:
-    sp<InputReaderInterface> mReader;
-    sp<InputReaderThread> mReaderThread;
-
-    sp<InputDispatcherInterface> mDispatcher;
-    sp<InputDispatcherThread> mDispatcherThread;
-
-    void initialize();
-};
-
-} // namespace android
-
-#endif // _UI_INPUT_MANAGER_H
diff --git a/libs/input/InputReader.cpp b/libs/input/InputReader.cpp
deleted file mode 100644
index 94e2a80..0000000
--- a/libs/input/InputReader.cpp
+++ /dev/null
@@ -1,6530 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 "InputReader"
-
-//#define LOG_NDEBUG 0
-
-// Log debug messages for each raw event received from the EventHub.
-#define DEBUG_RAW_EVENTS 0
-
-// Log debug messages about touch screen filtering hacks.
-#define DEBUG_HACKS 0
-
-// Log debug messages about virtual key processing.
-#define DEBUG_VIRTUAL_KEYS 0
-
-// Log debug messages about pointers.
-#define DEBUG_POINTERS 0
-
-// Log debug messages about pointer assignment calculations.
-#define DEBUG_POINTER_ASSIGNMENT 0
-
-// Log debug messages about gesture detection.
-#define DEBUG_GESTURES 0
-
-// Log debug messages about the vibrator.
-#define DEBUG_VIBRATOR 0
-
-#include "InputReader.h"
-
-#include <cutils/log.h>
-#include <input/Keyboard.h>
-#include <input/VirtualKeyMap.h>
-
-#include <stddef.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <errno.h>
-#include <limits.h>
-#include <math.h>
-
-#define INDENT "  "
-#define INDENT2 "    "
-#define INDENT3 "      "
-#define INDENT4 "        "
-#define INDENT5 "          "
-
-namespace android {
-
-// --- Constants ---
-
-// Maximum number of slots supported when using the slot-based Multitouch Protocol B.
-static const size_t MAX_SLOTS = 32;
-
-// --- Static Functions ---
-
-template<typename T>
-inline static T abs(const T& value) {
-    return value < 0 ? - value : value;
-}
-
-template<typename T>
-inline static T min(const T& a, const T& b) {
-    return a < b ? a : b;
-}
-
-template<typename T>
-inline static void swap(T& a, T& b) {
-    T temp = a;
-    a = b;
-    b = temp;
-}
-
-inline static float avg(float x, float y) {
-    return (x + y) / 2;
-}
-
-inline static float distance(float x1, float y1, float x2, float y2) {
-    return hypotf(x1 - x2, y1 - y2);
-}
-
-inline static int32_t signExtendNybble(int32_t value) {
-    return value >= 8 ? value - 16 : value;
-}
-
-static inline const char* toString(bool value) {
-    return value ? "true" : "false";
-}
-
-static int32_t rotateValueUsingRotationMap(int32_t value, int32_t orientation,
-        const int32_t map[][4], size_t mapSize) {
-    if (orientation != DISPLAY_ORIENTATION_0) {
-        for (size_t i = 0; i < mapSize; i++) {
-            if (value == map[i][0]) {
-                return map[i][orientation];
-            }
-        }
-    }
-    return value;
-}
-
-static const int32_t keyCodeRotationMap[][4] = {
-        // key codes enumerated counter-clockwise with the original (unrotated) key first
-        // no rotation,        90 degree rotation,  180 degree rotation, 270 degree rotation
-        { AKEYCODE_DPAD_DOWN,   AKEYCODE_DPAD_RIGHT,  AKEYCODE_DPAD_UP,     AKEYCODE_DPAD_LEFT },
-        { AKEYCODE_DPAD_RIGHT,  AKEYCODE_DPAD_UP,     AKEYCODE_DPAD_LEFT,   AKEYCODE_DPAD_DOWN },
-        { AKEYCODE_DPAD_UP,     AKEYCODE_DPAD_LEFT,   AKEYCODE_DPAD_DOWN,   AKEYCODE_DPAD_RIGHT },
-        { AKEYCODE_DPAD_LEFT,   AKEYCODE_DPAD_DOWN,   AKEYCODE_DPAD_RIGHT,  AKEYCODE_DPAD_UP },
-};
-static const size_t keyCodeRotationMapSize =
-        sizeof(keyCodeRotationMap) / sizeof(keyCodeRotationMap[0]);
-
-static int32_t rotateKeyCode(int32_t keyCode, int32_t orientation) {
-    return rotateValueUsingRotationMap(keyCode, orientation,
-            keyCodeRotationMap, keyCodeRotationMapSize);
-}
-
-static void rotateDelta(int32_t orientation, float* deltaX, float* deltaY) {
-    float temp;
-    switch (orientation) {
-    case DISPLAY_ORIENTATION_90:
-        temp = *deltaX;
-        *deltaX = *deltaY;
-        *deltaY = -temp;
-        break;
-
-    case DISPLAY_ORIENTATION_180:
-        *deltaX = -*deltaX;
-        *deltaY = -*deltaY;
-        break;
-
-    case DISPLAY_ORIENTATION_270:
-        temp = *deltaX;
-        *deltaX = -*deltaY;
-        *deltaY = temp;
-        break;
-    }
-}
-
-static inline bool sourcesMatchMask(uint32_t sources, uint32_t sourceMask) {
-    return (sources & sourceMask & ~ AINPUT_SOURCE_CLASS_MASK) != 0;
-}
-
-// Returns true if the pointer should be reported as being down given the specified
-// button states.  This determines whether the event is reported as a touch event.
-static bool isPointerDown(int32_t buttonState) {
-    return buttonState &
-            (AMOTION_EVENT_BUTTON_PRIMARY | AMOTION_EVENT_BUTTON_SECONDARY
-                    | AMOTION_EVENT_BUTTON_TERTIARY);
-}
-
-static float calculateCommonVector(float a, float b) {
-    if (a > 0 && b > 0) {
-        return a < b ? a : b;
-    } else if (a < 0 && b < 0) {
-        return a > b ? a : b;
-    } else {
-        return 0;
-    }
-}
-
-static void synthesizeButtonKey(InputReaderContext* context, int32_t action,
-        nsecs_t when, int32_t deviceId, uint32_t source,
-        uint32_t policyFlags, int32_t lastButtonState, int32_t currentButtonState,
-        int32_t buttonState, int32_t keyCode) {
-    if (
-            (action == AKEY_EVENT_ACTION_DOWN
-                    && !(lastButtonState & buttonState)
-                    && (currentButtonState & buttonState))
-            || (action == AKEY_EVENT_ACTION_UP
-                    && (lastButtonState & buttonState)
-                    && !(currentButtonState & buttonState))) {
-        NotifyKeyArgs args(when, deviceId, source, policyFlags,
-                action, 0, keyCode, 0, context->getGlobalMetaState(), when);
-        context->getListener()->notifyKey(&args);
-    }
-}
-
-static void synthesizeButtonKeys(InputReaderContext* context, int32_t action,
-        nsecs_t when, int32_t deviceId, uint32_t source,
-        uint32_t policyFlags, int32_t lastButtonState, int32_t currentButtonState) {
-    synthesizeButtonKey(context, action, when, deviceId, source, policyFlags,
-            lastButtonState, currentButtonState,
-            AMOTION_EVENT_BUTTON_BACK, AKEYCODE_BACK);
-    synthesizeButtonKey(context, action, when, deviceId, source, policyFlags,
-            lastButtonState, currentButtonState,
-            AMOTION_EVENT_BUTTON_FORWARD, AKEYCODE_FORWARD);
-}
-
-
-// --- InputReaderConfiguration ---
-
-bool InputReaderConfiguration::getDisplayInfo(bool external, DisplayViewport* outViewport) const {
-    const DisplayViewport& viewport = external ? mExternalDisplay : mInternalDisplay;
-    if (viewport.displayId >= 0) {
-        *outViewport = viewport;
-        return true;
-    }
-    return false;
-}
-
-void InputReaderConfiguration::setDisplayInfo(bool external, const DisplayViewport& viewport) {
-    DisplayViewport& v = external ? mExternalDisplay : mInternalDisplay;
-    v = viewport;
-}
-
-
-// --- InputReader ---
-
-InputReader::InputReader(const sp<EventHubInterface>& eventHub,
-        const sp<InputReaderPolicyInterface>& policy,
-        const sp<InputListenerInterface>& listener) :
-        mContext(this), mEventHub(eventHub), mPolicy(policy),
-        mGlobalMetaState(0), mGeneration(1),
-        mDisableVirtualKeysTimeout(LLONG_MIN), mNextTimeout(LLONG_MAX),
-        mConfigurationChangesToRefresh(0) {
-    mQueuedListener = new QueuedInputListener(listener);
-
-    { // acquire lock
-        AutoMutex _l(mLock);
-
-        refreshConfigurationLocked(0);
-        updateGlobalMetaStateLocked();
-    } // release lock
-}
-
-InputReader::~InputReader() {
-    for (size_t i = 0; i < mDevices.size(); i++) {
-        delete mDevices.valueAt(i);
-    }
-}
-
-void InputReader::loopOnce() {
-    int32_t oldGeneration;
-    int32_t timeoutMillis;
-    bool inputDevicesChanged = false;
-    Vector<InputDeviceInfo> inputDevices;
-    { // acquire lock
-        AutoMutex _l(mLock);
-
-        oldGeneration = mGeneration;
-        timeoutMillis = -1;
-
-        uint32_t changes = mConfigurationChangesToRefresh;
-        if (changes) {
-            mConfigurationChangesToRefresh = 0;
-            timeoutMillis = 0;
-            refreshConfigurationLocked(changes);
-        } else if (mNextTimeout != LLONG_MAX) {
-            nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
-            timeoutMillis = toMillisecondTimeoutDelay(now, mNextTimeout);
-        }
-    } // release lock
-
-    size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
-
-    { // acquire lock
-        AutoMutex _l(mLock);
-        mReaderIsAliveCondition.broadcast();
-
-        if (count) {
-            processEventsLocked(mEventBuffer, count);
-        }
-
-        if (mNextTimeout != LLONG_MAX) {
-            nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
-            if (now >= mNextTimeout) {
-#if DEBUG_RAW_EVENTS
-                ALOGD("Timeout expired, latency=%0.3fms", (now - mNextTimeout) * 0.000001f);
-#endif
-                mNextTimeout = LLONG_MAX;
-                timeoutExpiredLocked(now);
-            }
-        }
-
-        if (oldGeneration != mGeneration) {
-            inputDevicesChanged = true;
-            getInputDevicesLocked(inputDevices);
-        }
-    } // release lock
-
-    // Send out a message that the describes the changed input devices.
-    if (inputDevicesChanged) {
-        mPolicy->notifyInputDevicesChanged(inputDevices);
-    }
-
-    // Flush queued events out to the listener.
-    // This must happen outside of the lock because the listener could potentially call
-    // back into the InputReader's methods, such as getScanCodeState, or become blocked
-    // on another thread similarly waiting to acquire the InputReader lock thereby
-    // resulting in a deadlock.  This situation is actually quite plausible because the
-    // listener is actually the input dispatcher, which calls into the window manager,
-    // which occasionally calls into the input reader.
-    mQueuedListener->flush();
-}
-
-void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) {
-    for (const RawEvent* rawEvent = rawEvents; count;) {
-        int32_t type = rawEvent->type;
-        size_t batchSize = 1;
-        if (type < EventHubInterface::FIRST_SYNTHETIC_EVENT) {
-            int32_t deviceId = rawEvent->deviceId;
-            while (batchSize < count) {
-                if (rawEvent[batchSize].type >= EventHubInterface::FIRST_SYNTHETIC_EVENT
-                        || rawEvent[batchSize].deviceId != deviceId) {
-                    break;
-                }
-                batchSize += 1;
-            }
-#if DEBUG_RAW_EVENTS
-            ALOGD("BatchSize: %d Count: %d", batchSize, count);
-#endif
-            processEventsForDeviceLocked(deviceId, rawEvent, batchSize);
-        } else {
-            switch (rawEvent->type) {
-            case EventHubInterface::DEVICE_ADDED:
-                addDeviceLocked(rawEvent->when, rawEvent->deviceId);
-                break;
-            case EventHubInterface::DEVICE_REMOVED:
-                removeDeviceLocked(rawEvent->when, rawEvent->deviceId);
-                break;
-            case EventHubInterface::FINISHED_DEVICE_SCAN:
-                handleConfigurationChangedLocked(rawEvent->when);
-                break;
-            default:
-                ALOG_ASSERT(false); // can't happen
-                break;
-            }
-        }
-        count -= batchSize;
-        rawEvent += batchSize;
-    }
-}
-
-void InputReader::addDeviceLocked(nsecs_t when, int32_t deviceId) {
-    ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
-    if (deviceIndex >= 0) {
-        ALOGW("Ignoring spurious device added event for deviceId %d.", deviceId);
-        return;
-    }
-
-    InputDeviceIdentifier identifier = mEventHub->getDeviceIdentifier(deviceId);
-    uint32_t classes = mEventHub->getDeviceClasses(deviceId);
-    int32_t controllerNumber = mEventHub->getDeviceControllerNumber(deviceId);
-
-    InputDevice* device = createDeviceLocked(deviceId, controllerNumber, identifier, classes);
-    device->configure(when, &mConfig, 0);
-    device->reset(when);
-
-    if (device->isIgnored()) {
-        ALOGI("Device added: id=%d, name='%s' (ignored non-input device)", deviceId,
-                identifier.name.string());
-    } else {
-        ALOGI("Device added: id=%d, name='%s', sources=0x%08x", deviceId,
-                identifier.name.string(), device->getSources());
-    }
-
-    mDevices.add(deviceId, device);
-    bumpGenerationLocked();
-}
-
-void InputReader::removeDeviceLocked(nsecs_t when, int32_t deviceId) {
-    InputDevice* device = NULL;
-    ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
-    if (deviceIndex < 0) {
-        ALOGW("Ignoring spurious device removed event for deviceId %d.", deviceId);
-        return;
-    }
-
-    device = mDevices.valueAt(deviceIndex);
-    mDevices.removeItemsAt(deviceIndex, 1);
-    bumpGenerationLocked();
-
-    if (device->isIgnored()) {
-        ALOGI("Device removed: id=%d, name='%s' (ignored non-input device)",
-                device->getId(), device->getName().string());
-    } else {
-        ALOGI("Device removed: id=%d, name='%s', sources=0x%08x",
-                device->getId(), device->getName().string(), device->getSources());
-    }
-
-    device->reset(when);
-    delete device;
-}
-
-InputDevice* InputReader::createDeviceLocked(int32_t deviceId, int32_t controllerNumber,
-        const InputDeviceIdentifier& identifier, uint32_t classes) {
-    InputDevice* device = new InputDevice(&mContext, deviceId, bumpGenerationLocked(),
-            controllerNumber, identifier, classes);
-
-    // External devices.
-    if (classes & INPUT_DEVICE_CLASS_EXTERNAL) {
-        device->setExternal(true);
-    }
-
-    // Switch-like devices.
-    if (classes & INPUT_DEVICE_CLASS_SWITCH) {
-        device->addMapper(new SwitchInputMapper(device));
-    }
-
-    // Vibrator-like devices.
-    if (classes & INPUT_DEVICE_CLASS_VIBRATOR) {
-        device->addMapper(new VibratorInputMapper(device));
-    }
-
-    // Keyboard-like devices.
-    uint32_t keyboardSource = 0;
-    int32_t keyboardType = AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC;
-    if (classes & INPUT_DEVICE_CLASS_KEYBOARD) {
-        keyboardSource |= AINPUT_SOURCE_KEYBOARD;
-    }
-    if (classes & INPUT_DEVICE_CLASS_ALPHAKEY) {
-        keyboardType = AINPUT_KEYBOARD_TYPE_ALPHABETIC;
-    }
-    if (classes & INPUT_DEVICE_CLASS_DPAD) {
-        keyboardSource |= AINPUT_SOURCE_DPAD;
-    }
-    if (classes & INPUT_DEVICE_CLASS_GAMEPAD) {
-        keyboardSource |= AINPUT_SOURCE_GAMEPAD;
-    }
-
-    if (keyboardSource != 0) {
-        device->addMapper(new KeyboardInputMapper(device, keyboardSource, keyboardType));
-    }
-
-    // Cursor-like devices.
-    if (classes & INPUT_DEVICE_CLASS_CURSOR) {
-        device->addMapper(new CursorInputMapper(device));
-    }
-
-    // Touchscreens and touchpad devices.
-    if (classes & INPUT_DEVICE_CLASS_TOUCH_MT) {
-        device->addMapper(new MultiTouchInputMapper(device));
-    } else if (classes & INPUT_DEVICE_CLASS_TOUCH) {
-        device->addMapper(new SingleTouchInputMapper(device));
-    }
-
-    // Joystick-like devices.
-    if (classes & INPUT_DEVICE_CLASS_JOYSTICK) {
-        device->addMapper(new JoystickInputMapper(device));
-    }
-
-    return device;
-}
-
-void InputReader::processEventsForDeviceLocked(int32_t deviceId,
-        const RawEvent* rawEvents, size_t count) {
-    ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
-    if (deviceIndex < 0) {
-        ALOGW("Discarding event for unknown deviceId %d.", deviceId);
-        return;
-    }
-
-    InputDevice* device = mDevices.valueAt(deviceIndex);
-    if (device->isIgnored()) {
-        //ALOGD("Discarding event for ignored deviceId %d.", deviceId);
-        return;
-    }
-
-    device->process(rawEvents, count);
-}
-
-void InputReader::timeoutExpiredLocked(nsecs_t when) {
-    for (size_t i = 0; i < mDevices.size(); i++) {
-        InputDevice* device = mDevices.valueAt(i);
-        if (!device->isIgnored()) {
-            device->timeoutExpired(when);
-        }
-    }
-}
-
-void InputReader::handleConfigurationChangedLocked(nsecs_t when) {
-    // Reset global meta state because it depends on the list of all configured devices.
-    updateGlobalMetaStateLocked();
-
-    // Enqueue configuration changed.
-    NotifyConfigurationChangedArgs args(when);
-    mQueuedListener->notifyConfigurationChanged(&args);
-}
-
-void InputReader::refreshConfigurationLocked(uint32_t changes) {
-    mPolicy->getReaderConfiguration(&mConfig);
-    mEventHub->setExcludedDevices(mConfig.excludedDeviceNames);
-
-    if (changes) {
-        ALOGI("Reconfiguring input devices.  changes=0x%08x", changes);
-        nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
-
-        if (changes & InputReaderConfiguration::CHANGE_MUST_REOPEN) {
-            mEventHub->requestReopenDevices();
-        } else {
-            for (size_t i = 0; i < mDevices.size(); i++) {
-                InputDevice* device = mDevices.valueAt(i);
-                device->configure(now, &mConfig, changes);
-            }
-        }
-    }
-}
-
-void InputReader::updateGlobalMetaStateLocked() {
-    mGlobalMetaState = 0;
-
-    for (size_t i = 0; i < mDevices.size(); i++) {
-        InputDevice* device = mDevices.valueAt(i);
-        mGlobalMetaState |= device->getMetaState();
-    }
-}
-
-int32_t InputReader::getGlobalMetaStateLocked() {
-    return mGlobalMetaState;
-}
-
-void InputReader::disableVirtualKeysUntilLocked(nsecs_t time) {
-    mDisableVirtualKeysTimeout = time;
-}
-
-bool InputReader::shouldDropVirtualKeyLocked(nsecs_t now,
-        InputDevice* device, int32_t keyCode, int32_t scanCode) {
-    if (now < mDisableVirtualKeysTimeout) {
-        ALOGI("Dropping virtual key from device %s because virtual keys are "
-                "temporarily disabled for the next %0.3fms.  keyCode=%d, scanCode=%d",
-                device->getName().string(),
-                (mDisableVirtualKeysTimeout - now) * 0.000001,
-                keyCode, scanCode);
-        return true;
-    } else {
-        return false;
-    }
-}
-
-void InputReader::fadePointerLocked() {
-    for (size_t i = 0; i < mDevices.size(); i++) {
-        InputDevice* device = mDevices.valueAt(i);
-        device->fadePointer();
-    }
-}
-
-void InputReader::requestTimeoutAtTimeLocked(nsecs_t when) {
-    if (when < mNextTimeout) {
-        mNextTimeout = when;
-        mEventHub->wake();
-    }
-}
-
-int32_t InputReader::bumpGenerationLocked() {
-    return ++mGeneration;
-}
-
-void InputReader::getInputDevices(Vector<InputDeviceInfo>& outInputDevices) {
-    AutoMutex _l(mLock);
-    getInputDevicesLocked(outInputDevices);
-}
-
-void InputReader::getInputDevicesLocked(Vector<InputDeviceInfo>& outInputDevices) {
-    outInputDevices.clear();
-
-    size_t numDevices = mDevices.size();
-    for (size_t i = 0; i < numDevices; i++) {
-        InputDevice* device = mDevices.valueAt(i);
-        if (!device->isIgnored()) {
-            outInputDevices.push();
-            device->getDeviceInfo(&outInputDevices.editTop());
-        }
-    }
-}
-
-int32_t InputReader::getKeyCodeState(int32_t deviceId, uint32_t sourceMask,
-        int32_t keyCode) {
-    AutoMutex _l(mLock);
-
-    return getStateLocked(deviceId, sourceMask, keyCode, &InputDevice::getKeyCodeState);
-}
-
-int32_t InputReader::getScanCodeState(int32_t deviceId, uint32_t sourceMask,
-        int32_t scanCode) {
-    AutoMutex _l(mLock);
-
-    return getStateLocked(deviceId, sourceMask, scanCode, &InputDevice::getScanCodeState);
-}
-
-int32_t InputReader::getSwitchState(int32_t deviceId, uint32_t sourceMask, int32_t switchCode) {
-    AutoMutex _l(mLock);
-
-    return getStateLocked(deviceId, sourceMask, switchCode, &InputDevice::getSwitchState);
-}
-
-int32_t InputReader::getStateLocked(int32_t deviceId, uint32_t sourceMask, int32_t code,
-        GetStateFunc getStateFunc) {
-    int32_t result = AKEY_STATE_UNKNOWN;
-    if (deviceId >= 0) {
-        ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
-        if (deviceIndex >= 0) {
-            InputDevice* device = mDevices.valueAt(deviceIndex);
-            if (! device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) {
-                result = (device->*getStateFunc)(sourceMask, code);
-            }
-        }
-    } else {
-        size_t numDevices = mDevices.size();
-        for (size_t i = 0; i < numDevices; i++) {
-            InputDevice* device = mDevices.valueAt(i);
-            if (! device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) {
-                // If any device reports AKEY_STATE_DOWN or AKEY_STATE_VIRTUAL, return that
-                // value.  Otherwise, return AKEY_STATE_UP as long as one device reports it.
-                int32_t currentResult = (device->*getStateFunc)(sourceMask, code);
-                if (currentResult >= AKEY_STATE_DOWN) {
-                    return currentResult;
-                } else if (currentResult == AKEY_STATE_UP) {
-                    result = currentResult;
-                }
-            }
-        }
-    }
-    return result;
-}
-
-bool InputReader::hasKeys(int32_t deviceId, uint32_t sourceMask,
-        size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) {
-    AutoMutex _l(mLock);
-
-    memset(outFlags, 0, numCodes);
-    return markSupportedKeyCodesLocked(deviceId, sourceMask, numCodes, keyCodes, outFlags);
-}
-
-bool InputReader::markSupportedKeyCodesLocked(int32_t deviceId, uint32_t sourceMask,
-        size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) {
-    bool result = false;
-    if (deviceId >= 0) {
-        ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
-        if (deviceIndex >= 0) {
-            InputDevice* device = mDevices.valueAt(deviceIndex);
-            if (! device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) {
-                result = device->markSupportedKeyCodes(sourceMask,
-                        numCodes, keyCodes, outFlags);
-            }
-        }
-    } else {
-        size_t numDevices = mDevices.size();
-        for (size_t i = 0; i < numDevices; i++) {
-            InputDevice* device = mDevices.valueAt(i);
-            if (! device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) {
-                result |= device->markSupportedKeyCodes(sourceMask,
-                        numCodes, keyCodes, outFlags);
-            }
-        }
-    }
-    return result;
-}
-
-void InputReader::requestRefreshConfiguration(uint32_t changes) {
-    AutoMutex _l(mLock);
-
-    if (changes) {
-        bool needWake = !mConfigurationChangesToRefresh;
-        mConfigurationChangesToRefresh |= changes;
-
-        if (needWake) {
-            mEventHub->wake();
-        }
-    }
-}
-
-void InputReader::vibrate(int32_t deviceId, const nsecs_t* pattern, size_t patternSize,
-        ssize_t repeat, int32_t token) {
-    AutoMutex _l(mLock);
-
-    ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
-    if (deviceIndex >= 0) {
-        InputDevice* device = mDevices.valueAt(deviceIndex);
-        device->vibrate(pattern, patternSize, repeat, token);
-    }
-}
-
-void InputReader::cancelVibrate(int32_t deviceId, int32_t token) {
-    AutoMutex _l(mLock);
-
-    ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
-    if (deviceIndex >= 0) {
-        InputDevice* device = mDevices.valueAt(deviceIndex);
-        device->cancelVibrate(token);
-    }
-}
-
-void InputReader::dump(String8& dump) {
-    AutoMutex _l(mLock);
-
-    mEventHub->dump(dump);
-    dump.append("\n");
-
-    dump.append("Input Reader State:\n");
-
-    for (size_t i = 0; i < mDevices.size(); i++) {
-        mDevices.valueAt(i)->dump(dump);
-    }
-
-    dump.append(INDENT "Configuration:\n");
-    dump.append(INDENT2 "ExcludedDeviceNames: [");
-    for (size_t i = 0; i < mConfig.excludedDeviceNames.size(); i++) {
-        if (i != 0) {
-            dump.append(", ");
-        }
-        dump.append(mConfig.excludedDeviceNames.itemAt(i).string());
-    }
-    dump.append("]\n");
-    dump.appendFormat(INDENT2 "VirtualKeyQuietTime: %0.1fms\n",
-            mConfig.virtualKeyQuietTime * 0.000001f);
-
-    dump.appendFormat(INDENT2 "PointerVelocityControlParameters: "
-            "scale=%0.3f, lowThreshold=%0.3f, highThreshold=%0.3f, acceleration=%0.3f\n",
-            mConfig.pointerVelocityControlParameters.scale,
-            mConfig.pointerVelocityControlParameters.lowThreshold,
-            mConfig.pointerVelocityControlParameters.highThreshold,
-            mConfig.pointerVelocityControlParameters.acceleration);
-
-    dump.appendFormat(INDENT2 "WheelVelocityControlParameters: "
-            "scale=%0.3f, lowThreshold=%0.3f, highThreshold=%0.3f, acceleration=%0.3f\n",
-            mConfig.wheelVelocityControlParameters.scale,
-            mConfig.wheelVelocityControlParameters.lowThreshold,
-            mConfig.wheelVelocityControlParameters.highThreshold,
-            mConfig.wheelVelocityControlParameters.acceleration);
-
-    dump.appendFormat(INDENT2 "PointerGesture:\n");
-    dump.appendFormat(INDENT3 "Enabled: %s\n",
-            toString(mConfig.pointerGesturesEnabled));
-    dump.appendFormat(INDENT3 "QuietInterval: %0.1fms\n",
-            mConfig.pointerGestureQuietInterval * 0.000001f);
-    dump.appendFormat(INDENT3 "DragMinSwitchSpeed: %0.1fpx/s\n",
-            mConfig.pointerGestureDragMinSwitchSpeed);
-    dump.appendFormat(INDENT3 "TapInterval: %0.1fms\n",
-            mConfig.pointerGestureTapInterval * 0.000001f);
-    dump.appendFormat(INDENT3 "TapDragInterval: %0.1fms\n",
-            mConfig.pointerGestureTapDragInterval * 0.000001f);
-    dump.appendFormat(INDENT3 "TapSlop: %0.1fpx\n",
-            mConfig.pointerGestureTapSlop);
-    dump.appendFormat(INDENT3 "MultitouchSettleInterval: %0.1fms\n",
-            mConfig.pointerGestureMultitouchSettleInterval * 0.000001f);
-    dump.appendFormat(INDENT3 "MultitouchMinDistance: %0.1fpx\n",
-            mConfig.pointerGestureMultitouchMinDistance);
-    dump.appendFormat(INDENT3 "SwipeTransitionAngleCosine: %0.1f\n",
-            mConfig.pointerGestureSwipeTransitionAngleCosine);
-    dump.appendFormat(INDENT3 "SwipeMaxWidthRatio: %0.1f\n",
-            mConfig.pointerGestureSwipeMaxWidthRatio);
-    dump.appendFormat(INDENT3 "MovementSpeedRatio: %0.1f\n",
-            mConfig.pointerGestureMovementSpeedRatio);
-    dump.appendFormat(INDENT3 "ZoomSpeedRatio: %0.1f\n",
-            mConfig.pointerGestureZoomSpeedRatio);
-}
-
-void InputReader::monitor() {
-    // Acquire and release the lock to ensure that the reader has not deadlocked.
-    mLock.lock();
-    mEventHub->wake();
-    mReaderIsAliveCondition.wait(mLock);
-    mLock.unlock();
-
-    // Check the EventHub
-    mEventHub->monitor();
-}
-
-
-// --- InputReader::ContextImpl ---
-
-InputReader::ContextImpl::ContextImpl(InputReader* reader) :
-        mReader(reader) {
-}
-
-void InputReader::ContextImpl::updateGlobalMetaState() {
-    // lock is already held by the input loop
-    mReader->updateGlobalMetaStateLocked();
-}
-
-int32_t InputReader::ContextImpl::getGlobalMetaState() {
-    // lock is already held by the input loop
-    return mReader->getGlobalMetaStateLocked();
-}
-
-void InputReader::ContextImpl::disableVirtualKeysUntil(nsecs_t time) {
-    // lock is already held by the input loop
-    mReader->disableVirtualKeysUntilLocked(time);
-}
-
-bool InputReader::ContextImpl::shouldDropVirtualKey(nsecs_t now,
-        InputDevice* device, int32_t keyCode, int32_t scanCode) {
-    // lock is already held by the input loop
-    return mReader->shouldDropVirtualKeyLocked(now, device, keyCode, scanCode);
-}
-
-void InputReader::ContextImpl::fadePointer() {
-    // lock is already held by the input loop
-    mReader->fadePointerLocked();
-}
-
-void InputReader::ContextImpl::requestTimeoutAtTime(nsecs_t when) {
-    // lock is already held by the input loop
-    mReader->requestTimeoutAtTimeLocked(when);
-}
-
-int32_t InputReader::ContextImpl::bumpGeneration() {
-    // lock is already held by the input loop
-    return mReader->bumpGenerationLocked();
-}
-
-InputReaderPolicyInterface* InputReader::ContextImpl::getPolicy() {
-    return mReader->mPolicy.get();
-}
-
-InputListenerInterface* InputReader::ContextImpl::getListener() {
-    return mReader->mQueuedListener.get();
-}
-
-EventHubInterface* InputReader::ContextImpl::getEventHub() {
-    return mReader->mEventHub.get();
-}
-
-
-// --- InputReaderThread ---
-
-InputReaderThread::InputReaderThread(const sp<InputReaderInterface>& reader) :
-        Thread(/*canCallJava*/ true), mReader(reader) {
-}
-
-InputReaderThread::~InputReaderThread() {
-}
-
-bool InputReaderThread::threadLoop() {
-    mReader->loopOnce();
-    return true;
-}
-
-
-// --- InputDevice ---
-
-InputDevice::InputDevice(InputReaderContext* context, int32_t id, int32_t generation,
-        int32_t controllerNumber, const InputDeviceIdentifier& identifier, uint32_t classes) :
-        mContext(context), mId(id), mGeneration(generation), mControllerNumber(controllerNumber),
-        mIdentifier(identifier), mClasses(classes),
-        mSources(0), mIsExternal(false), mDropUntilNextSync(false) {
-}
-
-InputDevice::~InputDevice() {
-    size_t numMappers = mMappers.size();
-    for (size_t i = 0; i < numMappers; i++) {
-        delete mMappers[i];
-    }
-    mMappers.clear();
-}
-
-void InputDevice::dump(String8& dump) {
-    InputDeviceInfo deviceInfo;
-    getDeviceInfo(& deviceInfo);
-
-    dump.appendFormat(INDENT "Device %d: %s\n", deviceInfo.getId(),
-            deviceInfo.getDisplayName().string());
-    dump.appendFormat(INDENT2 "Generation: %d\n", mGeneration);
-    dump.appendFormat(INDENT2 "IsExternal: %s\n", toString(mIsExternal));
-    dump.appendFormat(INDENT2 "Sources: 0x%08x\n", deviceInfo.getSources());
-    dump.appendFormat(INDENT2 "KeyboardType: %d\n", deviceInfo.getKeyboardType());
-
-    const Vector<InputDeviceInfo::MotionRange>& ranges = deviceInfo.getMotionRanges();
-    if (!ranges.isEmpty()) {
-        dump.append(INDENT2 "Motion Ranges:\n");
-        for (size_t i = 0; i < ranges.size(); i++) {
-            const InputDeviceInfo::MotionRange& range = ranges.itemAt(i);
-            const char* label = getAxisLabel(range.axis);
-            char name[32];
-            if (label) {
-                strncpy(name, label, sizeof(name));
-                name[sizeof(name) - 1] = '\0';
-            } else {
-                snprintf(name, sizeof(name), "%d", range.axis);
-            }
-            dump.appendFormat(INDENT3 "%s: source=0x%08x, "
-                    "min=%0.3f, max=%0.3f, flat=%0.3f, fuzz=%0.3f, resolution=%0.3f\n",
-                    name, range.source, range.min, range.max, range.flat, range.fuzz,
-                    range.resolution);
-        }
-    }
-
-    size_t numMappers = mMappers.size();
-    for (size_t i = 0; i < numMappers; i++) {
-        InputMapper* mapper = mMappers[i];
-        mapper->dump(dump);
-    }
-}
-
-void InputDevice::addMapper(InputMapper* mapper) {
-    mMappers.add(mapper);
-}
-
-void InputDevice::configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes) {
-    mSources = 0;
-
-    if (!isIgnored()) {
-        if (!changes) { // first time only
-            mContext->getEventHub()->getConfiguration(mId, &mConfiguration);
-        }
-
-        if (!changes || (changes & InputReaderConfiguration::CHANGE_KEYBOARD_LAYOUTS)) {
-            if (!(mClasses & INPUT_DEVICE_CLASS_VIRTUAL)) {
-                sp<KeyCharacterMap> keyboardLayout =
-                        mContext->getPolicy()->getKeyboardLayoutOverlay(mIdentifier);
-                if (mContext->getEventHub()->setKeyboardLayoutOverlay(mId, keyboardLayout)) {
-                    bumpGeneration();
-                }
-            }
-        }
-
-        if (!changes || (changes & InputReaderConfiguration::CHANGE_DEVICE_ALIAS)) {
-            if (!(mClasses & INPUT_DEVICE_CLASS_VIRTUAL)) {
-                String8 alias = mContext->getPolicy()->getDeviceAlias(mIdentifier);
-                if (mAlias != alias) {
-                    mAlias = alias;
-                    bumpGeneration();
-                }
-            }
-        }
-
-        size_t numMappers = mMappers.size();
-        for (size_t i = 0; i < numMappers; i++) {
-            InputMapper* mapper = mMappers[i];
-            mapper->configure(when, config, changes);
-            mSources |= mapper->getSources();
-        }
-    }
-}
-
-void InputDevice::reset(nsecs_t when) {
-    size_t numMappers = mMappers.size();
-    for (size_t i = 0; i < numMappers; i++) {
-        InputMapper* mapper = mMappers[i];
-        mapper->reset(when);
-    }
-
-    mContext->updateGlobalMetaState();
-
-    notifyReset(when);
-}
-
-void InputDevice::process(const RawEvent* rawEvents, size_t count) {
-    // Process all of the events in order for each mapper.
-    // We cannot simply ask each mapper to process them in bulk because mappers may
-    // have side-effects that must be interleaved.  For example, joystick movement events and
-    // gamepad button presses are handled by different mappers but they should be dispatched
-    // in the order received.
-    size_t numMappers = mMappers.size();
-    for (const RawEvent* rawEvent = rawEvents; count--; rawEvent++) {
-#if DEBUG_RAW_EVENTS
-        ALOGD("Input event: device=%d type=0x%04x code=0x%04x value=0x%08x when=%lld",
-                rawEvent->deviceId, rawEvent->type, rawEvent->code, rawEvent->value,
-                rawEvent->when);
-#endif
-
-        if (mDropUntilNextSync) {
-            if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
-                mDropUntilNextSync = false;
-#if DEBUG_RAW_EVENTS
-                ALOGD("Recovered from input event buffer overrun.");
-#endif
-            } else {
-#if DEBUG_RAW_EVENTS
-                ALOGD("Dropped input event while waiting for next input sync.");
-#endif
-            }
-        } else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_DROPPED) {
-            ALOGI("Detected input event buffer overrun for device %s.", getName().string());
-            mDropUntilNextSync = true;
-            reset(rawEvent->when);
-        } else {
-            for (size_t i = 0; i < numMappers; i++) {
-                InputMapper* mapper = mMappers[i];
-                mapper->process(rawEvent);
-            }
-        }
-    }
-}
-
-void InputDevice::timeoutExpired(nsecs_t when) {
-    size_t numMappers = mMappers.size();
-    for (size_t i = 0; i < numMappers; i++) {
-        InputMapper* mapper = mMappers[i];
-        mapper->timeoutExpired(when);
-    }
-}
-
-void InputDevice::getDeviceInfo(InputDeviceInfo* outDeviceInfo) {
-    outDeviceInfo->initialize(mId, mGeneration, mControllerNumber, mIdentifier, mAlias,
-            mIsExternal);
-
-    size_t numMappers = mMappers.size();
-    for (size_t i = 0; i < numMappers; i++) {
-        InputMapper* mapper = mMappers[i];
-        mapper->populateDeviceInfo(outDeviceInfo);
-    }
-}
-
-int32_t InputDevice::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) {
-    return getState(sourceMask, keyCode, & InputMapper::getKeyCodeState);
-}
-
-int32_t InputDevice::getScanCodeState(uint32_t sourceMask, int32_t scanCode) {
-    return getState(sourceMask, scanCode, & InputMapper::getScanCodeState);
-}
-
-int32_t InputDevice::getSwitchState(uint32_t sourceMask, int32_t switchCode) {
-    return getState(sourceMask, switchCode, & InputMapper::getSwitchState);
-}
-
-int32_t InputDevice::getState(uint32_t sourceMask, int32_t code, GetStateFunc getStateFunc) {
-    int32_t result = AKEY_STATE_UNKNOWN;
-    size_t numMappers = mMappers.size();
-    for (size_t i = 0; i < numMappers; i++) {
-        InputMapper* mapper = mMappers[i];
-        if (sourcesMatchMask(mapper->getSources(), sourceMask)) {
-            // If any mapper reports AKEY_STATE_DOWN or AKEY_STATE_VIRTUAL, return that
-            // value.  Otherwise, return AKEY_STATE_UP as long as one mapper reports it.
-            int32_t currentResult = (mapper->*getStateFunc)(sourceMask, code);
-            if (currentResult >= AKEY_STATE_DOWN) {
-                return currentResult;
-            } else if (currentResult == AKEY_STATE_UP) {
-                result = currentResult;
-            }
-        }
-    }
-    return result;
-}
-
-bool InputDevice::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes,
-        const int32_t* keyCodes, uint8_t* outFlags) {
-    bool result = false;
-    size_t numMappers = mMappers.size();
-    for (size_t i = 0; i < numMappers; i++) {
-        InputMapper* mapper = mMappers[i];
-        if (sourcesMatchMask(mapper->getSources(), sourceMask)) {
-            result |= mapper->markSupportedKeyCodes(sourceMask, numCodes, keyCodes, outFlags);
-        }
-    }
-    return result;
-}
-
-void InputDevice::vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat,
-        int32_t token) {
-    size_t numMappers = mMappers.size();
-    for (size_t i = 0; i < numMappers; i++) {
-        InputMapper* mapper = mMappers[i];
-        mapper->vibrate(pattern, patternSize, repeat, token);
-    }
-}
-
-void InputDevice::cancelVibrate(int32_t token) {
-    size_t numMappers = mMappers.size();
-    for (size_t i = 0; i < numMappers; i++) {
-        InputMapper* mapper = mMappers[i];
-        mapper->cancelVibrate(token);
-    }
-}
-
-int32_t InputDevice::getMetaState() {
-    int32_t result = 0;
-    size_t numMappers = mMappers.size();
-    for (size_t i = 0; i < numMappers; i++) {
-        InputMapper* mapper = mMappers[i];
-        result |= mapper->getMetaState();
-    }
-    return result;
-}
-
-void InputDevice::fadePointer() {
-    size_t numMappers = mMappers.size();
-    for (size_t i = 0; i < numMappers; i++) {
-        InputMapper* mapper = mMappers[i];
-        mapper->fadePointer();
-    }
-}
-
-void InputDevice::bumpGeneration() {
-    mGeneration = mContext->bumpGeneration();
-}
-
-void InputDevice::notifyReset(nsecs_t when) {
-    NotifyDeviceResetArgs args(when, mId);
-    mContext->getListener()->notifyDeviceReset(&args);
-}
-
-
-// --- CursorButtonAccumulator ---
-
-CursorButtonAccumulator::CursorButtonAccumulator() {
-    clearButtons();
-}
-
-void CursorButtonAccumulator::reset(InputDevice* device) {
-    mBtnLeft = device->isKeyPressed(BTN_LEFT);
-    mBtnRight = device->isKeyPressed(BTN_RIGHT);
-    mBtnMiddle = device->isKeyPressed(BTN_MIDDLE);
-    mBtnBack = device->isKeyPressed(BTN_BACK);
-    mBtnSide = device->isKeyPressed(BTN_SIDE);
-    mBtnForward = device->isKeyPressed(BTN_FORWARD);
-    mBtnExtra = device->isKeyPressed(BTN_EXTRA);
-    mBtnTask = device->isKeyPressed(BTN_TASK);
-}
-
-void CursorButtonAccumulator::clearButtons() {
-    mBtnLeft = 0;
-    mBtnRight = 0;
-    mBtnMiddle = 0;
-    mBtnBack = 0;
-    mBtnSide = 0;
-    mBtnForward = 0;
-    mBtnExtra = 0;
-    mBtnTask = 0;
-}
-
-void CursorButtonAccumulator::process(const RawEvent* rawEvent) {
-    if (rawEvent->type == EV_KEY) {
-        switch (rawEvent->code) {
-        case BTN_LEFT:
-            mBtnLeft = rawEvent->value;
-            break;
-        case BTN_RIGHT:
-            mBtnRight = rawEvent->value;
-            break;
-        case BTN_MIDDLE:
-            mBtnMiddle = rawEvent->value;
-            break;
-        case BTN_BACK:
-            mBtnBack = rawEvent->value;
-            break;
-        case BTN_SIDE:
-            mBtnSide = rawEvent->value;
-            break;
-        case BTN_FORWARD:
-            mBtnForward = rawEvent->value;
-            break;
-        case BTN_EXTRA:
-            mBtnExtra = rawEvent->value;
-            break;
-        case BTN_TASK:
-            mBtnTask = rawEvent->value;
-            break;
-        }
-    }
-}
-
-uint32_t CursorButtonAccumulator::getButtonState() const {
-    uint32_t result = 0;
-    if (mBtnLeft) {
-        result |= AMOTION_EVENT_BUTTON_PRIMARY;
-    }
-    if (mBtnRight) {
-        result |= AMOTION_EVENT_BUTTON_SECONDARY;
-    }
-    if (mBtnMiddle) {
-        result |= AMOTION_EVENT_BUTTON_TERTIARY;
-    }
-    if (mBtnBack || mBtnSide) {
-        result |= AMOTION_EVENT_BUTTON_BACK;
-    }
-    if (mBtnForward || mBtnExtra) {
-        result |= AMOTION_EVENT_BUTTON_FORWARD;
-    }
-    return result;
-}
-
-
-// --- CursorMotionAccumulator ---
-
-CursorMotionAccumulator::CursorMotionAccumulator() {
-    clearRelativeAxes();
-}
-
-void CursorMotionAccumulator::reset(InputDevice* device) {
-    clearRelativeAxes();
-}
-
-void CursorMotionAccumulator::clearRelativeAxes() {
-    mRelX = 0;
-    mRelY = 0;
-}
-
-void CursorMotionAccumulator::process(const RawEvent* rawEvent) {
-    if (rawEvent->type == EV_REL) {
-        switch (rawEvent->code) {
-        case REL_X:
-            mRelX = rawEvent->value;
-            break;
-        case REL_Y:
-            mRelY = rawEvent->value;
-            break;
-        }
-    }
-}
-
-void CursorMotionAccumulator::finishSync() {
-    clearRelativeAxes();
-}
-
-
-// --- CursorScrollAccumulator ---
-
-CursorScrollAccumulator::CursorScrollAccumulator() :
-        mHaveRelWheel(false), mHaveRelHWheel(false) {
-    clearRelativeAxes();
-}
-
-void CursorScrollAccumulator::configure(InputDevice* device) {
-    mHaveRelWheel = device->getEventHub()->hasRelativeAxis(device->getId(), REL_WHEEL);
-    mHaveRelHWheel = device->getEventHub()->hasRelativeAxis(device->getId(), REL_HWHEEL);
-}
-
-void CursorScrollAccumulator::reset(InputDevice* device) {
-    clearRelativeAxes();
-}
-
-void CursorScrollAccumulator::clearRelativeAxes() {
-    mRelWheel = 0;
-    mRelHWheel = 0;
-}
-
-void CursorScrollAccumulator::process(const RawEvent* rawEvent) {
-    if (rawEvent->type == EV_REL) {
-        switch (rawEvent->code) {
-        case REL_WHEEL:
-            mRelWheel = rawEvent->value;
-            break;
-        case REL_HWHEEL:
-            mRelHWheel = rawEvent->value;
-            break;
-        }
-    }
-}
-
-void CursorScrollAccumulator::finishSync() {
-    clearRelativeAxes();
-}
-
-
-// --- TouchButtonAccumulator ---
-
-TouchButtonAccumulator::TouchButtonAccumulator() :
-        mHaveBtnTouch(false), mHaveStylus(false) {
-    clearButtons();
-}
-
-void TouchButtonAccumulator::configure(InputDevice* device) {
-    mHaveBtnTouch = device->hasKey(BTN_TOUCH);
-    mHaveStylus = device->hasKey(BTN_TOOL_PEN)
-            || device->hasKey(BTN_TOOL_RUBBER)
-            || device->hasKey(BTN_TOOL_BRUSH)
-            || device->hasKey(BTN_TOOL_PENCIL)
-            || device->hasKey(BTN_TOOL_AIRBRUSH);
-}
-
-void TouchButtonAccumulator::reset(InputDevice* device) {
-    mBtnTouch = device->isKeyPressed(BTN_TOUCH);
-    mBtnStylus = device->isKeyPressed(BTN_STYLUS);
-    mBtnStylus2 = device->isKeyPressed(BTN_STYLUS);
-    mBtnToolFinger = device->isKeyPressed(BTN_TOOL_FINGER);
-    mBtnToolPen = device->isKeyPressed(BTN_TOOL_PEN);
-    mBtnToolRubber = device->isKeyPressed(BTN_TOOL_RUBBER);
-    mBtnToolBrush = device->isKeyPressed(BTN_TOOL_BRUSH);
-    mBtnToolPencil = device->isKeyPressed(BTN_TOOL_PENCIL);
-    mBtnToolAirbrush = device->isKeyPressed(BTN_TOOL_AIRBRUSH);
-    mBtnToolMouse = device->isKeyPressed(BTN_TOOL_MOUSE);
-    mBtnToolLens = device->isKeyPressed(BTN_TOOL_LENS);
-    mBtnToolDoubleTap = device->isKeyPressed(BTN_TOOL_DOUBLETAP);
-    mBtnToolTripleTap = device->isKeyPressed(BTN_TOOL_TRIPLETAP);
-    mBtnToolQuadTap = device->isKeyPressed(BTN_TOOL_QUADTAP);
-}
-
-void TouchButtonAccumulator::clearButtons() {
-    mBtnTouch = 0;
-    mBtnStylus = 0;
-    mBtnStylus2 = 0;
-    mBtnToolFinger = 0;
-    mBtnToolPen = 0;
-    mBtnToolRubber = 0;
-    mBtnToolBrush = 0;
-    mBtnToolPencil = 0;
-    mBtnToolAirbrush = 0;
-    mBtnToolMouse = 0;
-    mBtnToolLens = 0;
-    mBtnToolDoubleTap = 0;
-    mBtnToolTripleTap = 0;
-    mBtnToolQuadTap = 0;
-}
-
-void TouchButtonAccumulator::process(const RawEvent* rawEvent) {
-    if (rawEvent->type == EV_KEY) {
-        switch (rawEvent->code) {
-        case BTN_TOUCH:
-            mBtnTouch = rawEvent->value;
-            break;
-        case BTN_STYLUS:
-            mBtnStylus = rawEvent->value;
-            break;
-        case BTN_STYLUS2:
-            mBtnStylus2 = rawEvent->value;
-            break;
-        case BTN_TOOL_FINGER:
-            mBtnToolFinger = rawEvent->value;
-            break;
-        case BTN_TOOL_PEN:
-            mBtnToolPen = rawEvent->value;
-            break;
-        case BTN_TOOL_RUBBER:
-            mBtnToolRubber = rawEvent->value;
-            break;
-        case BTN_TOOL_BRUSH:
-            mBtnToolBrush = rawEvent->value;
-            break;
-        case BTN_TOOL_PENCIL:
-            mBtnToolPencil = rawEvent->value;
-            break;
-        case BTN_TOOL_AIRBRUSH:
-            mBtnToolAirbrush = rawEvent->value;
-            break;
-        case BTN_TOOL_MOUSE:
-            mBtnToolMouse = rawEvent->value;
-            break;
-        case BTN_TOOL_LENS:
-            mBtnToolLens = rawEvent->value;
-            break;
-        case BTN_TOOL_DOUBLETAP:
-            mBtnToolDoubleTap = rawEvent->value;
-            break;
-        case BTN_TOOL_TRIPLETAP:
-            mBtnToolTripleTap = rawEvent->value;
-            break;
-        case BTN_TOOL_QUADTAP:
-            mBtnToolQuadTap = rawEvent->value;
-            break;
-        }
-    }
-}
-
-uint32_t TouchButtonAccumulator::getButtonState() const {
-    uint32_t result = 0;
-    if (mBtnStylus) {
-        result |= AMOTION_EVENT_BUTTON_SECONDARY;
-    }
-    if (mBtnStylus2) {
-        result |= AMOTION_EVENT_BUTTON_TERTIARY;
-    }
-    return result;
-}
-
-int32_t TouchButtonAccumulator::getToolType() const {
-    if (mBtnToolMouse || mBtnToolLens) {
-        return AMOTION_EVENT_TOOL_TYPE_MOUSE;
-    }
-    if (mBtnToolRubber) {
-        return AMOTION_EVENT_TOOL_TYPE_ERASER;
-    }
-    if (mBtnToolPen || mBtnToolBrush || mBtnToolPencil || mBtnToolAirbrush) {
-        return AMOTION_EVENT_TOOL_TYPE_STYLUS;
-    }
-    if (mBtnToolFinger || mBtnToolDoubleTap || mBtnToolTripleTap || mBtnToolQuadTap) {
-        return AMOTION_EVENT_TOOL_TYPE_FINGER;
-    }
-    return AMOTION_EVENT_TOOL_TYPE_UNKNOWN;
-}
-
-bool TouchButtonAccumulator::isToolActive() const {
-    return mBtnTouch || mBtnToolFinger || mBtnToolPen || mBtnToolRubber
-            || mBtnToolBrush || mBtnToolPencil || mBtnToolAirbrush
-            || mBtnToolMouse || mBtnToolLens
-            || mBtnToolDoubleTap || mBtnToolTripleTap || mBtnToolQuadTap;
-}
-
-bool TouchButtonAccumulator::isHovering() const {
-    return mHaveBtnTouch && !mBtnTouch;
-}
-
-bool TouchButtonAccumulator::hasStylus() const {
-    return mHaveStylus;
-}
-
-
-// --- RawPointerAxes ---
-
-RawPointerAxes::RawPointerAxes() {
-    clear();
-}
-
-void RawPointerAxes::clear() {
-    x.clear();
-    y.clear();
-    pressure.clear();
-    touchMajor.clear();
-    touchMinor.clear();
-    toolMajor.clear();
-    toolMinor.clear();
-    orientation.clear();
-    distance.clear();
-    tiltX.clear();
-    tiltY.clear();
-    trackingId.clear();
-    slot.clear();
-}
-
-
-// --- RawPointerData ---
-
-RawPointerData::RawPointerData() {
-    clear();
-}
-
-void RawPointerData::clear() {
-    pointerCount = 0;
-    clearIdBits();
-}
-
-void RawPointerData::copyFrom(const RawPointerData& other) {
-    pointerCount = other.pointerCount;
-    hoveringIdBits = other.hoveringIdBits;
-    touchingIdBits = other.touchingIdBits;
-
-    for (uint32_t i = 0; i < pointerCount; i++) {
-        pointers[i] = other.pointers[i];
-
-        int id = pointers[i].id;
-        idToIndex[id] = other.idToIndex[id];
-    }
-}
-
-void RawPointerData::getCentroidOfTouchingPointers(float* outX, float* outY) const {
-    float x = 0, y = 0;
-    uint32_t count = touchingIdBits.count();
-    if (count) {
-        for (BitSet32 idBits(touchingIdBits); !idBits.isEmpty(); ) {
-            uint32_t id = idBits.clearFirstMarkedBit();
-            const Pointer& pointer = pointerForId(id);
-            x += pointer.x;
-            y += pointer.y;
-        }
-        x /= count;
-        y /= count;
-    }
-    *outX = x;
-    *outY = y;
-}
-
-
-// --- CookedPointerData ---
-
-CookedPointerData::CookedPointerData() {
-    clear();
-}
-
-void CookedPointerData::clear() {
-    pointerCount = 0;
-    hoveringIdBits.clear();
-    touchingIdBits.clear();
-}
-
-void CookedPointerData::copyFrom(const CookedPointerData& other) {
-    pointerCount = other.pointerCount;
-    hoveringIdBits = other.hoveringIdBits;
-    touchingIdBits = other.touchingIdBits;
-
-    for (uint32_t i = 0; i < pointerCount; i++) {
-        pointerProperties[i].copyFrom(other.pointerProperties[i]);
-        pointerCoords[i].copyFrom(other.pointerCoords[i]);
-
-        int id = pointerProperties[i].id;
-        idToIndex[id] = other.idToIndex[id];
-    }
-}
-
-
-// --- SingleTouchMotionAccumulator ---
-
-SingleTouchMotionAccumulator::SingleTouchMotionAccumulator() {
-    clearAbsoluteAxes();
-}
-
-void SingleTouchMotionAccumulator::reset(InputDevice* device) {
-    mAbsX = device->getAbsoluteAxisValue(ABS_X);
-    mAbsY = device->getAbsoluteAxisValue(ABS_Y);
-    mAbsPressure = device->getAbsoluteAxisValue(ABS_PRESSURE);
-    mAbsToolWidth = device->getAbsoluteAxisValue(ABS_TOOL_WIDTH);
-    mAbsDistance = device->getAbsoluteAxisValue(ABS_DISTANCE);
-    mAbsTiltX = device->getAbsoluteAxisValue(ABS_TILT_X);
-    mAbsTiltY = device->getAbsoluteAxisValue(ABS_TILT_Y);
-}
-
-void SingleTouchMotionAccumulator::clearAbsoluteAxes() {
-    mAbsX = 0;
-    mAbsY = 0;
-    mAbsPressure = 0;
-    mAbsToolWidth = 0;
-    mAbsDistance = 0;
-    mAbsTiltX = 0;
-    mAbsTiltY = 0;
-}
-
-void SingleTouchMotionAccumulator::process(const RawEvent* rawEvent) {
-    if (rawEvent->type == EV_ABS) {
-        switch (rawEvent->code) {
-        case ABS_X:
-            mAbsX = rawEvent->value;
-            break;
-        case ABS_Y:
-            mAbsY = rawEvent->value;
-            break;
-        case ABS_PRESSURE:
-            mAbsPressure = rawEvent->value;
-            break;
-        case ABS_TOOL_WIDTH:
-            mAbsToolWidth = rawEvent->value;
-            break;
-        case ABS_DISTANCE:
-            mAbsDistance = rawEvent->value;
-            break;
-        case ABS_TILT_X:
-            mAbsTiltX = rawEvent->value;
-            break;
-        case ABS_TILT_Y:
-            mAbsTiltY = rawEvent->value;
-            break;
-        }
-    }
-}
-
-
-// --- MultiTouchMotionAccumulator ---
-
-MultiTouchMotionAccumulator::MultiTouchMotionAccumulator() :
-        mCurrentSlot(-1), mSlots(NULL), mSlotCount(0), mUsingSlotsProtocol(false),
-        mHaveStylus(false) {
-}
-
-MultiTouchMotionAccumulator::~MultiTouchMotionAccumulator() {
-    delete[] mSlots;
-}
-
-void MultiTouchMotionAccumulator::configure(InputDevice* device,
-        size_t slotCount, bool usingSlotsProtocol) {
-    mSlotCount = slotCount;
-    mUsingSlotsProtocol = usingSlotsProtocol;
-    mHaveStylus = device->hasAbsoluteAxis(ABS_MT_TOOL_TYPE);
-
-    delete[] mSlots;
-    mSlots = new Slot[slotCount];
-}
-
-void MultiTouchMotionAccumulator::reset(InputDevice* device) {
-    // Unfortunately there is no way to read the initial contents of the slots.
-    // So when we reset the accumulator, we must assume they are all zeroes.
-    if (mUsingSlotsProtocol) {
-        // Query the driver for the current slot index and use it as the initial slot
-        // before we start reading events from the device.  It is possible that the
-        // current slot index will not be the same as it was when the first event was
-        // written into the evdev buffer, which means the input mapper could start
-        // out of sync with the initial state of the events in the evdev buffer.
-        // In the extremely unlikely case that this happens, the data from
-        // two slots will be confused until the next ABS_MT_SLOT event is received.
-        // This can cause the touch point to "jump", but at least there will be
-        // no stuck touches.
-        int32_t initialSlot;
-        status_t status = device->getEventHub()->getAbsoluteAxisValue(device->getId(),
-                ABS_MT_SLOT, &initialSlot);
-        if (status) {
-            ALOGD("Could not retrieve current multitouch slot index.  status=%d", status);
-            initialSlot = -1;
-        }
-        clearSlots(initialSlot);
-    } else {
-        clearSlots(-1);
-    }
-}
-
-void MultiTouchMotionAccumulator::clearSlots(int32_t initialSlot) {
-    if (mSlots) {
-        for (size_t i = 0; i < mSlotCount; i++) {
-            mSlots[i].clear();
-        }
-    }
-    mCurrentSlot = initialSlot;
-}
-
-void MultiTouchMotionAccumulator::process(const RawEvent* rawEvent) {
-    if (rawEvent->type == EV_ABS) {
-        bool newSlot = false;
-        if (mUsingSlotsProtocol) {
-            if (rawEvent->code == ABS_MT_SLOT) {
-                mCurrentSlot = rawEvent->value;
-                newSlot = true;
-            }
-        } else if (mCurrentSlot < 0) {
-            mCurrentSlot = 0;
-        }
-
-        if (mCurrentSlot < 0 || size_t(mCurrentSlot) >= mSlotCount) {
-#if DEBUG_POINTERS
-            if (newSlot) {
-                ALOGW("MultiTouch device emitted invalid slot index %d but it "
-                        "should be between 0 and %d; ignoring this slot.",
-                        mCurrentSlot, mSlotCount - 1);
-            }
-#endif
-        } else {
-            Slot* slot = &mSlots[mCurrentSlot];
-
-            switch (rawEvent->code) {
-            case ABS_MT_POSITION_X:
-                slot->mInUse = true;
-                slot->mAbsMTPositionX = rawEvent->value;
-                break;
-            case ABS_MT_POSITION_Y:
-                slot->mInUse = true;
-                slot->mAbsMTPositionY = rawEvent->value;
-                break;
-            case ABS_MT_TOUCH_MAJOR:
-                slot->mInUse = true;
-                slot->mAbsMTTouchMajor = rawEvent->value;
-                break;
-            case ABS_MT_TOUCH_MINOR:
-                slot->mInUse = true;
-                slot->mAbsMTTouchMinor = rawEvent->value;
-                slot->mHaveAbsMTTouchMinor = true;
-                break;
-            case ABS_MT_WIDTH_MAJOR:
-                slot->mInUse = true;
-                slot->mAbsMTWidthMajor = rawEvent->value;
-                break;
-            case ABS_MT_WIDTH_MINOR:
-                slot->mInUse = true;
-                slot->mAbsMTWidthMinor = rawEvent->value;
-                slot->mHaveAbsMTWidthMinor = true;
-                break;
-            case ABS_MT_ORIENTATION:
-                slot->mInUse = true;
-                slot->mAbsMTOrientation = rawEvent->value;
-                break;
-            case ABS_MT_TRACKING_ID:
-                if (mUsingSlotsProtocol && rawEvent->value < 0) {
-                    // The slot is no longer in use but it retains its previous contents,
-                    // which may be reused for subsequent touches.
-                    slot->mInUse = false;
-                } else {
-                    slot->mInUse = true;
-                    slot->mAbsMTTrackingId = rawEvent->value;
-                }
-                break;
-            case ABS_MT_PRESSURE:
-                slot->mInUse = true;
-                slot->mAbsMTPressure = rawEvent->value;
-                break;
-            case ABS_MT_DISTANCE:
-                slot->mInUse = true;
-                slot->mAbsMTDistance = rawEvent->value;
-                break;
-            case ABS_MT_TOOL_TYPE:
-                slot->mInUse = true;
-                slot->mAbsMTToolType = rawEvent->value;
-                slot->mHaveAbsMTToolType = true;
-                break;
-            }
-        }
-    } else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_MT_REPORT) {
-        // MultiTouch Sync: The driver has returned all data for *one* of the pointers.
-        mCurrentSlot += 1;
-    }
-}
-
-void MultiTouchMotionAccumulator::finishSync() {
-    if (!mUsingSlotsProtocol) {
-        clearSlots(-1);
-    }
-}
-
-bool MultiTouchMotionAccumulator::hasStylus() const {
-    return mHaveStylus;
-}
-
-
-// --- MultiTouchMotionAccumulator::Slot ---
-
-MultiTouchMotionAccumulator::Slot::Slot() {
-    clear();
-}
-
-void MultiTouchMotionAccumulator::Slot::clear() {
-    mInUse = false;
-    mHaveAbsMTTouchMinor = false;
-    mHaveAbsMTWidthMinor = false;
-    mHaveAbsMTToolType = false;
-    mAbsMTPositionX = 0;
-    mAbsMTPositionY = 0;
-    mAbsMTTouchMajor = 0;
-    mAbsMTTouchMinor = 0;
-    mAbsMTWidthMajor = 0;
-    mAbsMTWidthMinor = 0;
-    mAbsMTOrientation = 0;
-    mAbsMTTrackingId = -1;
-    mAbsMTPressure = 0;
-    mAbsMTDistance = 0;
-    mAbsMTToolType = 0;
-}
-
-int32_t MultiTouchMotionAccumulator::Slot::getToolType() const {
-    if (mHaveAbsMTToolType) {
-        switch (mAbsMTToolType) {
-        case MT_TOOL_FINGER:
-            return AMOTION_EVENT_TOOL_TYPE_FINGER;
-        case MT_TOOL_PEN:
-            return AMOTION_EVENT_TOOL_TYPE_STYLUS;
-        }
-    }
-    return AMOTION_EVENT_TOOL_TYPE_UNKNOWN;
-}
-
-
-// --- InputMapper ---
-
-InputMapper::InputMapper(InputDevice* device) :
-        mDevice(device), mContext(device->getContext()) {
-}
-
-InputMapper::~InputMapper() {
-}
-
-void InputMapper::populateDeviceInfo(InputDeviceInfo* info) {
-    info->addSource(getSources());
-}
-
-void InputMapper::dump(String8& dump) {
-}
-
-void InputMapper::configure(nsecs_t when,
-        const InputReaderConfiguration* config, uint32_t changes) {
-}
-
-void InputMapper::reset(nsecs_t when) {
-}
-
-void InputMapper::timeoutExpired(nsecs_t when) {
-}
-
-int32_t InputMapper::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) {
-    return AKEY_STATE_UNKNOWN;
-}
-
-int32_t InputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) {
-    return AKEY_STATE_UNKNOWN;
-}
-
-int32_t InputMapper::getSwitchState(uint32_t sourceMask, int32_t switchCode) {
-    return AKEY_STATE_UNKNOWN;
-}
-
-bool InputMapper::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes,
-        const int32_t* keyCodes, uint8_t* outFlags) {
-    return false;
-}
-
-void InputMapper::vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat,
-        int32_t token) {
-}
-
-void InputMapper::cancelVibrate(int32_t token) {
-}
-
-int32_t InputMapper::getMetaState() {
-    return 0;
-}
-
-void InputMapper::fadePointer() {
-}
-
-status_t InputMapper::getAbsoluteAxisInfo(int32_t axis, RawAbsoluteAxisInfo* axisInfo) {
-    return getEventHub()->getAbsoluteAxisInfo(getDeviceId(), axis, axisInfo);
-}
-
-void InputMapper::bumpGeneration() {
-    mDevice->bumpGeneration();
-}
-
-void InputMapper::dumpRawAbsoluteAxisInfo(String8& dump,
-        const RawAbsoluteAxisInfo& axis, const char* name) {
-    if (axis.valid) {
-        dump.appendFormat(INDENT4 "%s: min=%d, max=%d, flat=%d, fuzz=%d, resolution=%d\n",
-                name, axis.minValue, axis.maxValue, axis.flat, axis.fuzz, axis.resolution);
-    } else {
-        dump.appendFormat(INDENT4 "%s: unknown range\n", name);
-    }
-}
-
-
-// --- SwitchInputMapper ---
-
-SwitchInputMapper::SwitchInputMapper(InputDevice* device) :
-        InputMapper(device), mUpdatedSwitchValues(0), mUpdatedSwitchMask(0) {
-}
-
-SwitchInputMapper::~SwitchInputMapper() {
-}
-
-uint32_t SwitchInputMapper::getSources() {
-    return AINPUT_SOURCE_SWITCH;
-}
-
-void SwitchInputMapper::process(const RawEvent* rawEvent) {
-    switch (rawEvent->type) {
-    case EV_SW:
-        processSwitch(rawEvent->code, rawEvent->value);
-        break;
-
-    case EV_SYN:
-        if (rawEvent->code == SYN_REPORT) {
-            sync(rawEvent->when);
-        }
-    }
-}
-
-void SwitchInputMapper::processSwitch(int32_t switchCode, int32_t switchValue) {
-    if (switchCode >= 0 && switchCode < 32) {
-        if (switchValue) {
-            mUpdatedSwitchValues |= 1 << switchCode;
-        }
-        mUpdatedSwitchMask |= 1 << switchCode;
-    }
-}
-
-void SwitchInputMapper::sync(nsecs_t when) {
-    if (mUpdatedSwitchMask) {
-        NotifySwitchArgs args(when, 0, mUpdatedSwitchValues, mUpdatedSwitchMask);
-        getListener()->notifySwitch(&args);
-
-        mUpdatedSwitchValues = 0;
-        mUpdatedSwitchMask = 0;
-    }
-}
-
-int32_t SwitchInputMapper::getSwitchState(uint32_t sourceMask, int32_t switchCode) {
-    return getEventHub()->getSwitchState(getDeviceId(), switchCode);
-}
-
-
-// --- VibratorInputMapper ---
-
-VibratorInputMapper::VibratorInputMapper(InputDevice* device) :
-        InputMapper(device), mVibrating(false) {
-}
-
-VibratorInputMapper::~VibratorInputMapper() {
-}
-
-uint32_t VibratorInputMapper::getSources() {
-    return 0;
-}
-
-void VibratorInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
-    InputMapper::populateDeviceInfo(info);
-
-    info->setVibrator(true);
-}
-
-void VibratorInputMapper::process(const RawEvent* rawEvent) {
-    // TODO: Handle FF_STATUS, although it does not seem to be widely supported.
-}
-
-void VibratorInputMapper::vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat,
-        int32_t token) {
-#if DEBUG_VIBRATOR
-    String8 patternStr;
-    for (size_t i = 0; i < patternSize; i++) {
-        if (i != 0) {
-            patternStr.append(", ");
-        }
-        patternStr.appendFormat("%lld", pattern[i]);
-    }
-    ALOGD("vibrate: deviceId=%d, pattern=[%s], repeat=%ld, token=%d",
-            getDeviceId(), patternStr.string(), repeat, token);
-#endif
-
-    mVibrating = true;
-    memcpy(mPattern, pattern, patternSize * sizeof(nsecs_t));
-    mPatternSize = patternSize;
-    mRepeat = repeat;
-    mToken = token;
-    mIndex = -1;
-
-    nextStep();
-}
-
-void VibratorInputMapper::cancelVibrate(int32_t token) {
-#if DEBUG_VIBRATOR
-    ALOGD("cancelVibrate: deviceId=%d, token=%d", getDeviceId(), token);
-#endif
-
-    if (mVibrating && mToken == token) {
-        stopVibrating();
-    }
-}
-
-void VibratorInputMapper::timeoutExpired(nsecs_t when) {
-    if (mVibrating) {
-        if (when >= mNextStepTime) {
-            nextStep();
-        } else {
-            getContext()->requestTimeoutAtTime(mNextStepTime);
-        }
-    }
-}
-
-void VibratorInputMapper::nextStep() {
-    mIndex += 1;
-    if (size_t(mIndex) >= mPatternSize) {
-        if (mRepeat < 0) {
-            // We are done.
-            stopVibrating();
-            return;
-        }
-        mIndex = mRepeat;
-    }
-
-    bool vibratorOn = mIndex & 1;
-    nsecs_t duration = mPattern[mIndex];
-    if (vibratorOn) {
-#if DEBUG_VIBRATOR
-        ALOGD("nextStep: sending vibrate deviceId=%d, duration=%lld",
-                getDeviceId(), duration);
-#endif
-        getEventHub()->vibrate(getDeviceId(), duration);
-    } else {
-#if DEBUG_VIBRATOR
-        ALOGD("nextStep: sending cancel vibrate deviceId=%d", getDeviceId());
-#endif
-        getEventHub()->cancelVibrate(getDeviceId());
-    }
-    nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
-    mNextStepTime = now + duration;
-    getContext()->requestTimeoutAtTime(mNextStepTime);
-#if DEBUG_VIBRATOR
-    ALOGD("nextStep: scheduled timeout in %0.3fms", duration * 0.000001f);
-#endif
-}
-
-void VibratorInputMapper::stopVibrating() {
-    mVibrating = false;
-#if DEBUG_VIBRATOR
-    ALOGD("stopVibrating: sending cancel vibrate deviceId=%d", getDeviceId());
-#endif
-    getEventHub()->cancelVibrate(getDeviceId());
-}
-
-void VibratorInputMapper::dump(String8& dump) {
-    dump.append(INDENT2 "Vibrator Input Mapper:\n");
-    dump.appendFormat(INDENT3 "Vibrating: %s\n", toString(mVibrating));
-}
-
-
-// --- KeyboardInputMapper ---
-
-KeyboardInputMapper::KeyboardInputMapper(InputDevice* device,
-        uint32_t source, int32_t keyboardType) :
-        InputMapper(device), mSource(source),
-        mKeyboardType(keyboardType) {
-}
-
-KeyboardInputMapper::~KeyboardInputMapper() {
-}
-
-uint32_t KeyboardInputMapper::getSources() {
-    return mSource;
-}
-
-void KeyboardInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
-    InputMapper::populateDeviceInfo(info);
-
-    info->setKeyboardType(mKeyboardType);
-    info->setKeyCharacterMap(getEventHub()->getKeyCharacterMap(getDeviceId()));
-}
-
-void KeyboardInputMapper::dump(String8& dump) {
-    dump.append(INDENT2 "Keyboard Input Mapper:\n");
-    dumpParameters(dump);
-    dump.appendFormat(INDENT3 "KeyboardType: %d\n", mKeyboardType);
-    dump.appendFormat(INDENT3 "Orientation: %d\n", mOrientation);
-    dump.appendFormat(INDENT3 "KeyDowns: %d keys currently down\n", mKeyDowns.size());
-    dump.appendFormat(INDENT3 "MetaState: 0x%0x\n", mMetaState);
-    dump.appendFormat(INDENT3 "DownTime: %lld\n", mDownTime);
-}
-
-
-void KeyboardInputMapper::configure(nsecs_t when,
-        const InputReaderConfiguration* config, uint32_t changes) {
-    InputMapper::configure(when, config, changes);
-
-    if (!changes) { // first time only
-        // Configure basic parameters.
-        configureParameters();
-    }
-
-    if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) {
-        if (mParameters.orientationAware && mParameters.hasAssociatedDisplay) {
-            DisplayViewport v;
-            if (config->getDisplayInfo(false /*external*/, &v)) {
-                mOrientation = v.orientation;
-            } else {
-                mOrientation = DISPLAY_ORIENTATION_0;
-            }
-        } else {
-            mOrientation = DISPLAY_ORIENTATION_0;
-        }
-    }
-}
-
-void KeyboardInputMapper::configureParameters() {
-    mParameters.orientationAware = false;
-    getDevice()->getConfiguration().tryGetProperty(String8("keyboard.orientationAware"),
-            mParameters.orientationAware);
-
-    mParameters.hasAssociatedDisplay = false;
-    if (mParameters.orientationAware) {
-        mParameters.hasAssociatedDisplay = true;
-    }
-}
-
-void KeyboardInputMapper::dumpParameters(String8& dump) {
-    dump.append(INDENT3 "Parameters:\n");
-    dump.appendFormat(INDENT4 "HasAssociatedDisplay: %s\n",
-            toString(mParameters.hasAssociatedDisplay));
-    dump.appendFormat(INDENT4 "OrientationAware: %s\n",
-            toString(mParameters.orientationAware));
-}
-
-void KeyboardInputMapper::reset(nsecs_t when) {
-    mMetaState = AMETA_NONE;
-    mDownTime = 0;
-    mKeyDowns.clear();
-    mCurrentHidUsage = 0;
-
-    resetLedState();
-
-    InputMapper::reset(when);
-}
-
-void KeyboardInputMapper::process(const RawEvent* rawEvent) {
-    switch (rawEvent->type) {
-    case EV_KEY: {
-        int32_t scanCode = rawEvent->code;
-        int32_t usageCode = mCurrentHidUsage;
-        mCurrentHidUsage = 0;
-
-        if (isKeyboardOrGamepadKey(scanCode)) {
-            int32_t keyCode;
-            uint32_t flags;
-            if (getEventHub()->mapKey(getDeviceId(), scanCode, usageCode, &keyCode, &flags)) {
-                keyCode = AKEYCODE_UNKNOWN;
-                flags = 0;
-            }
-            processKey(rawEvent->when, rawEvent->value != 0, keyCode, scanCode, flags);
-        }
-        break;
-    }
-    case EV_MSC: {
-        if (rawEvent->code == MSC_SCAN) {
-            mCurrentHidUsage = rawEvent->value;
-        }
-        break;
-    }
-    case EV_SYN: {
-        if (rawEvent->code == SYN_REPORT) {
-            mCurrentHidUsage = 0;
-        }
-    }
-    }
-}
-
-bool KeyboardInputMapper::isKeyboardOrGamepadKey(int32_t scanCode) {
-    return scanCode < BTN_MOUSE
-        || scanCode >= KEY_OK
-        || (scanCode >= BTN_MISC && scanCode < BTN_MOUSE)
-        || (scanCode >= BTN_JOYSTICK && scanCode < BTN_DIGI);
-}
-
-void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t keyCode,
-        int32_t scanCode, uint32_t policyFlags) {
-
-    if (down) {
-        // Rotate key codes according to orientation if needed.
-        if (mParameters.orientationAware && mParameters.hasAssociatedDisplay) {
-            keyCode = rotateKeyCode(keyCode, mOrientation);
-        }
-
-        // Add key down.
-        ssize_t keyDownIndex = findKeyDown(scanCode);
-        if (keyDownIndex >= 0) {
-            // key repeat, be sure to use same keycode as before in case of rotation
-            keyCode = mKeyDowns.itemAt(keyDownIndex).keyCode;
-        } else {
-            // key down
-            if ((policyFlags & POLICY_FLAG_VIRTUAL)
-                    && mContext->shouldDropVirtualKey(when,
-                            getDevice(), keyCode, scanCode)) {
-                return;
-            }
-
-            mKeyDowns.push();
-            KeyDown& keyDown = mKeyDowns.editTop();
-            keyDown.keyCode = keyCode;
-            keyDown.scanCode = scanCode;
-        }
-
-        mDownTime = when;
-    } else {
-        // Remove key down.
-        ssize_t keyDownIndex = findKeyDown(scanCode);
-        if (keyDownIndex >= 0) {
-            // key up, be sure to use same keycode as before in case of rotation
-            keyCode = mKeyDowns.itemAt(keyDownIndex).keyCode;
-            mKeyDowns.removeAt(size_t(keyDownIndex));
-        } else {
-            // key was not actually down
-            ALOGI("Dropping key up from device %s because the key was not down.  "
-                    "keyCode=%d, scanCode=%d",
-                    getDeviceName().string(), keyCode, scanCode);
-            return;
-        }
-    }
-
-    int32_t oldMetaState = mMetaState;
-    int32_t newMetaState = updateMetaState(keyCode, down, oldMetaState);
-    bool metaStateChanged = oldMetaState != newMetaState;
-    if (metaStateChanged) {
-        mMetaState = newMetaState;
-        updateLedState(false);
-    }
-
-    nsecs_t downTime = mDownTime;
-
-    // Key down on external an keyboard should wake the device.
-    // We don't do this for internal keyboards to prevent them from waking up in your pocket.
-    // For internal keyboards, the key layout file should specify the policy flags for
-    // each wake key individually.
-    // TODO: Use the input device configuration to control this behavior more finely.
-    if (down && getDevice()->isExternal()
-            && !(policyFlags & (POLICY_FLAG_WAKE | POLICY_FLAG_WAKE_DROPPED))) {
-        policyFlags |= POLICY_FLAG_WAKE_DROPPED;
-    }
-
-    if (metaStateChanged) {
-        getContext()->updateGlobalMetaState();
-    }
-
-    if (down && !isMetaKey(keyCode)) {
-        getContext()->fadePointer();
-    }
-
-    NotifyKeyArgs args(when, getDeviceId(), mSource, policyFlags,
-            down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
-            AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, newMetaState, downTime);
-    getListener()->notifyKey(&args);
-}
-
-ssize_t KeyboardInputMapper::findKeyDown(int32_t scanCode) {
-    size_t n = mKeyDowns.size();
-    for (size_t i = 0; i < n; i++) {
-        if (mKeyDowns[i].scanCode == scanCode) {
-            return i;
-        }
-    }
-    return -1;
-}
-
-int32_t KeyboardInputMapper::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) {
-    return getEventHub()->getKeyCodeState(getDeviceId(), keyCode);
-}
-
-int32_t KeyboardInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) {
-    return getEventHub()->getScanCodeState(getDeviceId(), scanCode);
-}
-
-bool KeyboardInputMapper::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes,
-        const int32_t* keyCodes, uint8_t* outFlags) {
-    return getEventHub()->markSupportedKeyCodes(getDeviceId(), numCodes, keyCodes, outFlags);
-}
-
-int32_t KeyboardInputMapper::getMetaState() {
-    return mMetaState;
-}
-
-void KeyboardInputMapper::resetLedState() {
-    initializeLedState(mCapsLockLedState, ALED_CAPS_LOCK);
-    initializeLedState(mNumLockLedState, ALED_NUM_LOCK);
-    initializeLedState(mScrollLockLedState, ALED_SCROLL_LOCK);
-
-    updateLedState(true);
-}
-
-void KeyboardInputMapper::initializeLedState(LedState& ledState, int32_t led) {
-    ledState.avail = getEventHub()->hasLed(getDeviceId(), led);
-    ledState.on = false;
-}
-
-void KeyboardInputMapper::updateLedState(bool reset) {
-    updateLedStateForModifier(mCapsLockLedState, ALED_CAPS_LOCK,
-            AMETA_CAPS_LOCK_ON, reset);
-    updateLedStateForModifier(mNumLockLedState, ALED_NUM_LOCK,
-            AMETA_NUM_LOCK_ON, reset);
-    updateLedStateForModifier(mScrollLockLedState, ALED_SCROLL_LOCK,
-            AMETA_SCROLL_LOCK_ON, reset);
-}
-
-void KeyboardInputMapper::updateLedStateForModifier(LedState& ledState,
-        int32_t led, int32_t modifier, bool reset) {
-    if (ledState.avail) {
-        bool desiredState = (mMetaState & modifier) != 0;
-        if (reset || ledState.on != desiredState) {
-            getEventHub()->setLedState(getDeviceId(), led, desiredState);
-            ledState.on = desiredState;
-        }
-    }
-}
-
-
-// --- CursorInputMapper ---
-
-CursorInputMapper::CursorInputMapper(InputDevice* device) :
-        InputMapper(device) {
-}
-
-CursorInputMapper::~CursorInputMapper() {
-}
-
-uint32_t CursorInputMapper::getSources() {
-    return mSource;
-}
-
-void CursorInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
-    InputMapper::populateDeviceInfo(info);
-
-    if (mParameters.mode == Parameters::MODE_POINTER) {
-        float minX, minY, maxX, maxY;
-        if (mPointerController->getBounds(&minX, &minY, &maxX, &maxY)) {
-            info->addMotionRange(AMOTION_EVENT_AXIS_X, mSource, minX, maxX, 0.0f, 0.0f, 0.0f);
-            info->addMotionRange(AMOTION_EVENT_AXIS_Y, mSource, minY, maxY, 0.0f, 0.0f, 0.0f);
-        }
-    } else {
-        info->addMotionRange(AMOTION_EVENT_AXIS_X, mSource, -1.0f, 1.0f, 0.0f, mXScale, 0.0f);
-        info->addMotionRange(AMOTION_EVENT_AXIS_Y, mSource, -1.0f, 1.0f, 0.0f, mYScale, 0.0f);
-    }
-    info->addMotionRange(AMOTION_EVENT_AXIS_PRESSURE, mSource, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f);
-
-    if (mCursorScrollAccumulator.haveRelativeVWheel()) {
-        info->addMotionRange(AMOTION_EVENT_AXIS_VSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f);
-    }
-    if (mCursorScrollAccumulator.haveRelativeHWheel()) {
-        info->addMotionRange(AMOTION_EVENT_AXIS_HSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f);
-    }
-}
-
-void CursorInputMapper::dump(String8& dump) {
-    dump.append(INDENT2 "Cursor Input Mapper:\n");
-    dumpParameters(dump);
-    dump.appendFormat(INDENT3 "XScale: %0.3f\n", mXScale);
-    dump.appendFormat(INDENT3 "YScale: %0.3f\n", mYScale);
-    dump.appendFormat(INDENT3 "XPrecision: %0.3f\n", mXPrecision);
-    dump.appendFormat(INDENT3 "YPrecision: %0.3f\n", mYPrecision);
-    dump.appendFormat(INDENT3 "HaveVWheel: %s\n",
-            toString(mCursorScrollAccumulator.haveRelativeVWheel()));
-    dump.appendFormat(INDENT3 "HaveHWheel: %s\n",
-            toString(mCursorScrollAccumulator.haveRelativeHWheel()));
-    dump.appendFormat(INDENT3 "VWheelScale: %0.3f\n", mVWheelScale);
-    dump.appendFormat(INDENT3 "HWheelScale: %0.3f\n", mHWheelScale);
-    dump.appendFormat(INDENT3 "Orientation: %d\n", mOrientation);
-    dump.appendFormat(INDENT3 "ButtonState: 0x%08x\n", mButtonState);
-    dump.appendFormat(INDENT3 "Down: %s\n", toString(isPointerDown(mButtonState)));
-    dump.appendFormat(INDENT3 "DownTime: %lld\n", mDownTime);
-}
-
-void CursorInputMapper::configure(nsecs_t when,
-        const InputReaderConfiguration* config, uint32_t changes) {
-    InputMapper::configure(when, config, changes);
-
-    if (!changes) { // first time only
-        mCursorScrollAccumulator.configure(getDevice());
-
-        // Configure basic parameters.
-        configureParameters();
-
-        // Configure device mode.
-        switch (mParameters.mode) {
-        case Parameters::MODE_POINTER:
-            mSource = AINPUT_SOURCE_MOUSE;
-            mXPrecision = 1.0f;
-            mYPrecision = 1.0f;
-            mXScale = 1.0f;
-            mYScale = 1.0f;
-            mPointerController = getPolicy()->obtainPointerController(getDeviceId());
-            break;
-        case Parameters::MODE_NAVIGATION:
-            mSource = AINPUT_SOURCE_TRACKBALL;
-            mXPrecision = TRACKBALL_MOVEMENT_THRESHOLD;
-            mYPrecision = TRACKBALL_MOVEMENT_THRESHOLD;
-            mXScale = 1.0f / TRACKBALL_MOVEMENT_THRESHOLD;
-            mYScale = 1.0f / TRACKBALL_MOVEMENT_THRESHOLD;
-            break;
-        }
-
-        mVWheelScale = 1.0f;
-        mHWheelScale = 1.0f;
-    }
-
-    if (!changes || (changes & InputReaderConfiguration::CHANGE_POINTER_SPEED)) {
-        mPointerVelocityControl.setParameters(config->pointerVelocityControlParameters);
-        mWheelXVelocityControl.setParameters(config->wheelVelocityControlParameters);
-        mWheelYVelocityControl.setParameters(config->wheelVelocityControlParameters);
-    }
-
-    if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) {
-        if (mParameters.orientationAware && mParameters.hasAssociatedDisplay) {
-            DisplayViewport v;
-            if (config->getDisplayInfo(false /*external*/, &v)) {
-                mOrientation = v.orientation;
-            } else {
-                mOrientation = DISPLAY_ORIENTATION_0;
-            }
-        } else {
-            mOrientation = DISPLAY_ORIENTATION_0;
-        }
-        bumpGeneration();
-    }
-}
-
-void CursorInputMapper::configureParameters() {
-    mParameters.mode = Parameters::MODE_POINTER;
-    String8 cursorModeString;
-    if (getDevice()->getConfiguration().tryGetProperty(String8("cursor.mode"), cursorModeString)) {
-        if (cursorModeString == "navigation") {
-            mParameters.mode = Parameters::MODE_NAVIGATION;
-        } else if (cursorModeString != "pointer" && cursorModeString != "default") {
-            ALOGW("Invalid value for cursor.mode: '%s'", cursorModeString.string());
-        }
-    }
-
-    mParameters.orientationAware = false;
-    getDevice()->getConfiguration().tryGetProperty(String8("cursor.orientationAware"),
-            mParameters.orientationAware);
-
-    mParameters.hasAssociatedDisplay = false;
-    if (mParameters.mode == Parameters::MODE_POINTER || mParameters.orientationAware) {
-        mParameters.hasAssociatedDisplay = true;
-    }
-}
-
-void CursorInputMapper::dumpParameters(String8& dump) {
-    dump.append(INDENT3 "Parameters:\n");
-    dump.appendFormat(INDENT4 "HasAssociatedDisplay: %s\n",
-            toString(mParameters.hasAssociatedDisplay));
-
-    switch (mParameters.mode) {
-    case Parameters::MODE_POINTER:
-        dump.append(INDENT4 "Mode: pointer\n");
-        break;
-    case Parameters::MODE_NAVIGATION:
-        dump.append(INDENT4 "Mode: navigation\n");
-        break;
-    default:
-        ALOG_ASSERT(false);
-    }
-
-    dump.appendFormat(INDENT4 "OrientationAware: %s\n",
-            toString(mParameters.orientationAware));
-}
-
-void CursorInputMapper::reset(nsecs_t when) {
-    mButtonState = 0;
-    mDownTime = 0;
-
-    mPointerVelocityControl.reset();
-    mWheelXVelocityControl.reset();
-    mWheelYVelocityControl.reset();
-
-    mCursorButtonAccumulator.reset(getDevice());
-    mCursorMotionAccumulator.reset(getDevice());
-    mCursorScrollAccumulator.reset(getDevice());
-
-    InputMapper::reset(when);
-}
-
-void CursorInputMapper::process(const RawEvent* rawEvent) {
-    mCursorButtonAccumulator.process(rawEvent);
-    mCursorMotionAccumulator.process(rawEvent);
-    mCursorScrollAccumulator.process(rawEvent);
-
-    if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
-        sync(rawEvent->when);
-    }
-}
-
-void CursorInputMapper::sync(nsecs_t when) {
-    int32_t lastButtonState = mButtonState;
-    int32_t currentButtonState = mCursorButtonAccumulator.getButtonState();
-    mButtonState = currentButtonState;
-
-    bool wasDown = isPointerDown(lastButtonState);
-    bool down = isPointerDown(currentButtonState);
-    bool downChanged;
-    if (!wasDown && down) {
-        mDownTime = when;
-        downChanged = true;
-    } else if (wasDown && !down) {
-        downChanged = true;
-    } else {
-        downChanged = false;
-    }
-    nsecs_t downTime = mDownTime;
-    bool buttonsChanged = currentButtonState != lastButtonState;
-    bool buttonsPressed = currentButtonState & ~lastButtonState;
-
-    float deltaX = mCursorMotionAccumulator.getRelativeX() * mXScale;
-    float deltaY = mCursorMotionAccumulator.getRelativeY() * mYScale;
-    bool moved = deltaX != 0 || deltaY != 0;
-
-    // Rotate delta according to orientation if needed.
-    if (mParameters.orientationAware && mParameters.hasAssociatedDisplay
-            && (deltaX != 0.0f || deltaY != 0.0f)) {
-        rotateDelta(mOrientation, &deltaX, &deltaY);
-    }
-
-    // Move the pointer.
-    PointerProperties pointerProperties;
-    pointerProperties.clear();
-    pointerProperties.id = 0;
-    pointerProperties.toolType = AMOTION_EVENT_TOOL_TYPE_MOUSE;
-
-    PointerCoords pointerCoords;
-    pointerCoords.clear();
-
-    float vscroll = mCursorScrollAccumulator.getRelativeVWheel();
-    float hscroll = mCursorScrollAccumulator.getRelativeHWheel();
-    bool scrolled = vscroll != 0 || hscroll != 0;
-
-    mWheelYVelocityControl.move(when, NULL, &vscroll);
-    mWheelXVelocityControl.move(when, &hscroll, NULL);
-
-    mPointerVelocityControl.move(when, &deltaX, &deltaY);
-
-    int32_t displayId;
-    if (mPointerController != NULL) {
-        if (moved || scrolled || buttonsChanged) {
-            mPointerController->setPresentation(
-                    PointerControllerInterface::PRESENTATION_POINTER);
-
-            if (moved) {
-                mPointerController->move(deltaX, deltaY);
-            }
-
-            if (buttonsChanged) {
-                mPointerController->setButtonState(currentButtonState);
-            }
-
-            mPointerController->unfade(PointerControllerInterface::TRANSITION_IMMEDIATE);
-        }
-
-        float x, y;
-        mPointerController->getPosition(&x, &y);
-        pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x);
-        pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y);
-        displayId = ADISPLAY_ID_DEFAULT;
-    } else {
-        pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, deltaX);
-        pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, deltaY);
-        displayId = ADISPLAY_ID_NONE;
-    }
-
-    pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, down ? 1.0f : 0.0f);
-
-    // Moving an external trackball or mouse should wake the device.
-    // We don't do this for internal cursor devices to prevent them from waking up
-    // the device in your pocket.
-    // TODO: Use the input device configuration to control this behavior more finely.
-    uint32_t policyFlags = 0;
-    if ((buttonsPressed || moved || scrolled) && getDevice()->isExternal()) {
-        policyFlags |= POLICY_FLAG_WAKE_DROPPED;
-    }
-
-    // Synthesize key down from buttons if needed.
-    synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_DOWN, when, getDeviceId(), mSource,
-            policyFlags, lastButtonState, currentButtonState);
-
-    // Send motion event.
-    if (downChanged || moved || scrolled || buttonsChanged) {
-        int32_t metaState = mContext->getGlobalMetaState();
-        int32_t motionEventAction;
-        if (downChanged) {
-            motionEventAction = down ? AMOTION_EVENT_ACTION_DOWN : AMOTION_EVENT_ACTION_UP;
-        } else if (down || mPointerController == NULL) {
-            motionEventAction = AMOTION_EVENT_ACTION_MOVE;
-        } else {
-            motionEventAction = AMOTION_EVENT_ACTION_HOVER_MOVE;
-        }
-
-        NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
-                motionEventAction, 0, metaState, currentButtonState, 0,
-                displayId, 1, &pointerProperties, &pointerCoords,
-                mXPrecision, mYPrecision, downTime);
-        getListener()->notifyMotion(&args);
-
-        // Send hover move after UP to tell the application that the mouse is hovering now.
-        if (motionEventAction == AMOTION_EVENT_ACTION_UP
-                && mPointerController != NULL) {
-            NotifyMotionArgs hoverArgs(when, getDeviceId(), mSource, policyFlags,
-                    AMOTION_EVENT_ACTION_HOVER_MOVE, 0,
-                    metaState, currentButtonState, AMOTION_EVENT_EDGE_FLAG_NONE,
-                    displayId, 1, &pointerProperties, &pointerCoords,
-                    mXPrecision, mYPrecision, downTime);
-            getListener()->notifyMotion(&hoverArgs);
-        }
-
-        // Send scroll events.
-        if (scrolled) {
-            pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_VSCROLL, vscroll);
-            pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll);
-
-            NotifyMotionArgs scrollArgs(when, getDeviceId(), mSource, policyFlags,
-                    AMOTION_EVENT_ACTION_SCROLL, 0, metaState, currentButtonState,
-                    AMOTION_EVENT_EDGE_FLAG_NONE,
-                    displayId, 1, &pointerProperties, &pointerCoords,
-                    mXPrecision, mYPrecision, downTime);
-            getListener()->notifyMotion(&scrollArgs);
-        }
-    }
-
-    // Synthesize key up from buttons if needed.
-    synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_UP, when, getDeviceId(), mSource,
-            policyFlags, lastButtonState, currentButtonState);
-
-    mCursorMotionAccumulator.finishSync();
-    mCursorScrollAccumulator.finishSync();
-}
-
-int32_t CursorInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) {
-    if (scanCode >= BTN_MOUSE && scanCode < BTN_JOYSTICK) {
-        return getEventHub()->getScanCodeState(getDeviceId(), scanCode);
-    } else {
-        return AKEY_STATE_UNKNOWN;
-    }
-}
-
-void CursorInputMapper::fadePointer() {
-    if (mPointerController != NULL) {
-        mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL);
-    }
-}
-
-
-// --- TouchInputMapper ---
-
-TouchInputMapper::TouchInputMapper(InputDevice* device) :
-        InputMapper(device),
-        mSource(0), mDeviceMode(DEVICE_MODE_DISABLED),
-        mSurfaceWidth(-1), mSurfaceHeight(-1), mSurfaceLeft(0), mSurfaceTop(0),
-        mSurfaceOrientation(DISPLAY_ORIENTATION_0) {
-}
-
-TouchInputMapper::~TouchInputMapper() {
-}
-
-uint32_t TouchInputMapper::getSources() {
-    return mSource;
-}
-
-void TouchInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
-    InputMapper::populateDeviceInfo(info);
-
-    if (mDeviceMode != DEVICE_MODE_DISABLED) {
-        info->addMotionRange(mOrientedRanges.x);
-        info->addMotionRange(mOrientedRanges.y);
-        info->addMotionRange(mOrientedRanges.pressure);
-
-        if (mOrientedRanges.haveSize) {
-            info->addMotionRange(mOrientedRanges.size);
-        }
-
-        if (mOrientedRanges.haveTouchSize) {
-            info->addMotionRange(mOrientedRanges.touchMajor);
-            info->addMotionRange(mOrientedRanges.touchMinor);
-        }
-
-        if (mOrientedRanges.haveToolSize) {
-            info->addMotionRange(mOrientedRanges.toolMajor);
-            info->addMotionRange(mOrientedRanges.toolMinor);
-        }
-
-        if (mOrientedRanges.haveOrientation) {
-            info->addMotionRange(mOrientedRanges.orientation);
-        }
-
-        if (mOrientedRanges.haveDistance) {
-            info->addMotionRange(mOrientedRanges.distance);
-        }
-
-        if (mOrientedRanges.haveTilt) {
-            info->addMotionRange(mOrientedRanges.tilt);
-        }
-
-        if (mCursorScrollAccumulator.haveRelativeVWheel()) {
-            info->addMotionRange(AMOTION_EVENT_AXIS_VSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f,
-                    0.0f);
-        }
-        if (mCursorScrollAccumulator.haveRelativeHWheel()) {
-            info->addMotionRange(AMOTION_EVENT_AXIS_HSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f,
-                    0.0f);
-        }
-        if (mCalibration.coverageCalibration == Calibration::COVERAGE_CALIBRATION_BOX) {
-            const InputDeviceInfo::MotionRange& x = mOrientedRanges.x;
-            const InputDeviceInfo::MotionRange& y = mOrientedRanges.y;
-            info->addMotionRange(AMOTION_EVENT_AXIS_GENERIC_1, mSource, x.min, x.max, x.flat,
-                    x.fuzz, x.resolution);
-            info->addMotionRange(AMOTION_EVENT_AXIS_GENERIC_2, mSource, y.min, y.max, y.flat,
-                    y.fuzz, y.resolution);
-            info->addMotionRange(AMOTION_EVENT_AXIS_GENERIC_3, mSource, x.min, x.max, x.flat,
-                    x.fuzz, x.resolution);
-            info->addMotionRange(AMOTION_EVENT_AXIS_GENERIC_4, mSource, y.min, y.max, y.flat,
-                    y.fuzz, y.resolution);
-        }
-        info->setButtonUnderPad(mParameters.hasButtonUnderPad);
-    }
-}
-
-void TouchInputMapper::dump(String8& dump) {
-    dump.append(INDENT2 "Touch Input Mapper:\n");
-    dumpParameters(dump);
-    dumpVirtualKeys(dump);
-    dumpRawPointerAxes(dump);
-    dumpCalibration(dump);
-    dumpSurface(dump);
-
-    dump.appendFormat(INDENT3 "Translation and Scaling Factors:\n");
-    dump.appendFormat(INDENT4 "XTranslate: %0.3f\n", mXTranslate);
-    dump.appendFormat(INDENT4 "YTranslate: %0.3f\n", mYTranslate);
-    dump.appendFormat(INDENT4 "XScale: %0.3f\n", mXScale);
-    dump.appendFormat(INDENT4 "YScale: %0.3f\n", mYScale);
-    dump.appendFormat(INDENT4 "XPrecision: %0.3f\n", mXPrecision);
-    dump.appendFormat(INDENT4 "YPrecision: %0.3f\n", mYPrecision);
-    dump.appendFormat(INDENT4 "GeometricScale: %0.3f\n", mGeometricScale);
-    dump.appendFormat(INDENT4 "PressureScale: %0.3f\n", mPressureScale);
-    dump.appendFormat(INDENT4 "SizeScale: %0.3f\n", mSizeScale);
-    dump.appendFormat(INDENT4 "OrientationScale: %0.3f\n", mOrientationScale);
-    dump.appendFormat(INDENT4 "DistanceScale: %0.3f\n", mDistanceScale);
-    dump.appendFormat(INDENT4 "HaveTilt: %s\n", toString(mHaveTilt));
-    dump.appendFormat(INDENT4 "TiltXCenter: %0.3f\n", mTiltXCenter);
-    dump.appendFormat(INDENT4 "TiltXScale: %0.3f\n", mTiltXScale);
-    dump.appendFormat(INDENT4 "TiltYCenter: %0.3f\n", mTiltYCenter);
-    dump.appendFormat(INDENT4 "TiltYScale: %0.3f\n", mTiltYScale);
-
-    dump.appendFormat(INDENT3 "Last Button State: 0x%08x\n", mLastButtonState);
-
-    dump.appendFormat(INDENT3 "Last Raw Touch: pointerCount=%d\n",
-            mLastRawPointerData.pointerCount);
-    for (uint32_t i = 0; i < mLastRawPointerData.pointerCount; i++) {
-        const RawPointerData::Pointer& pointer = mLastRawPointerData.pointers[i];
-        dump.appendFormat(INDENT4 "[%d]: id=%d, x=%d, y=%d, pressure=%d, "
-                "touchMajor=%d, touchMinor=%d, toolMajor=%d, toolMinor=%d, "
-                "orientation=%d, tiltX=%d, tiltY=%d, distance=%d, "
-                "toolType=%d, isHovering=%s\n", i,
-                pointer.id, pointer.x, pointer.y, pointer.pressure,
-                pointer.touchMajor, pointer.touchMinor,
-                pointer.toolMajor, pointer.toolMinor,
-                pointer.orientation, pointer.tiltX, pointer.tiltY, pointer.distance,
-                pointer.toolType, toString(pointer.isHovering));
-    }
-
-    dump.appendFormat(INDENT3 "Last Cooked Touch: pointerCount=%d\n",
-            mLastCookedPointerData.pointerCount);
-    for (uint32_t i = 0; i < mLastCookedPointerData.pointerCount; i++) {
-        const PointerProperties& pointerProperties = mLastCookedPointerData.pointerProperties[i];
-        const PointerCoords& pointerCoords = mLastCookedPointerData.pointerCoords[i];
-        dump.appendFormat(INDENT4 "[%d]: id=%d, x=%0.3f, y=%0.3f, pressure=%0.3f, "
-                "touchMajor=%0.3f, touchMinor=%0.3f, toolMajor=%0.3f, toolMinor=%0.3f, "
-                "orientation=%0.3f, tilt=%0.3f, distance=%0.3f, "
-                "toolType=%d, isHovering=%s\n", i,
-                pointerProperties.id,
-                pointerCoords.getX(),
-                pointerCoords.getY(),
-                pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE),
-                pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR),
-                pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR),
-                pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR),
-                pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR),
-                pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION),
-                pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TILT),
-                pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_DISTANCE),
-                pointerProperties.toolType,
-                toString(mLastCookedPointerData.isHovering(i)));
-    }
-
-    if (mDeviceMode == DEVICE_MODE_POINTER) {
-        dump.appendFormat(INDENT3 "Pointer Gesture Detector:\n");
-        dump.appendFormat(INDENT4 "XMovementScale: %0.3f\n",
-                mPointerXMovementScale);
-        dump.appendFormat(INDENT4 "YMovementScale: %0.3f\n",
-                mPointerYMovementScale);
-        dump.appendFormat(INDENT4 "XZoomScale: %0.3f\n",
-                mPointerXZoomScale);
-        dump.appendFormat(INDENT4 "YZoomScale: %0.3f\n",
-                mPointerYZoomScale);
-        dump.appendFormat(INDENT4 "MaxSwipeWidth: %f\n",
-                mPointerGestureMaxSwipeWidth);
-    }
-}
-
-void TouchInputMapper::configure(nsecs_t when,
-        const InputReaderConfiguration* config, uint32_t changes) {
-    InputMapper::configure(when, config, changes);
-
-    mConfig = *config;
-
-    if (!changes) { // first time only
-        // Configure basic parameters.
-        configureParameters();
-
-        // Configure common accumulators.
-        mCursorScrollAccumulator.configure(getDevice());
-        mTouchButtonAccumulator.configure(getDevice());
-
-        // Configure absolute axis information.
-        configureRawPointerAxes();
-
-        // Prepare input device calibration.
-        parseCalibration();
-        resolveCalibration();
-    }
-
-    if (!changes || (changes & InputReaderConfiguration::CHANGE_POINTER_SPEED)) {
-        // Update pointer speed.
-        mPointerVelocityControl.setParameters(mConfig.pointerVelocityControlParameters);
-        mWheelXVelocityControl.setParameters(mConfig.wheelVelocityControlParameters);
-        mWheelYVelocityControl.setParameters(mConfig.wheelVelocityControlParameters);
-    }
-
-    bool resetNeeded = false;
-    if (!changes || (changes & (InputReaderConfiguration::CHANGE_DISPLAY_INFO
-            | InputReaderConfiguration::CHANGE_POINTER_GESTURE_ENABLEMENT
-            | InputReaderConfiguration::CHANGE_SHOW_TOUCHES))) {
-        // Configure device sources, surface dimensions, orientation and
-        // scaling factors.
-        configureSurface(when, &resetNeeded);
-    }
-
-    if (changes && resetNeeded) {
-        // Send reset, unless this is the first time the device has been configured,
-        // in which case the reader will call reset itself after all mappers are ready.
-        getDevice()->notifyReset(when);
-    }
-}
-
-void TouchInputMapper::configureParameters() {
-    // Use the pointer presentation mode for devices that do not support distinct
-    // multitouch.  The spot-based presentation relies on being able to accurately
-    // locate two or more fingers on the touch pad.
-    mParameters.gestureMode = getEventHub()->hasInputProperty(getDeviceId(), INPUT_PROP_SEMI_MT)
-            ? Parameters::GESTURE_MODE_POINTER : Parameters::GESTURE_MODE_SPOTS;
-
-    String8 gestureModeString;
-    if (getDevice()->getConfiguration().tryGetProperty(String8("touch.gestureMode"),
-            gestureModeString)) {
-        if (gestureModeString == "pointer") {
-            mParameters.gestureMode = Parameters::GESTURE_MODE_POINTER;
-        } else if (gestureModeString == "spots") {
-            mParameters.gestureMode = Parameters::GESTURE_MODE_SPOTS;
-        } else if (gestureModeString != "default") {
-            ALOGW("Invalid value for touch.gestureMode: '%s'", gestureModeString.string());
-        }
-    }
-
-    if (getEventHub()->hasInputProperty(getDeviceId(), INPUT_PROP_DIRECT)) {
-        // The device is a touch screen.
-        mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_SCREEN;
-    } else if (getEventHub()->hasInputProperty(getDeviceId(), INPUT_PROP_POINTER)) {
-        // The device is a pointing device like a track pad.
-        mParameters.deviceType = Parameters::DEVICE_TYPE_POINTER;
-    } else if (getEventHub()->hasRelativeAxis(getDeviceId(), REL_X)
-            || getEventHub()->hasRelativeAxis(getDeviceId(), REL_Y)) {
-        // The device is a cursor device with a touch pad attached.
-        // By default don't use the touch pad to move the pointer.
-        mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_PAD;
-    } else {
-        // The device is a touch pad of unknown purpose.
-        mParameters.deviceType = Parameters::DEVICE_TYPE_POINTER;
-    }
-
-    mParameters.hasButtonUnderPad=
-            getEventHub()->hasInputProperty(getDeviceId(), INPUT_PROP_BUTTONPAD);
-
-    String8 deviceTypeString;
-    if (getDevice()->getConfiguration().tryGetProperty(String8("touch.deviceType"),
-            deviceTypeString)) {
-        if (deviceTypeString == "touchScreen") {
-            mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_SCREEN;
-        } else if (deviceTypeString == "touchPad") {
-            mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_PAD;
-        } else if (deviceTypeString == "touchNavigation") {
-            mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_NAVIGATION;
-        } else if (deviceTypeString == "pointer") {
-            mParameters.deviceType = Parameters::DEVICE_TYPE_POINTER;
-        } else if (deviceTypeString != "default") {
-            ALOGW("Invalid value for touch.deviceType: '%s'", deviceTypeString.string());
-        }
-    }
-
-    mParameters.orientationAware = mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN;
-    getDevice()->getConfiguration().tryGetProperty(String8("touch.orientationAware"),
-            mParameters.orientationAware);
-
-    mParameters.hasAssociatedDisplay = false;
-    mParameters.associatedDisplayIsExternal = false;
-    if (mParameters.orientationAware
-            || mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN
-            || mParameters.deviceType == Parameters::DEVICE_TYPE_POINTER) {
-        mParameters.hasAssociatedDisplay = true;
-        mParameters.associatedDisplayIsExternal =
-                mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN
-                        && getDevice()->isExternal();
-    }
-}
-
-void TouchInputMapper::dumpParameters(String8& dump) {
-    dump.append(INDENT3 "Parameters:\n");
-
-    switch (mParameters.gestureMode) {
-    case Parameters::GESTURE_MODE_POINTER:
-        dump.append(INDENT4 "GestureMode: pointer\n");
-        break;
-    case Parameters::GESTURE_MODE_SPOTS:
-        dump.append(INDENT4 "GestureMode: spots\n");
-        break;
-    default:
-        assert(false);
-    }
-
-    switch (mParameters.deviceType) {
-    case Parameters::DEVICE_TYPE_TOUCH_SCREEN:
-        dump.append(INDENT4 "DeviceType: touchScreen\n");
-        break;
-    case Parameters::DEVICE_TYPE_TOUCH_PAD:
-        dump.append(INDENT4 "DeviceType: touchPad\n");
-        break;
-    case Parameters::DEVICE_TYPE_TOUCH_NAVIGATION:
-        dump.append(INDENT4 "DeviceType: touchNavigation\n");
-        break;
-    case Parameters::DEVICE_TYPE_POINTER:
-        dump.append(INDENT4 "DeviceType: pointer\n");
-        break;
-    default:
-        ALOG_ASSERT(false);
-    }
-
-    dump.appendFormat(INDENT4 "AssociatedDisplay: hasAssociatedDisplay=%s, isExternal=%s\n",
-            toString(mParameters.hasAssociatedDisplay),
-            toString(mParameters.associatedDisplayIsExternal));
-    dump.appendFormat(INDENT4 "OrientationAware: %s\n",
-            toString(mParameters.orientationAware));
-}
-
-void TouchInputMapper::configureRawPointerAxes() {
-    mRawPointerAxes.clear();
-}
-
-void TouchInputMapper::dumpRawPointerAxes(String8& dump) {
-    dump.append(INDENT3 "Raw Touch Axes:\n");
-    dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.x, "X");
-    dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.y, "Y");
-    dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.pressure, "Pressure");
-    dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.touchMajor, "TouchMajor");
-    dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.touchMinor, "TouchMinor");
-    dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.toolMajor, "ToolMajor");
-    dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.toolMinor, "ToolMinor");
-    dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.orientation, "Orientation");
-    dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.distance, "Distance");
-    dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.tiltX, "TiltX");
-    dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.tiltY, "TiltY");
-    dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.trackingId, "TrackingId");
-    dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.slot, "Slot");
-}
-
-void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) {
-    int32_t oldDeviceMode = mDeviceMode;
-
-    // Determine device mode.
-    if (mParameters.deviceType == Parameters::DEVICE_TYPE_POINTER
-            && mConfig.pointerGesturesEnabled) {
-        mSource = AINPUT_SOURCE_MOUSE;
-        mDeviceMode = DEVICE_MODE_POINTER;
-        if (hasStylus()) {
-            mSource |= AINPUT_SOURCE_STYLUS;
-        }
-    } else if (mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN
-            && mParameters.hasAssociatedDisplay) {
-        mSource = AINPUT_SOURCE_TOUCHSCREEN;
-        mDeviceMode = DEVICE_MODE_DIRECT;
-        if (hasStylus()) {
-            mSource |= AINPUT_SOURCE_STYLUS;
-        }
-    } else if (mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_NAVIGATION) {
-        mSource = AINPUT_SOURCE_TOUCH_NAVIGATION;
-        mDeviceMode = DEVICE_MODE_NAVIGATION;
-    } else {
-        mSource = AINPUT_SOURCE_TOUCHPAD;
-        mDeviceMode = DEVICE_MODE_UNSCALED;
-    }
-
-    // Ensure we have valid X and Y axes.
-    if (!mRawPointerAxes.x.valid || !mRawPointerAxes.y.valid) {
-        ALOGW(INDENT "Touch device '%s' did not report support for X or Y axis!  "
-                "The device will be inoperable.", getDeviceName().string());
-        mDeviceMode = DEVICE_MODE_DISABLED;
-        return;
-    }
-
-    // Raw width and height in the natural orientation.
-    int32_t rawWidth = mRawPointerAxes.x.maxValue - mRawPointerAxes.x.minValue + 1;
-    int32_t rawHeight = mRawPointerAxes.y.maxValue - mRawPointerAxes.y.minValue + 1;
-
-    // Get associated display dimensions.
-    DisplayViewport newViewport;
-    if (mParameters.hasAssociatedDisplay) {
-        if (!mConfig.getDisplayInfo(mParameters.associatedDisplayIsExternal, &newViewport)) {
-            ALOGI(INDENT "Touch device '%s' could not query the properties of its associated "
-                    "display.  The device will be inoperable until the display size "
-                    "becomes available.",
-                    getDeviceName().string());
-            mDeviceMode = DEVICE_MODE_DISABLED;
-            return;
-        }
-    } else {
-        newViewport.setNonDisplayViewport(rawWidth, rawHeight);
-    }
-    bool viewportChanged = mViewport != newViewport;
-    if (viewportChanged) {
-        mViewport = newViewport;
-
-        if (mDeviceMode == DEVICE_MODE_DIRECT || mDeviceMode == DEVICE_MODE_POINTER) {
-            // Convert rotated viewport to natural surface coordinates.
-            int32_t naturalLogicalWidth, naturalLogicalHeight;
-            int32_t naturalPhysicalWidth, naturalPhysicalHeight;
-            int32_t naturalPhysicalLeft, naturalPhysicalTop;
-            int32_t naturalDeviceWidth, naturalDeviceHeight;
-            switch (mViewport.orientation) {
-            case DISPLAY_ORIENTATION_90:
-                naturalLogicalWidth = mViewport.logicalBottom - mViewport.logicalTop;
-                naturalLogicalHeight = mViewport.logicalRight - mViewport.logicalLeft;
-                naturalPhysicalWidth = mViewport.physicalBottom - mViewport.physicalTop;
-                naturalPhysicalHeight = mViewport.physicalRight - mViewport.physicalLeft;
-                naturalPhysicalLeft = mViewport.deviceHeight - mViewport.physicalBottom;
-                naturalPhysicalTop = mViewport.physicalLeft;
-                naturalDeviceWidth = mViewport.deviceHeight;
-                naturalDeviceHeight = mViewport.deviceWidth;
-                break;
-            case DISPLAY_ORIENTATION_180:
-                naturalLogicalWidth = mViewport.logicalRight - mViewport.logicalLeft;
-                naturalLogicalHeight = mViewport.logicalBottom - mViewport.logicalTop;
-                naturalPhysicalWidth = mViewport.physicalRight - mViewport.physicalLeft;
-                naturalPhysicalHeight = mViewport.physicalBottom - mViewport.physicalTop;
-                naturalPhysicalLeft = mViewport.deviceWidth - mViewport.physicalRight;
-                naturalPhysicalTop = mViewport.deviceHeight - mViewport.physicalBottom;
-                naturalDeviceWidth = mViewport.deviceWidth;
-                naturalDeviceHeight = mViewport.deviceHeight;
-                break;
-            case DISPLAY_ORIENTATION_270:
-                naturalLogicalWidth = mViewport.logicalBottom - mViewport.logicalTop;
-                naturalLogicalHeight = mViewport.logicalRight - mViewport.logicalLeft;
-                naturalPhysicalWidth = mViewport.physicalBottom - mViewport.physicalTop;
-                naturalPhysicalHeight = mViewport.physicalRight - mViewport.physicalLeft;
-                naturalPhysicalLeft = mViewport.physicalTop;
-                naturalPhysicalTop = mViewport.deviceWidth - mViewport.physicalRight;
-                naturalDeviceWidth = mViewport.deviceHeight;
-                naturalDeviceHeight = mViewport.deviceWidth;
-                break;
-            case DISPLAY_ORIENTATION_0:
-            default:
-                naturalLogicalWidth = mViewport.logicalRight - mViewport.logicalLeft;
-                naturalLogicalHeight = mViewport.logicalBottom - mViewport.logicalTop;
-                naturalPhysicalWidth = mViewport.physicalRight - mViewport.physicalLeft;
-                naturalPhysicalHeight = mViewport.physicalBottom - mViewport.physicalTop;
-                naturalPhysicalLeft = mViewport.physicalLeft;
-                naturalPhysicalTop = mViewport.physicalTop;
-                naturalDeviceWidth = mViewport.deviceWidth;
-                naturalDeviceHeight = mViewport.deviceHeight;
-                break;
-            }
-
-            mSurfaceWidth = naturalLogicalWidth * naturalDeviceWidth / naturalPhysicalWidth;
-            mSurfaceHeight = naturalLogicalHeight * naturalDeviceHeight / naturalPhysicalHeight;
-            mSurfaceLeft = naturalPhysicalLeft * naturalLogicalWidth / naturalPhysicalWidth;
-            mSurfaceTop = naturalPhysicalTop * naturalLogicalHeight / naturalPhysicalHeight;
-
-            mSurfaceOrientation = mParameters.orientationAware ?
-                    mViewport.orientation : DISPLAY_ORIENTATION_0;
-        } else {
-            mSurfaceWidth = rawWidth;
-            mSurfaceHeight = rawHeight;
-            mSurfaceLeft = 0;
-            mSurfaceTop = 0;
-            mSurfaceOrientation = DISPLAY_ORIENTATION_0;
-        }
-    }
-
-    // If moving between pointer modes, need to reset some state.
-    bool deviceModeChanged = mDeviceMode != oldDeviceMode;
-    if (deviceModeChanged) {
-        mOrientedRanges.clear();
-    }
-
-    // Create pointer controller if needed.
-    if (mDeviceMode == DEVICE_MODE_POINTER ||
-            (mDeviceMode == DEVICE_MODE_DIRECT && mConfig.showTouches)) {
-        if (mPointerController == NULL) {
-            mPointerController = getPolicy()->obtainPointerController(getDeviceId());
-        }
-    } else {
-        mPointerController.clear();
-    }
-
-    if (viewportChanged || deviceModeChanged) {
-        ALOGI("Device reconfigured: id=%d, name='%s', size %dx%d, orientation %d, mode %d, "
-                "display id %d",
-                getDeviceId(), getDeviceName().string(), mSurfaceWidth, mSurfaceHeight,
-                mSurfaceOrientation, mDeviceMode, mViewport.displayId);
-
-        // Configure X and Y factors.
-        mXScale = float(mSurfaceWidth) / rawWidth;
-        mYScale = float(mSurfaceHeight) / rawHeight;
-        mXTranslate = -mSurfaceLeft;
-        mYTranslate = -mSurfaceTop;
-        mXPrecision = 1.0f / mXScale;
-        mYPrecision = 1.0f / mYScale;
-
-        mOrientedRanges.x.axis = AMOTION_EVENT_AXIS_X;
-        mOrientedRanges.x.source = mSource;
-        mOrientedRanges.y.axis = AMOTION_EVENT_AXIS_Y;
-        mOrientedRanges.y.source = mSource;
-
-        configureVirtualKeys();
-
-        // Scale factor for terms that are not oriented in a particular axis.
-        // If the pixels are square then xScale == yScale otherwise we fake it
-        // by choosing an average.
-        mGeometricScale = avg(mXScale, mYScale);
-
-        // Size of diagonal axis.
-        float diagonalSize = hypotf(mSurfaceWidth, mSurfaceHeight);
-
-        // Size factors.
-        if (mCalibration.sizeCalibration != Calibration::SIZE_CALIBRATION_NONE) {
-            if (mRawPointerAxes.touchMajor.valid
-                    && mRawPointerAxes.touchMajor.maxValue != 0) {
-                mSizeScale = 1.0f / mRawPointerAxes.touchMajor.maxValue;
-            } else if (mRawPointerAxes.toolMajor.valid
-                    && mRawPointerAxes.toolMajor.maxValue != 0) {
-                mSizeScale = 1.0f / mRawPointerAxes.toolMajor.maxValue;
-            } else {
-                mSizeScale = 0.0f;
-            }
-
-            mOrientedRanges.haveTouchSize = true;
-            mOrientedRanges.haveToolSize = true;
-            mOrientedRanges.haveSize = true;
-
-            mOrientedRanges.touchMajor.axis = AMOTION_EVENT_AXIS_TOUCH_MAJOR;
-            mOrientedRanges.touchMajor.source = mSource;
-            mOrientedRanges.touchMajor.min = 0;
-            mOrientedRanges.touchMajor.max = diagonalSize;
-            mOrientedRanges.touchMajor.flat = 0;
-            mOrientedRanges.touchMajor.fuzz = 0;
-            mOrientedRanges.touchMajor.resolution = 0;
-
-            mOrientedRanges.touchMinor = mOrientedRanges.touchMajor;
-            mOrientedRanges.touchMinor.axis = AMOTION_EVENT_AXIS_TOUCH_MINOR;
-
-            mOrientedRanges.toolMajor.axis = AMOTION_EVENT_AXIS_TOOL_MAJOR;
-            mOrientedRanges.toolMajor.source = mSource;
-            mOrientedRanges.toolMajor.min = 0;
-            mOrientedRanges.toolMajor.max = diagonalSize;
-            mOrientedRanges.toolMajor.flat = 0;
-            mOrientedRanges.toolMajor.fuzz = 0;
-            mOrientedRanges.toolMajor.resolution = 0;
-
-            mOrientedRanges.toolMinor = mOrientedRanges.toolMajor;
-            mOrientedRanges.toolMinor.axis = AMOTION_EVENT_AXIS_TOOL_MINOR;
-
-            mOrientedRanges.size.axis = AMOTION_EVENT_AXIS_SIZE;
-            mOrientedRanges.size.source = mSource;
-            mOrientedRanges.size.min = 0;
-            mOrientedRanges.size.max = 1.0;
-            mOrientedRanges.size.flat = 0;
-            mOrientedRanges.size.fuzz = 0;
-            mOrientedRanges.size.resolution = 0;
-        } else {
-            mSizeScale = 0.0f;
-        }
-
-        // Pressure factors.
-        mPressureScale = 0;
-        if (mCalibration.pressureCalibration == Calibration::PRESSURE_CALIBRATION_PHYSICAL
-                || mCalibration.pressureCalibration
-                        == Calibration::PRESSURE_CALIBRATION_AMPLITUDE) {
-            if (mCalibration.havePressureScale) {
-                mPressureScale = mCalibration.pressureScale;
-            } else if (mRawPointerAxes.pressure.valid
-                    && mRawPointerAxes.pressure.maxValue != 0) {
-                mPressureScale = 1.0f / mRawPointerAxes.pressure.maxValue;
-            }
-        }
-
-        mOrientedRanges.pressure.axis = AMOTION_EVENT_AXIS_PRESSURE;
-        mOrientedRanges.pressure.source = mSource;
-        mOrientedRanges.pressure.min = 0;
-        mOrientedRanges.pressure.max = 1.0;
-        mOrientedRanges.pressure.flat = 0;
-        mOrientedRanges.pressure.fuzz = 0;
-        mOrientedRanges.pressure.resolution = 0;
-
-        // Tilt
-        mTiltXCenter = 0;
-        mTiltXScale = 0;
-        mTiltYCenter = 0;
-        mTiltYScale = 0;
-        mHaveTilt = mRawPointerAxes.tiltX.valid && mRawPointerAxes.tiltY.valid;
-        if (mHaveTilt) {
-            mTiltXCenter = avg(mRawPointerAxes.tiltX.minValue,
-                    mRawPointerAxes.tiltX.maxValue);
-            mTiltYCenter = avg(mRawPointerAxes.tiltY.minValue,
-                    mRawPointerAxes.tiltY.maxValue);
-            mTiltXScale = M_PI / 180;
-            mTiltYScale = M_PI / 180;
-
-            mOrientedRanges.haveTilt = true;
-
-            mOrientedRanges.tilt.axis = AMOTION_EVENT_AXIS_TILT;
-            mOrientedRanges.tilt.source = mSource;
-            mOrientedRanges.tilt.min = 0;
-            mOrientedRanges.tilt.max = M_PI_2;
-            mOrientedRanges.tilt.flat = 0;
-            mOrientedRanges.tilt.fuzz = 0;
-            mOrientedRanges.tilt.resolution = 0;
-        }
-
-        // Orientation
-        mOrientationScale = 0;
-        if (mHaveTilt) {
-            mOrientedRanges.haveOrientation = true;
-
-            mOrientedRanges.orientation.axis = AMOTION_EVENT_AXIS_ORIENTATION;
-            mOrientedRanges.orientation.source = mSource;
-            mOrientedRanges.orientation.min = -M_PI;
-            mOrientedRanges.orientation.max = M_PI;
-            mOrientedRanges.orientation.flat = 0;
-            mOrientedRanges.orientation.fuzz = 0;
-            mOrientedRanges.orientation.resolution = 0;
-        } else if (mCalibration.orientationCalibration !=
-                Calibration::ORIENTATION_CALIBRATION_NONE) {
-            if (mCalibration.orientationCalibration
-                    == Calibration::ORIENTATION_CALIBRATION_INTERPOLATED) {
-                if (mRawPointerAxes.orientation.valid) {
-                    if (mRawPointerAxes.orientation.maxValue > 0) {
-                        mOrientationScale = M_PI_2 / mRawPointerAxes.orientation.maxValue;
-                    } else if (mRawPointerAxes.orientation.minValue < 0) {
-                        mOrientationScale = -M_PI_2 / mRawPointerAxes.orientation.minValue;
-                    } else {
-                        mOrientationScale = 0;
-                    }
-                }
-            }
-
-            mOrientedRanges.haveOrientation = true;
-
-            mOrientedRanges.orientation.axis = AMOTION_EVENT_AXIS_ORIENTATION;
-            mOrientedRanges.orientation.source = mSource;
-            mOrientedRanges.orientation.min = -M_PI_2;
-            mOrientedRanges.orientation.max = M_PI_2;
-            mOrientedRanges.orientation.flat = 0;
-            mOrientedRanges.orientation.fuzz = 0;
-            mOrientedRanges.orientation.resolution = 0;
-        }
-
-        // Distance
-        mDistanceScale = 0;
-        if (mCalibration.distanceCalibration != Calibration::DISTANCE_CALIBRATION_NONE) {
-            if (mCalibration.distanceCalibration
-                    == Calibration::DISTANCE_CALIBRATION_SCALED) {
-                if (mCalibration.haveDistanceScale) {
-                    mDistanceScale = mCalibration.distanceScale;
-                } else {
-                    mDistanceScale = 1.0f;
-                }
-            }
-
-            mOrientedRanges.haveDistance = true;
-
-            mOrientedRanges.distance.axis = AMOTION_EVENT_AXIS_DISTANCE;
-            mOrientedRanges.distance.source = mSource;
-            mOrientedRanges.distance.min =
-                    mRawPointerAxes.distance.minValue * mDistanceScale;
-            mOrientedRanges.distance.max =
-                    mRawPointerAxes.distance.maxValue * mDistanceScale;
-            mOrientedRanges.distance.flat = 0;
-            mOrientedRanges.distance.fuzz =
-                    mRawPointerAxes.distance.fuzz * mDistanceScale;
-            mOrientedRanges.distance.resolution = 0;
-        }
-
-        // Compute oriented precision, scales and ranges.
-        // Note that the maximum value reported is an inclusive maximum value so it is one
-        // unit less than the total width or height of surface.
-        switch (mSurfaceOrientation) {
-        case DISPLAY_ORIENTATION_90:
-        case DISPLAY_ORIENTATION_270:
-            mOrientedXPrecision = mYPrecision;
-            mOrientedYPrecision = mXPrecision;
-
-            mOrientedRanges.x.min = mYTranslate;
-            mOrientedRanges.x.max = mSurfaceHeight + mYTranslate - 1;
-            mOrientedRanges.x.flat = 0;
-            mOrientedRanges.x.fuzz = 0;
-            mOrientedRanges.x.resolution = mRawPointerAxes.y.resolution * mYScale;
-
-            mOrientedRanges.y.min = mXTranslate;
-            mOrientedRanges.y.max = mSurfaceWidth + mXTranslate - 1;
-            mOrientedRanges.y.flat = 0;
-            mOrientedRanges.y.fuzz = 0;
-            mOrientedRanges.y.resolution = mRawPointerAxes.x.resolution * mXScale;
-            break;
-
-        default:
-            mOrientedXPrecision = mXPrecision;
-            mOrientedYPrecision = mYPrecision;
-
-            mOrientedRanges.x.min = mXTranslate;
-            mOrientedRanges.x.max = mSurfaceWidth + mXTranslate - 1;
-            mOrientedRanges.x.flat = 0;
-            mOrientedRanges.x.fuzz = 0;
-            mOrientedRanges.x.resolution = mRawPointerAxes.x.resolution * mXScale;
-
-            mOrientedRanges.y.min = mYTranslate;
-            mOrientedRanges.y.max = mSurfaceHeight + mYTranslate - 1;
-            mOrientedRanges.y.flat = 0;
-            mOrientedRanges.y.fuzz = 0;
-            mOrientedRanges.y.resolution = mRawPointerAxes.y.resolution * mYScale;
-            break;
-        }
-
-        if (mDeviceMode == DEVICE_MODE_POINTER) {
-            // Compute pointer gesture detection parameters.
-            float rawDiagonal = hypotf(rawWidth, rawHeight);
-            float displayDiagonal = hypotf(mSurfaceWidth, mSurfaceHeight);
-
-            // Scale movements such that one whole swipe of the touch pad covers a
-            // given area relative to the diagonal size of the display when no acceleration
-            // is applied.
-            // Assume that the touch pad has a square aspect ratio such that movements in
-            // X and Y of the same number of raw units cover the same physical distance.
-            mPointerXMovementScale = mConfig.pointerGestureMovementSpeedRatio
-                    * displayDiagonal / rawDiagonal;
-            mPointerYMovementScale = mPointerXMovementScale;
-
-            // Scale zooms to cover a smaller range of the display than movements do.
-            // This value determines the area around the pointer that is affected by freeform
-            // pointer gestures.
-            mPointerXZoomScale = mConfig.pointerGestureZoomSpeedRatio
-                    * displayDiagonal / rawDiagonal;
-            mPointerYZoomScale = mPointerXZoomScale;
-
-            // Max width between pointers to detect a swipe gesture is more than some fraction
-            // of the diagonal axis of the touch pad.  Touches that are wider than this are
-            // translated into freeform gestures.
-            mPointerGestureMaxSwipeWidth =
-                    mConfig.pointerGestureSwipeMaxWidthRatio * rawDiagonal;
-
-            // Abort current pointer usages because the state has changed.
-            abortPointerUsage(when, 0 /*policyFlags*/);
-        }
-
-        // Inform the dispatcher about the changes.
-        *outResetNeeded = true;
-        bumpGeneration();
-    }
-}
-
-void TouchInputMapper::dumpSurface(String8& dump) {
-    dump.appendFormat(INDENT3 "Viewport: displayId=%d, orientation=%d, "
-            "logicalFrame=[%d, %d, %d, %d], "
-            "physicalFrame=[%d, %d, %d, %d], "
-            "deviceSize=[%d, %d]\n",
-            mViewport.displayId, mViewport.orientation,
-            mViewport.logicalLeft, mViewport.logicalTop,
-            mViewport.logicalRight, mViewport.logicalBottom,
-            mViewport.physicalLeft, mViewport.physicalTop,
-            mViewport.physicalRight, mViewport.physicalBottom,
-            mViewport.deviceWidth, mViewport.deviceHeight);
-
-    dump.appendFormat(INDENT3 "SurfaceWidth: %dpx\n", mSurfaceWidth);
-    dump.appendFormat(INDENT3 "SurfaceHeight: %dpx\n", mSurfaceHeight);
-    dump.appendFormat(INDENT3 "SurfaceLeft: %d\n", mSurfaceLeft);
-    dump.appendFormat(INDENT3 "SurfaceTop: %d\n", mSurfaceTop);
-    dump.appendFormat(INDENT3 "SurfaceOrientation: %d\n", mSurfaceOrientation);
-}
-
-void TouchInputMapper::configureVirtualKeys() {
-    Vector<VirtualKeyDefinition> virtualKeyDefinitions;
-    getEventHub()->getVirtualKeyDefinitions(getDeviceId(), virtualKeyDefinitions);
-
-    mVirtualKeys.clear();
-
-    if (virtualKeyDefinitions.size() == 0) {
-        return;
-    }
-
-    mVirtualKeys.setCapacity(virtualKeyDefinitions.size());
-
-    int32_t touchScreenLeft = mRawPointerAxes.x.minValue;
-    int32_t touchScreenTop = mRawPointerAxes.y.minValue;
-    int32_t touchScreenWidth = mRawPointerAxes.x.maxValue - mRawPointerAxes.x.minValue + 1;
-    int32_t touchScreenHeight = mRawPointerAxes.y.maxValue - mRawPointerAxes.y.minValue + 1;
-
-    for (size_t i = 0; i < virtualKeyDefinitions.size(); i++) {
-        const VirtualKeyDefinition& virtualKeyDefinition =
-                virtualKeyDefinitions[i];
-
-        mVirtualKeys.add();
-        VirtualKey& virtualKey = mVirtualKeys.editTop();
-
-        virtualKey.scanCode = virtualKeyDefinition.scanCode;
-        int32_t keyCode;
-        uint32_t flags;
-        if (getEventHub()->mapKey(getDeviceId(), virtualKey.scanCode, 0, &keyCode, &flags)) {
-            ALOGW(INDENT "VirtualKey %d: could not obtain key code, ignoring",
-                    virtualKey.scanCode);
-            mVirtualKeys.pop(); // drop the key
-            continue;
-        }
-
-        virtualKey.keyCode = keyCode;
-        virtualKey.flags = flags;
-
-        // convert the key definition's display coordinates into touch coordinates for a hit box
-        int32_t halfWidth = virtualKeyDefinition.width / 2;
-        int32_t halfHeight = virtualKeyDefinition.height / 2;
-
-        virtualKey.hitLeft = (virtualKeyDefinition.centerX - halfWidth)
-                * touchScreenWidth / mSurfaceWidth + touchScreenLeft;
-        virtualKey.hitRight= (virtualKeyDefinition.centerX + halfWidth)
-                * touchScreenWidth / mSurfaceWidth + touchScreenLeft;
-        virtualKey.hitTop = (virtualKeyDefinition.centerY - halfHeight)
-                * touchScreenHeight / mSurfaceHeight + touchScreenTop;
-        virtualKey.hitBottom = (virtualKeyDefinition.centerY + halfHeight)
-                * touchScreenHeight / mSurfaceHeight + touchScreenTop;
-    }
-}
-
-void TouchInputMapper::dumpVirtualKeys(String8& dump) {
-    if (!mVirtualKeys.isEmpty()) {
-        dump.append(INDENT3 "Virtual Keys:\n");
-
-        for (size_t i = 0; i < mVirtualKeys.size(); i++) {
-            const VirtualKey& virtualKey = mVirtualKeys.itemAt(i);
-            dump.appendFormat(INDENT4 "%d: scanCode=%d, keyCode=%d, "
-                    "hitLeft=%d, hitRight=%d, hitTop=%d, hitBottom=%d\n",
-                    i, virtualKey.scanCode, virtualKey.keyCode,
-                    virtualKey.hitLeft, virtualKey.hitRight,
-                    virtualKey.hitTop, virtualKey.hitBottom);
-        }
-    }
-}
-
-void TouchInputMapper::parseCalibration() {
-    const PropertyMap& in = getDevice()->getConfiguration();
-    Calibration& out = mCalibration;
-
-    // Size
-    out.sizeCalibration = Calibration::SIZE_CALIBRATION_DEFAULT;
-    String8 sizeCalibrationString;
-    if (in.tryGetProperty(String8("touch.size.calibration"), sizeCalibrationString)) {
-        if (sizeCalibrationString == "none") {
-            out.sizeCalibration = Calibration::SIZE_CALIBRATION_NONE;
-        } else if (sizeCalibrationString == "geometric") {
-            out.sizeCalibration = Calibration::SIZE_CALIBRATION_GEOMETRIC;
-        } else if (sizeCalibrationString == "diameter") {
-            out.sizeCalibration = Calibration::SIZE_CALIBRATION_DIAMETER;
-        } else if (sizeCalibrationString == "box") {
-            out.sizeCalibration = Calibration::SIZE_CALIBRATION_BOX;
-        } else if (sizeCalibrationString == "area") {
-            out.sizeCalibration = Calibration::SIZE_CALIBRATION_AREA;
-        } else if (sizeCalibrationString != "default") {
-            ALOGW("Invalid value for touch.size.calibration: '%s'",
-                    sizeCalibrationString.string());
-        }
-    }
-
-    out.haveSizeScale = in.tryGetProperty(String8("touch.size.scale"),
-            out.sizeScale);
-    out.haveSizeBias = in.tryGetProperty(String8("touch.size.bias"),
-            out.sizeBias);
-    out.haveSizeIsSummed = in.tryGetProperty(String8("touch.size.isSummed"),
-            out.sizeIsSummed);
-
-    // Pressure
-    out.pressureCalibration = Calibration::PRESSURE_CALIBRATION_DEFAULT;
-    String8 pressureCalibrationString;
-    if (in.tryGetProperty(String8("touch.pressure.calibration"), pressureCalibrationString)) {
-        if (pressureCalibrationString == "none") {
-            out.pressureCalibration = Calibration::PRESSURE_CALIBRATION_NONE;
-        } else if (pressureCalibrationString == "physical") {
-            out.pressureCalibration = Calibration::PRESSURE_CALIBRATION_PHYSICAL;
-        } else if (pressureCalibrationString == "amplitude") {
-            out.pressureCalibration = Calibration::PRESSURE_CALIBRATION_AMPLITUDE;
-        } else if (pressureCalibrationString != "default") {
-            ALOGW("Invalid value for touch.pressure.calibration: '%s'",
-                    pressureCalibrationString.string());
-        }
-    }
-
-    out.havePressureScale = in.tryGetProperty(String8("touch.pressure.scale"),
-            out.pressureScale);
-
-    // Orientation
-    out.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_DEFAULT;
-    String8 orientationCalibrationString;
-    if (in.tryGetProperty(String8("touch.orientation.calibration"), orientationCalibrationString)) {
-        if (orientationCalibrationString == "none") {
-            out.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_NONE;
-        } else if (orientationCalibrationString == "interpolated") {
-            out.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_INTERPOLATED;
-        } else if (orientationCalibrationString == "vector") {
-            out.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_VECTOR;
-        } else if (orientationCalibrationString != "default") {
-            ALOGW("Invalid value for touch.orientation.calibration: '%s'",
-                    orientationCalibrationString.string());
-        }
-    }
-
-    // Distance
-    out.distanceCalibration = Calibration::DISTANCE_CALIBRATION_DEFAULT;
-    String8 distanceCalibrationString;
-    if (in.tryGetProperty(String8("touch.distance.calibration"), distanceCalibrationString)) {
-        if (distanceCalibrationString == "none") {
-            out.distanceCalibration = Calibration::DISTANCE_CALIBRATION_NONE;
-        } else if (distanceCalibrationString == "scaled") {
-            out.distanceCalibration = Calibration::DISTANCE_CALIBRATION_SCALED;
-        } else if (distanceCalibrationString != "default") {
-            ALOGW("Invalid value for touch.distance.calibration: '%s'",
-                    distanceCalibrationString.string());
-        }
-    }
-
-    out.haveDistanceScale = in.tryGetProperty(String8("touch.distance.scale"),
-            out.distanceScale);
-
-    out.coverageCalibration = Calibration::COVERAGE_CALIBRATION_DEFAULT;
-    String8 coverageCalibrationString;
-    if (in.tryGetProperty(String8("touch.coverage.calibration"), coverageCalibrationString)) {
-        if (coverageCalibrationString == "none") {
-            out.coverageCalibration = Calibration::COVERAGE_CALIBRATION_NONE;
-        } else if (coverageCalibrationString == "box") {
-            out.coverageCalibration = Calibration::COVERAGE_CALIBRATION_BOX;
-        } else if (coverageCalibrationString != "default") {
-            ALOGW("Invalid value for touch.coverage.calibration: '%s'",
-                    coverageCalibrationString.string());
-        }
-    }
-}
-
-void TouchInputMapper::resolveCalibration() {
-    // Size
-    if (mRawPointerAxes.touchMajor.valid || mRawPointerAxes.toolMajor.valid) {
-        if (mCalibration.sizeCalibration == Calibration::SIZE_CALIBRATION_DEFAULT) {
-            mCalibration.sizeCalibration = Calibration::SIZE_CALIBRATION_GEOMETRIC;
-        }
-    } else {
-        mCalibration.sizeCalibration = Calibration::SIZE_CALIBRATION_NONE;
-    }
-
-    // Pressure
-    if (mRawPointerAxes.pressure.valid) {
-        if (mCalibration.pressureCalibration == Calibration::PRESSURE_CALIBRATION_DEFAULT) {
-            mCalibration.pressureCalibration = Calibration::PRESSURE_CALIBRATION_PHYSICAL;
-        }
-    } else {
-        mCalibration.pressureCalibration = Calibration::PRESSURE_CALIBRATION_NONE;
-    }
-
-    // Orientation
-    if (mRawPointerAxes.orientation.valid) {
-        if (mCalibration.orientationCalibration == Calibration::ORIENTATION_CALIBRATION_DEFAULT) {
-            mCalibration.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_INTERPOLATED;
-        }
-    } else {
-        mCalibration.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_NONE;
-    }
-
-    // Distance
-    if (mRawPointerAxes.distance.valid) {
-        if (mCalibration.distanceCalibration == Calibration::DISTANCE_CALIBRATION_DEFAULT) {
-            mCalibration.distanceCalibration = Calibration::DISTANCE_CALIBRATION_SCALED;
-        }
-    } else {
-        mCalibration.distanceCalibration = Calibration::DISTANCE_CALIBRATION_NONE;
-    }
-
-    // Coverage
-    if (mCalibration.coverageCalibration == Calibration::COVERAGE_CALIBRATION_DEFAULT) {
-        mCalibration.coverageCalibration = Calibration::COVERAGE_CALIBRATION_NONE;
-    }
-}
-
-void TouchInputMapper::dumpCalibration(String8& dump) {
-    dump.append(INDENT3 "Calibration:\n");
-
-    // Size
-    switch (mCalibration.sizeCalibration) {
-    case Calibration::SIZE_CALIBRATION_NONE:
-        dump.append(INDENT4 "touch.size.calibration: none\n");
-        break;
-    case Calibration::SIZE_CALIBRATION_GEOMETRIC:
-        dump.append(INDENT4 "touch.size.calibration: geometric\n");
-        break;
-    case Calibration::SIZE_CALIBRATION_DIAMETER:
-        dump.append(INDENT4 "touch.size.calibration: diameter\n");
-        break;
-    case Calibration::SIZE_CALIBRATION_BOX:
-        dump.append(INDENT4 "touch.size.calibration: box\n");
-        break;
-    case Calibration::SIZE_CALIBRATION_AREA:
-        dump.append(INDENT4 "touch.size.calibration: area\n");
-        break;
-    default:
-        ALOG_ASSERT(false);
-    }
-
-    if (mCalibration.haveSizeScale) {
-        dump.appendFormat(INDENT4 "touch.size.scale: %0.3f\n",
-                mCalibration.sizeScale);
-    }
-
-    if (mCalibration.haveSizeBias) {
-        dump.appendFormat(INDENT4 "touch.size.bias: %0.3f\n",
-                mCalibration.sizeBias);
-    }
-
-    if (mCalibration.haveSizeIsSummed) {
-        dump.appendFormat(INDENT4 "touch.size.isSummed: %s\n",
-                toString(mCalibration.sizeIsSummed));
-    }
-
-    // Pressure
-    switch (mCalibration.pressureCalibration) {
-    case Calibration::PRESSURE_CALIBRATION_NONE:
-        dump.append(INDENT4 "touch.pressure.calibration: none\n");
-        break;
-    case Calibration::PRESSURE_CALIBRATION_PHYSICAL:
-        dump.append(INDENT4 "touch.pressure.calibration: physical\n");
-        break;
-    case Calibration::PRESSURE_CALIBRATION_AMPLITUDE:
-        dump.append(INDENT4 "touch.pressure.calibration: amplitude\n");
-        break;
-    default:
-        ALOG_ASSERT(false);
-    }
-
-    if (mCalibration.havePressureScale) {
-        dump.appendFormat(INDENT4 "touch.pressure.scale: %0.3f\n",
-                mCalibration.pressureScale);
-    }
-
-    // Orientation
-    switch (mCalibration.orientationCalibration) {
-    case Calibration::ORIENTATION_CALIBRATION_NONE:
-        dump.append(INDENT4 "touch.orientation.calibration: none\n");
-        break;
-    case Calibration::ORIENTATION_CALIBRATION_INTERPOLATED:
-        dump.append(INDENT4 "touch.orientation.calibration: interpolated\n");
-        break;
-    case Calibration::ORIENTATION_CALIBRATION_VECTOR:
-        dump.append(INDENT4 "touch.orientation.calibration: vector\n");
-        break;
-    default:
-        ALOG_ASSERT(false);
-    }
-
-    // Distance
-    switch (mCalibration.distanceCalibration) {
-    case Calibration::DISTANCE_CALIBRATION_NONE:
-        dump.append(INDENT4 "touch.distance.calibration: none\n");
-        break;
-    case Calibration::DISTANCE_CALIBRATION_SCALED:
-        dump.append(INDENT4 "touch.distance.calibration: scaled\n");
-        break;
-    default:
-        ALOG_ASSERT(false);
-    }
-
-    if (mCalibration.haveDistanceScale) {
-        dump.appendFormat(INDENT4 "touch.distance.scale: %0.3f\n",
-                mCalibration.distanceScale);
-    }
-
-    switch (mCalibration.coverageCalibration) {
-    case Calibration::COVERAGE_CALIBRATION_NONE:
-        dump.append(INDENT4 "touch.coverage.calibration: none\n");
-        break;
-    case Calibration::COVERAGE_CALIBRATION_BOX:
-        dump.append(INDENT4 "touch.coverage.calibration: box\n");
-        break;
-    default:
-        ALOG_ASSERT(false);
-    }
-}
-
-void TouchInputMapper::reset(nsecs_t when) {
-    mCursorButtonAccumulator.reset(getDevice());
-    mCursorScrollAccumulator.reset(getDevice());
-    mTouchButtonAccumulator.reset(getDevice());
-
-    mPointerVelocityControl.reset();
-    mWheelXVelocityControl.reset();
-    mWheelYVelocityControl.reset();
-
-    mCurrentRawPointerData.clear();
-    mLastRawPointerData.clear();
-    mCurrentCookedPointerData.clear();
-    mLastCookedPointerData.clear();
-    mCurrentButtonState = 0;
-    mLastButtonState = 0;
-    mCurrentRawVScroll = 0;
-    mCurrentRawHScroll = 0;
-    mCurrentFingerIdBits.clear();
-    mLastFingerIdBits.clear();
-    mCurrentStylusIdBits.clear();
-    mLastStylusIdBits.clear();
-    mCurrentMouseIdBits.clear();
-    mLastMouseIdBits.clear();
-    mPointerUsage = POINTER_USAGE_NONE;
-    mSentHoverEnter = false;
-    mDownTime = 0;
-
-    mCurrentVirtualKey.down = false;
-
-    mPointerGesture.reset();
-    mPointerSimple.reset();
-
-    if (mPointerController != NULL) {
-        mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL);
-        mPointerController->clearSpots();
-    }
-
-    InputMapper::reset(when);
-}
-
-void TouchInputMapper::process(const RawEvent* rawEvent) {
-    mCursorButtonAccumulator.process(rawEvent);
-    mCursorScrollAccumulator.process(rawEvent);
-    mTouchButtonAccumulator.process(rawEvent);
-
-    if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
-        sync(rawEvent->when);
-    }
-}
-
-void TouchInputMapper::sync(nsecs_t when) {
-    // Sync button state.
-    mCurrentButtonState = mTouchButtonAccumulator.getButtonState()
-            | mCursorButtonAccumulator.getButtonState();
-
-    // Sync scroll state.
-    mCurrentRawVScroll = mCursorScrollAccumulator.getRelativeVWheel();
-    mCurrentRawHScroll = mCursorScrollAccumulator.getRelativeHWheel();
-    mCursorScrollAccumulator.finishSync();
-
-    // Sync touch state.
-    bool havePointerIds = true;
-    mCurrentRawPointerData.clear();
-    syncTouch(when, &havePointerIds);
-
-#if DEBUG_RAW_EVENTS
-    if (!havePointerIds) {
-        ALOGD("syncTouch: pointerCount %d -> %d, no pointer ids",
-                mLastRawPointerData.pointerCount,
-                mCurrentRawPointerData.pointerCount);
-    } else {
-        ALOGD("syncTouch: pointerCount %d -> %d, touching ids 0x%08x -> 0x%08x, "
-                "hovering ids 0x%08x -> 0x%08x",
-                mLastRawPointerData.pointerCount,
-                mCurrentRawPointerData.pointerCount,
-                mLastRawPointerData.touchingIdBits.value,
-                mCurrentRawPointerData.touchingIdBits.value,
-                mLastRawPointerData.hoveringIdBits.value,
-                mCurrentRawPointerData.hoveringIdBits.value);
-    }
-#endif
-
-    // Reset state that we will compute below.
-    mCurrentFingerIdBits.clear();
-    mCurrentStylusIdBits.clear();
-    mCurrentMouseIdBits.clear();
-    mCurrentCookedPointerData.clear();
-
-    if (mDeviceMode == DEVICE_MODE_DISABLED) {
-        // Drop all input if the device is disabled.
-        mCurrentRawPointerData.clear();
-        mCurrentButtonState = 0;
-    } else {
-        // Preprocess pointer data.
-        if (!havePointerIds) {
-            assignPointerIds();
-        }
-
-        // Handle policy on initial down or hover events.
-        uint32_t policyFlags = 0;
-        bool initialDown = mLastRawPointerData.pointerCount == 0
-                && mCurrentRawPointerData.pointerCount != 0;
-        bool buttonsPressed = mCurrentButtonState & ~mLastButtonState;
-        if (initialDown || buttonsPressed) {
-            // If this is a touch screen, hide the pointer on an initial down.
-            if (mDeviceMode == DEVICE_MODE_DIRECT) {
-                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()) {
-                policyFlags |= POLICY_FLAG_WAKE_DROPPED;
-            }
-        }
-
-        // Synthesize key down from raw buttons if needed.
-        synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_DOWN, when, getDeviceId(), mSource,
-                policyFlags, mLastButtonState, mCurrentButtonState);
-
-        // Consume raw off-screen touches before cooking pointer data.
-        // If touches are consumed, subsequent code will not receive any pointer data.
-        if (consumeRawTouches(when, policyFlags)) {
-            mCurrentRawPointerData.clear();
-        }
-
-        // Cook pointer data.  This call populates the mCurrentCookedPointerData structure
-        // with cooked pointer data that has the same ids and indices as the raw data.
-        // The following code can use either the raw or cooked data, as needed.
-        cookPointerData();
-
-        // Dispatch the touches either directly or by translation through a pointer on screen.
-        if (mDeviceMode == DEVICE_MODE_POINTER) {
-            for (BitSet32 idBits(mCurrentRawPointerData.touchingIdBits); !idBits.isEmpty(); ) {
-                uint32_t id = idBits.clearFirstMarkedBit();
-                const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(id);
-                if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS
-                        || pointer.toolType == AMOTION_EVENT_TOOL_TYPE_ERASER) {
-                    mCurrentStylusIdBits.markBit(id);
-                } else if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_FINGER
-                        || pointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) {
-                    mCurrentFingerIdBits.markBit(id);
-                } else if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_MOUSE) {
-                    mCurrentMouseIdBits.markBit(id);
-                }
-            }
-            for (BitSet32 idBits(mCurrentRawPointerData.hoveringIdBits); !idBits.isEmpty(); ) {
-                uint32_t id = idBits.clearFirstMarkedBit();
-                const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(id);
-                if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS
-                        || pointer.toolType == AMOTION_EVENT_TOOL_TYPE_ERASER) {
-                    mCurrentStylusIdBits.markBit(id);
-                }
-            }
-
-            // Stylus takes precedence over all tools, then mouse, then finger.
-            PointerUsage pointerUsage = mPointerUsage;
-            if (!mCurrentStylusIdBits.isEmpty()) {
-                mCurrentMouseIdBits.clear();
-                mCurrentFingerIdBits.clear();
-                pointerUsage = POINTER_USAGE_STYLUS;
-            } else if (!mCurrentMouseIdBits.isEmpty()) {
-                mCurrentFingerIdBits.clear();
-                pointerUsage = POINTER_USAGE_MOUSE;
-            } else if (!mCurrentFingerIdBits.isEmpty() || isPointerDown(mCurrentButtonState)) {
-                pointerUsage = POINTER_USAGE_GESTURES;
-            }
-
-            dispatchPointerUsage(when, policyFlags, pointerUsage);
-        } else {
-            if (mDeviceMode == DEVICE_MODE_DIRECT
-                    && mConfig.showTouches && mPointerController != NULL) {
-                mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_SPOT);
-                mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL);
-
-                mPointerController->setButtonState(mCurrentButtonState);
-                mPointerController->setSpots(mCurrentCookedPointerData.pointerCoords,
-                        mCurrentCookedPointerData.idToIndex,
-                        mCurrentCookedPointerData.touchingIdBits);
-            }
-
-            dispatchHoverExit(when, policyFlags);
-            dispatchTouches(when, policyFlags);
-            dispatchHoverEnterAndMove(when, policyFlags);
-        }
-
-        // Synthesize key up from raw buttons if needed.
-        synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_UP, when, getDeviceId(), mSource,
-                policyFlags, mLastButtonState, mCurrentButtonState);
-    }
-
-    // Copy current touch to last touch in preparation for the next cycle.
-    mLastRawPointerData.copyFrom(mCurrentRawPointerData);
-    mLastCookedPointerData.copyFrom(mCurrentCookedPointerData);
-    mLastButtonState = mCurrentButtonState;
-    mLastFingerIdBits = mCurrentFingerIdBits;
-    mLastStylusIdBits = mCurrentStylusIdBits;
-    mLastMouseIdBits = mCurrentMouseIdBits;
-
-    // Clear some transient state.
-    mCurrentRawVScroll = 0;
-    mCurrentRawHScroll = 0;
-}
-
-void TouchInputMapper::timeoutExpired(nsecs_t when) {
-    if (mDeviceMode == DEVICE_MODE_POINTER) {
-        if (mPointerUsage == POINTER_USAGE_GESTURES) {
-            dispatchPointerGestures(when, 0 /*policyFlags*/, true /*isTimeout*/);
-        }
-    }
-}
-
-bool TouchInputMapper::consumeRawTouches(nsecs_t when, uint32_t policyFlags) {
-    // Check for release of a virtual key.
-    if (mCurrentVirtualKey.down) {
-        if (mCurrentRawPointerData.touchingIdBits.isEmpty()) {
-            // Pointer went up while virtual key was down.
-            mCurrentVirtualKey.down = false;
-            if (!mCurrentVirtualKey.ignored) {
-#if DEBUG_VIRTUAL_KEYS
-                ALOGD("VirtualKeys: Generating key up: keyCode=%d, scanCode=%d",
-                        mCurrentVirtualKey.keyCode, mCurrentVirtualKey.scanCode);
-#endif
-                dispatchVirtualKey(when, policyFlags,
-                        AKEY_EVENT_ACTION_UP,
-                        AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY);
-            }
-            return true;
-        }
-
-        if (mCurrentRawPointerData.touchingIdBits.count() == 1) {
-            uint32_t id = mCurrentRawPointerData.touchingIdBits.firstMarkedBit();
-            const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(id);
-            const VirtualKey* virtualKey = findVirtualKeyHit(pointer.x, pointer.y);
-            if (virtualKey && virtualKey->keyCode == mCurrentVirtualKey.keyCode) {
-                // Pointer is still within the space of the virtual key.
-                return true;
-            }
-        }
-
-        // Pointer left virtual key area or another pointer also went down.
-        // Send key cancellation but do not consume the touch yet.
-        // This is useful when the user swipes through from the virtual key area
-        // into the main display surface.
-        mCurrentVirtualKey.down = false;
-        if (!mCurrentVirtualKey.ignored) {
-#if DEBUG_VIRTUAL_KEYS
-            ALOGD("VirtualKeys: Canceling key: keyCode=%d, scanCode=%d",
-                    mCurrentVirtualKey.keyCode, mCurrentVirtualKey.scanCode);
-#endif
-            dispatchVirtualKey(when, policyFlags,
-                    AKEY_EVENT_ACTION_UP,
-                    AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY
-                            | AKEY_EVENT_FLAG_CANCELED);
-        }
-    }
-
-    if (mLastRawPointerData.touchingIdBits.isEmpty()
-            && !mCurrentRawPointerData.touchingIdBits.isEmpty()) {
-        // Pointer just went down.  Check for virtual key press or off-screen touches.
-        uint32_t id = mCurrentRawPointerData.touchingIdBits.firstMarkedBit();
-        const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(id);
-        if (!isPointInsideSurface(pointer.x, pointer.y)) {
-            // If exactly one pointer went down, check for virtual key hit.
-            // Otherwise we will drop the entire stroke.
-            if (mCurrentRawPointerData.touchingIdBits.count() == 1) {
-                const VirtualKey* virtualKey = findVirtualKeyHit(pointer.x, pointer.y);
-                if (virtualKey) {
-                    mCurrentVirtualKey.down = true;
-                    mCurrentVirtualKey.downTime = when;
-                    mCurrentVirtualKey.keyCode = virtualKey->keyCode;
-                    mCurrentVirtualKey.scanCode = virtualKey->scanCode;
-                    mCurrentVirtualKey.ignored = mContext->shouldDropVirtualKey(
-                            when, getDevice(), virtualKey->keyCode, virtualKey->scanCode);
-
-                    if (!mCurrentVirtualKey.ignored) {
-#if DEBUG_VIRTUAL_KEYS
-                        ALOGD("VirtualKeys: Generating key down: keyCode=%d, scanCode=%d",
-                                mCurrentVirtualKey.keyCode,
-                                mCurrentVirtualKey.scanCode);
-#endif
-                        dispatchVirtualKey(when, policyFlags,
-                                AKEY_EVENT_ACTION_DOWN,
-                                AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY);
-                    }
-                }
-            }
-            return true;
-        }
-    }
-
-    // Disable all virtual key touches that happen within a short time interval of the
-    // most recent touch within the screen area.  The idea is to filter out stray
-    // virtual key presses when interacting with the touch screen.
-    //
-    // Problems we're trying to solve:
-    //
-    // 1. While scrolling a list or dragging the window shade, the user swipes down into a
-    //    virtual key area that is implemented by a separate touch panel and accidentally
-    //    triggers a virtual key.
-    //
-    // 2. While typing in the on screen keyboard, the user taps slightly outside the screen
-    //    area and accidentally triggers a virtual key.  This often happens when virtual keys
-    //    are layed out below the screen near to where the on screen keyboard's space bar
-    //    is displayed.
-    if (mConfig.virtualKeyQuietTime > 0 && !mCurrentRawPointerData.touchingIdBits.isEmpty()) {
-        mContext->disableVirtualKeysUntil(when + mConfig.virtualKeyQuietTime);
-    }
-    return false;
-}
-
-void TouchInputMapper::dispatchVirtualKey(nsecs_t when, uint32_t policyFlags,
-        int32_t keyEventAction, int32_t keyEventFlags) {
-    int32_t keyCode = mCurrentVirtualKey.keyCode;
-    int32_t scanCode = mCurrentVirtualKey.scanCode;
-    nsecs_t downTime = mCurrentVirtualKey.downTime;
-    int32_t metaState = mContext->getGlobalMetaState();
-    policyFlags |= POLICY_FLAG_VIRTUAL;
-
-    NotifyKeyArgs args(when, getDeviceId(), AINPUT_SOURCE_KEYBOARD, policyFlags,
-            keyEventAction, keyEventFlags, keyCode, scanCode, metaState, downTime);
-    getListener()->notifyKey(&args);
-}
-
-void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) {
-    BitSet32 currentIdBits = mCurrentCookedPointerData.touchingIdBits;
-    BitSet32 lastIdBits = mLastCookedPointerData.touchingIdBits;
-    int32_t metaState = getContext()->getGlobalMetaState();
-    int32_t buttonState = mCurrentButtonState;
-
-    if (currentIdBits == lastIdBits) {
-        if (!currentIdBits.isEmpty()) {
-            // No pointer id changes so this is a move event.
-            // The listener takes care of batching moves so we don't have to deal with that here.
-            dispatchMotion(when, policyFlags, mSource,
-                    AMOTION_EVENT_ACTION_MOVE, 0, metaState, buttonState,
-                    AMOTION_EVENT_EDGE_FLAG_NONE,
-                    mCurrentCookedPointerData.pointerProperties,
-                    mCurrentCookedPointerData.pointerCoords,
-                    mCurrentCookedPointerData.idToIndex,
-                    currentIdBits, -1,
-                    mOrientedXPrecision, mOrientedYPrecision, mDownTime);
-        }
-    } else {
-        // There may be pointers going up and pointers going down and pointers moving
-        // all at the same time.
-        BitSet32 upIdBits(lastIdBits.value & ~currentIdBits.value);
-        BitSet32 downIdBits(currentIdBits.value & ~lastIdBits.value);
-        BitSet32 moveIdBits(lastIdBits.value & currentIdBits.value);
-        BitSet32 dispatchedIdBits(lastIdBits.value);
-
-        // Update last coordinates of pointers that have moved so that we observe the new
-        // pointer positions at the same time as other pointers that have just gone up.
-        bool moveNeeded = updateMovedPointers(
-                mCurrentCookedPointerData.pointerProperties,
-                mCurrentCookedPointerData.pointerCoords,
-                mCurrentCookedPointerData.idToIndex,
-                mLastCookedPointerData.pointerProperties,
-                mLastCookedPointerData.pointerCoords,
-                mLastCookedPointerData.idToIndex,
-                moveIdBits);
-        if (buttonState != mLastButtonState) {
-            moveNeeded = true;
-        }
-
-        // Dispatch pointer up events.
-        while (!upIdBits.isEmpty()) {
-            uint32_t upId = upIdBits.clearFirstMarkedBit();
-
-            dispatchMotion(when, policyFlags, mSource,
-                    AMOTION_EVENT_ACTION_POINTER_UP, 0, metaState, buttonState, 0,
-                    mLastCookedPointerData.pointerProperties,
-                    mLastCookedPointerData.pointerCoords,
-                    mLastCookedPointerData.idToIndex,
-                    dispatchedIdBits, upId,
-                    mOrientedXPrecision, mOrientedYPrecision, mDownTime);
-            dispatchedIdBits.clearBit(upId);
-        }
-
-        // Dispatch move events if any of the remaining pointers moved from their old locations.
-        // Although applications receive new locations as part of individual pointer up
-        // events, they do not generally handle them except when presented in a move event.
-        if (moveNeeded) {
-            ALOG_ASSERT(moveIdBits.value == dispatchedIdBits.value);
-            dispatchMotion(when, policyFlags, mSource,
-                    AMOTION_EVENT_ACTION_MOVE, 0, metaState, buttonState, 0,
-                    mCurrentCookedPointerData.pointerProperties,
-                    mCurrentCookedPointerData.pointerCoords,
-                    mCurrentCookedPointerData.idToIndex,
-                    dispatchedIdBits, -1,
-                    mOrientedXPrecision, mOrientedYPrecision, mDownTime);
-        }
-
-        // Dispatch pointer down events using the new pointer locations.
-        while (!downIdBits.isEmpty()) {
-            uint32_t downId = downIdBits.clearFirstMarkedBit();
-            dispatchedIdBits.markBit(downId);
-
-            if (dispatchedIdBits.count() == 1) {
-                // First pointer is going down.  Set down time.
-                mDownTime = when;
-            }
-
-            dispatchMotion(when, policyFlags, mSource,
-                    AMOTION_EVENT_ACTION_POINTER_DOWN, 0, metaState, buttonState, 0,
-                    mCurrentCookedPointerData.pointerProperties,
-                    mCurrentCookedPointerData.pointerCoords,
-                    mCurrentCookedPointerData.idToIndex,
-                    dispatchedIdBits, downId,
-                    mOrientedXPrecision, mOrientedYPrecision, mDownTime);
-        }
-    }
-}
-
-void TouchInputMapper::dispatchHoverExit(nsecs_t when, uint32_t policyFlags) {
-    if (mSentHoverEnter &&
-            (mCurrentCookedPointerData.hoveringIdBits.isEmpty()
-                    || !mCurrentCookedPointerData.touchingIdBits.isEmpty())) {
-        int32_t metaState = getContext()->getGlobalMetaState();
-        dispatchMotion(when, policyFlags, mSource,
-                AMOTION_EVENT_ACTION_HOVER_EXIT, 0, metaState, mLastButtonState, 0,
-                mLastCookedPointerData.pointerProperties,
-                mLastCookedPointerData.pointerCoords,
-                mLastCookedPointerData.idToIndex,
-                mLastCookedPointerData.hoveringIdBits, -1,
-                mOrientedXPrecision, mOrientedYPrecision, mDownTime);
-        mSentHoverEnter = false;
-    }
-}
-
-void TouchInputMapper::dispatchHoverEnterAndMove(nsecs_t when, uint32_t policyFlags) {
-    if (mCurrentCookedPointerData.touchingIdBits.isEmpty()
-            && !mCurrentCookedPointerData.hoveringIdBits.isEmpty()) {
-        int32_t metaState = getContext()->getGlobalMetaState();
-        if (!mSentHoverEnter) {
-            dispatchMotion(when, policyFlags, mSource,
-                    AMOTION_EVENT_ACTION_HOVER_ENTER, 0, metaState, mCurrentButtonState, 0,
-                    mCurrentCookedPointerData.pointerProperties,
-                    mCurrentCookedPointerData.pointerCoords,
-                    mCurrentCookedPointerData.idToIndex,
-                    mCurrentCookedPointerData.hoveringIdBits, -1,
-                    mOrientedXPrecision, mOrientedYPrecision, mDownTime);
-            mSentHoverEnter = true;
-        }
-
-        dispatchMotion(when, policyFlags, mSource,
-                AMOTION_EVENT_ACTION_HOVER_MOVE, 0, metaState, mCurrentButtonState, 0,
-                mCurrentCookedPointerData.pointerProperties,
-                mCurrentCookedPointerData.pointerCoords,
-                mCurrentCookedPointerData.idToIndex,
-                mCurrentCookedPointerData.hoveringIdBits, -1,
-                mOrientedXPrecision, mOrientedYPrecision, mDownTime);
-    }
-}
-
-void TouchInputMapper::cookPointerData() {
-    uint32_t currentPointerCount = mCurrentRawPointerData.pointerCount;
-
-    mCurrentCookedPointerData.clear();
-    mCurrentCookedPointerData.pointerCount = currentPointerCount;
-    mCurrentCookedPointerData.hoveringIdBits = mCurrentRawPointerData.hoveringIdBits;
-    mCurrentCookedPointerData.touchingIdBits = mCurrentRawPointerData.touchingIdBits;
-
-    // Walk through the the active pointers and map device coordinates onto
-    // surface coordinates and adjust for display orientation.
-    for (uint32_t i = 0; i < currentPointerCount; i++) {
-        const RawPointerData::Pointer& in = mCurrentRawPointerData.pointers[i];
-
-        // Size
-        float touchMajor, touchMinor, toolMajor, toolMinor, size;
-        switch (mCalibration.sizeCalibration) {
-        case Calibration::SIZE_CALIBRATION_GEOMETRIC:
-        case Calibration::SIZE_CALIBRATION_DIAMETER:
-        case Calibration::SIZE_CALIBRATION_BOX:
-        case Calibration::SIZE_CALIBRATION_AREA:
-            if (mRawPointerAxes.touchMajor.valid && mRawPointerAxes.toolMajor.valid) {
-                touchMajor = in.touchMajor;
-                touchMinor = mRawPointerAxes.touchMinor.valid ? in.touchMinor : in.touchMajor;
-                toolMajor = in.toolMajor;
-                toolMinor = mRawPointerAxes.toolMinor.valid ? in.toolMinor : in.toolMajor;
-                size = mRawPointerAxes.touchMinor.valid
-                        ? avg(in.touchMajor, in.touchMinor) : in.touchMajor;
-            } else if (mRawPointerAxes.touchMajor.valid) {
-                toolMajor = touchMajor = in.touchMajor;
-                toolMinor = touchMinor = mRawPointerAxes.touchMinor.valid
-                        ? in.touchMinor : in.touchMajor;
-                size = mRawPointerAxes.touchMinor.valid
-                        ? avg(in.touchMajor, in.touchMinor) : in.touchMajor;
-            } else if (mRawPointerAxes.toolMajor.valid) {
-                touchMajor = toolMajor = in.toolMajor;
-                touchMinor = toolMinor = mRawPointerAxes.toolMinor.valid
-                        ? in.toolMinor : in.toolMajor;
-                size = mRawPointerAxes.toolMinor.valid
-                        ? avg(in.toolMajor, in.toolMinor) : in.toolMajor;
-            } else {
-                ALOG_ASSERT(false, "No touch or tool axes.  "
-                        "Size calibration should have been resolved to NONE.");
-                touchMajor = 0;
-                touchMinor = 0;
-                toolMajor = 0;
-                toolMinor = 0;
-                size = 0;
-            }
-
-            if (mCalibration.haveSizeIsSummed && mCalibration.sizeIsSummed) {
-                uint32_t touchingCount = mCurrentRawPointerData.touchingIdBits.count();
-                if (touchingCount > 1) {
-                    touchMajor /= touchingCount;
-                    touchMinor /= touchingCount;
-                    toolMajor /= touchingCount;
-                    toolMinor /= touchingCount;
-                    size /= touchingCount;
-                }
-            }
-
-            if (mCalibration.sizeCalibration == Calibration::SIZE_CALIBRATION_GEOMETRIC) {
-                touchMajor *= mGeometricScale;
-                touchMinor *= mGeometricScale;
-                toolMajor *= mGeometricScale;
-                toolMinor *= mGeometricScale;
-            } else if (mCalibration.sizeCalibration == Calibration::SIZE_CALIBRATION_AREA) {
-                touchMajor = touchMajor > 0 ? sqrtf(touchMajor) : 0;
-                touchMinor = touchMajor;
-                toolMajor = toolMajor > 0 ? sqrtf(toolMajor) : 0;
-                toolMinor = toolMajor;
-            } else if (mCalibration.sizeCalibration == Calibration::SIZE_CALIBRATION_DIAMETER) {
-                touchMinor = touchMajor;
-                toolMinor = toolMajor;
-            }
-
-            mCalibration.applySizeScaleAndBias(&touchMajor);
-            mCalibration.applySizeScaleAndBias(&touchMinor);
-            mCalibration.applySizeScaleAndBias(&toolMajor);
-            mCalibration.applySizeScaleAndBias(&toolMinor);
-            size *= mSizeScale;
-            break;
-        default:
-            touchMajor = 0;
-            touchMinor = 0;
-            toolMajor = 0;
-            toolMinor = 0;
-            size = 0;
-            break;
-        }
-
-        // Pressure
-        float pressure;
-        switch (mCalibration.pressureCalibration) {
-        case Calibration::PRESSURE_CALIBRATION_PHYSICAL:
-        case Calibration::PRESSURE_CALIBRATION_AMPLITUDE:
-            pressure = in.pressure * mPressureScale;
-            break;
-        default:
-            pressure = in.isHovering ? 0 : 1;
-            break;
-        }
-
-        // Tilt and Orientation
-        float tilt;
-        float orientation;
-        if (mHaveTilt) {
-            float tiltXAngle = (in.tiltX - mTiltXCenter) * mTiltXScale;
-            float tiltYAngle = (in.tiltY - mTiltYCenter) * mTiltYScale;
-            orientation = atan2f(-sinf(tiltXAngle), sinf(tiltYAngle));
-            tilt = acosf(cosf(tiltXAngle) * cosf(tiltYAngle));
-        } else {
-            tilt = 0;
-
-            switch (mCalibration.orientationCalibration) {
-            case Calibration::ORIENTATION_CALIBRATION_INTERPOLATED:
-                orientation = in.orientation * mOrientationScale;
-                break;
-            case Calibration::ORIENTATION_CALIBRATION_VECTOR: {
-                int32_t c1 = signExtendNybble((in.orientation & 0xf0) >> 4);
-                int32_t c2 = signExtendNybble(in.orientation & 0x0f);
-                if (c1 != 0 || c2 != 0) {
-                    orientation = atan2f(c1, c2) * 0.5f;
-                    float confidence = hypotf(c1, c2);
-                    float scale = 1.0f + confidence / 16.0f;
-                    touchMajor *= scale;
-                    touchMinor /= scale;
-                    toolMajor *= scale;
-                    toolMinor /= scale;
-                } else {
-                    orientation = 0;
-                }
-                break;
-            }
-            default:
-                orientation = 0;
-            }
-        }
-
-        // Distance
-        float distance;
-        switch (mCalibration.distanceCalibration) {
-        case Calibration::DISTANCE_CALIBRATION_SCALED:
-            distance = in.distance * mDistanceScale;
-            break;
-        default:
-            distance = 0;
-        }
-
-        // Coverage
-        int32_t rawLeft, rawTop, rawRight, rawBottom;
-        switch (mCalibration.coverageCalibration) {
-        case Calibration::COVERAGE_CALIBRATION_BOX:
-            rawLeft = (in.toolMinor & 0xffff0000) >> 16;
-            rawRight = in.toolMinor & 0x0000ffff;
-            rawBottom = in.toolMajor & 0x0000ffff;
-            rawTop = (in.toolMajor & 0xffff0000) >> 16;
-            break;
-        default:
-            rawLeft = rawTop = rawRight = rawBottom = 0;
-            break;
-        }
-
-        // X, Y, and the bounding box for coverage information
-        // Adjust coords for surface orientation.
-        float x, y, left, top, right, bottom;
-        switch (mSurfaceOrientation) {
-        case DISPLAY_ORIENTATION_90:
-            x = float(in.y - mRawPointerAxes.y.minValue) * mYScale + mYTranslate;
-            y = float(mRawPointerAxes.x.maxValue - in.x) * mXScale + mXTranslate;
-            left = float(rawTop - mRawPointerAxes.y.minValue) * mYScale + mYTranslate;
-            right = float(rawBottom- mRawPointerAxes.y.minValue) * mYScale + mYTranslate;
-            bottom = float(mRawPointerAxes.x.maxValue - rawLeft) * mXScale + mXTranslate;
-            top = float(mRawPointerAxes.x.maxValue - rawRight) * mXScale + mXTranslate;
-            orientation -= M_PI_2;
-            if (orientation < mOrientedRanges.orientation.min) {
-                orientation += (mOrientedRanges.orientation.max - mOrientedRanges.orientation.min);
-            }
-            break;
-        case DISPLAY_ORIENTATION_180:
-            x = float(mRawPointerAxes.x.maxValue - in.x) * mXScale + mXTranslate;
-            y = float(mRawPointerAxes.y.maxValue - in.y) * mYScale + mYTranslate;
-            left = float(mRawPointerAxes.x.maxValue - rawRight) * mXScale + mXTranslate;
-            right = float(mRawPointerAxes.x.maxValue - rawLeft) * mXScale + mXTranslate;
-            bottom = float(mRawPointerAxes.y.maxValue - rawTop) * mYScale + mYTranslate;
-            top = float(mRawPointerAxes.y.maxValue - rawBottom) * mYScale + mYTranslate;
-            orientation -= M_PI;
-            if (orientation < mOrientedRanges.orientation.min) {
-                orientation += (mOrientedRanges.orientation.max - mOrientedRanges.orientation.min);
-            }
-            break;
-        case DISPLAY_ORIENTATION_270:
-            x = float(mRawPointerAxes.y.maxValue - in.y) * mYScale + mYTranslate;
-            y = float(in.x - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;
-            left = float(mRawPointerAxes.y.maxValue - rawBottom) * mYScale + mYTranslate;
-            right = float(mRawPointerAxes.y.maxValue - rawTop) * mYScale + mYTranslate;
-            bottom = float(rawRight - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;
-            top = float(rawLeft - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;
-            orientation += M_PI_2;
-            if (orientation > mOrientedRanges.orientation.max) {
-                orientation -= (mOrientedRanges.orientation.max - mOrientedRanges.orientation.min);
-            }
-            break;
-        default:
-            x = float(in.x - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;
-            y = float(in.y - mRawPointerAxes.y.minValue) * mYScale + mYTranslate;
-            left = float(rawLeft - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;
-            right = float(rawRight - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;
-            bottom = float(rawBottom - mRawPointerAxes.y.minValue) * mYScale + mYTranslate;
-            top = float(rawTop - mRawPointerAxes.y.minValue) * mYScale + mYTranslate;
-            break;
-        }
-
-        // Write output coords.
-        PointerCoords& out = mCurrentCookedPointerData.pointerCoords[i];
-        out.clear();
-        out.setAxisValue(AMOTION_EVENT_AXIS_X, x);
-        out.setAxisValue(AMOTION_EVENT_AXIS_Y, y);
-        out.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, pressure);
-        out.setAxisValue(AMOTION_EVENT_AXIS_SIZE, size);
-        out.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, touchMajor);
-        out.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, touchMinor);
-        out.setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, orientation);
-        out.setAxisValue(AMOTION_EVENT_AXIS_TILT, tilt);
-        out.setAxisValue(AMOTION_EVENT_AXIS_DISTANCE, distance);
-        if (mCalibration.coverageCalibration == Calibration::COVERAGE_CALIBRATION_BOX) {
-            out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_1, left);
-            out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_2, top);
-            out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_3, right);
-            out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_4, bottom);
-        } else {
-            out.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, toolMajor);
-            out.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, toolMinor);
-        }
-
-        // Write output properties.
-        PointerProperties& properties = mCurrentCookedPointerData.pointerProperties[i];
-        uint32_t id = in.id;
-        properties.clear();
-        properties.id = id;
-        properties.toolType = in.toolType;
-
-        // Write id index.
-        mCurrentCookedPointerData.idToIndex[id] = i;
-    }
-}
-
-void TouchInputMapper::dispatchPointerUsage(nsecs_t when, uint32_t policyFlags,
-        PointerUsage pointerUsage) {
-    if (pointerUsage != mPointerUsage) {
-        abortPointerUsage(when, policyFlags);
-        mPointerUsage = pointerUsage;
-    }
-
-    switch (mPointerUsage) {
-    case POINTER_USAGE_GESTURES:
-        dispatchPointerGestures(when, policyFlags, false /*isTimeout*/);
-        break;
-    case POINTER_USAGE_STYLUS:
-        dispatchPointerStylus(when, policyFlags);
-        break;
-    case POINTER_USAGE_MOUSE:
-        dispatchPointerMouse(when, policyFlags);
-        break;
-    default:
-        break;
-    }
-}
-
-void TouchInputMapper::abortPointerUsage(nsecs_t when, uint32_t policyFlags) {
-    switch (mPointerUsage) {
-    case POINTER_USAGE_GESTURES:
-        abortPointerGestures(when, policyFlags);
-        break;
-    case POINTER_USAGE_STYLUS:
-        abortPointerStylus(when, policyFlags);
-        break;
-    case POINTER_USAGE_MOUSE:
-        abortPointerMouse(when, policyFlags);
-        break;
-    default:
-        break;
-    }
-
-    mPointerUsage = POINTER_USAGE_NONE;
-}
-
-void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlags,
-        bool isTimeout) {
-    // Update current gesture coordinates.
-    bool cancelPreviousGesture, finishPreviousGesture;
-    bool sendEvents = preparePointerGestures(when,
-            &cancelPreviousGesture, &finishPreviousGesture, isTimeout);
-    if (!sendEvents) {
-        return;
-    }
-    if (finishPreviousGesture) {
-        cancelPreviousGesture = false;
-    }
-
-    // Update the pointer presentation and spots.
-    if (mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS) {
-        mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_SPOT);
-        if (finishPreviousGesture || cancelPreviousGesture) {
-            mPointerController->clearSpots();
-        }
-        mPointerController->setSpots(mPointerGesture.currentGestureCoords,
-                mPointerGesture.currentGestureIdToIndex,
-                mPointerGesture.currentGestureIdBits);
-    } else {
-        mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_POINTER);
-    }
-
-    // Show or hide the pointer if needed.
-    switch (mPointerGesture.currentGestureMode) {
-    case PointerGesture::NEUTRAL:
-    case PointerGesture::QUIET:
-        if (mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS
-                && (mPointerGesture.lastGestureMode == PointerGesture::SWIPE
-                        || mPointerGesture.lastGestureMode == PointerGesture::FREEFORM)) {
-            // Remind the user of where the pointer is after finishing a gesture with spots.
-            mPointerController->unfade(PointerControllerInterface::TRANSITION_GRADUAL);
-        }
-        break;
-    case PointerGesture::TAP:
-    case PointerGesture::TAP_DRAG:
-    case PointerGesture::BUTTON_CLICK_OR_DRAG:
-    case PointerGesture::HOVER:
-    case PointerGesture::PRESS:
-        // Unfade the pointer when the current gesture manipulates the
-        // area directly under the pointer.
-        mPointerController->unfade(PointerControllerInterface::TRANSITION_IMMEDIATE);
-        break;
-    case PointerGesture::SWIPE:
-    case PointerGesture::FREEFORM:
-        // Fade the pointer when the current gesture manipulates a different
-        // area and there are spots to guide the user experience.
-        if (mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS) {
-            mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL);
-        } else {
-            mPointerController->unfade(PointerControllerInterface::TRANSITION_IMMEDIATE);
-        }
-        break;
-    }
-
-    // Send events!
-    int32_t metaState = getContext()->getGlobalMetaState();
-    int32_t buttonState = mCurrentButtonState;
-
-    // Update last coordinates of pointers that have moved so that we observe the new
-    // pointer positions at the same time as other pointers that have just gone up.
-    bool down = mPointerGesture.currentGestureMode == PointerGesture::TAP
-            || mPointerGesture.currentGestureMode == PointerGesture::TAP_DRAG
-            || mPointerGesture.currentGestureMode == PointerGesture::BUTTON_CLICK_OR_DRAG
-            || mPointerGesture.currentGestureMode == PointerGesture::PRESS
-            || mPointerGesture.currentGestureMode == PointerGesture::SWIPE
-            || mPointerGesture.currentGestureMode == PointerGesture::FREEFORM;
-    bool moveNeeded = false;
-    if (down && !cancelPreviousGesture && !finishPreviousGesture
-            && !mPointerGesture.lastGestureIdBits.isEmpty()
-            && !mPointerGesture.currentGestureIdBits.isEmpty()) {
-        BitSet32 movedGestureIdBits(mPointerGesture.currentGestureIdBits.value
-                & mPointerGesture.lastGestureIdBits.value);
-        moveNeeded = updateMovedPointers(mPointerGesture.currentGestureProperties,
-                mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex,
-                mPointerGesture.lastGestureProperties,
-                mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex,
-                movedGestureIdBits);
-        if (buttonState != mLastButtonState) {
-            moveNeeded = true;
-        }
-    }
-
-    // Send motion events for all pointers that went up or were canceled.
-    BitSet32 dispatchedGestureIdBits(mPointerGesture.lastGestureIdBits);
-    if (!dispatchedGestureIdBits.isEmpty()) {
-        if (cancelPreviousGesture) {
-            dispatchMotion(when, policyFlags, mSource,
-                    AMOTION_EVENT_ACTION_CANCEL, 0, metaState, buttonState,
-                    AMOTION_EVENT_EDGE_FLAG_NONE,
-                    mPointerGesture.lastGestureProperties,
-                    mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex,
-                    dispatchedGestureIdBits, -1,
-                    0, 0, mPointerGesture.downTime);
-
-            dispatchedGestureIdBits.clear();
-        } else {
-            BitSet32 upGestureIdBits;
-            if (finishPreviousGesture) {
-                upGestureIdBits = dispatchedGestureIdBits;
-            } else {
-                upGestureIdBits.value = dispatchedGestureIdBits.value
-                        & ~mPointerGesture.currentGestureIdBits.value;
-            }
-            while (!upGestureIdBits.isEmpty()) {
-                uint32_t id = upGestureIdBits.clearFirstMarkedBit();
-
-                dispatchMotion(when, policyFlags, mSource,
-                        AMOTION_EVENT_ACTION_POINTER_UP, 0,
-                        metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
-                        mPointerGesture.lastGestureProperties,
-                        mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex,
-                        dispatchedGestureIdBits, id,
-                        0, 0, mPointerGesture.downTime);
-
-                dispatchedGestureIdBits.clearBit(id);
-            }
-        }
-    }
-
-    // Send motion events for all pointers that moved.
-    if (moveNeeded) {
-        dispatchMotion(when, policyFlags, mSource,
-                AMOTION_EVENT_ACTION_MOVE, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
-                mPointerGesture.currentGestureProperties,
-                mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex,
-                dispatchedGestureIdBits, -1,
-                0, 0, mPointerGesture.downTime);
-    }
-
-    // Send motion events for all pointers that went down.
-    if (down) {
-        BitSet32 downGestureIdBits(mPointerGesture.currentGestureIdBits.value
-                & ~dispatchedGestureIdBits.value);
-        while (!downGestureIdBits.isEmpty()) {
-            uint32_t id = downGestureIdBits.clearFirstMarkedBit();
-            dispatchedGestureIdBits.markBit(id);
-
-            if (dispatchedGestureIdBits.count() == 1) {
-                mPointerGesture.downTime = when;
-            }
-
-            dispatchMotion(when, policyFlags, mSource,
-                    AMOTION_EVENT_ACTION_POINTER_DOWN, 0, metaState, buttonState, 0,
-                    mPointerGesture.currentGestureProperties,
-                    mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex,
-                    dispatchedGestureIdBits, id,
-                    0, 0, mPointerGesture.downTime);
-        }
-    }
-
-    // Send motion events for hover.
-    if (mPointerGesture.currentGestureMode == PointerGesture::HOVER) {
-        dispatchMotion(when, policyFlags, mSource,
-                AMOTION_EVENT_ACTION_HOVER_MOVE, 0,
-                metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
-                mPointerGesture.currentGestureProperties,
-                mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex,
-                mPointerGesture.currentGestureIdBits, -1,
-                0, 0, mPointerGesture.downTime);
-    } else if (dispatchedGestureIdBits.isEmpty()
-            && !mPointerGesture.lastGestureIdBits.isEmpty()) {
-        // Synthesize a hover move event after all pointers go up to indicate that
-        // the pointer is hovering again even if the user is not currently touching
-        // the touch pad.  This ensures that a view will receive a fresh hover enter
-        // event after a tap.
-        float x, y;
-        mPointerController->getPosition(&x, &y);
-
-        PointerProperties pointerProperties;
-        pointerProperties.clear();
-        pointerProperties.id = 0;
-        pointerProperties.toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
-
-        PointerCoords pointerCoords;
-        pointerCoords.clear();
-        pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x);
-        pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y);
-
-        NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
-                AMOTION_EVENT_ACTION_HOVER_MOVE, 0,
-                metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
-                mViewport.displayId, 1, &pointerProperties, &pointerCoords,
-                0, 0, mPointerGesture.downTime);
-        getListener()->notifyMotion(&args);
-    }
-
-    // Update state.
-    mPointerGesture.lastGestureMode = mPointerGesture.currentGestureMode;
-    if (!down) {
-        mPointerGesture.lastGestureIdBits.clear();
-    } else {
-        mPointerGesture.lastGestureIdBits = mPointerGesture.currentGestureIdBits;
-        for (BitSet32 idBits(mPointerGesture.currentGestureIdBits); !idBits.isEmpty(); ) {
-            uint32_t id = idBits.clearFirstMarkedBit();
-            uint32_t index = mPointerGesture.currentGestureIdToIndex[id];
-            mPointerGesture.lastGestureProperties[index].copyFrom(
-                    mPointerGesture.currentGestureProperties[index]);
-            mPointerGesture.lastGestureCoords[index].copyFrom(
-                    mPointerGesture.currentGestureCoords[index]);
-            mPointerGesture.lastGestureIdToIndex[id] = index;
-        }
-    }
-}
-
-void TouchInputMapper::abortPointerGestures(nsecs_t when, uint32_t policyFlags) {
-    // Cancel previously dispatches pointers.
-    if (!mPointerGesture.lastGestureIdBits.isEmpty()) {
-        int32_t metaState = getContext()->getGlobalMetaState();
-        int32_t buttonState = mCurrentButtonState;
-        dispatchMotion(when, policyFlags, mSource,
-                AMOTION_EVENT_ACTION_CANCEL, 0, metaState, buttonState,
-                AMOTION_EVENT_EDGE_FLAG_NONE,
-                mPointerGesture.lastGestureProperties,
-                mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex,
-                mPointerGesture.lastGestureIdBits, -1,
-                0, 0, mPointerGesture.downTime);
-    }
-
-    // Reset the current pointer gesture.
-    mPointerGesture.reset();
-    mPointerVelocityControl.reset();
-
-    // Remove any current spots.
-    if (mPointerController != NULL) {
-        mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL);
-        mPointerController->clearSpots();
-    }
-}
-
-bool TouchInputMapper::preparePointerGestures(nsecs_t when,
-        bool* outCancelPreviousGesture, bool* outFinishPreviousGesture, bool isTimeout) {
-    *outCancelPreviousGesture = false;
-    *outFinishPreviousGesture = false;
-
-    // Handle TAP timeout.
-    if (isTimeout) {
-#if DEBUG_GESTURES
-        ALOGD("Gestures: Processing timeout");
-#endif
-
-        if (mPointerGesture.lastGestureMode == PointerGesture::TAP) {
-            if (when <= mPointerGesture.tapUpTime + mConfig.pointerGestureTapDragInterval) {
-                // The tap/drag timeout has not yet expired.
-                getContext()->requestTimeoutAtTime(mPointerGesture.tapUpTime
-                        + mConfig.pointerGestureTapDragInterval);
-            } else {
-                // The tap is finished.
-#if DEBUG_GESTURES
-                ALOGD("Gestures: TAP finished");
-#endif
-                *outFinishPreviousGesture = true;
-
-                mPointerGesture.activeGestureId = -1;
-                mPointerGesture.currentGestureMode = PointerGesture::NEUTRAL;
-                mPointerGesture.currentGestureIdBits.clear();
-
-                mPointerVelocityControl.reset();
-                return true;
-            }
-        }
-
-        // We did not handle this timeout.
-        return false;
-    }
-
-    const uint32_t currentFingerCount = mCurrentFingerIdBits.count();
-    const uint32_t lastFingerCount = mLastFingerIdBits.count();
-
-    // Update the velocity tracker.
-    {
-        VelocityTracker::Position positions[MAX_POINTERS];
-        uint32_t count = 0;
-        for (BitSet32 idBits(mCurrentFingerIdBits); !idBits.isEmpty(); count++) {
-            uint32_t id = idBits.clearFirstMarkedBit();
-            const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(id);
-            positions[count].x = pointer.x * mPointerXMovementScale;
-            positions[count].y = pointer.y * mPointerYMovementScale;
-        }
-        mPointerGesture.velocityTracker.addMovement(when,
-                mCurrentFingerIdBits, positions);
-    }
-
-    // If the gesture ever enters a mode other than TAP, HOVER or TAP_DRAG, without first returning
-    // to NEUTRAL, then we should not generate tap event.
-    if (mPointerGesture.lastGestureMode != PointerGesture::HOVER
-            && mPointerGesture.lastGestureMode != PointerGesture::TAP
-            && mPointerGesture.lastGestureMode != PointerGesture::TAP_DRAG) {
-        mPointerGesture.resetTap();
-    }
-
-    // Pick a new active touch id if needed.
-    // Choose an arbitrary pointer that just went down, if there is one.
-    // Otherwise choose an arbitrary remaining pointer.
-    // This guarantees we always have an active touch id when there is at least one pointer.
-    // We keep the same active touch id for as long as possible.
-    bool activeTouchChanged = false;
-    int32_t lastActiveTouchId = mPointerGesture.activeTouchId;
-    int32_t activeTouchId = lastActiveTouchId;
-    if (activeTouchId < 0) {
-        if (!mCurrentFingerIdBits.isEmpty()) {
-            activeTouchChanged = true;
-            activeTouchId = mPointerGesture.activeTouchId =
-                    mCurrentFingerIdBits.firstMarkedBit();
-            mPointerGesture.firstTouchTime = when;
-        }
-    } else if (!mCurrentFingerIdBits.hasBit(activeTouchId)) {
-        activeTouchChanged = true;
-        if (!mCurrentFingerIdBits.isEmpty()) {
-            activeTouchId = mPointerGesture.activeTouchId =
-                    mCurrentFingerIdBits.firstMarkedBit();
-        } else {
-            activeTouchId = mPointerGesture.activeTouchId = -1;
-        }
-    }
-
-    // Determine whether we are in quiet time.
-    bool isQuietTime = false;
-    if (activeTouchId < 0) {
-        mPointerGesture.resetQuietTime();
-    } else {
-        isQuietTime = when < mPointerGesture.quietTime + mConfig.pointerGestureQuietInterval;
-        if (!isQuietTime) {
-            if ((mPointerGesture.lastGestureMode == PointerGesture::PRESS
-                    || mPointerGesture.lastGestureMode == PointerGesture::SWIPE
-                    || mPointerGesture.lastGestureMode == PointerGesture::FREEFORM)
-                    && currentFingerCount < 2) {
-                // Enter quiet time when exiting swipe or freeform state.
-                // This is to prevent accidentally entering the hover state and flinging the
-                // pointer when finishing a swipe and there is still one pointer left onscreen.
-                isQuietTime = true;
-            } else if (mPointerGesture.lastGestureMode == PointerGesture::BUTTON_CLICK_OR_DRAG
-                    && currentFingerCount >= 2
-                    && !isPointerDown(mCurrentButtonState)) {
-                // Enter quiet time when releasing the button and there are still two or more
-                // fingers down.  This may indicate that one finger was used to press the button
-                // but it has not gone up yet.
-                isQuietTime = true;
-            }
-            if (isQuietTime) {
-                mPointerGesture.quietTime = when;
-            }
-        }
-    }
-
-    // Switch states based on button and pointer state.
-    if (isQuietTime) {
-        // Case 1: Quiet time. (QUIET)
-#if DEBUG_GESTURES
-        ALOGD("Gestures: QUIET for next %0.3fms", (mPointerGesture.quietTime
-                + mConfig.pointerGestureQuietInterval - when) * 0.000001f);
-#endif
-        if (mPointerGesture.lastGestureMode != PointerGesture::QUIET) {
-            *outFinishPreviousGesture = true;
-        }
-
-        mPointerGesture.activeGestureId = -1;
-        mPointerGesture.currentGestureMode = PointerGesture::QUIET;
-        mPointerGesture.currentGestureIdBits.clear();
-
-        mPointerVelocityControl.reset();
-    } else if (isPointerDown(mCurrentButtonState)) {
-        // Case 2: Button is pressed. (BUTTON_CLICK_OR_DRAG)
-        // The pointer follows the active touch point.
-        // Emit DOWN, MOVE, UP events at the pointer location.
-        //
-        // Only the active touch matters; other fingers are ignored.  This policy helps
-        // to handle the case where the user places a second finger on the touch pad
-        // to apply the necessary force to depress an integrated button below the surface.
-        // We don't want the second finger to be delivered to applications.
-        //
-        // For this to work well, we need to make sure to track the pointer that is really
-        // active.  If the user first puts one finger down to click then adds another
-        // finger to drag then the active pointer should switch to the finger that is
-        // being dragged.
-#if DEBUG_GESTURES
-        ALOGD("Gestures: BUTTON_CLICK_OR_DRAG activeTouchId=%d, "
-                "currentFingerCount=%d", activeTouchId, currentFingerCount);
-#endif
-        // Reset state when just starting.
-        if (mPointerGesture.lastGestureMode != PointerGesture::BUTTON_CLICK_OR_DRAG) {
-            *outFinishPreviousGesture = true;
-            mPointerGesture.activeGestureId = 0;
-        }
-
-        // Switch pointers if needed.
-        // Find the fastest pointer and follow it.
-        if (activeTouchId >= 0 && currentFingerCount > 1) {
-            int32_t bestId = -1;
-            float bestSpeed = mConfig.pointerGestureDragMinSwitchSpeed;
-            for (BitSet32 idBits(mCurrentFingerIdBits); !idBits.isEmpty(); ) {
-                uint32_t id = idBits.clearFirstMarkedBit();
-                float vx, vy;
-                if (mPointerGesture.velocityTracker.getVelocity(id, &vx, &vy)) {
-                    float speed = hypotf(vx, vy);
-                    if (speed > bestSpeed) {
-                        bestId = id;
-                        bestSpeed = speed;
-                    }
-                }
-            }
-            if (bestId >= 0 && bestId != activeTouchId) {
-                mPointerGesture.activeTouchId = activeTouchId = bestId;
-                activeTouchChanged = true;
-#if DEBUG_GESTURES
-                ALOGD("Gestures: BUTTON_CLICK_OR_DRAG switched pointers, "
-                        "bestId=%d, bestSpeed=%0.3f", bestId, bestSpeed);
-#endif
-            }
-        }
-
-        if (activeTouchId >= 0 && mLastFingerIdBits.hasBit(activeTouchId)) {
-            const RawPointerData::Pointer& currentPointer =
-                    mCurrentRawPointerData.pointerForId(activeTouchId);
-            const RawPointerData::Pointer& lastPointer =
-                    mLastRawPointerData.pointerForId(activeTouchId);
-            float deltaX = (currentPointer.x - lastPointer.x) * mPointerXMovementScale;
-            float deltaY = (currentPointer.y - lastPointer.y) * mPointerYMovementScale;
-
-            rotateDelta(mSurfaceOrientation, &deltaX, &deltaY);
-            mPointerVelocityControl.move(when, &deltaX, &deltaY);
-
-            // Move the pointer using a relative motion.
-            // When using spots, the click will occur at the position of the anchor
-            // spot and all other spots will move there.
-            mPointerController->move(deltaX, deltaY);
-        } else {
-            mPointerVelocityControl.reset();
-        }
-
-        float x, y;
-        mPointerController->getPosition(&x, &y);
-
-        mPointerGesture.currentGestureMode = PointerGesture::BUTTON_CLICK_OR_DRAG;
-        mPointerGesture.currentGestureIdBits.clear();
-        mPointerGesture.currentGestureIdBits.markBit(mPointerGesture.activeGestureId);
-        mPointerGesture.currentGestureIdToIndex[mPointerGesture.activeGestureId] = 0;
-        mPointerGesture.currentGestureProperties[0].clear();
-        mPointerGesture.currentGestureProperties[0].id = mPointerGesture.activeGestureId;
-        mPointerGesture.currentGestureProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
-        mPointerGesture.currentGestureCoords[0].clear();
-        mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x);
-        mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, y);
-        mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 1.0f);
-    } else if (currentFingerCount == 0) {
-        // Case 3. No fingers down and button is not pressed. (NEUTRAL)
-        if (mPointerGesture.lastGestureMode != PointerGesture::NEUTRAL) {
-            *outFinishPreviousGesture = true;
-        }
-
-        // Watch for taps coming out of HOVER or TAP_DRAG mode.
-        // Checking for taps after TAP_DRAG allows us to detect double-taps.
-        bool tapped = false;
-        if ((mPointerGesture.lastGestureMode == PointerGesture::HOVER
-                || mPointerGesture.lastGestureMode == PointerGesture::TAP_DRAG)
-                && lastFingerCount == 1) {
-            if (when <= mPointerGesture.tapDownTime + mConfig.pointerGestureTapInterval) {
-                float x, y;
-                mPointerController->getPosition(&x, &y);
-                if (fabs(x - mPointerGesture.tapX) <= mConfig.pointerGestureTapSlop
-                        && fabs(y - mPointerGesture.tapY) <= mConfig.pointerGestureTapSlop) {
-#if DEBUG_GESTURES
-                    ALOGD("Gestures: TAP");
-#endif
-
-                    mPointerGesture.tapUpTime = when;
-                    getContext()->requestTimeoutAtTime(when
-                            + mConfig.pointerGestureTapDragInterval);
-
-                    mPointerGesture.activeGestureId = 0;
-                    mPointerGesture.currentGestureMode = PointerGesture::TAP;
-                    mPointerGesture.currentGestureIdBits.clear();
-                    mPointerGesture.currentGestureIdBits.markBit(
-                            mPointerGesture.activeGestureId);
-                    mPointerGesture.currentGestureIdToIndex[
-                            mPointerGesture.activeGestureId] = 0;
-                    mPointerGesture.currentGestureProperties[0].clear();
-                    mPointerGesture.currentGestureProperties[0].id =
-                            mPointerGesture.activeGestureId;
-                    mPointerGesture.currentGestureProperties[0].toolType =
-                            AMOTION_EVENT_TOOL_TYPE_FINGER;
-                    mPointerGesture.currentGestureCoords[0].clear();
-                    mPointerGesture.currentGestureCoords[0].setAxisValue(
-                            AMOTION_EVENT_AXIS_X, mPointerGesture.tapX);
-                    mPointerGesture.currentGestureCoords[0].setAxisValue(
-                            AMOTION_EVENT_AXIS_Y, mPointerGesture.tapY);
-                    mPointerGesture.currentGestureCoords[0].setAxisValue(
-                            AMOTION_EVENT_AXIS_PRESSURE, 1.0f);
-
-                    tapped = true;
-                } else {
-#if DEBUG_GESTURES
-                    ALOGD("Gestures: Not a TAP, deltaX=%f, deltaY=%f",
-                            x - mPointerGesture.tapX,
-                            y - mPointerGesture.tapY);
-#endif
-                }
-            } else {
-#if DEBUG_GESTURES
-                if (mPointerGesture.tapDownTime != LLONG_MIN) {
-                    ALOGD("Gestures: Not a TAP, %0.3fms since down",
-                            (when - mPointerGesture.tapDownTime) * 0.000001f);
-                } else {
-                    ALOGD("Gestures: Not a TAP, incompatible mode transitions");
-                }
-#endif
-            }
-        }
-
-        mPointerVelocityControl.reset();
-
-        if (!tapped) {
-#if DEBUG_GESTURES
-            ALOGD("Gestures: NEUTRAL");
-#endif
-            mPointerGesture.activeGestureId = -1;
-            mPointerGesture.currentGestureMode = PointerGesture::NEUTRAL;
-            mPointerGesture.currentGestureIdBits.clear();
-        }
-    } else if (currentFingerCount == 1) {
-        // Case 4. Exactly one finger down, button is not pressed. (HOVER or TAP_DRAG)
-        // The pointer follows the active touch point.
-        // When in HOVER, emit HOVER_MOVE events at the pointer location.
-        // When in TAP_DRAG, emit MOVE events at the pointer location.
-        ALOG_ASSERT(activeTouchId >= 0);
-
-        mPointerGesture.currentGestureMode = PointerGesture::HOVER;
-        if (mPointerGesture.lastGestureMode == PointerGesture::TAP) {
-            if (when <= mPointerGesture.tapUpTime + mConfig.pointerGestureTapDragInterval) {
-                float x, y;
-                mPointerController->getPosition(&x, &y);
-                if (fabs(x - mPointerGesture.tapX) <= mConfig.pointerGestureTapSlop
-                        && fabs(y - mPointerGesture.tapY) <= mConfig.pointerGestureTapSlop) {
-                    mPointerGesture.currentGestureMode = PointerGesture::TAP_DRAG;
-                } else {
-#if DEBUG_GESTURES
-                    ALOGD("Gestures: Not a TAP_DRAG, deltaX=%f, deltaY=%f",
-                            x - mPointerGesture.tapX,
-                            y - mPointerGesture.tapY);
-#endif
-                }
-            } else {
-#if DEBUG_GESTURES
-                ALOGD("Gestures: Not a TAP_DRAG, %0.3fms time since up",
-                        (when - mPointerGesture.tapUpTime) * 0.000001f);
-#endif
-            }
-        } else if (mPointerGesture.lastGestureMode == PointerGesture::TAP_DRAG) {
-            mPointerGesture.currentGestureMode = PointerGesture::TAP_DRAG;
-        }
-
-        if (mLastFingerIdBits.hasBit(activeTouchId)) {
-            const RawPointerData::Pointer& currentPointer =
-                    mCurrentRawPointerData.pointerForId(activeTouchId);
-            const RawPointerData::Pointer& lastPointer =
-                    mLastRawPointerData.pointerForId(activeTouchId);
-            float deltaX = (currentPointer.x - lastPointer.x)
-                    * mPointerXMovementScale;
-            float deltaY = (currentPointer.y - lastPointer.y)
-                    * mPointerYMovementScale;
-
-            rotateDelta(mSurfaceOrientation, &deltaX, &deltaY);
-            mPointerVelocityControl.move(when, &deltaX, &deltaY);
-
-            // Move the pointer using a relative motion.
-            // When using spots, the hover or drag will occur at the position of the anchor spot.
-            mPointerController->move(deltaX, deltaY);
-        } else {
-            mPointerVelocityControl.reset();
-        }
-
-        bool down;
-        if (mPointerGesture.currentGestureMode == PointerGesture::TAP_DRAG) {
-#if DEBUG_GESTURES
-            ALOGD("Gestures: TAP_DRAG");
-#endif
-            down = true;
-        } else {
-#if DEBUG_GESTURES
-            ALOGD("Gestures: HOVER");
-#endif
-            if (mPointerGesture.lastGestureMode != PointerGesture::HOVER) {
-                *outFinishPreviousGesture = true;
-            }
-            mPointerGesture.activeGestureId = 0;
-            down = false;
-        }
-
-        float x, y;
-        mPointerController->getPosition(&x, &y);
-
-        mPointerGesture.currentGestureIdBits.clear();
-        mPointerGesture.currentGestureIdBits.markBit(mPointerGesture.activeGestureId);
-        mPointerGesture.currentGestureIdToIndex[mPointerGesture.activeGestureId] = 0;
-        mPointerGesture.currentGestureProperties[0].clear();
-        mPointerGesture.currentGestureProperties[0].id = mPointerGesture.activeGestureId;
-        mPointerGesture.currentGestureProperties[0].toolType =
-                AMOTION_EVENT_TOOL_TYPE_FINGER;
-        mPointerGesture.currentGestureCoords[0].clear();
-        mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x);
-        mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, y);
-        mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE,
-                down ? 1.0f : 0.0f);
-
-        if (lastFingerCount == 0 && currentFingerCount != 0) {
-            mPointerGesture.resetTap();
-            mPointerGesture.tapDownTime = when;
-            mPointerGesture.tapX = x;
-            mPointerGesture.tapY = y;
-        }
-    } else {
-        // Case 5. At least two fingers down, button is not pressed. (PRESS, SWIPE or FREEFORM)
-        // We need to provide feedback for each finger that goes down so we cannot wait
-        // for the fingers to move before deciding what to do.
-        //
-        // The ambiguous case is deciding what to do when there are two fingers down but they
-        // have not moved enough to determine whether they are part of a drag or part of a
-        // freeform gesture, or just a press or long-press at the pointer location.
-        //
-        // When there are two fingers we start with the PRESS hypothesis and we generate a
-        // down at the pointer location.
-        //
-        // When the two fingers move enough or when additional fingers are added, we make
-        // a decision to transition into SWIPE or FREEFORM mode accordingly.
-        ALOG_ASSERT(activeTouchId >= 0);
-
-        bool settled = when >= mPointerGesture.firstTouchTime
-                + mConfig.pointerGestureMultitouchSettleInterval;
-        if (mPointerGesture.lastGestureMode != PointerGesture::PRESS
-                && mPointerGesture.lastGestureMode != PointerGesture::SWIPE
-                && mPointerGesture.lastGestureMode != PointerGesture::FREEFORM) {
-            *outFinishPreviousGesture = true;
-        } else if (!settled && currentFingerCount > lastFingerCount) {
-            // Additional pointers have gone down but not yet settled.
-            // Reset the gesture.
-#if DEBUG_GESTURES
-            ALOGD("Gestures: Resetting gesture since additional pointers went down for MULTITOUCH, "
-                    "settle time remaining %0.3fms", (mPointerGesture.firstTouchTime
-                            + mConfig.pointerGestureMultitouchSettleInterval - when)
-                            * 0.000001f);
-#endif
-            *outCancelPreviousGesture = true;
-        } else {
-            // Continue previous gesture.
-            mPointerGesture.currentGestureMode = mPointerGesture.lastGestureMode;
-        }
-
-        if (*outFinishPreviousGesture || *outCancelPreviousGesture) {
-            mPointerGesture.currentGestureMode = PointerGesture::PRESS;
-            mPointerGesture.activeGestureId = 0;
-            mPointerGesture.referenceIdBits.clear();
-            mPointerVelocityControl.reset();
-
-            // Use the centroid and pointer location as the reference points for the gesture.
-#if DEBUG_GESTURES
-            ALOGD("Gestures: Using centroid as reference for MULTITOUCH, "
-                    "settle time remaining %0.3fms", (mPointerGesture.firstTouchTime
-                            + mConfig.pointerGestureMultitouchSettleInterval - when)
-                            * 0.000001f);
-#endif
-            mCurrentRawPointerData.getCentroidOfTouchingPointers(
-                    &mPointerGesture.referenceTouchX,
-                    &mPointerGesture.referenceTouchY);
-            mPointerController->getPosition(&mPointerGesture.referenceGestureX,
-                    &mPointerGesture.referenceGestureY);
-        }
-
-        // Clear the reference deltas for fingers not yet included in the reference calculation.
-        for (BitSet32 idBits(mCurrentFingerIdBits.value
-                & ~mPointerGesture.referenceIdBits.value); !idBits.isEmpty(); ) {
-            uint32_t id = idBits.clearFirstMarkedBit();
-            mPointerGesture.referenceDeltas[id].dx = 0;
-            mPointerGesture.referenceDeltas[id].dy = 0;
-        }
-        mPointerGesture.referenceIdBits = mCurrentFingerIdBits;
-
-        // Add delta for all fingers and calculate a common movement delta.
-        float commonDeltaX = 0, commonDeltaY = 0;
-        BitSet32 commonIdBits(mLastFingerIdBits.value
-                & mCurrentFingerIdBits.value);
-        for (BitSet32 idBits(commonIdBits); !idBits.isEmpty(); ) {
-            bool first = (idBits == commonIdBits);
-            uint32_t id = idBits.clearFirstMarkedBit();
-            const RawPointerData::Pointer& cpd = mCurrentRawPointerData.pointerForId(id);
-            const RawPointerData::Pointer& lpd = mLastRawPointerData.pointerForId(id);
-            PointerGesture::Delta& delta = mPointerGesture.referenceDeltas[id];
-            delta.dx += cpd.x - lpd.x;
-            delta.dy += cpd.y - lpd.y;
-
-            if (first) {
-                commonDeltaX = delta.dx;
-                commonDeltaY = delta.dy;
-            } else {
-                commonDeltaX = calculateCommonVector(commonDeltaX, delta.dx);
-                commonDeltaY = calculateCommonVector(commonDeltaY, delta.dy);
-            }
-        }
-
-        // Consider transitions from PRESS to SWIPE or MULTITOUCH.
-        if (mPointerGesture.currentGestureMode == PointerGesture::PRESS) {
-            float dist[MAX_POINTER_ID + 1];
-            int32_t distOverThreshold = 0;
-            for (BitSet32 idBits(mPointerGesture.referenceIdBits); !idBits.isEmpty(); ) {
-                uint32_t id = idBits.clearFirstMarkedBit();
-                PointerGesture::Delta& delta = mPointerGesture.referenceDeltas[id];
-                dist[id] = hypotf(delta.dx * mPointerXZoomScale,
-                        delta.dy * mPointerYZoomScale);
-                if (dist[id] > mConfig.pointerGestureMultitouchMinDistance) {
-                    distOverThreshold += 1;
-                }
-            }
-
-            // Only transition when at least two pointers have moved further than
-            // the minimum distance threshold.
-            if (distOverThreshold >= 2) {
-                if (currentFingerCount > 2) {
-                    // There are more than two pointers, switch to FREEFORM.
-#if DEBUG_GESTURES
-                    ALOGD("Gestures: PRESS transitioned to FREEFORM, number of pointers %d > 2",
-                            currentFingerCount);
-#endif
-                    *outCancelPreviousGesture = true;
-                    mPointerGesture.currentGestureMode = PointerGesture::FREEFORM;
-                } else {
-                    // There are exactly two pointers.
-                    BitSet32 idBits(mCurrentFingerIdBits);
-                    uint32_t id1 = idBits.clearFirstMarkedBit();
-                    uint32_t id2 = idBits.firstMarkedBit();
-                    const RawPointerData::Pointer& p1 = mCurrentRawPointerData.pointerForId(id1);
-                    const RawPointerData::Pointer& p2 = mCurrentRawPointerData.pointerForId(id2);
-                    float mutualDistance = distance(p1.x, p1.y, p2.x, p2.y);
-                    if (mutualDistance > mPointerGestureMaxSwipeWidth) {
-                        // There are two pointers but they are too far apart for a SWIPE,
-                        // switch to FREEFORM.
-#if DEBUG_GESTURES
-                        ALOGD("Gestures: PRESS transitioned to FREEFORM, distance %0.3f > %0.3f",
-                                mutualDistance, mPointerGestureMaxSwipeWidth);
-#endif
-                        *outCancelPreviousGesture = true;
-                        mPointerGesture.currentGestureMode = PointerGesture::FREEFORM;
-                    } else {
-                        // There are two pointers.  Wait for both pointers to start moving
-                        // before deciding whether this is a SWIPE or FREEFORM gesture.
-                        float dist1 = dist[id1];
-                        float dist2 = dist[id2];
-                        if (dist1 >= mConfig.pointerGestureMultitouchMinDistance
-                                && dist2 >= mConfig.pointerGestureMultitouchMinDistance) {
-                            // Calculate the dot product of the displacement vectors.
-                            // When the vectors are oriented in approximately the same direction,
-                            // the angle betweeen them is near zero and the cosine of the angle
-                            // approches 1.0.  Recall that dot(v1, v2) = cos(angle) * mag(v1) * mag(v2).
-                            PointerGesture::Delta& delta1 = mPointerGesture.referenceDeltas[id1];
-                            PointerGesture::Delta& delta2 = mPointerGesture.referenceDeltas[id2];
-                            float dx1 = delta1.dx * mPointerXZoomScale;
-                            float dy1 = delta1.dy * mPointerYZoomScale;
-                            float dx2 = delta2.dx * mPointerXZoomScale;
-                            float dy2 = delta2.dy * mPointerYZoomScale;
-                            float dot = dx1 * dx2 + dy1 * dy2;
-                            float cosine = dot / (dist1 * dist2); // denominator always > 0
-                            if (cosine >= mConfig.pointerGestureSwipeTransitionAngleCosine) {
-                                // Pointers are moving in the same direction.  Switch to SWIPE.
-#if DEBUG_GESTURES
-                                ALOGD("Gestures: PRESS transitioned to SWIPE, "
-                                        "dist1 %0.3f >= %0.3f, dist2 %0.3f >= %0.3f, "
-                                        "cosine %0.3f >= %0.3f",
-                                        dist1, mConfig.pointerGestureMultitouchMinDistance,
-                                        dist2, mConfig.pointerGestureMultitouchMinDistance,
-                                        cosine, mConfig.pointerGestureSwipeTransitionAngleCosine);
-#endif
-                                mPointerGesture.currentGestureMode = PointerGesture::SWIPE;
-                            } else {
-                                // Pointers are moving in different directions.  Switch to FREEFORM.
-#if DEBUG_GESTURES
-                                ALOGD("Gestures: PRESS transitioned to FREEFORM, "
-                                        "dist1 %0.3f >= %0.3f, dist2 %0.3f >= %0.3f, "
-                                        "cosine %0.3f < %0.3f",
-                                        dist1, mConfig.pointerGestureMultitouchMinDistance,
-                                        dist2, mConfig.pointerGestureMultitouchMinDistance,
-                                        cosine, mConfig.pointerGestureSwipeTransitionAngleCosine);
-#endif
-                                *outCancelPreviousGesture = true;
-                                mPointerGesture.currentGestureMode = PointerGesture::FREEFORM;
-                            }
-                        }
-                    }
-                }
-            }
-        } else if (mPointerGesture.currentGestureMode == PointerGesture::SWIPE) {
-            // Switch from SWIPE to FREEFORM if additional pointers go down.
-            // Cancel previous gesture.
-            if (currentFingerCount > 2) {
-#if DEBUG_GESTURES
-                ALOGD("Gestures: SWIPE transitioned to FREEFORM, number of pointers %d > 2",
-                        currentFingerCount);
-#endif
-                *outCancelPreviousGesture = true;
-                mPointerGesture.currentGestureMode = PointerGesture::FREEFORM;
-            }
-        }
-
-        // Move the reference points based on the overall group motion of the fingers
-        // except in PRESS mode while waiting for a transition to occur.
-        if (mPointerGesture.currentGestureMode != PointerGesture::PRESS
-                && (commonDeltaX || commonDeltaY)) {
-            for (BitSet32 idBits(mPointerGesture.referenceIdBits); !idBits.isEmpty(); ) {
-                uint32_t id = idBits.clearFirstMarkedBit();
-                PointerGesture::Delta& delta = mPointerGesture.referenceDeltas[id];
-                delta.dx = 0;
-                delta.dy = 0;
-            }
-
-            mPointerGesture.referenceTouchX += commonDeltaX;
-            mPointerGesture.referenceTouchY += commonDeltaY;
-
-            commonDeltaX *= mPointerXMovementScale;
-            commonDeltaY *= mPointerYMovementScale;
-
-            rotateDelta(mSurfaceOrientation, &commonDeltaX, &commonDeltaY);
-            mPointerVelocityControl.move(when, &commonDeltaX, &commonDeltaY);
-
-            mPointerGesture.referenceGestureX += commonDeltaX;
-            mPointerGesture.referenceGestureY += commonDeltaY;
-        }
-
-        // Report gestures.
-        if (mPointerGesture.currentGestureMode == PointerGesture::PRESS
-                || mPointerGesture.currentGestureMode == PointerGesture::SWIPE) {
-            // PRESS or SWIPE mode.
-#if DEBUG_GESTURES
-            ALOGD("Gestures: PRESS or SWIPE activeTouchId=%d,"
-                    "activeGestureId=%d, currentTouchPointerCount=%d",
-                    activeTouchId, mPointerGesture.activeGestureId, currentFingerCount);
-#endif
-            ALOG_ASSERT(mPointerGesture.activeGestureId >= 0);
-
-            mPointerGesture.currentGestureIdBits.clear();
-            mPointerGesture.currentGestureIdBits.markBit(mPointerGesture.activeGestureId);
-            mPointerGesture.currentGestureIdToIndex[mPointerGesture.activeGestureId] = 0;
-            mPointerGesture.currentGestureProperties[0].clear();
-            mPointerGesture.currentGestureProperties[0].id = mPointerGesture.activeGestureId;
-            mPointerGesture.currentGestureProperties[0].toolType =
-                    AMOTION_EVENT_TOOL_TYPE_FINGER;
-            mPointerGesture.currentGestureCoords[0].clear();
-            mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X,
-                    mPointerGesture.referenceGestureX);
-            mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y,
-                    mPointerGesture.referenceGestureY);
-            mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 1.0f);
-        } else if (mPointerGesture.currentGestureMode == PointerGesture::FREEFORM) {
-            // FREEFORM mode.
-#if DEBUG_GESTURES
-            ALOGD("Gestures: FREEFORM activeTouchId=%d,"
-                    "activeGestureId=%d, currentTouchPointerCount=%d",
-                    activeTouchId, mPointerGesture.activeGestureId, currentFingerCount);
-#endif
-            ALOG_ASSERT(mPointerGesture.activeGestureId >= 0);
-
-            mPointerGesture.currentGestureIdBits.clear();
-
-            BitSet32 mappedTouchIdBits;
-            BitSet32 usedGestureIdBits;
-            if (mPointerGesture.lastGestureMode != PointerGesture::FREEFORM) {
-                // Initially, assign the active gesture id to the active touch point
-                // if there is one.  No other touch id bits are mapped yet.
-                if (!*outCancelPreviousGesture) {
-                    mappedTouchIdBits.markBit(activeTouchId);
-                    usedGestureIdBits.markBit(mPointerGesture.activeGestureId);
-                    mPointerGesture.freeformTouchToGestureIdMap[activeTouchId] =
-                            mPointerGesture.activeGestureId;
-                } else {
-                    mPointerGesture.activeGestureId = -1;
-                }
-            } else {
-                // Otherwise, assume we mapped all touches from the previous frame.
-                // Reuse all mappings that are still applicable.
-                mappedTouchIdBits.value = mLastFingerIdBits.value
-                        & mCurrentFingerIdBits.value;
-                usedGestureIdBits = mPointerGesture.lastGestureIdBits;
-
-                // Check whether we need to choose a new active gesture id because the
-                // current went went up.
-                for (BitSet32 upTouchIdBits(mLastFingerIdBits.value
-                        & ~mCurrentFingerIdBits.value);
-                        !upTouchIdBits.isEmpty(); ) {
-                    uint32_t upTouchId = upTouchIdBits.clearFirstMarkedBit();
-                    uint32_t upGestureId = mPointerGesture.freeformTouchToGestureIdMap[upTouchId];
-                    if (upGestureId == uint32_t(mPointerGesture.activeGestureId)) {
-                        mPointerGesture.activeGestureId = -1;
-                        break;
-                    }
-                }
-            }
-
-#if DEBUG_GESTURES
-            ALOGD("Gestures: FREEFORM follow up "
-                    "mappedTouchIdBits=0x%08x, usedGestureIdBits=0x%08x, "
-                    "activeGestureId=%d",
-                    mappedTouchIdBits.value, usedGestureIdBits.value,
-                    mPointerGesture.activeGestureId);
-#endif
-
-            BitSet32 idBits(mCurrentFingerIdBits);
-            for (uint32_t i = 0; i < currentFingerCount; i++) {
-                uint32_t touchId = idBits.clearFirstMarkedBit();
-                uint32_t gestureId;
-                if (!mappedTouchIdBits.hasBit(touchId)) {
-                    gestureId = usedGestureIdBits.markFirstUnmarkedBit();
-                    mPointerGesture.freeformTouchToGestureIdMap[touchId] = gestureId;
-#if DEBUG_GESTURES
-                    ALOGD("Gestures: FREEFORM "
-                            "new mapping for touch id %d -> gesture id %d",
-                            touchId, gestureId);
-#endif
-                } else {
-                    gestureId = mPointerGesture.freeformTouchToGestureIdMap[touchId];
-#if DEBUG_GESTURES
-                    ALOGD("Gestures: FREEFORM "
-                            "existing mapping for touch id %d -> gesture id %d",
-                            touchId, gestureId);
-#endif
-                }
-                mPointerGesture.currentGestureIdBits.markBit(gestureId);
-                mPointerGesture.currentGestureIdToIndex[gestureId] = i;
-
-                const RawPointerData::Pointer& pointer =
-                        mCurrentRawPointerData.pointerForId(touchId);
-                float deltaX = (pointer.x - mPointerGesture.referenceTouchX)
-                        * mPointerXZoomScale;
-                float deltaY = (pointer.y - mPointerGesture.referenceTouchY)
-                        * mPointerYZoomScale;
-                rotateDelta(mSurfaceOrientation, &deltaX, &deltaY);
-
-                mPointerGesture.currentGestureProperties[i].clear();
-                mPointerGesture.currentGestureProperties[i].id = gestureId;
-                mPointerGesture.currentGestureProperties[i].toolType =
-                        AMOTION_EVENT_TOOL_TYPE_FINGER;
-                mPointerGesture.currentGestureCoords[i].clear();
-                mPointerGesture.currentGestureCoords[i].setAxisValue(
-                        AMOTION_EVENT_AXIS_X, mPointerGesture.referenceGestureX + deltaX);
-                mPointerGesture.currentGestureCoords[i].setAxisValue(
-                        AMOTION_EVENT_AXIS_Y, mPointerGesture.referenceGestureY + deltaY);
-                mPointerGesture.currentGestureCoords[i].setAxisValue(
-                        AMOTION_EVENT_AXIS_PRESSURE, 1.0f);
-            }
-
-            if (mPointerGesture.activeGestureId < 0) {
-                mPointerGesture.activeGestureId =
-                        mPointerGesture.currentGestureIdBits.firstMarkedBit();
-#if DEBUG_GESTURES
-                ALOGD("Gestures: FREEFORM new "
-                        "activeGestureId=%d", mPointerGesture.activeGestureId);
-#endif
-            }
-        }
-    }
-
-    mPointerController->setButtonState(mCurrentButtonState);
-
-#if DEBUG_GESTURES
-    ALOGD("Gestures: finishPreviousGesture=%s, cancelPreviousGesture=%s, "
-            "currentGestureMode=%d, currentGestureIdBits=0x%08x, "
-            "lastGestureMode=%d, lastGestureIdBits=0x%08x",
-            toString(*outFinishPreviousGesture), toString(*outCancelPreviousGesture),
-            mPointerGesture.currentGestureMode, mPointerGesture.currentGestureIdBits.value,
-            mPointerGesture.lastGestureMode, mPointerGesture.lastGestureIdBits.value);
-    for (BitSet32 idBits = mPointerGesture.currentGestureIdBits; !idBits.isEmpty(); ) {
-        uint32_t id = idBits.clearFirstMarkedBit();
-        uint32_t index = mPointerGesture.currentGestureIdToIndex[id];
-        const PointerProperties& properties = mPointerGesture.currentGestureProperties[index];
-        const PointerCoords& coords = mPointerGesture.currentGestureCoords[index];
-        ALOGD("  currentGesture[%d]: index=%d, toolType=%d, "
-                "x=%0.3f, y=%0.3f, pressure=%0.3f",
-                id, index, properties.toolType,
-                coords.getAxisValue(AMOTION_EVENT_AXIS_X),
-                coords.getAxisValue(AMOTION_EVENT_AXIS_Y),
-                coords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE));
-    }
-    for (BitSet32 idBits = mPointerGesture.lastGestureIdBits; !idBits.isEmpty(); ) {
-        uint32_t id = idBits.clearFirstMarkedBit();
-        uint32_t index = mPointerGesture.lastGestureIdToIndex[id];
-        const PointerProperties& properties = mPointerGesture.lastGestureProperties[index];
-        const PointerCoords& coords = mPointerGesture.lastGestureCoords[index];
-        ALOGD("  lastGesture[%d]: index=%d, toolType=%d, "
-                "x=%0.3f, y=%0.3f, pressure=%0.3f",
-                id, index, properties.toolType,
-                coords.getAxisValue(AMOTION_EVENT_AXIS_X),
-                coords.getAxisValue(AMOTION_EVENT_AXIS_Y),
-                coords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE));
-    }
-#endif
-    return true;
-}
-
-void TouchInputMapper::dispatchPointerStylus(nsecs_t when, uint32_t policyFlags) {
-    mPointerSimple.currentCoords.clear();
-    mPointerSimple.currentProperties.clear();
-
-    bool down, hovering;
-    if (!mCurrentStylusIdBits.isEmpty()) {
-        uint32_t id = mCurrentStylusIdBits.firstMarkedBit();
-        uint32_t index = mCurrentCookedPointerData.idToIndex[id];
-        float x = mCurrentCookedPointerData.pointerCoords[index].getX();
-        float y = mCurrentCookedPointerData.pointerCoords[index].getY();
-        mPointerController->setPosition(x, y);
-
-        hovering = mCurrentCookedPointerData.hoveringIdBits.hasBit(id);
-        down = !hovering;
-
-        mPointerController->getPosition(&x, &y);
-        mPointerSimple.currentCoords.copyFrom(mCurrentCookedPointerData.pointerCoords[index]);
-        mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x);
-        mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y);
-        mPointerSimple.currentProperties.id = 0;
-        mPointerSimple.currentProperties.toolType =
-                mCurrentCookedPointerData.pointerProperties[index].toolType;
-    } else {
-        down = false;
-        hovering = false;
-    }
-
-    dispatchPointerSimple(when, policyFlags, down, hovering);
-}
-
-void TouchInputMapper::abortPointerStylus(nsecs_t when, uint32_t policyFlags) {
-    abortPointerSimple(when, policyFlags);
-}
-
-void TouchInputMapper::dispatchPointerMouse(nsecs_t when, uint32_t policyFlags) {
-    mPointerSimple.currentCoords.clear();
-    mPointerSimple.currentProperties.clear();
-
-    bool down, hovering;
-    if (!mCurrentMouseIdBits.isEmpty()) {
-        uint32_t id = mCurrentMouseIdBits.firstMarkedBit();
-        uint32_t currentIndex = mCurrentRawPointerData.idToIndex[id];
-        if (mLastMouseIdBits.hasBit(id)) {
-            uint32_t lastIndex = mCurrentRawPointerData.idToIndex[id];
-            float deltaX = (mCurrentRawPointerData.pointers[currentIndex].x
-                    - mLastRawPointerData.pointers[lastIndex].x)
-                    * mPointerXMovementScale;
-            float deltaY = (mCurrentRawPointerData.pointers[currentIndex].y
-                    - mLastRawPointerData.pointers[lastIndex].y)
-                    * mPointerYMovementScale;
-
-            rotateDelta(mSurfaceOrientation, &deltaX, &deltaY);
-            mPointerVelocityControl.move(when, &deltaX, &deltaY);
-
-            mPointerController->move(deltaX, deltaY);
-        } else {
-            mPointerVelocityControl.reset();
-        }
-
-        down = isPointerDown(mCurrentButtonState);
-        hovering = !down;
-
-        float x, y;
-        mPointerController->getPosition(&x, &y);
-        mPointerSimple.currentCoords.copyFrom(
-                mCurrentCookedPointerData.pointerCoords[currentIndex]);
-        mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x);
-        mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y);
-        mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE,
-                hovering ? 0.0f : 1.0f);
-        mPointerSimple.currentProperties.id = 0;
-        mPointerSimple.currentProperties.toolType =
-                mCurrentCookedPointerData.pointerProperties[currentIndex].toolType;
-    } else {
-        mPointerVelocityControl.reset();
-
-        down = false;
-        hovering = false;
-    }
-
-    dispatchPointerSimple(when, policyFlags, down, hovering);
-}
-
-void TouchInputMapper::abortPointerMouse(nsecs_t when, uint32_t policyFlags) {
-    abortPointerSimple(when, policyFlags);
-
-    mPointerVelocityControl.reset();
-}
-
-void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags,
-        bool down, bool hovering) {
-    int32_t metaState = getContext()->getGlobalMetaState();
-
-    if (mPointerController != NULL) {
-        if (down || hovering) {
-            mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_POINTER);
-            mPointerController->clearSpots();
-            mPointerController->setButtonState(mCurrentButtonState);
-            mPointerController->unfade(PointerControllerInterface::TRANSITION_IMMEDIATE);
-        } else if (!down && !hovering && (mPointerSimple.down || mPointerSimple.hovering)) {
-            mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL);
-        }
-    }
-
-    if (mPointerSimple.down && !down) {
-        mPointerSimple.down = false;
-
-        // Send up.
-        NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
-                 AMOTION_EVENT_ACTION_UP, 0, metaState, mLastButtonState, 0,
-                 mViewport.displayId,
-                 1, &mPointerSimple.lastProperties, &mPointerSimple.lastCoords,
-                 mOrientedXPrecision, mOrientedYPrecision,
-                 mPointerSimple.downTime);
-        getListener()->notifyMotion(&args);
-    }
-
-    if (mPointerSimple.hovering && !hovering) {
-        mPointerSimple.hovering = false;
-
-        // Send hover exit.
-        NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
-                AMOTION_EVENT_ACTION_HOVER_EXIT, 0, metaState, mLastButtonState, 0,
-                mViewport.displayId,
-                1, &mPointerSimple.lastProperties, &mPointerSimple.lastCoords,
-                mOrientedXPrecision, mOrientedYPrecision,
-                mPointerSimple.downTime);
-        getListener()->notifyMotion(&args);
-    }
-
-    if (down) {
-        if (!mPointerSimple.down) {
-            mPointerSimple.down = true;
-            mPointerSimple.downTime = when;
-
-            // Send down.
-            NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
-                    AMOTION_EVENT_ACTION_DOWN, 0, metaState, mCurrentButtonState, 0,
-                    mViewport.displayId,
-                    1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
-                    mOrientedXPrecision, mOrientedYPrecision,
-                    mPointerSimple.downTime);
-            getListener()->notifyMotion(&args);
-        }
-
-        // Send move.
-        NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
-                AMOTION_EVENT_ACTION_MOVE, 0, metaState, mCurrentButtonState, 0,
-                mViewport.displayId,
-                1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
-                mOrientedXPrecision, mOrientedYPrecision,
-                mPointerSimple.downTime);
-        getListener()->notifyMotion(&args);
-    }
-
-    if (hovering) {
-        if (!mPointerSimple.hovering) {
-            mPointerSimple.hovering = true;
-
-            // Send hover enter.
-            NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
-                    AMOTION_EVENT_ACTION_HOVER_ENTER, 0, metaState, mCurrentButtonState, 0,
-                    mViewport.displayId,
-                    1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
-                    mOrientedXPrecision, mOrientedYPrecision,
-                    mPointerSimple.downTime);
-            getListener()->notifyMotion(&args);
-        }
-
-        // Send hover move.
-        NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
-                AMOTION_EVENT_ACTION_HOVER_MOVE, 0, metaState, mCurrentButtonState, 0,
-                mViewport.displayId,
-                1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
-                mOrientedXPrecision, mOrientedYPrecision,
-                mPointerSimple.downTime);
-        getListener()->notifyMotion(&args);
-    }
-
-    if (mCurrentRawVScroll || mCurrentRawHScroll) {
-        float vscroll = mCurrentRawVScroll;
-        float hscroll = mCurrentRawHScroll;
-        mWheelYVelocityControl.move(when, NULL, &vscroll);
-        mWheelXVelocityControl.move(when, &hscroll, NULL);
-
-        // Send scroll.
-        PointerCoords pointerCoords;
-        pointerCoords.copyFrom(mPointerSimple.currentCoords);
-        pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_VSCROLL, vscroll);
-        pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll);
-
-        NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
-                AMOTION_EVENT_ACTION_SCROLL, 0, metaState, mCurrentButtonState, 0,
-                mViewport.displayId,
-                1, &mPointerSimple.currentProperties, &pointerCoords,
-                mOrientedXPrecision, mOrientedYPrecision,
-                mPointerSimple.downTime);
-        getListener()->notifyMotion(&args);
-    }
-
-    // Save state.
-    if (down || hovering) {
-        mPointerSimple.lastCoords.copyFrom(mPointerSimple.currentCoords);
-        mPointerSimple.lastProperties.copyFrom(mPointerSimple.currentProperties);
-    } else {
-        mPointerSimple.reset();
-    }
-}
-
-void TouchInputMapper::abortPointerSimple(nsecs_t when, uint32_t policyFlags) {
-    mPointerSimple.currentCoords.clear();
-    mPointerSimple.currentProperties.clear();
-
-    dispatchPointerSimple(when, policyFlags, false, false);
-}
-
-void TouchInputMapper::dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source,
-        int32_t action, int32_t flags, int32_t metaState, int32_t buttonState, int32_t edgeFlags,
-        const PointerProperties* properties, const PointerCoords* coords,
-        const uint32_t* idToIndex, BitSet32 idBits,
-        int32_t changedId, float xPrecision, float yPrecision, nsecs_t downTime) {
-    PointerCoords pointerCoords[MAX_POINTERS];
-    PointerProperties pointerProperties[MAX_POINTERS];
-    uint32_t pointerCount = 0;
-    while (!idBits.isEmpty()) {
-        uint32_t id = idBits.clearFirstMarkedBit();
-        uint32_t index = idToIndex[id];
-        pointerProperties[pointerCount].copyFrom(properties[index]);
-        pointerCoords[pointerCount].copyFrom(coords[index]);
-
-        if (changedId >= 0 && id == uint32_t(changedId)) {
-            action |= pointerCount << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
-        }
-
-        pointerCount += 1;
-    }
-
-    ALOG_ASSERT(pointerCount != 0);
-
-    if (changedId >= 0 && pointerCount == 1) {
-        // Replace initial down and final up action.
-        // We can compare the action without masking off the changed pointer index
-        // because we know the index is 0.
-        if (action == AMOTION_EVENT_ACTION_POINTER_DOWN) {
-            action = AMOTION_EVENT_ACTION_DOWN;
-        } else if (action == AMOTION_EVENT_ACTION_POINTER_UP) {
-            action = AMOTION_EVENT_ACTION_UP;
-        } else {
-            // Can't happen.
-            ALOG_ASSERT(false);
-        }
-    }
-
-    NotifyMotionArgs args(when, getDeviceId(), source, policyFlags,
-            action, flags, metaState, buttonState, edgeFlags,
-            mViewport.displayId, pointerCount, pointerProperties, pointerCoords,
-            xPrecision, yPrecision, downTime);
-    getListener()->notifyMotion(&args);
-}
-
-bool TouchInputMapper::updateMovedPointers(const PointerProperties* inProperties,
-        const PointerCoords* inCoords, const uint32_t* inIdToIndex,
-        PointerProperties* outProperties, PointerCoords* outCoords, const uint32_t* outIdToIndex,
-        BitSet32 idBits) const {
-    bool changed = false;
-    while (!idBits.isEmpty()) {
-        uint32_t id = idBits.clearFirstMarkedBit();
-        uint32_t inIndex = inIdToIndex[id];
-        uint32_t outIndex = outIdToIndex[id];
-
-        const PointerProperties& curInProperties = inProperties[inIndex];
-        const PointerCoords& curInCoords = inCoords[inIndex];
-        PointerProperties& curOutProperties = outProperties[outIndex];
-        PointerCoords& curOutCoords = outCoords[outIndex];
-
-        if (curInProperties != curOutProperties) {
-            curOutProperties.copyFrom(curInProperties);
-            changed = true;
-        }
-
-        if (curInCoords != curOutCoords) {
-            curOutCoords.copyFrom(curInCoords);
-            changed = true;
-        }
-    }
-    return changed;
-}
-
-void TouchInputMapper::fadePointer() {
-    if (mPointerController != NULL) {
-        mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL);
-    }
-}
-
-bool TouchInputMapper::isPointInsideSurface(int32_t x, int32_t y) {
-    return x >= mRawPointerAxes.x.minValue && x <= mRawPointerAxes.x.maxValue
-            && y >= mRawPointerAxes.y.minValue && y <= mRawPointerAxes.y.maxValue;
-}
-
-const TouchInputMapper::VirtualKey* TouchInputMapper::findVirtualKeyHit(
-        int32_t x, int32_t y) {
-    size_t numVirtualKeys = mVirtualKeys.size();
-    for (size_t i = 0; i < numVirtualKeys; i++) {
-        const VirtualKey& virtualKey = mVirtualKeys[i];
-
-#if DEBUG_VIRTUAL_KEYS
-        ALOGD("VirtualKeys: Hit test (%d, %d): keyCode=%d, scanCode=%d, "
-                "left=%d, top=%d, right=%d, bottom=%d",
-                x, y,
-                virtualKey.keyCode, virtualKey.scanCode,
-                virtualKey.hitLeft, virtualKey.hitTop,
-                virtualKey.hitRight, virtualKey.hitBottom);
-#endif
-
-        if (virtualKey.isHit(x, y)) {
-            return & virtualKey;
-        }
-    }
-
-    return NULL;
-}
-
-void TouchInputMapper::assignPointerIds() {
-    uint32_t currentPointerCount = mCurrentRawPointerData.pointerCount;
-    uint32_t lastPointerCount = mLastRawPointerData.pointerCount;
-
-    mCurrentRawPointerData.clearIdBits();
-
-    if (currentPointerCount == 0) {
-        // No pointers to assign.
-        return;
-    }
-
-    if (lastPointerCount == 0) {
-        // All pointers are new.
-        for (uint32_t i = 0; i < currentPointerCount; i++) {
-            uint32_t id = i;
-            mCurrentRawPointerData.pointers[i].id = id;
-            mCurrentRawPointerData.idToIndex[id] = i;
-            mCurrentRawPointerData.markIdBit(id, mCurrentRawPointerData.isHovering(i));
-        }
-        return;
-    }
-
-    if (currentPointerCount == 1 && lastPointerCount == 1
-            && mCurrentRawPointerData.pointers[0].toolType
-                    == mLastRawPointerData.pointers[0].toolType) {
-        // Only one pointer and no change in count so it must have the same id as before.
-        uint32_t id = mLastRawPointerData.pointers[0].id;
-        mCurrentRawPointerData.pointers[0].id = id;
-        mCurrentRawPointerData.idToIndex[id] = 0;
-        mCurrentRawPointerData.markIdBit(id, mCurrentRawPointerData.isHovering(0));
-        return;
-    }
-
-    // General case.
-    // We build a heap of squared euclidean distances between current and last pointers
-    // associated with the current and last pointer indices.  Then, we find the best
-    // match (by distance) for each current pointer.
-    // The pointers must have the same tool type but it is possible for them to
-    // transition from hovering to touching or vice-versa while retaining the same id.
-    PointerDistanceHeapElement heap[MAX_POINTERS * MAX_POINTERS];
-
-    uint32_t heapSize = 0;
-    for (uint32_t currentPointerIndex = 0; currentPointerIndex < currentPointerCount;
-            currentPointerIndex++) {
-        for (uint32_t lastPointerIndex = 0; lastPointerIndex < lastPointerCount;
-                lastPointerIndex++) {
-            const RawPointerData::Pointer& currentPointer =
-                    mCurrentRawPointerData.pointers[currentPointerIndex];
-            const RawPointerData::Pointer& lastPointer =
-                    mLastRawPointerData.pointers[lastPointerIndex];
-            if (currentPointer.toolType == lastPointer.toolType) {
-                int64_t deltaX = currentPointer.x - lastPointer.x;
-                int64_t deltaY = currentPointer.y - lastPointer.y;
-
-                uint64_t distance = uint64_t(deltaX * deltaX + deltaY * deltaY);
-
-                // Insert new element into the heap (sift up).
-                heap[heapSize].currentPointerIndex = currentPointerIndex;
-                heap[heapSize].lastPointerIndex = lastPointerIndex;
-                heap[heapSize].distance = distance;
-                heapSize += 1;
-            }
-        }
-    }
-
-    // Heapify
-    for (uint32_t startIndex = heapSize / 2; startIndex != 0; ) {
-        startIndex -= 1;
-        for (uint32_t parentIndex = startIndex; ;) {
-            uint32_t childIndex = parentIndex * 2 + 1;
-            if (childIndex >= heapSize) {
-                break;
-            }
-
-            if (childIndex + 1 < heapSize
-                    && heap[childIndex + 1].distance < heap[childIndex].distance) {
-                childIndex += 1;
-            }
-
-            if (heap[parentIndex].distance <= heap[childIndex].distance) {
-                break;
-            }
-
-            swap(heap[parentIndex], heap[childIndex]);
-            parentIndex = childIndex;
-        }
-    }
-
-#if DEBUG_POINTER_ASSIGNMENT
-    ALOGD("assignPointerIds - initial distance min-heap: size=%d", heapSize);
-    for (size_t i = 0; i < heapSize; i++) {
-        ALOGD("  heap[%d]: cur=%d, last=%d, distance=%lld",
-                i, heap[i].currentPointerIndex, heap[i].lastPointerIndex,
-                heap[i].distance);
-    }
-#endif
-
-    // Pull matches out by increasing order of distance.
-    // To avoid reassigning pointers that have already been matched, the loop keeps track
-    // of which last and current pointers have been matched using the matchedXXXBits variables.
-    // It also tracks the used pointer id bits.
-    BitSet32 matchedLastBits(0);
-    BitSet32 matchedCurrentBits(0);
-    BitSet32 usedIdBits(0);
-    bool first = true;
-    for (uint32_t i = min(currentPointerCount, lastPointerCount); heapSize > 0 && i > 0; i--) {
-        while (heapSize > 0) {
-            if (first) {
-                // The first time through the loop, we just consume the root element of
-                // the heap (the one with smallest distance).
-                first = false;
-            } else {
-                // Previous iterations consumed the root element of the heap.
-                // Pop root element off of the heap (sift down).
-                heap[0] = heap[heapSize];
-                for (uint32_t parentIndex = 0; ;) {
-                    uint32_t childIndex = parentIndex * 2 + 1;
-                    if (childIndex >= heapSize) {
-                        break;
-                    }
-
-                    if (childIndex + 1 < heapSize
-                            && heap[childIndex + 1].distance < heap[childIndex].distance) {
-                        childIndex += 1;
-                    }
-
-                    if (heap[parentIndex].distance <= heap[childIndex].distance) {
-                        break;
-                    }
-
-                    swap(heap[parentIndex], heap[childIndex]);
-                    parentIndex = childIndex;
-                }
-
-#if DEBUG_POINTER_ASSIGNMENT
-                ALOGD("assignPointerIds - reduced distance min-heap: size=%d", heapSize);
-                for (size_t i = 0; i < heapSize; i++) {
-                    ALOGD("  heap[%d]: cur=%d, last=%d, distance=%lld",
-                            i, heap[i].currentPointerIndex, heap[i].lastPointerIndex,
-                            heap[i].distance);
-                }
-#endif
-            }
-
-            heapSize -= 1;
-
-            uint32_t currentPointerIndex = heap[0].currentPointerIndex;
-            if (matchedCurrentBits.hasBit(currentPointerIndex)) continue; // already matched
-
-            uint32_t lastPointerIndex = heap[0].lastPointerIndex;
-            if (matchedLastBits.hasBit(lastPointerIndex)) continue; // already matched
-
-            matchedCurrentBits.markBit(currentPointerIndex);
-            matchedLastBits.markBit(lastPointerIndex);
-
-            uint32_t id = mLastRawPointerData.pointers[lastPointerIndex].id;
-            mCurrentRawPointerData.pointers[currentPointerIndex].id = id;
-            mCurrentRawPointerData.idToIndex[id] = currentPointerIndex;
-            mCurrentRawPointerData.markIdBit(id,
-                    mCurrentRawPointerData.isHovering(currentPointerIndex));
-            usedIdBits.markBit(id);
-
-#if DEBUG_POINTER_ASSIGNMENT
-            ALOGD("assignPointerIds - matched: cur=%d, last=%d, id=%d, distance=%lld",
-                    lastPointerIndex, currentPointerIndex, id, heap[0].distance);
-#endif
-            break;
-        }
-    }
-
-    // Assign fresh ids to pointers that were not matched in the process.
-    for (uint32_t i = currentPointerCount - matchedCurrentBits.count(); i != 0; i--) {
-        uint32_t currentPointerIndex = matchedCurrentBits.markFirstUnmarkedBit();
-        uint32_t id = usedIdBits.markFirstUnmarkedBit();
-
-        mCurrentRawPointerData.pointers[currentPointerIndex].id = id;
-        mCurrentRawPointerData.idToIndex[id] = currentPointerIndex;
-        mCurrentRawPointerData.markIdBit(id,
-                mCurrentRawPointerData.isHovering(currentPointerIndex));
-
-#if DEBUG_POINTER_ASSIGNMENT
-        ALOGD("assignPointerIds - assigned: cur=%d, id=%d",
-                currentPointerIndex, id);
-#endif
-    }
-}
-
-int32_t TouchInputMapper::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) {
-    if (mCurrentVirtualKey.down && mCurrentVirtualKey.keyCode == keyCode) {
-        return AKEY_STATE_VIRTUAL;
-    }
-
-    size_t numVirtualKeys = mVirtualKeys.size();
-    for (size_t i = 0; i < numVirtualKeys; i++) {
-        const VirtualKey& virtualKey = mVirtualKeys[i];
-        if (virtualKey.keyCode == keyCode) {
-            return AKEY_STATE_UP;
-        }
-    }
-
-    return AKEY_STATE_UNKNOWN;
-}
-
-int32_t TouchInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) {
-    if (mCurrentVirtualKey.down && mCurrentVirtualKey.scanCode == scanCode) {
-        return AKEY_STATE_VIRTUAL;
-    }
-
-    size_t numVirtualKeys = mVirtualKeys.size();
-    for (size_t i = 0; i < numVirtualKeys; i++) {
-        const VirtualKey& virtualKey = mVirtualKeys[i];
-        if (virtualKey.scanCode == scanCode) {
-            return AKEY_STATE_UP;
-        }
-    }
-
-    return AKEY_STATE_UNKNOWN;
-}
-
-bool TouchInputMapper::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes,
-        const int32_t* keyCodes, uint8_t* outFlags) {
-    size_t numVirtualKeys = mVirtualKeys.size();
-    for (size_t i = 0; i < numVirtualKeys; i++) {
-        const VirtualKey& virtualKey = mVirtualKeys[i];
-
-        for (size_t i = 0; i < numCodes; i++) {
-            if (virtualKey.keyCode == keyCodes[i]) {
-                outFlags[i] = 1;
-            }
-        }
-    }
-
-    return true;
-}
-
-
-// --- SingleTouchInputMapper ---
-
-SingleTouchInputMapper::SingleTouchInputMapper(InputDevice* device) :
-        TouchInputMapper(device) {
-}
-
-SingleTouchInputMapper::~SingleTouchInputMapper() {
-}
-
-void SingleTouchInputMapper::reset(nsecs_t when) {
-    mSingleTouchMotionAccumulator.reset(getDevice());
-
-    TouchInputMapper::reset(when);
-}
-
-void SingleTouchInputMapper::process(const RawEvent* rawEvent) {
-    TouchInputMapper::process(rawEvent);
-
-    mSingleTouchMotionAccumulator.process(rawEvent);
-}
-
-void SingleTouchInputMapper::syncTouch(nsecs_t when, bool* outHavePointerIds) {
-    if (mTouchButtonAccumulator.isToolActive()) {
-        mCurrentRawPointerData.pointerCount = 1;
-        mCurrentRawPointerData.idToIndex[0] = 0;
-
-        bool isHovering = mTouchButtonAccumulator.getToolType() != AMOTION_EVENT_TOOL_TYPE_MOUSE
-                && (mTouchButtonAccumulator.isHovering()
-                        || (mRawPointerAxes.pressure.valid
-                                && mSingleTouchMotionAccumulator.getAbsolutePressure() <= 0));
-        mCurrentRawPointerData.markIdBit(0, isHovering);
-
-        RawPointerData::Pointer& outPointer = mCurrentRawPointerData.pointers[0];
-        outPointer.id = 0;
-        outPointer.x = mSingleTouchMotionAccumulator.getAbsoluteX();
-        outPointer.y = mSingleTouchMotionAccumulator.getAbsoluteY();
-        outPointer.pressure = mSingleTouchMotionAccumulator.getAbsolutePressure();
-        outPointer.touchMajor = 0;
-        outPointer.touchMinor = 0;
-        outPointer.toolMajor = mSingleTouchMotionAccumulator.getAbsoluteToolWidth();
-        outPointer.toolMinor = mSingleTouchMotionAccumulator.getAbsoluteToolWidth();
-        outPointer.orientation = 0;
-        outPointer.distance = mSingleTouchMotionAccumulator.getAbsoluteDistance();
-        outPointer.tiltX = mSingleTouchMotionAccumulator.getAbsoluteTiltX();
-        outPointer.tiltY = mSingleTouchMotionAccumulator.getAbsoluteTiltY();
-        outPointer.toolType = mTouchButtonAccumulator.getToolType();
-        if (outPointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) {
-            outPointer.toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
-        }
-        outPointer.isHovering = isHovering;
-    }
-}
-
-void SingleTouchInputMapper::configureRawPointerAxes() {
-    TouchInputMapper::configureRawPointerAxes();
-
-    getAbsoluteAxisInfo(ABS_X, &mRawPointerAxes.x);
-    getAbsoluteAxisInfo(ABS_Y, &mRawPointerAxes.y);
-    getAbsoluteAxisInfo(ABS_PRESSURE, &mRawPointerAxes.pressure);
-    getAbsoluteAxisInfo(ABS_TOOL_WIDTH, &mRawPointerAxes.toolMajor);
-    getAbsoluteAxisInfo(ABS_DISTANCE, &mRawPointerAxes.distance);
-    getAbsoluteAxisInfo(ABS_TILT_X, &mRawPointerAxes.tiltX);
-    getAbsoluteAxisInfo(ABS_TILT_Y, &mRawPointerAxes.tiltY);
-}
-
-bool SingleTouchInputMapper::hasStylus() const {
-    return mTouchButtonAccumulator.hasStylus();
-}
-
-
-// --- MultiTouchInputMapper ---
-
-MultiTouchInputMapper::MultiTouchInputMapper(InputDevice* device) :
-        TouchInputMapper(device) {
-}
-
-MultiTouchInputMapper::~MultiTouchInputMapper() {
-}
-
-void MultiTouchInputMapper::reset(nsecs_t when) {
-    mMultiTouchMotionAccumulator.reset(getDevice());
-
-    mPointerIdBits.clear();
-
-    TouchInputMapper::reset(when);
-}
-
-void MultiTouchInputMapper::process(const RawEvent* rawEvent) {
-    TouchInputMapper::process(rawEvent);
-
-    mMultiTouchMotionAccumulator.process(rawEvent);
-}
-
-void MultiTouchInputMapper::syncTouch(nsecs_t when, bool* outHavePointerIds) {
-    size_t inCount = mMultiTouchMotionAccumulator.getSlotCount();
-    size_t outCount = 0;
-    BitSet32 newPointerIdBits;
-
-    for (size_t inIndex = 0; inIndex < inCount; inIndex++) {
-        const MultiTouchMotionAccumulator::Slot* inSlot =
-                mMultiTouchMotionAccumulator.getSlot(inIndex);
-        if (!inSlot->isInUse()) {
-            continue;
-        }
-
-        if (outCount >= MAX_POINTERS) {
-#if DEBUG_POINTERS
-            ALOGD("MultiTouch device %s emitted more than maximum of %d pointers; "
-                    "ignoring the rest.",
-                    getDeviceName().string(), MAX_POINTERS);
-#endif
-            break; // too many fingers!
-        }
-
-        RawPointerData::Pointer& outPointer = mCurrentRawPointerData.pointers[outCount];
-        outPointer.x = inSlot->getX();
-        outPointer.y = inSlot->getY();
-        outPointer.pressure = inSlot->getPressure();
-        outPointer.touchMajor = inSlot->getTouchMajor();
-        outPointer.touchMinor = inSlot->getTouchMinor();
-        outPointer.toolMajor = inSlot->getToolMajor();
-        outPointer.toolMinor = inSlot->getToolMinor();
-        outPointer.orientation = inSlot->getOrientation();
-        outPointer.distance = inSlot->getDistance();
-        outPointer.tiltX = 0;
-        outPointer.tiltY = 0;
-
-        outPointer.toolType = inSlot->getToolType();
-        if (outPointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) {
-            outPointer.toolType = mTouchButtonAccumulator.getToolType();
-            if (outPointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) {
-                outPointer.toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
-            }
-        }
-
-        bool isHovering = mTouchButtonAccumulator.getToolType() != AMOTION_EVENT_TOOL_TYPE_MOUSE
-                && (mTouchButtonAccumulator.isHovering()
-                        || (mRawPointerAxes.pressure.valid && inSlot->getPressure() <= 0));
-        outPointer.isHovering = isHovering;
-
-        // Assign pointer id using tracking id if available.
-        if (*outHavePointerIds) {
-            int32_t trackingId = inSlot->getTrackingId();
-            int32_t id = -1;
-            if (trackingId >= 0) {
-                for (BitSet32 idBits(mPointerIdBits); !idBits.isEmpty(); ) {
-                    uint32_t n = idBits.clearFirstMarkedBit();
-                    if (mPointerTrackingIdMap[n] == trackingId) {
-                        id = n;
-                    }
-                }
-
-                if (id < 0 && !mPointerIdBits.isFull()) {
-                    id = mPointerIdBits.markFirstUnmarkedBit();
-                    mPointerTrackingIdMap[id] = trackingId;
-                }
-            }
-            if (id < 0) {
-                *outHavePointerIds = false;
-                mCurrentRawPointerData.clearIdBits();
-                newPointerIdBits.clear();
-            } else {
-                outPointer.id = id;
-                mCurrentRawPointerData.idToIndex[id] = outCount;
-                mCurrentRawPointerData.markIdBit(id, isHovering);
-                newPointerIdBits.markBit(id);
-            }
-        }
-
-        outCount += 1;
-    }
-
-    mCurrentRawPointerData.pointerCount = outCount;
-    mPointerIdBits = newPointerIdBits;
-
-    mMultiTouchMotionAccumulator.finishSync();
-}
-
-void MultiTouchInputMapper::configureRawPointerAxes() {
-    TouchInputMapper::configureRawPointerAxes();
-
-    getAbsoluteAxisInfo(ABS_MT_POSITION_X, &mRawPointerAxes.x);
-    getAbsoluteAxisInfo(ABS_MT_POSITION_Y, &mRawPointerAxes.y);
-    getAbsoluteAxisInfo(ABS_MT_TOUCH_MAJOR, &mRawPointerAxes.touchMajor);
-    getAbsoluteAxisInfo(ABS_MT_TOUCH_MINOR, &mRawPointerAxes.touchMinor);
-    getAbsoluteAxisInfo(ABS_MT_WIDTH_MAJOR, &mRawPointerAxes.toolMajor);
-    getAbsoluteAxisInfo(ABS_MT_WIDTH_MINOR, &mRawPointerAxes.toolMinor);
-    getAbsoluteAxisInfo(ABS_MT_ORIENTATION, &mRawPointerAxes.orientation);
-    getAbsoluteAxisInfo(ABS_MT_PRESSURE, &mRawPointerAxes.pressure);
-    getAbsoluteAxisInfo(ABS_MT_DISTANCE, &mRawPointerAxes.distance);
-    getAbsoluteAxisInfo(ABS_MT_TRACKING_ID, &mRawPointerAxes.trackingId);
-    getAbsoluteAxisInfo(ABS_MT_SLOT, &mRawPointerAxes.slot);
-
-    if (mRawPointerAxes.trackingId.valid
-            && mRawPointerAxes.slot.valid
-            && mRawPointerAxes.slot.minValue == 0 && mRawPointerAxes.slot.maxValue > 0) {
-        size_t slotCount = mRawPointerAxes.slot.maxValue + 1;
-        if (slotCount > MAX_SLOTS) {
-            ALOGW("MultiTouch Device %s reported %d slots but the framework "
-                    "only supports a maximum of %d slots at this time.",
-                    getDeviceName().string(), slotCount, MAX_SLOTS);
-            slotCount = MAX_SLOTS;
-        }
-        mMultiTouchMotionAccumulator.configure(getDevice(),
-                slotCount, true /*usingSlotsProtocol*/);
-    } else {
-        mMultiTouchMotionAccumulator.configure(getDevice(),
-                MAX_POINTERS, false /*usingSlotsProtocol*/);
-    }
-}
-
-bool MultiTouchInputMapper::hasStylus() const {
-    return mMultiTouchMotionAccumulator.hasStylus()
-            || mTouchButtonAccumulator.hasStylus();
-}
-
-
-// --- JoystickInputMapper ---
-
-JoystickInputMapper::JoystickInputMapper(InputDevice* device) :
-        InputMapper(device) {
-}
-
-JoystickInputMapper::~JoystickInputMapper() {
-}
-
-uint32_t JoystickInputMapper::getSources() {
-    return AINPUT_SOURCE_JOYSTICK;
-}
-
-void JoystickInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
-    InputMapper::populateDeviceInfo(info);
-
-    for (size_t i = 0; i < mAxes.size(); i++) {
-        const Axis& axis = mAxes.valueAt(i);
-        addMotionRange(axis.axisInfo.axis, axis, info);
-
-        if (axis.axisInfo.mode == AxisInfo::MODE_SPLIT) {
-            addMotionRange(axis.axisInfo.highAxis, axis, info);
-
-        }
-    }
-}
-
-void JoystickInputMapper::addMotionRange(int32_t axisId, const Axis& axis,
-        InputDeviceInfo* info) {
-    info->addMotionRange(axisId, AINPUT_SOURCE_JOYSTICK,
-            axis.min, axis.max, axis.flat, axis.fuzz, axis.resolution);
-    /* In order to ease the transition for developers from using the old axes
-     * to the newer, more semantically correct axes, we'll continue to register
-     * the old axes as duplicates of their corresponding new ones.  */
-    int32_t compatAxis = getCompatAxis(axisId);
-    if (compatAxis >= 0) {
-        info->addMotionRange(compatAxis, AINPUT_SOURCE_JOYSTICK,
-                axis.min, axis.max, axis.flat, axis.fuzz, axis.resolution);
-    }
-}
-
-/* A mapping from axes the joystick actually has to the axes that should be
- * artificially created for compatibility purposes.
- * Returns -1 if no compatibility axis is needed. */
-int32_t JoystickInputMapper::getCompatAxis(int32_t axis) {
-    switch(axis) {
-    case AMOTION_EVENT_AXIS_LTRIGGER:
-        return AMOTION_EVENT_AXIS_BRAKE;
-    case AMOTION_EVENT_AXIS_RTRIGGER:
-        return AMOTION_EVENT_AXIS_GAS;
-    }
-    return -1;
-}
-
-void JoystickInputMapper::dump(String8& dump) {
-    dump.append(INDENT2 "Joystick Input Mapper:\n");
-
-    dump.append(INDENT3 "Axes:\n");
-    size_t numAxes = mAxes.size();
-    for (size_t i = 0; i < numAxes; i++) {
-        const Axis& axis = mAxes.valueAt(i);
-        const char* label = getAxisLabel(axis.axisInfo.axis);
-        if (label) {
-            dump.appendFormat(INDENT4 "%s", label);
-        } else {
-            dump.appendFormat(INDENT4 "%d", axis.axisInfo.axis);
-        }
-        if (axis.axisInfo.mode == AxisInfo::MODE_SPLIT) {
-            label = getAxisLabel(axis.axisInfo.highAxis);
-            if (label) {
-                dump.appendFormat(" / %s (split at %d)", label, axis.axisInfo.splitValue);
-            } else {
-                dump.appendFormat(" / %d (split at %d)", axis.axisInfo.highAxis,
-                        axis.axisInfo.splitValue);
-            }
-        } else if (axis.axisInfo.mode == AxisInfo::MODE_INVERT) {
-            dump.append(" (invert)");
-        }
-
-        dump.appendFormat(": min=%0.5f, max=%0.5f, flat=%0.5f, fuzz=%0.5f, resolution=%0.5f\n",
-                axis.min, axis.max, axis.flat, axis.fuzz, axis.resolution);
-        dump.appendFormat(INDENT4 "  scale=%0.5f, offset=%0.5f, "
-                "highScale=%0.5f, highOffset=%0.5f\n",
-                axis.scale, axis.offset, axis.highScale, axis.highOffset);
-        dump.appendFormat(INDENT4 "  rawAxis=%d, rawMin=%d, rawMax=%d, "
-                "rawFlat=%d, rawFuzz=%d, rawResolution=%d\n",
-                mAxes.keyAt(i), axis.rawAxisInfo.minValue, axis.rawAxisInfo.maxValue,
-                axis.rawAxisInfo.flat, axis.rawAxisInfo.fuzz, axis.rawAxisInfo.resolution);
-    }
-}
-
-void JoystickInputMapper::configure(nsecs_t when,
-        const InputReaderConfiguration* config, uint32_t changes) {
-    InputMapper::configure(when, config, changes);
-
-    if (!changes) { // first time only
-        // Collect all axes.
-        for (int32_t abs = 0; abs <= ABS_MAX; abs++) {
-            if (!(getAbsAxisUsage(abs, getDevice()->getClasses())
-                    & INPUT_DEVICE_CLASS_JOYSTICK)) {
-                continue; // axis must be claimed by a different device
-            }
-
-            RawAbsoluteAxisInfo rawAxisInfo;
-            getAbsoluteAxisInfo(abs, &rawAxisInfo);
-            if (rawAxisInfo.valid) {
-                // Map axis.
-                AxisInfo axisInfo;
-                bool explicitlyMapped = !getEventHub()->mapAxis(getDeviceId(), abs, &axisInfo);
-                if (!explicitlyMapped) {
-                    // Axis is not explicitly mapped, will choose a generic axis later.
-                    axisInfo.mode = AxisInfo::MODE_NORMAL;
-                    axisInfo.axis = -1;
-                }
-
-                // Apply flat override.
-                int32_t rawFlat = axisInfo.flatOverride < 0
-                        ? rawAxisInfo.flat : axisInfo.flatOverride;
-
-                // Calculate scaling factors and limits.
-                Axis axis;
-                if (axisInfo.mode == AxisInfo::MODE_SPLIT) {
-                    float scale = 1.0f / (axisInfo.splitValue - rawAxisInfo.minValue);
-                    float highScale = 1.0f / (rawAxisInfo.maxValue - axisInfo.splitValue);
-                    axis.initialize(rawAxisInfo, axisInfo, explicitlyMapped,
-                            scale, 0.0f, highScale, 0.0f,
-                            0.0f, 1.0f, rawFlat * scale, rawAxisInfo.fuzz * scale,
-                            rawAxisInfo.resolution * scale);
-                } else if (isCenteredAxis(axisInfo.axis)) {
-                    float scale = 2.0f / (rawAxisInfo.maxValue - rawAxisInfo.minValue);
-                    float offset = avg(rawAxisInfo.minValue, rawAxisInfo.maxValue) * -scale;
-                    axis.initialize(rawAxisInfo, axisInfo, explicitlyMapped,
-                            scale, offset, scale, offset,
-                            -1.0f, 1.0f, rawFlat * scale, rawAxisInfo.fuzz * scale,
-                            rawAxisInfo.resolution * scale);
-                } else {
-                    float scale = 1.0f / (rawAxisInfo.maxValue - rawAxisInfo.minValue);
-                    axis.initialize(rawAxisInfo, axisInfo, explicitlyMapped,
-                            scale, 0.0f, scale, 0.0f,
-                            0.0f, 1.0f, rawFlat * scale, rawAxisInfo.fuzz * scale,
-                            rawAxisInfo.resolution * scale);
-                }
-
-                // To eliminate noise while the joystick is at rest, filter out small variations
-                // in axis values up front.
-                axis.filter = axis.fuzz ? axis.fuzz : axis.flat * 0.25f;
-
-                mAxes.add(abs, axis);
-            }
-        }
-
-        // If there are too many axes, start dropping them.
-        // Prefer to keep explicitly mapped axes.
-        if (mAxes.size() > PointerCoords::MAX_AXES) {
-            ALOGI("Joystick '%s' has %d axes but the framework only supports a maximum of %d.",
-                    getDeviceName().string(), mAxes.size(), PointerCoords::MAX_AXES);
-            pruneAxes(true);
-            pruneAxes(false);
-        }
-
-        // Assign generic axis ids to remaining axes.
-        int32_t nextGenericAxisId = AMOTION_EVENT_AXIS_GENERIC_1;
-        size_t numAxes = mAxes.size();
-        for (size_t i = 0; i < numAxes; i++) {
-            Axis& axis = mAxes.editValueAt(i);
-            if (axis.axisInfo.axis < 0) {
-                while (nextGenericAxisId <= AMOTION_EVENT_AXIS_GENERIC_16
-                        && haveAxis(nextGenericAxisId)) {
-                    nextGenericAxisId += 1;
-                }
-
-                if (nextGenericAxisId <= AMOTION_EVENT_AXIS_GENERIC_16) {
-                    axis.axisInfo.axis = nextGenericAxisId;
-                    nextGenericAxisId += 1;
-                } else {
-                    ALOGI("Ignoring joystick '%s' axis %d because all of the generic axis ids "
-                            "have already been assigned to other axes.",
-                            getDeviceName().string(), mAxes.keyAt(i));
-                    mAxes.removeItemsAt(i--);
-                    numAxes -= 1;
-                }
-            }
-        }
-    }
-}
-
-bool JoystickInputMapper::haveAxis(int32_t axisId) {
-    size_t numAxes = mAxes.size();
-    for (size_t i = 0; i < numAxes; i++) {
-        const Axis& axis = mAxes.valueAt(i);
-        if (axis.axisInfo.axis == axisId
-                || (axis.axisInfo.mode == AxisInfo::MODE_SPLIT
-                        && axis.axisInfo.highAxis == axisId)) {
-            return true;
-        }
-    }
-    return false;
-}
-
-void JoystickInputMapper::pruneAxes(bool ignoreExplicitlyMappedAxes) {
-    size_t i = mAxes.size();
-    while (mAxes.size() > PointerCoords::MAX_AXES && i-- > 0) {
-        if (ignoreExplicitlyMappedAxes && mAxes.valueAt(i).explicitlyMapped) {
-            continue;
-        }
-        ALOGI("Discarding joystick '%s' axis %d because there are too many axes.",
-                getDeviceName().string(), mAxes.keyAt(i));
-        mAxes.removeItemsAt(i);
-    }
-}
-
-bool JoystickInputMapper::isCenteredAxis(int32_t axis) {
-    switch (axis) {
-    case AMOTION_EVENT_AXIS_X:
-    case AMOTION_EVENT_AXIS_Y:
-    case AMOTION_EVENT_AXIS_Z:
-    case AMOTION_EVENT_AXIS_RX:
-    case AMOTION_EVENT_AXIS_RY:
-    case AMOTION_EVENT_AXIS_RZ:
-    case AMOTION_EVENT_AXIS_HAT_X:
-    case AMOTION_EVENT_AXIS_HAT_Y:
-    case AMOTION_EVENT_AXIS_ORIENTATION:
-    case AMOTION_EVENT_AXIS_RUDDER:
-    case AMOTION_EVENT_AXIS_WHEEL:
-        return true;
-    default:
-        return false;
-    }
-}
-
-void JoystickInputMapper::reset(nsecs_t when) {
-    // Recenter all axes.
-    size_t numAxes = mAxes.size();
-    for (size_t i = 0; i < numAxes; i++) {
-        Axis& axis = mAxes.editValueAt(i);
-        axis.resetValue();
-    }
-
-    InputMapper::reset(when);
-}
-
-void JoystickInputMapper::process(const RawEvent* rawEvent) {
-    switch (rawEvent->type) {
-    case EV_ABS: {
-        ssize_t index = mAxes.indexOfKey(rawEvent->code);
-        if (index >= 0) {
-            Axis& axis = mAxes.editValueAt(index);
-            float newValue, highNewValue;
-            switch (axis.axisInfo.mode) {
-            case AxisInfo::MODE_INVERT:
-                newValue = (axis.rawAxisInfo.maxValue - rawEvent->value)
-                        * axis.scale + axis.offset;
-                highNewValue = 0.0f;
-                break;
-            case AxisInfo::MODE_SPLIT:
-                if (rawEvent->value < axis.axisInfo.splitValue) {
-                    newValue = (axis.axisInfo.splitValue - rawEvent->value)
-                            * axis.scale + axis.offset;
-                    highNewValue = 0.0f;
-                } else if (rawEvent->value > axis.axisInfo.splitValue) {
-                    newValue = 0.0f;
-                    highNewValue = (rawEvent->value - axis.axisInfo.splitValue)
-                            * axis.highScale + axis.highOffset;
-                } else {
-                    newValue = 0.0f;
-                    highNewValue = 0.0f;
-                }
-                break;
-            default:
-                newValue = rawEvent->value * axis.scale + axis.offset;
-                highNewValue = 0.0f;
-                break;
-            }
-            axis.newValue = newValue;
-            axis.highNewValue = highNewValue;
-        }
-        break;
-    }
-
-    case EV_SYN:
-        switch (rawEvent->code) {
-        case SYN_REPORT:
-            sync(rawEvent->when, false /*force*/);
-            break;
-        }
-        break;
-    }
-}
-
-void JoystickInputMapper::sync(nsecs_t when, bool force) {
-    if (!filterAxes(force)) {
-        return;
-    }
-
-    int32_t metaState = mContext->getGlobalMetaState();
-    int32_t buttonState = 0;
-
-    PointerProperties pointerProperties;
-    pointerProperties.clear();
-    pointerProperties.id = 0;
-    pointerProperties.toolType = AMOTION_EVENT_TOOL_TYPE_UNKNOWN;
-
-    PointerCoords pointerCoords;
-    pointerCoords.clear();
-
-    size_t numAxes = mAxes.size();
-    for (size_t i = 0; i < numAxes; i++) {
-        const Axis& axis = mAxes.valueAt(i);
-        setPointerCoordsAxisValue(&pointerCoords, axis.axisInfo.axis, axis.currentValue);
-        if (axis.axisInfo.mode == AxisInfo::MODE_SPLIT) {
-            setPointerCoordsAxisValue(&pointerCoords, axis.axisInfo.highAxis,
-                    axis.highCurrentValue);
-        }
-    }
-
-    // Moving a joystick axis should not wake the device because joysticks can
-    // be fairly noisy even when not in use.  On the other hand, pushing a gamepad
-    // button will likely wake the device.
-    // TODO: Use the input device configuration to control this behavior more finely.
-    uint32_t policyFlags = 0;
-
-    NotifyMotionArgs args(when, getDeviceId(), AINPUT_SOURCE_JOYSTICK, policyFlags,
-            AMOTION_EVENT_ACTION_MOVE, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
-            ADISPLAY_ID_NONE, 1, &pointerProperties, &pointerCoords, 0, 0, 0);
-    getListener()->notifyMotion(&args);
-}
-
-void JoystickInputMapper::setPointerCoordsAxisValue(PointerCoords* pointerCoords,
-        int32_t axis, float value) {
-    pointerCoords->setAxisValue(axis, value);
-    /* In order to ease the transition for developers from using the old axes
-     * to the newer, more semantically correct axes, we'll continue to produce
-     * values for the old axes as mirrors of the value of their corresponding
-     * new axes. */
-    int32_t compatAxis = getCompatAxis(axis);
-    if (compatAxis >= 0) {
-        pointerCoords->setAxisValue(compatAxis, value);
-    }
-}
-
-bool JoystickInputMapper::filterAxes(bool force) {
-    bool atLeastOneSignificantChange = force;
-    size_t numAxes = mAxes.size();
-    for (size_t i = 0; i < numAxes; i++) {
-        Axis& axis = mAxes.editValueAt(i);
-        if (force || hasValueChangedSignificantly(axis.filter,
-                axis.newValue, axis.currentValue, axis.min, axis.max)) {
-            axis.currentValue = axis.newValue;
-            atLeastOneSignificantChange = true;
-        }
-        if (axis.axisInfo.mode == AxisInfo::MODE_SPLIT) {
-            if (force || hasValueChangedSignificantly(axis.filter,
-                    axis.highNewValue, axis.highCurrentValue, axis.min, axis.max)) {
-                axis.highCurrentValue = axis.highNewValue;
-                atLeastOneSignificantChange = true;
-            }
-        }
-    }
-    return atLeastOneSignificantChange;
-}
-
-bool JoystickInputMapper::hasValueChangedSignificantly(
-        float filter, float newValue, float currentValue, float min, float max) {
-    if (newValue != currentValue) {
-        // Filter out small changes in value unless the value is converging on the axis
-        // bounds or center point.  This is intended to reduce the amount of information
-        // sent to applications by particularly noisy joysticks (such as PS3).
-        if (fabs(newValue - currentValue) > filter
-                || hasMovedNearerToValueWithinFilteredRange(filter, newValue, currentValue, min)
-                || hasMovedNearerToValueWithinFilteredRange(filter, newValue, currentValue, max)
-                || hasMovedNearerToValueWithinFilteredRange(filter, newValue, currentValue, 0)) {
-            return true;
-        }
-    }
-    return false;
-}
-
-bool JoystickInputMapper::hasMovedNearerToValueWithinFilteredRange(
-        float filter, float newValue, float currentValue, float thresholdValue) {
-    float newDistance = fabs(newValue - thresholdValue);
-    if (newDistance < filter) {
-        float oldDistance = fabs(currentValue - thresholdValue);
-        if (newDistance < oldDistance) {
-            return true;
-        }
-    }
-    return false;
-}
-
-} // namespace android
diff --git a/libs/input/InputReader.h b/libs/input/InputReader.h
deleted file mode 100644
index 674f67d..0000000
--- a/libs/input/InputReader.h
+++ /dev/null
@@ -1,1817 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _UI_INPUT_READER_H
-#define _UI_INPUT_READER_H
-
-#include "EventHub.h"
-#include "PointerController.h"
-#include "InputListener.h"
-
-#include <input/Input.h>
-#include <input/VelocityControl.h>
-#include <input/VelocityTracker.h>
-#include <utils/KeyedVector.h>
-#include <utils/threads.h>
-#include <utils/Timers.h>
-#include <utils/RefBase.h>
-#include <utils/String8.h>
-#include <utils/BitSet.h>
-
-#include <stddef.h>
-#include <unistd.h>
-
-// Maximum supported size of a vibration pattern.
-// Must be at least 2.
-#define MAX_VIBRATE_PATTERN_SIZE 100
-
-// Maximum allowable delay value in a vibration pattern before
-// which the delay will be truncated.
-#define MAX_VIBRATE_PATTERN_DELAY_NSECS (1000000 * 1000000000LL)
-
-namespace android {
-
-class InputDevice;
-class InputMapper;
-
-/*
- * Describes how coordinates are mapped on a physical display.
- * See com.android.server.display.DisplayViewport.
- */
-struct DisplayViewport {
-    int32_t displayId; // -1 if invalid
-    int32_t orientation;
-    int32_t logicalLeft;
-    int32_t logicalTop;
-    int32_t logicalRight;
-    int32_t logicalBottom;
-    int32_t physicalLeft;
-    int32_t physicalTop;
-    int32_t physicalRight;
-    int32_t physicalBottom;
-    int32_t deviceWidth;
-    int32_t deviceHeight;
-
-    DisplayViewport() :
-            displayId(ADISPLAY_ID_NONE), orientation(DISPLAY_ORIENTATION_0),
-            logicalLeft(0), logicalTop(0), logicalRight(0), logicalBottom(0),
-            physicalLeft(0), physicalTop(0), physicalRight(0), physicalBottom(0),
-            deviceWidth(0), deviceHeight(0) {
-    }
-
-    bool operator==(const DisplayViewport& other) const {
-        return displayId == other.displayId
-                && orientation == other.orientation
-                && logicalLeft == other.logicalLeft
-                && logicalTop == other.logicalTop
-                && logicalRight == other.logicalRight
-                && logicalBottom == other.logicalBottom
-                && physicalLeft == other.physicalLeft
-                && physicalTop == other.physicalTop
-                && physicalRight == other.physicalRight
-                && physicalBottom == other.physicalBottom
-                && deviceWidth == other.deviceWidth
-                && deviceHeight == other.deviceHeight;
-    }
-
-    bool operator!=(const DisplayViewport& other) const {
-        return !(*this == other);
-    }
-
-    inline bool isValid() const {
-        return displayId >= 0;
-    }
-
-    void setNonDisplayViewport(int32_t width, int32_t height) {
-        displayId = ADISPLAY_ID_NONE;
-        orientation = DISPLAY_ORIENTATION_0;
-        logicalLeft = 0;
-        logicalTop = 0;
-        logicalRight = width;
-        logicalBottom = height;
-        physicalLeft = 0;
-        physicalTop = 0;
-        physicalRight = width;
-        physicalBottom = height;
-        deviceWidth = width;
-        deviceHeight = height;
-    }
-};
-
-/*
- * Input reader configuration.
- *
- * Specifies various options that modify the behavior of the input reader.
- */
-struct InputReaderConfiguration {
-    // Describes changes that have occurred.
-    enum {
-        // The pointer speed changed.
-        CHANGE_POINTER_SPEED = 1 << 0,
-
-        // The pointer gesture control changed.
-        CHANGE_POINTER_GESTURE_ENABLEMENT = 1 << 1,
-
-        // The display size or orientation changed.
-        CHANGE_DISPLAY_INFO = 1 << 2,
-
-        // The visible touches option changed.
-        CHANGE_SHOW_TOUCHES = 1 << 3,
-
-        // The keyboard layouts must be reloaded.
-        CHANGE_KEYBOARD_LAYOUTS = 1 << 4,
-
-        // The device name alias supplied by the may have changed for some devices.
-        CHANGE_DEVICE_ALIAS = 1 << 5,
-
-        // All devices must be reopened.
-        CHANGE_MUST_REOPEN = 1 << 31,
-    };
-
-    // Gets the amount of time to disable virtual keys after the screen is touched
-    // in order to filter out accidental virtual key presses due to swiping gestures
-    // or taps near the edge of the display.  May be 0 to disable the feature.
-    nsecs_t virtualKeyQuietTime;
-
-    // The excluded device names for the platform.
-    // Devices with these names will be ignored.
-    Vector<String8> excludedDeviceNames;
-
-    // Velocity control parameters for mouse pointer movements.
-    VelocityControlParameters pointerVelocityControlParameters;
-
-    // Velocity control parameters for mouse wheel movements.
-    VelocityControlParameters wheelVelocityControlParameters;
-
-    // True if pointer gestures are enabled.
-    bool pointerGesturesEnabled;
-
-    // Quiet time between certain pointer gesture transitions.
-    // Time to allow for all fingers or buttons to settle into a stable state before
-    // starting a new gesture.
-    nsecs_t pointerGestureQuietInterval;
-
-    // The minimum speed that a pointer must travel for us to consider switching the active
-    // touch pointer to it during a drag.  This threshold is set to avoid switching due
-    // to noise from a finger resting on the touch pad (perhaps just pressing it down).
-    float pointerGestureDragMinSwitchSpeed; // in pixels per second
-
-    // Tap gesture delay time.
-    // The time between down and up must be less than this to be considered a tap.
-    nsecs_t pointerGestureTapInterval;
-
-    // Tap drag gesture delay time.
-    // The time between the previous tap's up and the next down must be less than
-    // this to be considered a drag.  Otherwise, the previous tap is finished and a
-    // new tap begins.
-    //
-    // Note that the previous tap will be held down for this entire duration so this
-    // interval must be shorter than the long press timeout.
-    nsecs_t pointerGestureTapDragInterval;
-
-    // The distance in pixels that the pointer is allowed to move from initial down
-    // to up and still be called a tap.
-    float pointerGestureTapSlop; // in pixels
-
-    // Time after the first touch points go down to settle on an initial centroid.
-    // This is intended to be enough time to handle cases where the user puts down two
-    // fingers at almost but not quite exactly the same time.
-    nsecs_t pointerGestureMultitouchSettleInterval;
-
-    // The transition from PRESS to SWIPE or FREEFORM gesture mode is made when
-    // at least two pointers have moved at least this far from their starting place.
-    float pointerGestureMultitouchMinDistance; // in pixels
-
-    // The transition from PRESS to SWIPE gesture mode can only occur when the
-    // cosine of the angle between the two vectors is greater than or equal to than this value
-    // which indicates that the vectors are oriented in the same direction.
-    // When the vectors are oriented in the exactly same direction, the cosine is 1.0.
-    // (In exactly opposite directions, the cosine is -1.0.)
-    float pointerGestureSwipeTransitionAngleCosine;
-
-    // The transition from PRESS to SWIPE gesture mode can only occur when the
-    // fingers are no more than this far apart relative to the diagonal size of
-    // the touch pad.  For example, a ratio of 0.5 means that the fingers must be
-    // no more than half the diagonal size of the touch pad apart.
-    float pointerGestureSwipeMaxWidthRatio;
-
-    // The gesture movement speed factor relative to the size of the display.
-    // Movement speed applies when the fingers are moving in the same direction.
-    // Without acceleration, a full swipe of the touch pad diagonal in movement mode
-    // will cover this portion of the display diagonal.
-    float pointerGestureMovementSpeedRatio;
-
-    // The gesture zoom speed factor relative to the size of the display.
-    // Zoom speed applies when the fingers are mostly moving relative to each other
-    // to execute a scale gesture or similar.
-    // Without acceleration, a full swipe of the touch pad diagonal in zoom mode
-    // will cover this portion of the display diagonal.
-    float pointerGestureZoomSpeedRatio;
-
-    // True to show the location of touches on the touch screen as spots.
-    bool showTouches;
-
-    InputReaderConfiguration() :
-            virtualKeyQuietTime(0),
-            pointerVelocityControlParameters(1.0f, 500.0f, 3000.0f, 3.0f),
-            wheelVelocityControlParameters(1.0f, 15.0f, 50.0f, 4.0f),
-            pointerGesturesEnabled(true),
-            pointerGestureQuietInterval(100 * 1000000LL), // 100 ms
-            pointerGestureDragMinSwitchSpeed(50), // 50 pixels per second
-            pointerGestureTapInterval(150 * 1000000LL), // 150 ms
-            pointerGestureTapDragInterval(150 * 1000000LL), // 150 ms
-            pointerGestureTapSlop(10.0f), // 10 pixels
-            pointerGestureMultitouchSettleInterval(100 * 1000000LL), // 100 ms
-            pointerGestureMultitouchMinDistance(15), // 15 pixels
-            pointerGestureSwipeTransitionAngleCosine(0.2588f), // cosine of 75 degrees
-            pointerGestureSwipeMaxWidthRatio(0.25f),
-            pointerGestureMovementSpeedRatio(0.8f),
-            pointerGestureZoomSpeedRatio(0.3f),
-            showTouches(false) { }
-
-    bool getDisplayInfo(bool external, DisplayViewport* outViewport) const;
-    void setDisplayInfo(bool external, const DisplayViewport& viewport);
-
-private:
-    DisplayViewport mInternalDisplay;
-    DisplayViewport mExternalDisplay;
-};
-
-
-/*
- * Input reader policy interface.
- *
- * The input reader policy is used by the input reader to interact with the Window Manager
- * and other system components.
- *
- * The actual implementation is partially supported by callbacks into the DVM
- * via JNI.  This interface is also mocked in the unit tests.
- *
- * These methods must NOT re-enter the input reader since they may be called while
- * holding the input reader lock.
- */
-class InputReaderPolicyInterface : public virtual RefBase {
-protected:
-    InputReaderPolicyInterface() { }
-    virtual ~InputReaderPolicyInterface() { }
-
-public:
-    /* Gets the input reader configuration. */
-    virtual void getReaderConfiguration(InputReaderConfiguration* outConfig) = 0;
-
-    /* Gets a pointer controller associated with the specified cursor device (ie. a mouse). */
-    virtual sp<PointerControllerInterface> obtainPointerController(int32_t deviceId) = 0;
-
-    /* Notifies the input reader policy that some input devices have changed
-     * and provides information about all current input devices.
-     */
-    virtual void notifyInputDevicesChanged(const Vector<InputDeviceInfo>& inputDevices) = 0;
-
-    /* Gets the keyboard layout for a particular input device. */
-    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;
-};
-
-
-/* Processes raw input events and sends cooked event data to an input listener. */
-class InputReaderInterface : public virtual RefBase {
-protected:
-    InputReaderInterface() { }
-    virtual ~InputReaderInterface() { }
-
-public:
-    /* Dumps the state of the input reader.
-     *
-     * This method may be called on any thread (usually by the input manager). */
-    virtual void dump(String8& dump) = 0;
-
-    /* Called by the heatbeat to ensures that the reader has not deadlocked. */
-    virtual void monitor() = 0;
-
-    /* Runs a single iteration of the processing loop.
-     * Nominally reads and processes one incoming message from the EventHub.
-     *
-     * This method should be called on the input reader thread.
-     */
-    virtual void loopOnce() = 0;
-
-    /* Gets information about all input devices.
-     *
-     * This method may be called on any thread (usually by the input manager).
-     */
-    virtual void getInputDevices(Vector<InputDeviceInfo>& outInputDevices) = 0;
-
-    /* Query current input state. */
-    virtual int32_t getScanCodeState(int32_t deviceId, uint32_t sourceMask,
-            int32_t scanCode) = 0;
-    virtual int32_t getKeyCodeState(int32_t deviceId, uint32_t sourceMask,
-            int32_t keyCode) = 0;
-    virtual int32_t getSwitchState(int32_t deviceId, uint32_t sourceMask,
-            int32_t sw) = 0;
-
-    /* Determine whether physical keys exist for the given framework-domain key codes. */
-    virtual bool hasKeys(int32_t deviceId, uint32_t sourceMask,
-            size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) = 0;
-
-    /* Requests that a reconfiguration of all input devices.
-     * The changes flag is a bitfield that indicates what has changed and whether
-     * the input devices must all be reopened. */
-    virtual void requestRefreshConfiguration(uint32_t changes) = 0;
-
-    /* Controls the vibrator of a particular input device. */
-    virtual void vibrate(int32_t deviceId, const nsecs_t* pattern, size_t patternSize,
-            ssize_t repeat, int32_t token) = 0;
-    virtual void cancelVibrate(int32_t deviceId, int32_t token) = 0;
-};
-
-
-/* Internal interface used by individual input devices to access global input device state
- * and parameters maintained by the input reader.
- */
-class InputReaderContext {
-public:
-    InputReaderContext() { }
-    virtual ~InputReaderContext() { }
-
-    virtual void updateGlobalMetaState() = 0;
-    virtual int32_t getGlobalMetaState() = 0;
-
-    virtual void disableVirtualKeysUntil(nsecs_t time) = 0;
-    virtual bool shouldDropVirtualKey(nsecs_t now,
-            InputDevice* device, int32_t keyCode, int32_t scanCode) = 0;
-
-    virtual void fadePointer() = 0;
-
-    virtual void requestTimeoutAtTime(nsecs_t when) = 0;
-    virtual int32_t bumpGeneration() = 0;
-
-    virtual InputReaderPolicyInterface* getPolicy() = 0;
-    virtual InputListenerInterface* getListener() = 0;
-    virtual EventHubInterface* getEventHub() = 0;
-};
-
-
-/* The input reader reads raw event data from the event hub and processes it into input events
- * that it sends to the input listener.  Some functions of the input reader, such as early
- * event filtering in low power states, are controlled by a separate policy object.
- *
- * The InputReader owns a collection of InputMappers.  Most of the work it does happens
- * on the input reader thread but the InputReader can receive queries from other system
- * components running on arbitrary threads.  To keep things manageable, the InputReader
- * uses a single Mutex to guard its state.  The Mutex may be held while calling into the
- * EventHub or the InputReaderPolicy but it is never held while calling into the
- * InputListener.
- */
-class InputReader : public InputReaderInterface {
-public:
-    InputReader(const sp<EventHubInterface>& eventHub,
-            const sp<InputReaderPolicyInterface>& policy,
-            const sp<InputListenerInterface>& listener);
-    virtual ~InputReader();
-
-    virtual void dump(String8& dump);
-    virtual void monitor();
-
-    virtual void loopOnce();
-
-    virtual void getInputDevices(Vector<InputDeviceInfo>& outInputDevices);
-
-    virtual int32_t getScanCodeState(int32_t deviceId, uint32_t sourceMask,
-            int32_t scanCode);
-    virtual int32_t getKeyCodeState(int32_t deviceId, uint32_t sourceMask,
-            int32_t keyCode);
-    virtual int32_t getSwitchState(int32_t deviceId, uint32_t sourceMask,
-            int32_t sw);
-
-    virtual bool hasKeys(int32_t deviceId, uint32_t sourceMask,
-            size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags);
-
-    virtual void requestRefreshConfiguration(uint32_t changes);
-
-    virtual void vibrate(int32_t deviceId, const nsecs_t* pattern, size_t patternSize,
-            ssize_t repeat, int32_t token);
-    virtual void cancelVibrate(int32_t deviceId, int32_t token);
-
-protected:
-    // These members are protected so they can be instrumented by test cases.
-    virtual InputDevice* createDeviceLocked(int32_t deviceId, int32_t controllerNumber,
-            const InputDeviceIdentifier& identifier, uint32_t classes);
-
-    class ContextImpl : public InputReaderContext {
-        InputReader* mReader;
-
-    public:
-        ContextImpl(InputReader* reader);
-
-        virtual void updateGlobalMetaState();
-        virtual int32_t getGlobalMetaState();
-        virtual void disableVirtualKeysUntil(nsecs_t time);
-        virtual bool shouldDropVirtualKey(nsecs_t now,
-                InputDevice* device, int32_t keyCode, int32_t scanCode);
-        virtual void fadePointer();
-        virtual void requestTimeoutAtTime(nsecs_t when);
-        virtual int32_t bumpGeneration();
-        virtual InputReaderPolicyInterface* getPolicy();
-        virtual InputListenerInterface* getListener();
-        virtual EventHubInterface* getEventHub();
-    } mContext;
-
-    friend class ContextImpl;
-
-private:
-    Mutex mLock;
-
-    Condition mReaderIsAliveCondition;
-
-    sp<EventHubInterface> mEventHub;
-    sp<InputReaderPolicyInterface> mPolicy;
-    sp<QueuedInputListener> mQueuedListener;
-
-    InputReaderConfiguration mConfig;
-
-    // The event queue.
-    static const int EVENT_BUFFER_SIZE = 256;
-    RawEvent mEventBuffer[EVENT_BUFFER_SIZE];
-
-    KeyedVector<int32_t, InputDevice*> mDevices;
-
-    // low-level input event decoding and device management
-    void processEventsLocked(const RawEvent* rawEvents, size_t count);
-
-    void addDeviceLocked(nsecs_t when, int32_t deviceId);
-    void removeDeviceLocked(nsecs_t when, int32_t deviceId);
-    void processEventsForDeviceLocked(int32_t deviceId, const RawEvent* rawEvents, size_t count);
-    void timeoutExpiredLocked(nsecs_t when);
-
-    void handleConfigurationChangedLocked(nsecs_t when);
-
-    int32_t mGlobalMetaState;
-    void updateGlobalMetaStateLocked();
-    int32_t getGlobalMetaStateLocked();
-
-    void fadePointerLocked();
-
-    int32_t mGeneration;
-    int32_t bumpGenerationLocked();
-
-    void getInputDevicesLocked(Vector<InputDeviceInfo>& outInputDevices);
-
-    nsecs_t mDisableVirtualKeysTimeout;
-    void disableVirtualKeysUntilLocked(nsecs_t time);
-    bool shouldDropVirtualKeyLocked(nsecs_t now,
-            InputDevice* device, int32_t keyCode, int32_t scanCode);
-
-    nsecs_t mNextTimeout;
-    void requestTimeoutAtTimeLocked(nsecs_t when);
-
-    uint32_t mConfigurationChangesToRefresh;
-    void refreshConfigurationLocked(uint32_t changes);
-
-    // state queries
-    typedef int32_t (InputDevice::*GetStateFunc)(uint32_t sourceMask, int32_t code);
-    int32_t getStateLocked(int32_t deviceId, uint32_t sourceMask, int32_t code,
-            GetStateFunc getStateFunc);
-    bool markSupportedKeyCodesLocked(int32_t deviceId, uint32_t sourceMask, size_t numCodes,
-            const int32_t* keyCodes, uint8_t* outFlags);
-};
-
-
-/* Reads raw events from the event hub and processes them, endlessly. */
-class InputReaderThread : public Thread {
-public:
-    InputReaderThread(const sp<InputReaderInterface>& reader);
-    virtual ~InputReaderThread();
-
-private:
-    sp<InputReaderInterface> mReader;
-
-    virtual bool threadLoop();
-};
-
-
-/* Represents the state of a single input device. */
-class InputDevice {
-public:
-    InputDevice(InputReaderContext* context, int32_t id, int32_t generation, int32_t
-            controllerNumber, const InputDeviceIdentifier& identifier, uint32_t classes);
-    ~InputDevice();
-
-    inline InputReaderContext* getContext() { return mContext; }
-    inline int32_t getId() const { return mId; }
-    inline int32_t getControllerNumber() const { return mControllerNumber; }
-    inline int32_t getGeneration() const { return mGeneration; }
-    inline const String8& getName() const { return mIdentifier.name; }
-    inline uint32_t getClasses() const { return mClasses; }
-    inline uint32_t getSources() const { return mSources; }
-
-    inline bool isExternal() { return mIsExternal; }
-    inline void setExternal(bool external) { mIsExternal = external; }
-
-    inline bool isIgnored() { return mMappers.isEmpty(); }
-
-    void dump(String8& dump);
-    void addMapper(InputMapper* mapper);
-    void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes);
-    void reset(nsecs_t when);
-    void process(const RawEvent* rawEvents, size_t count);
-    void timeoutExpired(nsecs_t when);
-
-    void getDeviceInfo(InputDeviceInfo* outDeviceInfo);
-    int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode);
-    int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode);
-    int32_t getSwitchState(uint32_t sourceMask, int32_t switchCode);
-    bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes,
-            const int32_t* keyCodes, uint8_t* outFlags);
-    void vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat, int32_t token);
-    void cancelVibrate(int32_t token);
-
-    int32_t getMetaState();
-
-    void fadePointer();
-
-    void bumpGeneration();
-
-    void notifyReset(nsecs_t when);
-
-    inline const PropertyMap& getConfiguration() { return mConfiguration; }
-    inline EventHubInterface* getEventHub() { return mContext->getEventHub(); }
-
-    bool hasKey(int32_t code) {
-        return getEventHub()->hasScanCode(mId, code);
-    }
-
-    bool hasAbsoluteAxis(int32_t code) {
-        RawAbsoluteAxisInfo info;
-        getEventHub()->getAbsoluteAxisInfo(mId, code, &info);
-        return info.valid;
-    }
-
-    bool isKeyPressed(int32_t code) {
-        return getEventHub()->getScanCodeState(mId, code) == AKEY_STATE_DOWN;
-    }
-
-    int32_t getAbsoluteAxisValue(int32_t code) {
-        int32_t value;
-        getEventHub()->getAbsoluteAxisValue(mId, code, &value);
-        return value;
-    }
-
-private:
-    InputReaderContext* mContext;
-    int32_t mId;
-    int32_t mGeneration;
-    int32_t mControllerNumber;
-    InputDeviceIdentifier mIdentifier;
-    String8 mAlias;
-    uint32_t mClasses;
-
-    Vector<InputMapper*> mMappers;
-
-    uint32_t mSources;
-    bool mIsExternal;
-    bool mDropUntilNextSync;
-
-    typedef int32_t (InputMapper::*GetStateFunc)(uint32_t sourceMask, int32_t code);
-    int32_t getState(uint32_t sourceMask, int32_t code, GetStateFunc getStateFunc);
-
-    PropertyMap mConfiguration;
-};
-
-
-/* Keeps track of the state of mouse or touch pad buttons. */
-class CursorButtonAccumulator {
-public:
-    CursorButtonAccumulator();
-    void reset(InputDevice* device);
-
-    void process(const RawEvent* rawEvent);
-
-    uint32_t getButtonState() const;
-
-private:
-    bool mBtnLeft;
-    bool mBtnRight;
-    bool mBtnMiddle;
-    bool mBtnBack;
-    bool mBtnSide;
-    bool mBtnForward;
-    bool mBtnExtra;
-    bool mBtnTask;
-
-    void clearButtons();
-};
-
-
-/* Keeps track of cursor movements. */
-
-class CursorMotionAccumulator {
-public:
-    CursorMotionAccumulator();
-    void reset(InputDevice* device);
-
-    void process(const RawEvent* rawEvent);
-    void finishSync();
-
-    inline int32_t getRelativeX() const { return mRelX; }
-    inline int32_t getRelativeY() const { return mRelY; }
-
-private:
-    int32_t mRelX;
-    int32_t mRelY;
-
-    void clearRelativeAxes();
-};
-
-
-/* Keeps track of cursor scrolling motions. */
-
-class CursorScrollAccumulator {
-public:
-    CursorScrollAccumulator();
-    void configure(InputDevice* device);
-    void reset(InputDevice* device);
-
-    void process(const RawEvent* rawEvent);
-    void finishSync();
-
-    inline bool haveRelativeVWheel() const { return mHaveRelWheel; }
-    inline bool haveRelativeHWheel() const { return mHaveRelHWheel; }
-
-    inline int32_t getRelativeX() const { return mRelX; }
-    inline int32_t getRelativeY() const { return mRelY; }
-    inline int32_t getRelativeVWheel() const { return mRelWheel; }
-    inline int32_t getRelativeHWheel() const { return mRelHWheel; }
-
-private:
-    bool mHaveRelWheel;
-    bool mHaveRelHWheel;
-
-    int32_t mRelX;
-    int32_t mRelY;
-    int32_t mRelWheel;
-    int32_t mRelHWheel;
-
-    void clearRelativeAxes();
-};
-
-
-/* Keeps track of the state of touch, stylus and tool buttons. */
-class TouchButtonAccumulator {
-public:
-    TouchButtonAccumulator();
-    void configure(InputDevice* device);
-    void reset(InputDevice* device);
-
-    void process(const RawEvent* rawEvent);
-
-    uint32_t getButtonState() const;
-    int32_t getToolType() const;
-    bool isToolActive() const;
-    bool isHovering() const;
-    bool hasStylus() const;
-
-private:
-    bool mHaveBtnTouch;
-    bool mHaveStylus;
-
-    bool mBtnTouch;
-    bool mBtnStylus;
-    bool mBtnStylus2;
-    bool mBtnToolFinger;
-    bool mBtnToolPen;
-    bool mBtnToolRubber;
-    bool mBtnToolBrush;
-    bool mBtnToolPencil;
-    bool mBtnToolAirbrush;
-    bool mBtnToolMouse;
-    bool mBtnToolLens;
-    bool mBtnToolDoubleTap;
-    bool mBtnToolTripleTap;
-    bool mBtnToolQuadTap;
-
-    void clearButtons();
-};
-
-
-/* Raw axis information from the driver. */
-struct RawPointerAxes {
-    RawAbsoluteAxisInfo x;
-    RawAbsoluteAxisInfo y;
-    RawAbsoluteAxisInfo pressure;
-    RawAbsoluteAxisInfo touchMajor;
-    RawAbsoluteAxisInfo touchMinor;
-    RawAbsoluteAxisInfo toolMajor;
-    RawAbsoluteAxisInfo toolMinor;
-    RawAbsoluteAxisInfo orientation;
-    RawAbsoluteAxisInfo distance;
-    RawAbsoluteAxisInfo tiltX;
-    RawAbsoluteAxisInfo tiltY;
-    RawAbsoluteAxisInfo trackingId;
-    RawAbsoluteAxisInfo slot;
-
-    RawPointerAxes();
-    void clear();
-};
-
-
-/* Raw data for a collection of pointers including a pointer id mapping table. */
-struct RawPointerData {
-    struct Pointer {
-        uint32_t id;
-        int32_t x;
-        int32_t y;
-        int32_t pressure;
-        int32_t touchMajor;
-        int32_t touchMinor;
-        int32_t toolMajor;
-        int32_t toolMinor;
-        int32_t orientation;
-        int32_t distance;
-        int32_t tiltX;
-        int32_t tiltY;
-        int32_t toolType; // a fully decoded AMOTION_EVENT_TOOL_TYPE constant
-        bool isHovering;
-    };
-
-    uint32_t pointerCount;
-    Pointer pointers[MAX_POINTERS];
-    BitSet32 hoveringIdBits, touchingIdBits;
-    uint32_t idToIndex[MAX_POINTER_ID + 1];
-
-    RawPointerData();
-    void clear();
-    void copyFrom(const RawPointerData& other);
-    void getCentroidOfTouchingPointers(float* outX, float* outY) const;
-
-    inline void markIdBit(uint32_t id, bool isHovering) {
-        if (isHovering) {
-            hoveringIdBits.markBit(id);
-        } else {
-            touchingIdBits.markBit(id);
-        }
-    }
-
-    inline void clearIdBits() {
-        hoveringIdBits.clear();
-        touchingIdBits.clear();
-    }
-
-    inline const Pointer& pointerForId(uint32_t id) const {
-        return pointers[idToIndex[id]];
-    }
-
-    inline bool isHovering(uint32_t pointerIndex) {
-        return pointers[pointerIndex].isHovering;
-    }
-};
-
-
-/* Cooked data for a collection of pointers including a pointer id mapping table. */
-struct CookedPointerData {
-    uint32_t pointerCount;
-    PointerProperties pointerProperties[MAX_POINTERS];
-    PointerCoords pointerCoords[MAX_POINTERS];
-    BitSet32 hoveringIdBits, touchingIdBits;
-    uint32_t idToIndex[MAX_POINTER_ID + 1];
-
-    CookedPointerData();
-    void clear();
-    void copyFrom(const CookedPointerData& other);
-
-    inline const PointerCoords& pointerCoordsForId(uint32_t id) const {
-        return pointerCoords[idToIndex[id]];
-    }
-
-    inline bool isHovering(uint32_t pointerIndex) {
-        return hoveringIdBits.hasBit(pointerProperties[pointerIndex].id);
-    }
-};
-
-
-/* Keeps track of the state of single-touch protocol. */
-class SingleTouchMotionAccumulator {
-public:
-    SingleTouchMotionAccumulator();
-
-    void process(const RawEvent* rawEvent);
-    void reset(InputDevice* device);
-
-    inline int32_t getAbsoluteX() const { return mAbsX; }
-    inline int32_t getAbsoluteY() const { return mAbsY; }
-    inline int32_t getAbsolutePressure() const { return mAbsPressure; }
-    inline int32_t getAbsoluteToolWidth() const { return mAbsToolWidth; }
-    inline int32_t getAbsoluteDistance() const { return mAbsDistance; }
-    inline int32_t getAbsoluteTiltX() const { return mAbsTiltX; }
-    inline int32_t getAbsoluteTiltY() const { return mAbsTiltY; }
-
-private:
-    int32_t mAbsX;
-    int32_t mAbsY;
-    int32_t mAbsPressure;
-    int32_t mAbsToolWidth;
-    int32_t mAbsDistance;
-    int32_t mAbsTiltX;
-    int32_t mAbsTiltY;
-
-    void clearAbsoluteAxes();
-};
-
-
-/* Keeps track of the state of multi-touch protocol. */
-class MultiTouchMotionAccumulator {
-public:
-    class Slot {
-    public:
-        inline bool isInUse() const { return mInUse; }
-        inline int32_t getX() const { return mAbsMTPositionX; }
-        inline int32_t getY() const { return mAbsMTPositionY; }
-        inline int32_t getTouchMajor() const { return mAbsMTTouchMajor; }
-        inline int32_t getTouchMinor() const {
-            return mHaveAbsMTTouchMinor ? mAbsMTTouchMinor : mAbsMTTouchMajor; }
-        inline int32_t getToolMajor() const { return mAbsMTWidthMajor; }
-        inline int32_t getToolMinor() const {
-            return mHaveAbsMTWidthMinor ? mAbsMTWidthMinor : mAbsMTWidthMajor; }
-        inline int32_t getOrientation() const { return mAbsMTOrientation; }
-        inline int32_t getTrackingId() const { return mAbsMTTrackingId; }
-        inline int32_t getPressure() const { return mAbsMTPressure; }
-        inline int32_t getDistance() const { return mAbsMTDistance; }
-        inline int32_t getToolType() const;
-
-    private:
-        friend class MultiTouchMotionAccumulator;
-
-        bool mInUse;
-        bool mHaveAbsMTTouchMinor;
-        bool mHaveAbsMTWidthMinor;
-        bool mHaveAbsMTToolType;
-
-        int32_t mAbsMTPositionX;
-        int32_t mAbsMTPositionY;
-        int32_t mAbsMTTouchMajor;
-        int32_t mAbsMTTouchMinor;
-        int32_t mAbsMTWidthMajor;
-        int32_t mAbsMTWidthMinor;
-        int32_t mAbsMTOrientation;
-        int32_t mAbsMTTrackingId;
-        int32_t mAbsMTPressure;
-        int32_t mAbsMTDistance;
-        int32_t mAbsMTToolType;
-
-        Slot();
-        void clear();
-    };
-
-    MultiTouchMotionAccumulator();
-    ~MultiTouchMotionAccumulator();
-
-    void configure(InputDevice* device, size_t slotCount, bool usingSlotsProtocol);
-    void reset(InputDevice* device);
-    void process(const RawEvent* rawEvent);
-    void finishSync();
-    bool hasStylus() const;
-
-    inline size_t getSlotCount() const { return mSlotCount; }
-    inline const Slot* getSlot(size_t index) const { return &mSlots[index]; }
-
-private:
-    int32_t mCurrentSlot;
-    Slot* mSlots;
-    size_t mSlotCount;
-    bool mUsingSlotsProtocol;
-    bool mHaveStylus;
-
-    void clearSlots(int32_t initialSlot);
-};
-
-
-/* An input mapper transforms raw input events into cooked event data.
- * A single input device can have multiple associated input mappers in order to interpret
- * different classes of events.
- *
- * InputMapper lifecycle:
- * - create
- * - configure with 0 changes
- * - reset
- * - process, process, process (may occasionally reconfigure with non-zero changes or reset)
- * - reset
- * - destroy
- */
-class InputMapper {
-public:
-    InputMapper(InputDevice* device);
-    virtual ~InputMapper();
-
-    inline InputDevice* getDevice() { return mDevice; }
-    inline int32_t getDeviceId() { return mDevice->getId(); }
-    inline const String8 getDeviceName() { return mDevice->getName(); }
-    inline InputReaderContext* getContext() { return mContext; }
-    inline InputReaderPolicyInterface* getPolicy() { return mContext->getPolicy(); }
-    inline InputListenerInterface* getListener() { return mContext->getListener(); }
-    inline EventHubInterface* getEventHub() { return mContext->getEventHub(); }
-
-    virtual uint32_t getSources() = 0;
-    virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo);
-    virtual void dump(String8& dump);
-    virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes);
-    virtual void reset(nsecs_t when);
-    virtual void process(const RawEvent* rawEvent) = 0;
-    virtual void timeoutExpired(nsecs_t when);
-
-    virtual int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode);
-    virtual int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode);
-    virtual int32_t getSwitchState(uint32_t sourceMask, int32_t switchCode);
-    virtual bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes,
-            const int32_t* keyCodes, uint8_t* outFlags);
-    virtual void vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat,
-            int32_t token);
-    virtual void cancelVibrate(int32_t token);
-
-    virtual int32_t getMetaState();
-
-    virtual void fadePointer();
-
-protected:
-    InputDevice* mDevice;
-    InputReaderContext* mContext;
-
-    status_t getAbsoluteAxisInfo(int32_t axis, RawAbsoluteAxisInfo* axisInfo);
-    void bumpGeneration();
-
-    static void dumpRawAbsoluteAxisInfo(String8& dump,
-            const RawAbsoluteAxisInfo& axis, const char* name);
-};
-
-
-class SwitchInputMapper : public InputMapper {
-public:
-    SwitchInputMapper(InputDevice* device);
-    virtual ~SwitchInputMapper();
-
-    virtual uint32_t getSources();
-    virtual void process(const RawEvent* rawEvent);
-
-    virtual int32_t getSwitchState(uint32_t sourceMask, int32_t switchCode);
-
-private:
-    uint32_t mUpdatedSwitchValues;
-    uint32_t mUpdatedSwitchMask;
-
-    void processSwitch(int32_t switchCode, int32_t switchValue);
-    void sync(nsecs_t when);
-};
-
-
-class VibratorInputMapper : public InputMapper {
-public:
-    VibratorInputMapper(InputDevice* device);
-    virtual ~VibratorInputMapper();
-
-    virtual uint32_t getSources();
-    virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo);
-    virtual void process(const RawEvent* rawEvent);
-
-    virtual void vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat,
-            int32_t token);
-    virtual void cancelVibrate(int32_t token);
-    virtual void timeoutExpired(nsecs_t when);
-    virtual void dump(String8& dump);
-
-private:
-    bool mVibrating;
-    nsecs_t mPattern[MAX_VIBRATE_PATTERN_SIZE];
-    size_t mPatternSize;
-    ssize_t mRepeat;
-    int32_t mToken;
-    ssize_t mIndex;
-    nsecs_t mNextStepTime;
-
-    void nextStep();
-    void stopVibrating();
-};
-
-
-class KeyboardInputMapper : public InputMapper {
-public:
-    KeyboardInputMapper(InputDevice* device, uint32_t source, int32_t keyboardType);
-    virtual ~KeyboardInputMapper();
-
-    virtual uint32_t getSources();
-    virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo);
-    virtual void dump(String8& dump);
-    virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes);
-    virtual void reset(nsecs_t when);
-    virtual void process(const RawEvent* rawEvent);
-
-    virtual int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode);
-    virtual int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode);
-    virtual bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes,
-            const int32_t* keyCodes, uint8_t* outFlags);
-
-    virtual int32_t getMetaState();
-
-private:
-    struct KeyDown {
-        int32_t keyCode;
-        int32_t scanCode;
-    };
-
-    uint32_t mSource;
-    int32_t mKeyboardType;
-
-    int32_t mOrientation; // orientation for dpad keys
-
-    Vector<KeyDown> mKeyDowns; // keys that are down
-    int32_t mMetaState;
-    nsecs_t mDownTime; // time of most recent key down
-
-    int32_t mCurrentHidUsage; // most recent HID usage seen this packet, or 0 if none
-
-    struct LedState {
-        bool avail; // led is available
-        bool on;    // we think the led is currently on
-    };
-    LedState mCapsLockLedState;
-    LedState mNumLockLedState;
-    LedState mScrollLockLedState;
-
-    // Immutable configuration parameters.
-    struct Parameters {
-        bool hasAssociatedDisplay;
-        bool orientationAware;
-    } mParameters;
-
-    void configureParameters();
-    void dumpParameters(String8& dump);
-
-    bool isKeyboardOrGamepadKey(int32_t scanCode);
-
-    void processKey(nsecs_t when, bool down, int32_t keyCode, int32_t scanCode,
-            uint32_t policyFlags);
-
-    ssize_t findKeyDown(int32_t scanCode);
-
-    void resetLedState();
-    void initializeLedState(LedState& ledState, int32_t led);
-    void updateLedState(bool reset);
-    void updateLedStateForModifier(LedState& ledState, int32_t led,
-            int32_t modifier, bool reset);
-};
-
-
-class CursorInputMapper : public InputMapper {
-public:
-    CursorInputMapper(InputDevice* device);
-    virtual ~CursorInputMapper();
-
-    virtual uint32_t getSources();
-    virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo);
-    virtual void dump(String8& dump);
-    virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes);
-    virtual void reset(nsecs_t when);
-    virtual void process(const RawEvent* rawEvent);
-
-    virtual int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode);
-
-    virtual void fadePointer();
-
-private:
-    // Amount that trackball needs to move in order to generate a key event.
-    static const int32_t TRACKBALL_MOVEMENT_THRESHOLD = 6;
-
-    // Immutable configuration parameters.
-    struct Parameters {
-        enum Mode {
-            MODE_POINTER,
-            MODE_NAVIGATION,
-        };
-
-        Mode mode;
-        bool hasAssociatedDisplay;
-        bool orientationAware;
-    } mParameters;
-
-    CursorButtonAccumulator mCursorButtonAccumulator;
-    CursorMotionAccumulator mCursorMotionAccumulator;
-    CursorScrollAccumulator mCursorScrollAccumulator;
-
-    int32_t mSource;
-    float mXScale;
-    float mYScale;
-    float mXPrecision;
-    float mYPrecision;
-
-    float mVWheelScale;
-    float mHWheelScale;
-
-    // Velocity controls for mouse pointer and wheel movements.
-    // The controls for X and Y wheel movements are separate to keep them decoupled.
-    VelocityControl mPointerVelocityControl;
-    VelocityControl mWheelXVelocityControl;
-    VelocityControl mWheelYVelocityControl;
-
-    int32_t mOrientation;
-
-    sp<PointerControllerInterface> mPointerController;
-
-    int32_t mButtonState;
-    nsecs_t mDownTime;
-
-    void configureParameters();
-    void dumpParameters(String8& dump);
-
-    void sync(nsecs_t when);
-};
-
-
-class TouchInputMapper : public InputMapper {
-public:
-    TouchInputMapper(InputDevice* device);
-    virtual ~TouchInputMapper();
-
-    virtual uint32_t getSources();
-    virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo);
-    virtual void dump(String8& dump);
-    virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes);
-    virtual void reset(nsecs_t when);
-    virtual void process(const RawEvent* rawEvent);
-
-    virtual int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode);
-    virtual int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode);
-    virtual bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes,
-            const int32_t* keyCodes, uint8_t* outFlags);
-
-    virtual void fadePointer();
-    virtual void timeoutExpired(nsecs_t when);
-
-protected:
-    CursorButtonAccumulator mCursorButtonAccumulator;
-    CursorScrollAccumulator mCursorScrollAccumulator;
-    TouchButtonAccumulator mTouchButtonAccumulator;
-
-    struct VirtualKey {
-        int32_t keyCode;
-        int32_t scanCode;
-        uint32_t flags;
-
-        // computed hit box, specified in touch screen coords based on known display size
-        int32_t hitLeft;
-        int32_t hitTop;
-        int32_t hitRight;
-        int32_t hitBottom;
-
-        inline bool isHit(int32_t x, int32_t y) const {
-            return x >= hitLeft && x <= hitRight && y >= hitTop && y <= hitBottom;
-        }
-    };
-
-    // Input sources and device mode.
-    uint32_t mSource;
-
-    enum DeviceMode {
-        DEVICE_MODE_DISABLED, // input is disabled
-        DEVICE_MODE_DIRECT, // direct mapping (touchscreen)
-        DEVICE_MODE_UNSCALED, // unscaled mapping (touchpad)
-        DEVICE_MODE_NAVIGATION, // unscaled mapping with assist gesture (touch navigation)
-        DEVICE_MODE_POINTER, // pointer mapping (pointer)
-    };
-    DeviceMode mDeviceMode;
-
-    // The reader's configuration.
-    InputReaderConfiguration mConfig;
-
-    // Immutable configuration parameters.
-    struct Parameters {
-        enum DeviceType {
-            DEVICE_TYPE_TOUCH_SCREEN,
-            DEVICE_TYPE_TOUCH_PAD,
-            DEVICE_TYPE_TOUCH_NAVIGATION,
-            DEVICE_TYPE_POINTER,
-        };
-
-        DeviceType deviceType;
-        bool hasAssociatedDisplay;
-        bool associatedDisplayIsExternal;
-        bool orientationAware;
-        bool hasButtonUnderPad;
-
-        enum GestureMode {
-            GESTURE_MODE_POINTER,
-            GESTURE_MODE_SPOTS,
-        };
-        GestureMode gestureMode;
-    } mParameters;
-
-    // Immutable calibration parameters in parsed form.
-    struct Calibration {
-        // Size
-        enum SizeCalibration {
-            SIZE_CALIBRATION_DEFAULT,
-            SIZE_CALIBRATION_NONE,
-            SIZE_CALIBRATION_GEOMETRIC,
-            SIZE_CALIBRATION_DIAMETER,
-            SIZE_CALIBRATION_BOX,
-            SIZE_CALIBRATION_AREA,
-        };
-
-        SizeCalibration sizeCalibration;
-
-        bool haveSizeScale;
-        float sizeScale;
-        bool haveSizeBias;
-        float sizeBias;
-        bool haveSizeIsSummed;
-        bool sizeIsSummed;
-
-        // Pressure
-        enum PressureCalibration {
-            PRESSURE_CALIBRATION_DEFAULT,
-            PRESSURE_CALIBRATION_NONE,
-            PRESSURE_CALIBRATION_PHYSICAL,
-            PRESSURE_CALIBRATION_AMPLITUDE,
-        };
-
-        PressureCalibration pressureCalibration;
-        bool havePressureScale;
-        float pressureScale;
-
-        // Orientation
-        enum OrientationCalibration {
-            ORIENTATION_CALIBRATION_DEFAULT,
-            ORIENTATION_CALIBRATION_NONE,
-            ORIENTATION_CALIBRATION_INTERPOLATED,
-            ORIENTATION_CALIBRATION_VECTOR,
-        };
-
-        OrientationCalibration orientationCalibration;
-
-        // Distance
-        enum DistanceCalibration {
-            DISTANCE_CALIBRATION_DEFAULT,
-            DISTANCE_CALIBRATION_NONE,
-            DISTANCE_CALIBRATION_SCALED,
-        };
-
-        DistanceCalibration distanceCalibration;
-        bool haveDistanceScale;
-        float distanceScale;
-
-        enum CoverageCalibration {
-            COVERAGE_CALIBRATION_DEFAULT,
-            COVERAGE_CALIBRATION_NONE,
-            COVERAGE_CALIBRATION_BOX,
-        };
-
-        CoverageCalibration coverageCalibration;
-
-        inline void applySizeScaleAndBias(float* outSize) const {
-            if (haveSizeScale) {
-                *outSize *= sizeScale;
-            }
-            if (haveSizeBias) {
-                *outSize += sizeBias;
-            }
-            if (*outSize < 0) {
-                *outSize = 0;
-            }
-        }
-    } mCalibration;
-
-    // Raw pointer axis information from the driver.
-    RawPointerAxes mRawPointerAxes;
-
-    // Raw pointer sample data.
-    RawPointerData mCurrentRawPointerData;
-    RawPointerData mLastRawPointerData;
-
-    // Cooked pointer sample data.
-    CookedPointerData mCurrentCookedPointerData;
-    CookedPointerData mLastCookedPointerData;
-
-    // Button state.
-    int32_t mCurrentButtonState;
-    int32_t mLastButtonState;
-
-    // Scroll state.
-    int32_t mCurrentRawVScroll;
-    int32_t mCurrentRawHScroll;
-
-    // Id bits used to differentiate fingers, stylus and mouse tools.
-    BitSet32 mCurrentFingerIdBits; // finger or unknown
-    BitSet32 mLastFingerIdBits;
-    BitSet32 mCurrentStylusIdBits; // stylus or eraser
-    BitSet32 mLastStylusIdBits;
-    BitSet32 mCurrentMouseIdBits; // mouse or lens
-    BitSet32 mLastMouseIdBits;
-
-    // True if we sent a HOVER_ENTER event.
-    bool mSentHoverEnter;
-
-    // The time the primary pointer last went down.
-    nsecs_t mDownTime;
-
-    // The pointer controller, or null if the device is not a pointer.
-    sp<PointerControllerInterface> mPointerController;
-
-    Vector<VirtualKey> mVirtualKeys;
-
-    virtual void configureParameters();
-    virtual void dumpParameters(String8& dump);
-    virtual void configureRawPointerAxes();
-    virtual void dumpRawPointerAxes(String8& dump);
-    virtual void configureSurface(nsecs_t when, bool* outResetNeeded);
-    virtual void dumpSurface(String8& dump);
-    virtual void configureVirtualKeys();
-    virtual void dumpVirtualKeys(String8& dump);
-    virtual void parseCalibration();
-    virtual void resolveCalibration();
-    virtual void dumpCalibration(String8& dump);
-    virtual bool hasStylus() const = 0;
-
-    virtual void syncTouch(nsecs_t when, bool* outHavePointerIds) = 0;
-
-private:
-    // The current viewport.
-    // The components of the viewport are specified in the display's rotated orientation.
-    DisplayViewport mViewport;
-
-    // The surface orientation, width and height set by configureSurface().
-    // The width and height are derived from the viewport but are specified
-    // in the natural orientation.
-    // The surface origin specifies how the surface coordinates should be translated
-    // to align with the logical display coordinate space.
-    // The orientation may be different from the viewport orientation as it specifies
-    // the rotation of the surface coordinates required to produce the viewport's
-    // requested orientation, so it will depend on whether the device is orientation aware.
-    int32_t mSurfaceWidth;
-    int32_t mSurfaceHeight;
-    int32_t mSurfaceLeft;
-    int32_t mSurfaceTop;
-    int32_t mSurfaceOrientation;
-
-    // Translation and scaling factors, orientation-independent.
-    float mXTranslate;
-    float mXScale;
-    float mXPrecision;
-
-    float mYTranslate;
-    float mYScale;
-    float mYPrecision;
-
-    float mGeometricScale;
-
-    float mPressureScale;
-
-    float mSizeScale;
-
-    float mOrientationScale;
-
-    float mDistanceScale;
-
-    bool mHaveTilt;
-    float mTiltXCenter;
-    float mTiltXScale;
-    float mTiltYCenter;
-    float mTiltYScale;
-
-    // Oriented motion ranges for input device info.
-    struct OrientedRanges {
-        InputDeviceInfo::MotionRange x;
-        InputDeviceInfo::MotionRange y;
-        InputDeviceInfo::MotionRange pressure;
-
-        bool haveSize;
-        InputDeviceInfo::MotionRange size;
-
-        bool haveTouchSize;
-        InputDeviceInfo::MotionRange touchMajor;
-        InputDeviceInfo::MotionRange touchMinor;
-
-        bool haveToolSize;
-        InputDeviceInfo::MotionRange toolMajor;
-        InputDeviceInfo::MotionRange toolMinor;
-
-        bool haveOrientation;
-        InputDeviceInfo::MotionRange orientation;
-
-        bool haveDistance;
-        InputDeviceInfo::MotionRange distance;
-
-        bool haveTilt;
-        InputDeviceInfo::MotionRange tilt;
-
-        OrientedRanges() {
-            clear();
-        }
-
-        void clear() {
-            haveSize = false;
-            haveTouchSize = false;
-            haveToolSize = false;
-            haveOrientation = false;
-            haveDistance = false;
-            haveTilt = false;
-        }
-    } mOrientedRanges;
-
-    // Oriented dimensions and precision.
-    float mOrientedXPrecision;
-    float mOrientedYPrecision;
-
-    struct CurrentVirtualKeyState {
-        bool down;
-        bool ignored;
-        nsecs_t downTime;
-        int32_t keyCode;
-        int32_t scanCode;
-    } mCurrentVirtualKey;
-
-    // Scale factor for gesture or mouse based pointer movements.
-    float mPointerXMovementScale;
-    float mPointerYMovementScale;
-
-    // Scale factor for gesture based zooming and other freeform motions.
-    float mPointerXZoomScale;
-    float mPointerYZoomScale;
-
-    // The maximum swipe width.
-    float mPointerGestureMaxSwipeWidth;
-
-    struct PointerDistanceHeapElement {
-        uint32_t currentPointerIndex : 8;
-        uint32_t lastPointerIndex : 8;
-        uint64_t distance : 48; // squared distance
-    };
-
-    enum PointerUsage {
-        POINTER_USAGE_NONE,
-        POINTER_USAGE_GESTURES,
-        POINTER_USAGE_STYLUS,
-        POINTER_USAGE_MOUSE,
-    };
-    PointerUsage mPointerUsage;
-
-    struct PointerGesture {
-        enum Mode {
-            // No fingers, button is not pressed.
-            // Nothing happening.
-            NEUTRAL,
-
-            // No fingers, button is not pressed.
-            // Tap detected.
-            // Emits DOWN and UP events at the pointer location.
-            TAP,
-
-            // Exactly one finger dragging following a tap.
-            // Pointer follows the active finger.
-            // Emits DOWN, MOVE and UP events at the pointer location.
-            //
-            // Detect double-taps when the finger goes up while in TAP_DRAG mode.
-            TAP_DRAG,
-
-            // Button is pressed.
-            // Pointer follows the active finger if there is one.  Other fingers are ignored.
-            // Emits DOWN, MOVE and UP events at the pointer location.
-            BUTTON_CLICK_OR_DRAG,
-
-            // Exactly one finger, button is not pressed.
-            // Pointer follows the active finger.
-            // Emits HOVER_MOVE events at the pointer location.
-            //
-            // Detect taps when the finger goes up while in HOVER mode.
-            HOVER,
-
-            // Exactly two fingers but neither have moved enough to clearly indicate
-            // whether a swipe or freeform gesture was intended.  We consider the
-            // pointer to be pressed so this enables clicking or long-pressing on buttons.
-            // Pointer does not move.
-            // Emits DOWN, MOVE and UP events with a single stationary pointer coordinate.
-            PRESS,
-
-            // Exactly two fingers moving in the same direction, button is not pressed.
-            // Pointer does not move.
-            // Emits DOWN, MOVE and UP events with a single pointer coordinate that
-            // follows the midpoint between both fingers.
-            SWIPE,
-
-            // Two or more fingers moving in arbitrary directions, button is not pressed.
-            // Pointer does not move.
-            // Emits DOWN, POINTER_DOWN, MOVE, POINTER_UP and UP events that follow
-            // each finger individually relative to the initial centroid of the finger.
-            FREEFORM,
-
-            // Waiting for quiet time to end before starting the next gesture.
-            QUIET,
-        };
-
-        // Time the first finger went down.
-        nsecs_t firstTouchTime;
-
-        // The active pointer id from the raw touch data.
-        int32_t activeTouchId; // -1 if none
-
-        // The active pointer id from the gesture last delivered to the application.
-        int32_t activeGestureId; // -1 if none
-
-        // Pointer coords and ids for the current and previous pointer gesture.
-        Mode currentGestureMode;
-        BitSet32 currentGestureIdBits;
-        uint32_t currentGestureIdToIndex[MAX_POINTER_ID + 1];
-        PointerProperties currentGestureProperties[MAX_POINTERS];
-        PointerCoords currentGestureCoords[MAX_POINTERS];
-
-        Mode lastGestureMode;
-        BitSet32 lastGestureIdBits;
-        uint32_t lastGestureIdToIndex[MAX_POINTER_ID + 1];
-        PointerProperties lastGestureProperties[MAX_POINTERS];
-        PointerCoords lastGestureCoords[MAX_POINTERS];
-
-        // Time the pointer gesture last went down.
-        nsecs_t downTime;
-
-        // Time when the pointer went down for a TAP.
-        nsecs_t tapDownTime;
-
-        // Time when the pointer went up for a TAP.
-        nsecs_t tapUpTime;
-
-        // Location of initial tap.
-        float tapX, tapY;
-
-        // Time we started waiting for quiescence.
-        nsecs_t quietTime;
-
-        // Reference points for multitouch gestures.
-        float referenceTouchX;    // reference touch X/Y coordinates in surface units
-        float referenceTouchY;
-        float referenceGestureX;  // reference gesture X/Y coordinates in pixels
-        float referenceGestureY;
-
-        // Distance that each pointer has traveled which has not yet been
-        // subsumed into the reference gesture position.
-        BitSet32 referenceIdBits;
-        struct Delta {
-            float dx, dy;
-        };
-        Delta referenceDeltas[MAX_POINTER_ID + 1];
-
-        // Describes how touch ids are mapped to gesture ids for freeform gestures.
-        uint32_t freeformTouchToGestureIdMap[MAX_POINTER_ID + 1];
-
-        // A velocity tracker for determining whether to switch active pointers during drags.
-        VelocityTracker velocityTracker;
-
-        void reset() {
-            firstTouchTime = LLONG_MIN;
-            activeTouchId = -1;
-            activeGestureId = -1;
-            currentGestureMode = NEUTRAL;
-            currentGestureIdBits.clear();
-            lastGestureMode = NEUTRAL;
-            lastGestureIdBits.clear();
-            downTime = 0;
-            velocityTracker.clear();
-            resetTap();
-            resetQuietTime();
-        }
-
-        void resetTap() {
-            tapDownTime = LLONG_MIN;
-            tapUpTime = LLONG_MIN;
-        }
-
-        void resetQuietTime() {
-            quietTime = LLONG_MIN;
-        }
-    } mPointerGesture;
-
-    struct PointerSimple {
-        PointerCoords currentCoords;
-        PointerProperties currentProperties;
-        PointerCoords lastCoords;
-        PointerProperties lastProperties;
-
-        // True if the pointer is down.
-        bool down;
-
-        // True if the pointer is hovering.
-        bool hovering;
-
-        // Time the pointer last went down.
-        nsecs_t downTime;
-
-        void reset() {
-            currentCoords.clear();
-            currentProperties.clear();
-            lastCoords.clear();
-            lastProperties.clear();
-            down = false;
-            hovering = false;
-            downTime = 0;
-        }
-    } mPointerSimple;
-
-    // The pointer and scroll velocity controls.
-    VelocityControl mPointerVelocityControl;
-    VelocityControl mWheelXVelocityControl;
-    VelocityControl mWheelYVelocityControl;
-
-    void sync(nsecs_t when);
-
-    bool consumeRawTouches(nsecs_t when, uint32_t policyFlags);
-    void dispatchVirtualKey(nsecs_t when, uint32_t policyFlags,
-            int32_t keyEventAction, int32_t keyEventFlags);
-
-    void dispatchTouches(nsecs_t when, uint32_t policyFlags);
-    void dispatchHoverExit(nsecs_t when, uint32_t policyFlags);
-    void dispatchHoverEnterAndMove(nsecs_t when, uint32_t policyFlags);
-    void cookPointerData();
-
-    void dispatchPointerUsage(nsecs_t when, uint32_t policyFlags, PointerUsage pointerUsage);
-    void abortPointerUsage(nsecs_t when, uint32_t policyFlags);
-
-    void dispatchPointerGestures(nsecs_t when, uint32_t policyFlags, bool isTimeout);
-    void abortPointerGestures(nsecs_t when, uint32_t policyFlags);
-    bool preparePointerGestures(nsecs_t when,
-            bool* outCancelPreviousGesture, bool* outFinishPreviousGesture,
-            bool isTimeout);
-
-    void dispatchPointerStylus(nsecs_t when, uint32_t policyFlags);
-    void abortPointerStylus(nsecs_t when, uint32_t policyFlags);
-
-    void dispatchPointerMouse(nsecs_t when, uint32_t policyFlags);
-    void abortPointerMouse(nsecs_t when, uint32_t policyFlags);
-
-    void dispatchPointerSimple(nsecs_t when, uint32_t policyFlags,
-            bool down, bool hovering);
-    void abortPointerSimple(nsecs_t when, uint32_t policyFlags);
-
-    // Dispatches a motion event.
-    // If the changedId is >= 0 and the action is POINTER_DOWN or POINTER_UP, the
-    // method will take care of setting the index and transmuting the action to DOWN or UP
-    // it is the first / last pointer to go down / up.
-    void dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source,
-            int32_t action, int32_t flags, int32_t metaState, int32_t buttonState,
-            int32_t edgeFlags,
-            const PointerProperties* properties, const PointerCoords* coords,
-            const uint32_t* idToIndex, BitSet32 idBits,
-            int32_t changedId, float xPrecision, float yPrecision, nsecs_t downTime);
-
-    // Updates pointer coords and properties for pointers with specified ids that have moved.
-    // Returns true if any of them changed.
-    bool updateMovedPointers(const PointerProperties* inProperties,
-            const PointerCoords* inCoords, const uint32_t* inIdToIndex,
-            PointerProperties* outProperties, PointerCoords* outCoords,
-            const uint32_t* outIdToIndex, BitSet32 idBits) const;
-
-    bool isPointInsideSurface(int32_t x, int32_t y);
-    const VirtualKey* findVirtualKeyHit(int32_t x, int32_t y);
-
-    void assignPointerIds();
-};
-
-
-class SingleTouchInputMapper : public TouchInputMapper {
-public:
-    SingleTouchInputMapper(InputDevice* device);
-    virtual ~SingleTouchInputMapper();
-
-    virtual void reset(nsecs_t when);
-    virtual void process(const RawEvent* rawEvent);
-
-protected:
-    virtual void syncTouch(nsecs_t when, bool* outHavePointerIds);
-    virtual void configureRawPointerAxes();
-    virtual bool hasStylus() const;
-
-private:
-    SingleTouchMotionAccumulator mSingleTouchMotionAccumulator;
-};
-
-
-class MultiTouchInputMapper : public TouchInputMapper {
-public:
-    MultiTouchInputMapper(InputDevice* device);
-    virtual ~MultiTouchInputMapper();
-
-    virtual void reset(nsecs_t when);
-    virtual void process(const RawEvent* rawEvent);
-
-protected:
-    virtual void syncTouch(nsecs_t when, bool* outHavePointerIds);
-    virtual void configureRawPointerAxes();
-    virtual bool hasStylus() const;
-
-private:
-    MultiTouchMotionAccumulator mMultiTouchMotionAccumulator;
-
-    // Specifies the pointer id bits that are in use, and their associated tracking id.
-    BitSet32 mPointerIdBits;
-    int32_t mPointerTrackingIdMap[MAX_POINTER_ID + 1];
-};
-
-
-class JoystickInputMapper : public InputMapper {
-public:
-    JoystickInputMapper(InputDevice* device);
-    virtual ~JoystickInputMapper();
-
-    virtual uint32_t getSources();
-    virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo);
-    virtual void dump(String8& dump);
-    virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes);
-    virtual void reset(nsecs_t when);
-    virtual void process(const RawEvent* rawEvent);
-
-private:
-    struct Axis {
-        RawAbsoluteAxisInfo rawAxisInfo;
-        AxisInfo axisInfo;
-
-        bool explicitlyMapped; // true if the axis was explicitly assigned an axis id
-
-        float scale;   // scale factor from raw to normalized values
-        float offset;  // offset to add after scaling for normalization
-        float highScale;  // scale factor from raw to normalized values of high split
-        float highOffset; // offset to add after scaling for normalization of high split
-
-        float min;        // normalized inclusive minimum
-        float max;        // normalized inclusive maximum
-        float flat;       // normalized flat region size
-        float fuzz;       // normalized error tolerance
-        float resolution; // normalized resolution in units/mm
-
-        float filter;  // filter out small variations of this size
-        float currentValue; // current value
-        float newValue; // most recent value
-        float highCurrentValue; // current value of high split
-        float highNewValue; // most recent value of high split
-
-        void initialize(const RawAbsoluteAxisInfo& rawAxisInfo, const AxisInfo& axisInfo,
-                bool explicitlyMapped, float scale, float offset,
-                float highScale, float highOffset,
-                float min, float max, float flat, float fuzz, float resolution) {
-            this->rawAxisInfo = rawAxisInfo;
-            this->axisInfo = axisInfo;
-            this->explicitlyMapped = explicitlyMapped;
-            this->scale = scale;
-            this->offset = offset;
-            this->highScale = highScale;
-            this->highOffset = highOffset;
-            this->min = min;
-            this->max = max;
-            this->flat = flat;
-            this->fuzz = fuzz;
-            this->resolution = resolution;
-            this->filter = 0;
-            resetValue();
-        }
-
-        void resetValue() {
-            this->currentValue = 0;
-            this->newValue = 0;
-            this->highCurrentValue = 0;
-            this->highNewValue = 0;
-        }
-    };
-
-    // Axes indexed by raw ABS_* axis index.
-    KeyedVector<int32_t, Axis> mAxes;
-
-    void sync(nsecs_t when, bool force);
-
-    bool haveAxis(int32_t axisId);
-    void pruneAxes(bool ignoreExplicitlyMappedAxes);
-    bool filterAxes(bool force);
-
-    static bool hasValueChangedSignificantly(float filter,
-            float newValue, float currentValue, float min, float max);
-    static bool hasMovedNearerToValueWithinFilteredRange(float filter,
-            float newValue, float currentValue, float thresholdValue);
-
-    static bool isCenteredAxis(int32_t axis);
-    static int32_t getCompatAxis(int32_t axis);
-
-    static void addMotionRange(int32_t axisId, const Axis& axis, InputDeviceInfo* info);
-    static void setPointerCoordsAxisValue(PointerCoords* pointerCoords, int32_t axis,
-            float value);
-};
-
-} // namespace android
-
-#endif // _UI_INPUT_READER_H
diff --git a/libs/input/InputWindow.cpp b/libs/input/InputWindow.cpp
deleted file mode 100644
index fe61918..0000000
--- a/libs/input/InputWindow.cpp
+++ /dev/null
@@ -1,64 +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.
- */
-
-#define LOG_TAG "InputWindow"
-
-#include "InputWindow.h"
-
-#include <cutils/log.h>
-
-namespace android {
-
-// --- InputWindowInfo ---
-
-bool InputWindowInfo::touchableRegionContainsPoint(int32_t x, int32_t y) const {
-    return touchableRegion.contains(x, y);
-}
-
-bool InputWindowInfo::frameContainsPoint(int32_t x, int32_t y) const {
-    return x >= frameLeft && x <= frameRight
-            && y >= frameTop && y <= frameBottom;
-}
-
-bool InputWindowInfo::isTrustedOverlay() const {
-    return layoutParamsType == TYPE_INPUT_METHOD
-            || layoutParamsType == TYPE_INPUT_METHOD_DIALOG
-            || layoutParamsType == TYPE_SECURE_SYSTEM_OVERLAY;
-}
-
-bool InputWindowInfo::supportsSplitTouch() const {
-    return layoutParamsFlags & FLAG_SPLIT_TOUCH;
-}
-
-
-// --- InputWindowHandle ---
-
-InputWindowHandle::InputWindowHandle(const sp<InputApplicationHandle>& inputApplicationHandle) :
-    inputApplicationHandle(inputApplicationHandle), mInfo(NULL) {
-}
-
-InputWindowHandle::~InputWindowHandle() {
-    delete mInfo;
-}
-
-void InputWindowHandle::releaseInfo() {
-    if (mInfo) {
-        delete mInfo;
-        mInfo = NULL;
-    }
-}
-
-} // namespace android
diff --git a/libs/input/InputWindow.h b/libs/input/InputWindow.h
deleted file mode 100644
index 28fa7ab..0000000
--- a/libs/input/InputWindow.h
+++ /dev/null
@@ -1,206 +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.
- */
-
-#ifndef _UI_INPUT_WINDOW_H
-#define _UI_INPUT_WINDOW_H
-
-#include <input/Input.h>
-#include <input/InputTransport.h>
-#include <utils/RefBase.h>
-#include <utils/Timers.h>
-#include <utils/String8.h>
-
-#include <SkRegion.h>
-
-#include "InputApplication.h"
-
-namespace android {
-
-/*
- * Describes the properties of a window that can receive input.
- */
-struct InputWindowInfo {
-    // Window flags from WindowManager.LayoutParams
-    enum {
-        FLAG_ALLOW_LOCK_WHILE_SCREEN_ON     = 0x00000001,
-        FLAG_DIM_BEHIND        = 0x00000002,
-        FLAG_BLUR_BEHIND        = 0x00000004,
-        FLAG_NOT_FOCUSABLE      = 0x00000008,
-        FLAG_NOT_TOUCHABLE      = 0x00000010,
-        FLAG_NOT_TOUCH_MODAL    = 0x00000020,
-        FLAG_TOUCHABLE_WHEN_WAKING = 0x00000040,
-        FLAG_KEEP_SCREEN_ON     = 0x00000080,
-        FLAG_LAYOUT_IN_SCREEN   = 0x00000100,
-        FLAG_LAYOUT_NO_LIMITS   = 0x00000200,
-        FLAG_FULLSCREEN      = 0x00000400,
-        FLAG_FORCE_NOT_FULLSCREEN   = 0x00000800,
-        FLAG_DITHER             = 0x00001000,
-        FLAG_SECURE             = 0x00002000,
-        FLAG_SCALED             = 0x00004000,
-        FLAG_IGNORE_CHEEK_PRESSES    = 0x00008000,
-        FLAG_LAYOUT_INSET_DECOR = 0x00010000,
-        FLAG_ALT_FOCUSABLE_IM = 0x00020000,
-        FLAG_WATCH_OUTSIDE_TOUCH = 0x00040000,
-        FLAG_SHOW_WHEN_LOCKED = 0x00080000,
-        FLAG_SHOW_WALLPAPER = 0x00100000,
-        FLAG_TURN_SCREEN_ON = 0x00200000,
-        FLAG_DISMISS_KEYGUARD = 0x00400000,
-        FLAG_SPLIT_TOUCH = 0x00800000,
-        FLAG_SLIPPERY = 0x20000000,
-        FLAG_NEEDS_MENU_KEY = 0x40000000,
-    };
-
-    // Private Window flags from WindowManager.LayoutParams
-    enum {
-        PRIVATE_FLAG_SYSTEM_ERROR = 0x00000100,
-    };
-
-    // Window types from WindowManager.LayoutParams
-    enum {
-        FIRST_APPLICATION_WINDOW = 1,
-        TYPE_BASE_APPLICATION   = 1,
-        TYPE_APPLICATION        = 2,
-        TYPE_APPLICATION_STARTING = 3,
-        LAST_APPLICATION_WINDOW = 99,
-        FIRST_SUB_WINDOW        = 1000,
-        TYPE_APPLICATION_PANEL  = FIRST_SUB_WINDOW,
-        TYPE_APPLICATION_MEDIA  = FIRST_SUB_WINDOW+1,
-        TYPE_APPLICATION_SUB_PANEL = FIRST_SUB_WINDOW+2,
-        TYPE_APPLICATION_ATTACHED_DIALOG = FIRST_SUB_WINDOW+3,
-        TYPE_APPLICATION_MEDIA_OVERLAY  = FIRST_SUB_WINDOW+4,
-        LAST_SUB_WINDOW         = 1999,
-        FIRST_SYSTEM_WINDOW     = 2000,
-        TYPE_STATUS_BAR         = FIRST_SYSTEM_WINDOW,
-        TYPE_SEARCH_BAR         = FIRST_SYSTEM_WINDOW+1,
-        TYPE_PHONE              = FIRST_SYSTEM_WINDOW+2,
-        TYPE_SYSTEM_ALERT       = FIRST_SYSTEM_WINDOW+3,
-        TYPE_KEYGUARD           = FIRST_SYSTEM_WINDOW+4,
-        TYPE_TOAST              = FIRST_SYSTEM_WINDOW+5,
-        TYPE_SYSTEM_OVERLAY     = FIRST_SYSTEM_WINDOW+6,
-        TYPE_PRIORITY_PHONE     = FIRST_SYSTEM_WINDOW+7,
-        TYPE_SYSTEM_DIALOG      = FIRST_SYSTEM_WINDOW+8,
-        TYPE_KEYGUARD_DIALOG    = FIRST_SYSTEM_WINDOW+9,
-        TYPE_SYSTEM_ERROR       = FIRST_SYSTEM_WINDOW+10,
-        TYPE_INPUT_METHOD       = FIRST_SYSTEM_WINDOW+11,
-        TYPE_INPUT_METHOD_DIALOG= FIRST_SYSTEM_WINDOW+12,
-        TYPE_WALLPAPER          = FIRST_SYSTEM_WINDOW+13,
-        TYPE_STATUS_BAR_PANEL   = FIRST_SYSTEM_WINDOW+14,
-        TYPE_SECURE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW+15,
-        TYPE_DRAG               = FIRST_SYSTEM_WINDOW+16,
-        TYPE_STATUS_BAR_SUB_PANEL  = FIRST_SYSTEM_WINDOW+17,
-        TYPE_POINTER            = FIRST_SYSTEM_WINDOW+18,
-        TYPE_NAVIGATION_BAR     = FIRST_SYSTEM_WINDOW+19,
-        TYPE_VOLUME_OVERLAY = FIRST_SYSTEM_WINDOW+20,
-        TYPE_BOOT_PROGRESS = FIRST_SYSTEM_WINDOW+21,
-        LAST_SYSTEM_WINDOW      = 2999,
-    };
-
-    enum {
-        INPUT_FEATURE_DISABLE_TOUCH_PAD_GESTURES = 0x00000001,
-        INPUT_FEATURE_NO_INPUT_CHANNEL = 0x00000002,
-        INPUT_FEATURE_DISABLE_USER_ACTIVITY = 0x00000004,
-    };
-
-    sp<InputChannel> inputChannel;
-    String8 name;
-    int32_t layoutParamsFlags;
-    int32_t layoutParamsPrivateFlags;
-    int32_t layoutParamsType;
-    nsecs_t dispatchingTimeout;
-    int32_t frameLeft;
-    int32_t frameTop;
-    int32_t frameRight;
-    int32_t frameBottom;
-    float scaleFactor;
-    SkRegion touchableRegion;
-    bool visible;
-    bool canReceiveKeys;
-    bool hasFocus;
-    bool hasWallpaper;
-    bool paused;
-    int32_t layer;
-    int32_t ownerPid;
-    int32_t ownerUid;
-    int32_t inputFeatures;
-    int32_t displayId;
-
-    bool touchableRegionContainsPoint(int32_t x, int32_t y) const;
-    bool frameContainsPoint(int32_t x, int32_t y) const;
-
-    /* Returns true if the window is of a trusted type that is allowed to silently
-     * overlay other windows for the purpose of implementing the secure views feature.
-     * Trusted overlays, such as IME windows, can partly obscure other windows without causing
-     * motion events to be delivered to them with AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED.
-     */
-    bool isTrustedOverlay() const;
-
-    bool supportsSplitTouch() const;
-};
-
-
-/*
- * Handle for a window that can receive input.
- *
- * Used by the native input dispatcher to indirectly refer to the window manager objects
- * that describe a window.
- */
-class InputWindowHandle : public RefBase {
-public:
-    const sp<InputApplicationHandle> inputApplicationHandle;
-
-    inline const InputWindowInfo* getInfo() const {
-        return mInfo;
-    }
-
-    inline sp<InputChannel> getInputChannel() const {
-        return mInfo ? mInfo->inputChannel : NULL;
-    }
-
-    inline String8 getName() const {
-        return mInfo ? mInfo->name : String8("<invalid>");
-    }
-
-    inline nsecs_t getDispatchingTimeout(nsecs_t defaultValue) const {
-        return mInfo ? mInfo->dispatchingTimeout : defaultValue;
-    }
-
-    /**
-     * Requests that the state of this object be updated to reflect
-     * the most current available information about the application.
-     *
-     * This method should only be called from within the input dispatcher's
-     * critical section.
-     *
-     * Returns true on success, or false if the handle is no longer valid.
-     */
-    virtual bool updateInfo() = 0;
-
-    /**
-     * Releases the storage used by the associated information when it is
-     * no longer needed.
-     */
-    void releaseInfo();
-
-protected:
-    InputWindowHandle(const sp<InputApplicationHandle>& inputApplicationHandle);
-    virtual ~InputWindowHandle();
-
-    InputWindowInfo* mInfo;
-};
-
-} // namespace android
-
-#endif // _UI_INPUT_WINDOW_H
diff --git a/libs/input/PointerController.h b/libs/input/PointerController.h
index 790c0bb..b9e4ce7 100644
--- a/libs/input/PointerController.h
+++ b/libs/input/PointerController.h
@@ -21,6 +21,7 @@
 
 #include <ui/DisplayInfo.h>
 #include <input/Input.h>
+#include <inputflinger/PointerControllerInterface.h>
 #include <utils/BitSet.h>
 #include <utils/RefBase.h>
 #include <utils/Looper.h>
@@ -30,84 +31,6 @@
 
 namespace android {
 
-/**
- * Interface for tracking a mouse / touch pad pointer and touch pad spots.
- *
- * The spots are sprites on screen that visually represent the positions of
- * fingers
- *
- * The pointer controller is responsible for providing synchronization and for tracking
- * display orientation changes if needed.
- */
-class PointerControllerInterface : public virtual RefBase {
-protected:
-    PointerControllerInterface() { }
-    virtual ~PointerControllerInterface() { }
-
-public:
-    /* Gets the bounds of the region that the pointer can traverse.
-     * Returns true if the bounds are available. */
-    virtual bool getBounds(float* outMinX, float* outMinY,
-            float* outMaxX, float* outMaxY) const = 0;
-
-    /* Move the pointer. */
-    virtual void move(float deltaX, float deltaY) = 0;
-
-    /* Sets a mask that indicates which buttons are pressed. */
-    virtual void setButtonState(int32_t buttonState) = 0;
-
-    /* Gets a mask that indicates which buttons are pressed. */
-    virtual int32_t getButtonState() const = 0;
-
-    /* Sets the absolute location of the pointer. */
-    virtual void setPosition(float x, float y) = 0;
-
-    /* Gets the absolute location of the pointer. */
-    virtual void getPosition(float* outX, float* outY) const = 0;
-
-    enum Transition {
-        // Fade/unfade immediately.
-        TRANSITION_IMMEDIATE,
-        // Fade/unfade gradually.
-        TRANSITION_GRADUAL,
-    };
-
-    /* Fades the pointer out now. */
-    virtual void fade(Transition transition) = 0;
-
-    /* Makes the pointer visible if it has faded out.
-     * The pointer never unfades itself automatically.  This method must be called
-     * by the client whenever the pointer is moved or a button is pressed and it
-     * wants to ensure that the pointer becomes visible again. */
-    virtual void unfade(Transition transition) = 0;
-
-    enum Presentation {
-        // Show the mouse pointer.
-        PRESENTATION_POINTER,
-        // Show spots and a spot anchor in place of the mouse pointer.
-        PRESENTATION_SPOT,
-    };
-
-    /* Sets the mode of the pointer controller. */
-    virtual void setPresentation(Presentation presentation) = 0;
-
-    /* Sets the spots for the current gesture.
-     * The spots are not subject to the inactivity timeout like the pointer
-     * itself it since they are expected to remain visible for so long as
-     * the fingers are on the touch pad.
-     *
-     * The values of the AMOTION_EVENT_AXIS_PRESSURE axis is significant.
-     * For spotCoords, pressure != 0 indicates that the spot's location is being
-     * pressed (not hovering).
-     */
-    virtual void setSpots(const PointerCoords* spotCoords, const uint32_t* spotIdToIndex,
-            BitSet32 spotIdBits) = 0;
-
-    /* Removes all spots. */
-    virtual void clearSpots() = 0;
-};
-
-
 /*
  * Pointer resources.
  */
diff --git a/libs/input/tests/Android.mk b/libs/input/tests/Android.mk
deleted file mode 100644
index 9278f41..0000000
--- a/libs/input/tests/Android.mk
+++ /dev/null
@@ -1,48 +0,0 @@
-# Build the unit tests.
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-# Build the unit tests.
-test_src_files := \
-    InputReader_test.cpp \
-    InputDispatcher_test.cpp
-
-shared_libraries := \
-    libcutils \
-    liblog \
-    libandroidfw \
-    libutils \
-    libhardware \
-    libhardware_legacy \
-    libui \
-    libskia \
-    libstlport \
-    libinput \
-    libinputservice
-
-static_libraries := \
-    libgtest \
-    libgtest_main
-
-c_includes := \
-    bionic \
-    bionic/libstdc++/include \
-    external/gtest/include \
-    external/stlport/stlport \
-    external/skia/include/core
-
-module_tags := eng tests
-
-$(foreach file,$(test_src_files), \
-    $(eval include $(CLEAR_VARS)) \
-    $(eval LOCAL_SHARED_LIBRARIES := $(shared_libraries)) \
-    $(eval LOCAL_STATIC_LIBRARIES := $(static_libraries)) \
-    $(eval LOCAL_C_INCLUDES := $(c_includes)) \
-    $(eval LOCAL_SRC_FILES := $(file)) \
-    $(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \
-    $(eval LOCAL_MODULE_TAGS := $(module_tags)) \
-    $(eval include $(BUILD_NATIVE_TEST)) \
-)
-
-# Build the manual test programs.
-include $(call all-makefiles-under, $(LOCAL_PATH))
diff --git a/libs/input/tests/InputDispatcher_test.cpp b/libs/input/tests/InputDispatcher_test.cpp
deleted file mode 100644
index 26b4fab..0000000
--- a/libs/input/tests/InputDispatcher_test.cpp
+++ /dev/null
@@ -1,247 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "../InputDispatcher.h"
-
-#include <gtest/gtest.h>
-#include <linux/input.h>
-
-namespace android {
-
-// An arbitrary time value.
-static const nsecs_t ARBITRARY_TIME = 1234;
-
-// An arbitrary device id.
-static const int32_t DEVICE_ID = 1;
-
-// 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;
-
-
-// --- FakeInputDispatcherPolicy ---
-
-class FakeInputDispatcherPolicy : public InputDispatcherPolicyInterface {
-    InputDispatcherConfiguration mConfig;
-
-protected:
-    virtual ~FakeInputDispatcherPolicy() {
-    }
-
-public:
-    FakeInputDispatcherPolicy() {
-    }
-
-private:
-    virtual void notifyConfigurationChanged(nsecs_t when) {
-    }
-
-    virtual nsecs_t notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle,
-            const sp<InputWindowHandle>& inputWindowHandle,
-            const String8& reason) {
-        return 0;
-    }
-
-    virtual void notifyInputChannelBroken(const sp<InputWindowHandle>& inputWindowHandle) {
-    }
-
-    virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) {
-        *outConfig = mConfig;
-    }
-
-    virtual bool isKeyRepeatEnabled() {
-        return true;
-    }
-
-    virtual bool filterInputEvent(const InputEvent* inputEvent, uint32_t policyFlags) {
-        return true;
-    }
-
-    virtual void interceptKeyBeforeQueueing(const KeyEvent* keyEvent, uint32_t& policyFlags) {
-    }
-
-    virtual void interceptMotionBeforeQueueing(nsecs_t when, uint32_t& policyFlags) {
-    }
-
-    virtual nsecs_t interceptKeyBeforeDispatching(const sp<InputWindowHandle>& inputWindowHandle,
-            const KeyEvent* keyEvent, uint32_t policyFlags) {
-        return 0;
-    }
-
-    virtual bool dispatchUnhandledKey(const sp<InputWindowHandle>& inputWindowHandle,
-            const KeyEvent* keyEvent, uint32_t policyFlags, KeyEvent* outFallbackKeyEvent) {
-        return false;
-    }
-
-    virtual void notifySwitch(nsecs_t when,
-            uint32_t switchValues, uint32_t switchMask, uint32_t policyFlags) {
-    }
-
-    virtual void pokeUserActivity(nsecs_t eventTime, int32_t eventType) {
-    }
-
-    virtual bool checkInjectEventsPermissionNonReentrant(
-            int32_t injectorPid, int32_t injectorUid) {
-        return false;
-    }
-};
-
-
-// --- InputDispatcherTest ---
-
-class InputDispatcherTest : public testing::Test {
-protected:
-    sp<FakeInputDispatcherPolicy> mFakePolicy;
-    sp<InputDispatcher> mDispatcher;
-
-    virtual void SetUp() {
-        mFakePolicy = new FakeInputDispatcherPolicy();
-        mDispatcher = new InputDispatcher(mFakePolicy);
-    }
-
-    virtual void TearDown() {
-        mFakePolicy.clear();
-        mDispatcher.clear();
-    }
-};
-
-
-TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesKeyEvents) {
-    KeyEvent event;
-
-    // Rejects undefined key actions.
-    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,
-            INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
-            << "Should reject key events with undefined action.";
-
-    // Rejects ACTION_MULTIPLE since it is not supported despite being defined in the API.
-    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,
-            INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
-            << "Should reject key events with ACTION_MULTIPLE.";
-}
-
-TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) {
-    MotionEvent event;
-    PointerProperties pointerProperties[MAX_POINTERS + 1];
-    PointerCoords pointerCoords[MAX_POINTERS + 1];
-    for (int i = 0; i <= MAX_POINTERS; i++) {
-        pointerProperties[i].clear();
-        pointerProperties[i].id = i;
-        pointerCoords[i].clear();
-    }
-
-    // Rejects undefined motion actions.
-    event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
-            /*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,
-            INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
-            << "Should reject motion events with undefined action.";
-
-    // Rejects pointer down with invalid index.
-    event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
-            AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
-            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,
-            INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
-            << "Should reject motion events with pointer down index too large.";
-
-    event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
-            AMOTION_EVENT_ACTION_POINTER_DOWN | (-1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
-            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,
-            INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
-            << "Should reject motion events with pointer down index too small.";
-
-    // Rejects pointer up with invalid index.
-    event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
-            AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
-            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,
-            INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
-            << "Should reject motion events with pointer up index too large.";
-
-    event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
-            AMOTION_EVENT_ACTION_POINTER_UP | (-1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
-            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,
-            INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
-            << "Should reject motion events with pointer up index too small.";
-
-    // Rejects motion events with invalid number of pointers.
-    event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
-            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,
-            INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
-            << "Should reject motion events with 0 pointers.";
-
-    event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
-            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,
-            INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
-            << "Should reject motion events with more than MAX_POINTERS pointers.";
-
-    // Rejects motion events with invalid pointer ids.
-    pointerProperties[0].id = -1;
-    event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
-            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,
-            INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
-            << "Should reject motion events with pointer ids less than 0.";
-
-    pointerProperties[0].id = MAX_POINTER_ID + 1;
-    event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
-            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,
-            INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
-            << "Should reject motion events with pointer ids greater than MAX_POINTER_ID.";
-
-    // Rejects motion events with duplicate pointer ids.
-    pointerProperties[0].id = 1;
-    pointerProperties[1].id = 1;
-    event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
-            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,
-            INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
-            << "Should reject motion events with duplicate pointer ids.";
-}
-
-} // namespace android
diff --git a/libs/input/tests/InputReader_test.cpp b/libs/input/tests/InputReader_test.cpp
deleted file mode 100644
index aaa973d..0000000
--- a/libs/input/tests/InputReader_test.cpp
+++ /dev/null
@@ -1,5099 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "../InputReader.h"
-
-#include <utils/List.h>
-#include <gtest/gtest.h>
-#include <math.h>
-
-namespace android {
-
-// An arbitrary time value.
-static const nsecs_t ARBITRARY_TIME = 1234;
-
-// Arbitrary display properties.
-static const int32_t DISPLAY_ID = 0;
-static const int32_t DISPLAY_WIDTH = 480;
-static const int32_t DISPLAY_HEIGHT = 800;
-
-// Error tolerance for floating point assertions.
-static const float EPSILON = 0.001f;
-
-template<typename T>
-static inline T min(T a, T b) {
-    return a < b ? a : b;
-}
-
-static inline float avg(float x, float y) {
-    return (x + y) / 2;
-}
-
-
-// --- FakePointerController ---
-
-class FakePointerController : public PointerControllerInterface {
-    bool mHaveBounds;
-    float mMinX, mMinY, mMaxX, mMaxY;
-    float mX, mY;
-    int32_t mButtonState;
-
-protected:
-    virtual ~FakePointerController() { }
-
-public:
-    FakePointerController() :
-        mHaveBounds(false), mMinX(0), mMinY(0), mMaxX(0), mMaxY(0), mX(0), mY(0),
-        mButtonState(0) {
-    }
-
-    void setBounds(float minX, float minY, float maxX, float maxY) {
-        mHaveBounds = true;
-        mMinX = minX;
-        mMinY = minY;
-        mMaxX = maxX;
-        mMaxY = maxY;
-    }
-
-    virtual void setPosition(float x, float y) {
-        mX = x;
-        mY = y;
-    }
-
-    virtual void setButtonState(int32_t buttonState) {
-        mButtonState = buttonState;
-    }
-
-    virtual int32_t getButtonState() const {
-        return mButtonState;
-    }
-
-    virtual void getPosition(float* outX, float* outY) const {
-        *outX = mX;
-        *outY = mY;
-    }
-
-private:
-    virtual bool getBounds(float* outMinX, float* outMinY, float* outMaxX, float* outMaxY) const {
-        *outMinX = mMinX;
-        *outMinY = mMinY;
-        *outMaxX = mMaxX;
-        *outMaxY = mMaxY;
-        return mHaveBounds;
-    }
-
-    virtual void move(float deltaX, float deltaY) {
-        mX += deltaX;
-        if (mX < mMinX) mX = mMinX;
-        if (mX > mMaxX) mX = mMaxX;
-        mY += deltaY;
-        if (mY < mMinY) mY = mMinY;
-        if (mY > mMaxY) mY = mMaxY;
-    }
-
-    virtual void fade(Transition transition) {
-    }
-
-    virtual void unfade(Transition transition) {
-    }
-
-    virtual void setPresentation(Presentation presentation) {
-    }
-
-    virtual void setSpots(const PointerCoords* spotCoords,
-            const uint32_t* spotIdToIndex, BitSet32 spotIdBits) {
-    }
-
-    virtual void clearSpots() {
-    }
-};
-
-
-// --- FakeInputReaderPolicy ---
-
-class FakeInputReaderPolicy : public InputReaderPolicyInterface {
-    InputReaderConfiguration mConfig;
-    KeyedVector<int32_t, sp<FakePointerController> > mPointerControllers;
-    Vector<InputDeviceInfo> mInputDevices;
-
-protected:
-    virtual ~FakeInputReaderPolicy() { }
-
-public:
-    FakeInputReaderPolicy() {
-    }
-
-    void setDisplayInfo(int32_t displayId, int32_t width, int32_t height, int32_t orientation) {
-        // Set the size of both the internal and external display at the same time.
-        bool isRotated = (orientation == DISPLAY_ORIENTATION_90
-                || orientation == DISPLAY_ORIENTATION_270);
-        DisplayViewport v;
-        v.displayId = displayId;
-        v.orientation = orientation;
-        v.logicalLeft = 0;
-        v.logicalTop = 0;
-        v.logicalRight = isRotated ? height : width;
-        v.logicalBottom = isRotated ? width : height;
-        v.physicalLeft = 0;
-        v.physicalTop = 0;
-        v.physicalRight = isRotated ? height : width;
-        v.physicalBottom = isRotated ? width : height;
-        v.deviceWidth = isRotated ? height : width;
-        v.deviceHeight = isRotated ? width : height;
-        mConfig.setDisplayInfo(false /*external*/, v);
-        mConfig.setDisplayInfo(true /*external*/, v);
-    }
-
-    void addExcludedDeviceName(const String8& deviceName) {
-        mConfig.excludedDeviceNames.push(deviceName);
-    }
-
-    void setPointerController(int32_t deviceId, const sp<FakePointerController>& controller) {
-        mPointerControllers.add(deviceId, controller);
-    }
-
-    const InputReaderConfiguration* getReaderConfiguration() const {
-        return &mConfig;
-    }
-
-    const Vector<InputDeviceInfo>& getInputDevices() const {
-        return mInputDevices;
-    }
-
-private:
-    virtual void getReaderConfiguration(InputReaderConfiguration* outConfig) {
-        *outConfig = mConfig;
-    }
-
-    virtual sp<PointerControllerInterface> obtainPointerController(int32_t deviceId) {
-        return mPointerControllers.valueFor(deviceId);
-    }
-
-    virtual void notifyInputDevicesChanged(const Vector<InputDeviceInfo>& inputDevices) {
-        mInputDevices = inputDevices;
-    }
-
-    virtual sp<KeyCharacterMap> getKeyboardLayoutOverlay(const InputDeviceIdentifier& identifier) {
-        return NULL;
-    }
-
-    virtual String8 getDeviceAlias(const InputDeviceIdentifier& identifier) {
-        return String8::empty();
-    }
-};
-
-
-// --- FakeInputListener ---
-
-class FakeInputListener : public InputListenerInterface {
-private:
-    List<NotifyConfigurationChangedArgs> mNotifyConfigurationChangedArgsQueue;
-    List<NotifyDeviceResetArgs> mNotifyDeviceResetArgsQueue;
-    List<NotifyKeyArgs> mNotifyKeyArgsQueue;
-    List<NotifyMotionArgs> mNotifyMotionArgsQueue;
-    List<NotifySwitchArgs> mNotifySwitchArgsQueue;
-
-protected:
-    virtual ~FakeInputListener() { }
-
-public:
-    FakeInputListener() {
-    }
-
-    void assertNotifyConfigurationChangedWasCalled(
-            NotifyConfigurationChangedArgs* outEventArgs = NULL) {
-        ASSERT_FALSE(mNotifyConfigurationChangedArgsQueue.empty())
-                << "Expected notifyConfigurationChanged() to have been called.";
-        if (outEventArgs) {
-            *outEventArgs = *mNotifyConfigurationChangedArgsQueue.begin();
-        }
-        mNotifyConfigurationChangedArgsQueue.erase(mNotifyConfigurationChangedArgsQueue.begin());
-    }
-
-    void assertNotifyDeviceResetWasCalled(
-            NotifyDeviceResetArgs* outEventArgs = NULL) {
-        ASSERT_FALSE(mNotifyDeviceResetArgsQueue.empty())
-                << "Expected notifyDeviceReset() to have been called.";
-        if (outEventArgs) {
-            *outEventArgs = *mNotifyDeviceResetArgsQueue.begin();
-        }
-        mNotifyDeviceResetArgsQueue.erase(mNotifyDeviceResetArgsQueue.begin());
-    }
-
-    void assertNotifyKeyWasCalled(NotifyKeyArgs* outEventArgs = NULL) {
-        ASSERT_FALSE(mNotifyKeyArgsQueue.empty())
-                << "Expected notifyKey() to have been called.";
-        if (outEventArgs) {
-            *outEventArgs = *mNotifyKeyArgsQueue.begin();
-        }
-        mNotifyKeyArgsQueue.erase(mNotifyKeyArgsQueue.begin());
-    }
-
-    void assertNotifyKeyWasNotCalled() {
-        ASSERT_TRUE(mNotifyKeyArgsQueue.empty())
-                << "Expected notifyKey() to not have been called.";
-    }
-
-    void assertNotifyMotionWasCalled(NotifyMotionArgs* outEventArgs = NULL) {
-        ASSERT_FALSE(mNotifyMotionArgsQueue.empty())
-                << "Expected notifyMotion() to have been called.";
-        if (outEventArgs) {
-            *outEventArgs = *mNotifyMotionArgsQueue.begin();
-        }
-        mNotifyMotionArgsQueue.erase(mNotifyMotionArgsQueue.begin());
-    }
-
-    void assertNotifyMotionWasNotCalled() {
-        ASSERT_TRUE(mNotifyMotionArgsQueue.empty())
-                << "Expected notifyMotion() to not have been called.";
-    }
-
-    void assertNotifySwitchWasCalled(NotifySwitchArgs* outEventArgs = NULL) {
-        ASSERT_FALSE(mNotifySwitchArgsQueue.empty())
-                << "Expected notifySwitch() to have been called.";
-        if (outEventArgs) {
-            *outEventArgs = *mNotifySwitchArgsQueue.begin();
-        }
-        mNotifySwitchArgsQueue.erase(mNotifySwitchArgsQueue.begin());
-    }
-
-private:
-    virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) {
-        mNotifyConfigurationChangedArgsQueue.push_back(*args);
-    }
-
-    virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args) {
-        mNotifyDeviceResetArgsQueue.push_back(*args);
-    }
-
-    virtual void notifyKey(const NotifyKeyArgs* args) {
-        mNotifyKeyArgsQueue.push_back(*args);
-    }
-
-    virtual void notifyMotion(const NotifyMotionArgs* args) {
-        mNotifyMotionArgsQueue.push_back(*args);
-    }
-
-    virtual void notifySwitch(const NotifySwitchArgs* args) {
-        mNotifySwitchArgsQueue.push_back(*args);
-    }
-};
-
-
-// --- FakeEventHub ---
-
-class FakeEventHub : public EventHubInterface {
-    struct KeyInfo {
-        int32_t keyCode;
-        uint32_t flags;
-    };
-
-    struct Device {
-        InputDeviceIdentifier identifier;
-        uint32_t classes;
-        PropertyMap configuration;
-        KeyedVector<int, RawAbsoluteAxisInfo> absoluteAxes;
-        KeyedVector<int, bool> relativeAxes;
-        KeyedVector<int32_t, int32_t> keyCodeStates;
-        KeyedVector<int32_t, int32_t> scanCodeStates;
-        KeyedVector<int32_t, int32_t> switchStates;
-        KeyedVector<int32_t, int32_t> absoluteAxisValue;
-        KeyedVector<int32_t, KeyInfo> keysByScanCode;
-        KeyedVector<int32_t, KeyInfo> keysByUsageCode;
-        KeyedVector<int32_t, bool> leds;
-        Vector<VirtualKeyDefinition> virtualKeys;
-
-        Device(uint32_t classes) :
-                classes(classes) {
-        }
-    };
-
-    KeyedVector<int32_t, Device*> mDevices;
-    Vector<String8> mExcludedDevices;
-    List<RawEvent> mEvents;
-
-protected:
-    virtual ~FakeEventHub() {
-        for (size_t i = 0; i < mDevices.size(); i++) {
-            delete mDevices.valueAt(i);
-        }
-    }
-
-public:
-    FakeEventHub() { }
-
-    void addDevice(int32_t deviceId, const String8& name, uint32_t classes) {
-        Device* device = new Device(classes);
-        device->identifier.name = name;
-        mDevices.add(deviceId, device);
-
-        enqueueEvent(ARBITRARY_TIME, deviceId, EventHubInterface::DEVICE_ADDED, 0, 0);
-    }
-
-    void removeDevice(int32_t deviceId) {
-        delete mDevices.valueFor(deviceId);
-        mDevices.removeItem(deviceId);
-
-        enqueueEvent(ARBITRARY_TIME, deviceId, EventHubInterface::DEVICE_REMOVED, 0, 0);
-    }
-
-    void finishDeviceScan() {
-        enqueueEvent(ARBITRARY_TIME, 0, EventHubInterface::FINISHED_DEVICE_SCAN, 0, 0);
-    }
-
-    void addConfigurationProperty(int32_t deviceId, const String8& key, const String8& value) {
-        Device* device = getDevice(deviceId);
-        device->configuration.addProperty(key, value);
-    }
-
-    void addConfigurationMap(int32_t deviceId, const PropertyMap* configuration) {
-        Device* device = getDevice(deviceId);
-        device->configuration.addAll(configuration);
-    }
-
-    void addAbsoluteAxis(int32_t deviceId, int axis,
-            int32_t minValue, int32_t maxValue, int flat, int fuzz, int resolution = 0) {
-        Device* device = getDevice(deviceId);
-
-        RawAbsoluteAxisInfo info;
-        info.valid = true;
-        info.minValue = minValue;
-        info.maxValue = maxValue;
-        info.flat = flat;
-        info.fuzz = fuzz;
-        info.resolution = resolution;
-        device->absoluteAxes.add(axis, info);
-    }
-
-    void addRelativeAxis(int32_t deviceId, int32_t axis) {
-        Device* device = getDevice(deviceId);
-        device->relativeAxes.add(axis, true);
-    }
-
-    void setKeyCodeState(int32_t deviceId, int32_t keyCode, int32_t state) {
-        Device* device = getDevice(deviceId);
-        device->keyCodeStates.replaceValueFor(keyCode, state);
-    }
-
-    void setScanCodeState(int32_t deviceId, int32_t scanCode, int32_t state) {
-        Device* device = getDevice(deviceId);
-        device->scanCodeStates.replaceValueFor(scanCode, state);
-    }
-
-    void setSwitchState(int32_t deviceId, int32_t switchCode, int32_t state) {
-        Device* device = getDevice(deviceId);
-        device->switchStates.replaceValueFor(switchCode, state);
-    }
-
-    void setAbsoluteAxisValue(int32_t deviceId, int32_t axis, int32_t value) {
-        Device* device = getDevice(deviceId);
-        device->absoluteAxisValue.replaceValueFor(axis, value);
-    }
-
-    void addKey(int32_t deviceId, int32_t scanCode, int32_t usageCode,
-            int32_t keyCode, uint32_t flags) {
-        Device* device = getDevice(deviceId);
-        KeyInfo info;
-        info.keyCode = keyCode;
-        info.flags = flags;
-        if (scanCode) {
-            device->keysByScanCode.add(scanCode, info);
-        }
-        if (usageCode) {
-            device->keysByUsageCode.add(usageCode, info);
-        }
-    }
-
-    void addLed(int32_t deviceId, int32_t led, bool initialState) {
-        Device* device = getDevice(deviceId);
-        device->leds.add(led, initialState);
-    }
-
-    bool getLedState(int32_t deviceId, int32_t led) {
-        Device* device = getDevice(deviceId);
-        return device->leds.valueFor(led);
-    }
-
-    Vector<String8>& getExcludedDevices() {
-        return mExcludedDevices;
-    }
-
-    void addVirtualKeyDefinition(int32_t deviceId, const VirtualKeyDefinition& definition) {
-        Device* device = getDevice(deviceId);
-        device->virtualKeys.push(definition);
-    }
-
-    void enqueueEvent(nsecs_t when, int32_t deviceId, int32_t type,
-            int32_t code, int32_t value) {
-        RawEvent event;
-        event.when = when;
-        event.deviceId = deviceId;
-        event.type = type;
-        event.code = code;
-        event.value = value;
-        mEvents.push_back(event);
-
-        if (type == EV_ABS) {
-            setAbsoluteAxisValue(deviceId, code, value);
-        }
-    }
-
-    void assertQueueIsEmpty() {
-        ASSERT_EQ(size_t(0), mEvents.size())
-                << "Expected the event queue to be empty (fully consumed).";
-    }
-
-private:
-    Device* getDevice(int32_t deviceId) const {
-        ssize_t index = mDevices.indexOfKey(deviceId);
-        return index >= 0 ? mDevices.valueAt(index) : NULL;
-    }
-
-    virtual uint32_t getDeviceClasses(int32_t deviceId) const {
-        Device* device = getDevice(deviceId);
-        return device ? device->classes : 0;
-    }
-
-    virtual InputDeviceIdentifier getDeviceIdentifier(int32_t deviceId) const {
-        Device* device = getDevice(deviceId);
-        return device ? device->identifier : InputDeviceIdentifier();
-    }
-
-    virtual int32_t getDeviceControllerNumber(int32_t deviceId) const {
-        return 0;
-    }
-
-    virtual void getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) const {
-        Device* device = getDevice(deviceId);
-        if (device) {
-            *outConfiguration = device->configuration;
-        }
-    }
-
-    virtual status_t getAbsoluteAxisInfo(int32_t deviceId, int axis,
-            RawAbsoluteAxisInfo* outAxisInfo) const {
-        Device* device = getDevice(deviceId);
-        if (device) {
-            ssize_t index = device->absoluteAxes.indexOfKey(axis);
-            if (index >= 0) {
-                *outAxisInfo = device->absoluteAxes.valueAt(index);
-                return OK;
-            }
-        }
-        outAxisInfo->clear();
-        return -1;
-    }
-
-    virtual bool hasRelativeAxis(int32_t deviceId, int axis) const {
-        Device* device = getDevice(deviceId);
-        if (device) {
-            return device->relativeAxes.indexOfKey(axis) >= 0;
-        }
-        return false;
-    }
-
-    virtual bool hasInputProperty(int32_t deviceId, int property) const {
-        return false;
-    }
-
-    virtual status_t mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode,
-            int32_t* outKeycode, uint32_t* outFlags) const {
-        Device* device = getDevice(deviceId);
-        if (device) {
-            const KeyInfo* key = getKey(device, scanCode, usageCode);
-            if (key) {
-                if (outKeycode) {
-                    *outKeycode = key->keyCode;
-                }
-                if (outFlags) {
-                    *outFlags = key->flags;
-                }
-                return OK;
-            }
-        }
-        return NAME_NOT_FOUND;
-    }
-
-    const KeyInfo* getKey(Device* device, int32_t scanCode, int32_t usageCode) const {
-        if (usageCode) {
-            ssize_t index = device->keysByUsageCode.indexOfKey(usageCode);
-            if (index >= 0) {
-                return &device->keysByUsageCode.valueAt(index);
-            }
-        }
-        if (scanCode) {
-            ssize_t index = device->keysByScanCode.indexOfKey(scanCode);
-            if (index >= 0) {
-                return &device->keysByScanCode.valueAt(index);
-            }
-        }
-        return NULL;
-    }
-
-    virtual status_t mapAxis(int32_t deviceId, int32_t scanCode,
-            AxisInfo* outAxisInfo) const {
-        return NAME_NOT_FOUND;
-    }
-
-    virtual void setExcludedDevices(const Vector<String8>& devices) {
-        mExcludedDevices = devices;
-    }
-
-    virtual size_t getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
-        if (mEvents.empty()) {
-            return 0;
-        }
-
-        *buffer = *mEvents.begin();
-        mEvents.erase(mEvents.begin());
-        return 1;
-    }
-
-    virtual int32_t getScanCodeState(int32_t deviceId, int32_t scanCode) const {
-        Device* device = getDevice(deviceId);
-        if (device) {
-            ssize_t index = device->scanCodeStates.indexOfKey(scanCode);
-            if (index >= 0) {
-                return device->scanCodeStates.valueAt(index);
-            }
-        }
-        return AKEY_STATE_UNKNOWN;
-    }
-
-    virtual int32_t getKeyCodeState(int32_t deviceId, int32_t keyCode) const {
-        Device* device = getDevice(deviceId);
-        if (device) {
-            ssize_t index = device->keyCodeStates.indexOfKey(keyCode);
-            if (index >= 0) {
-                return device->keyCodeStates.valueAt(index);
-            }
-        }
-        return AKEY_STATE_UNKNOWN;
-    }
-
-    virtual int32_t getSwitchState(int32_t deviceId, int32_t sw) const {
-        Device* device = getDevice(deviceId);
-        if (device) {
-            ssize_t index = device->switchStates.indexOfKey(sw);
-            if (index >= 0) {
-                return device->switchStates.valueAt(index);
-            }
-        }
-        return AKEY_STATE_UNKNOWN;
-    }
-
-    virtual status_t getAbsoluteAxisValue(int32_t deviceId, int32_t axis,
-            int32_t* outValue) const {
-        Device* device = getDevice(deviceId);
-        if (device) {
-            ssize_t index = device->absoluteAxisValue.indexOfKey(axis);
-            if (index >= 0) {
-                *outValue = device->absoluteAxisValue.valueAt(index);
-                return OK;
-            }
-        }
-        *outValue = 0;
-        return -1;
-    }
-
-    virtual bool markSupportedKeyCodes(int32_t deviceId, size_t numCodes, const int32_t* keyCodes,
-            uint8_t* outFlags) const {
-        bool result = false;
-        Device* device = getDevice(deviceId);
-        if (device) {
-            for (size_t i = 0; i < numCodes; i++) {
-                for (size_t j = 0; j < device->keysByScanCode.size(); j++) {
-                    if (keyCodes[i] == device->keysByScanCode.valueAt(j).keyCode) {
-                        outFlags[i] = 1;
-                        result = true;
-                    }
-                }
-                for (size_t j = 0; j < device->keysByUsageCode.size(); j++) {
-                    if (keyCodes[i] == device->keysByUsageCode.valueAt(j).keyCode) {
-                        outFlags[i] = 1;
-                        result = true;
-                    }
-                }
-            }
-        }
-        return result;
-    }
-
-    virtual bool hasScanCode(int32_t deviceId, int32_t scanCode) const {
-        Device* device = getDevice(deviceId);
-        if (device) {
-            ssize_t index = device->keysByScanCode.indexOfKey(scanCode);
-            return index >= 0;
-        }
-        return false;
-    }
-
-    virtual bool hasLed(int32_t deviceId, int32_t led) const {
-        Device* device = getDevice(deviceId);
-        return device && device->leds.indexOfKey(led) >= 0;
-    }
-
-    virtual void setLedState(int32_t deviceId, int32_t led, bool on) {
-        Device* device = getDevice(deviceId);
-        if (device) {
-            ssize_t index = device->leds.indexOfKey(led);
-            if (index >= 0) {
-                device->leds.replaceValueAt(led, on);
-            } else {
-                ADD_FAILURE()
-                        << "Attempted to set the state of an LED that the EventHub declared "
-                        "was not present.  led=" << led;
-            }
-        }
-    }
-
-    virtual void getVirtualKeyDefinitions(int32_t deviceId,
-            Vector<VirtualKeyDefinition>& outVirtualKeys) const {
-        outVirtualKeys.clear();
-
-        Device* device = getDevice(deviceId);
-        if (device) {
-            outVirtualKeys.appendVector(device->virtualKeys);
-        }
-    }
-
-    virtual sp<KeyCharacterMap> getKeyCharacterMap(int32_t deviceId) const {
-        return NULL;
-    }
-
-    virtual bool setKeyboardLayoutOverlay(int32_t deviceId, const sp<KeyCharacterMap>& map) {
-        return false;
-    }
-
-    virtual void vibrate(int32_t deviceId, nsecs_t duration) {
-    }
-
-    virtual void cancelVibrate(int32_t deviceId) {
-    }
-
-    virtual bool isExternal(int32_t deviceId) const {
-        return false;
-    }
-
-    virtual void dump(String8& dump) {
-    }
-
-    virtual void monitor() {
-    }
-
-    virtual void requestReopenDevices() {
-    }
-
-    virtual void wake() {
-    }
-};
-
-
-// --- FakeInputReaderContext ---
-
-class FakeInputReaderContext : public InputReaderContext {
-    sp<EventHubInterface> mEventHub;
-    sp<InputReaderPolicyInterface> mPolicy;
-    sp<InputListenerInterface> mListener;
-    int32_t mGlobalMetaState;
-    bool mUpdateGlobalMetaStateWasCalled;
-    int32_t mGeneration;
-
-public:
-    FakeInputReaderContext(const sp<EventHubInterface>& eventHub,
-            const sp<InputReaderPolicyInterface>& policy,
-            const sp<InputListenerInterface>& listener) :
-            mEventHub(eventHub), mPolicy(policy), mListener(listener),
-            mGlobalMetaState(0) {
-    }
-
-    virtual ~FakeInputReaderContext() { }
-
-    void assertUpdateGlobalMetaStateWasCalled() {
-        ASSERT_TRUE(mUpdateGlobalMetaStateWasCalled)
-                << "Expected updateGlobalMetaState() to have been called.";
-        mUpdateGlobalMetaStateWasCalled = false;
-    }
-
-    void setGlobalMetaState(int32_t state) {
-        mGlobalMetaState = state;
-    }
-
-private:
-    virtual void updateGlobalMetaState() {
-        mUpdateGlobalMetaStateWasCalled = true;
-    }
-
-    virtual int32_t getGlobalMetaState() {
-        return mGlobalMetaState;
-    }
-
-    virtual EventHubInterface* getEventHub() {
-        return mEventHub.get();
-    }
-
-    virtual InputReaderPolicyInterface* getPolicy() {
-        return mPolicy.get();
-    }
-
-    virtual InputListenerInterface* getListener() {
-        return mListener.get();
-    }
-
-    virtual void disableVirtualKeysUntil(nsecs_t time) {
-    }
-
-    virtual bool shouldDropVirtualKey(nsecs_t now,
-            InputDevice* device, int32_t keyCode, int32_t scanCode) {
-        return false;
-    }
-
-    virtual void fadePointer() {
-    }
-
-    virtual void requestTimeoutAtTime(nsecs_t when) {
-    }
-
-    virtual int32_t bumpGeneration() {
-        return ++mGeneration;
-    }
-};
-
-
-// --- FakeInputMapper ---
-
-class FakeInputMapper : public InputMapper {
-    uint32_t mSources;
-    int32_t mKeyboardType;
-    int32_t mMetaState;
-    KeyedVector<int32_t, int32_t> mKeyCodeStates;
-    KeyedVector<int32_t, int32_t> mScanCodeStates;
-    KeyedVector<int32_t, int32_t> mSwitchStates;
-    Vector<int32_t> mSupportedKeyCodes;
-    RawEvent mLastEvent;
-
-    bool mConfigureWasCalled;
-    bool mResetWasCalled;
-    bool mProcessWasCalled;
-
-public:
-    FakeInputMapper(InputDevice* device, uint32_t sources) :
-            InputMapper(device),
-            mSources(sources), mKeyboardType(AINPUT_KEYBOARD_TYPE_NONE),
-            mMetaState(0),
-            mConfigureWasCalled(false), mResetWasCalled(false), mProcessWasCalled(false) {
-    }
-
-    virtual ~FakeInputMapper() { }
-
-    void setKeyboardType(int32_t keyboardType) {
-        mKeyboardType = keyboardType;
-    }
-
-    void setMetaState(int32_t metaState) {
-        mMetaState = metaState;
-    }
-
-    void assertConfigureWasCalled() {
-        ASSERT_TRUE(mConfigureWasCalled)
-                << "Expected configure() to have been called.";
-        mConfigureWasCalled = false;
-    }
-
-    void assertResetWasCalled() {
-        ASSERT_TRUE(mResetWasCalled)
-                << "Expected reset() to have been called.";
-        mResetWasCalled = false;
-    }
-
-    void assertProcessWasCalled(RawEvent* outLastEvent = NULL) {
-        ASSERT_TRUE(mProcessWasCalled)
-                << "Expected process() to have been called.";
-        if (outLastEvent) {
-            *outLastEvent = mLastEvent;
-        }
-        mProcessWasCalled = false;
-    }
-
-    void setKeyCodeState(int32_t keyCode, int32_t state) {
-        mKeyCodeStates.replaceValueFor(keyCode, state);
-    }
-
-    void setScanCodeState(int32_t scanCode, int32_t state) {
-        mScanCodeStates.replaceValueFor(scanCode, state);
-    }
-
-    void setSwitchState(int32_t switchCode, int32_t state) {
-        mSwitchStates.replaceValueFor(switchCode, state);
-    }
-
-    void addSupportedKeyCode(int32_t keyCode) {
-        mSupportedKeyCodes.add(keyCode);
-    }
-
-private:
-    virtual uint32_t getSources() {
-        return mSources;
-    }
-
-    virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo) {
-        InputMapper::populateDeviceInfo(deviceInfo);
-
-        if (mKeyboardType != AINPUT_KEYBOARD_TYPE_NONE) {
-            deviceInfo->setKeyboardType(mKeyboardType);
-        }
-    }
-
-    virtual void configure(nsecs_t when,
-            const InputReaderConfiguration* config, uint32_t changes) {
-        mConfigureWasCalled = true;
-    }
-
-    virtual void reset(nsecs_t when) {
-        mResetWasCalled = true;
-    }
-
-    virtual void process(const RawEvent* rawEvent) {
-        mLastEvent = *rawEvent;
-        mProcessWasCalled = true;
-    }
-
-    virtual int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode) {
-        ssize_t index = mKeyCodeStates.indexOfKey(keyCode);
-        return index >= 0 ? mKeyCodeStates.valueAt(index) : AKEY_STATE_UNKNOWN;
-    }
-
-    virtual int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode) {
-        ssize_t index = mScanCodeStates.indexOfKey(scanCode);
-        return index >= 0 ? mScanCodeStates.valueAt(index) : AKEY_STATE_UNKNOWN;
-    }
-
-    virtual int32_t getSwitchState(uint32_t sourceMask, int32_t switchCode) {
-        ssize_t index = mSwitchStates.indexOfKey(switchCode);
-        return index >= 0 ? mSwitchStates.valueAt(index) : AKEY_STATE_UNKNOWN;
-    }
-
-    virtual bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes,
-            const int32_t* keyCodes, uint8_t* outFlags) {
-        bool result = false;
-        for (size_t i = 0; i < numCodes; i++) {
-            for (size_t j = 0; j < mSupportedKeyCodes.size(); j++) {
-                if (keyCodes[i] == mSupportedKeyCodes[j]) {
-                    outFlags[i] = 1;
-                    result = true;
-                }
-            }
-        }
-        return result;
-    }
-
-    virtual int32_t getMetaState() {
-        return mMetaState;
-    }
-
-    virtual void fadePointer() {
-    }
-};
-
-
-// --- InstrumentedInputReader ---
-
-class InstrumentedInputReader : public InputReader {
-    InputDevice* mNextDevice;
-
-public:
-    InstrumentedInputReader(const sp<EventHubInterface>& eventHub,
-            const sp<InputReaderPolicyInterface>& policy,
-            const sp<InputListenerInterface>& listener) :
-            InputReader(eventHub, policy, listener),
-            mNextDevice(NULL) {
-    }
-
-    virtual ~InstrumentedInputReader() {
-        if (mNextDevice) {
-            delete mNextDevice;
-        }
-    }
-
-    void setNextDevice(InputDevice* device) {
-        mNextDevice = device;
-    }
-
-    InputDevice* newDevice(int32_t deviceId, int32_t controllerNumber, const String8& name,
-            uint32_t classes) {
-        InputDeviceIdentifier identifier;
-        identifier.name = name;
-        int32_t generation = deviceId + 1;
-        return new InputDevice(&mContext, deviceId, generation, controllerNumber, identifier,
-                classes);
-    }
-
-protected:
-    virtual InputDevice* createDeviceLocked(int32_t deviceId, int32_t controllerNumber,
-            const InputDeviceIdentifier& identifier, uint32_t classes) {
-        if (mNextDevice) {
-            InputDevice* device = mNextDevice;
-            mNextDevice = NULL;
-            return device;
-        }
-        return InputReader::createDeviceLocked(deviceId, controllerNumber, identifier, classes);
-    }
-
-    friend class InputReaderTest;
-};
-
-
-// --- InputReaderTest ---
-
-class InputReaderTest : public testing::Test {
-protected:
-    sp<FakeInputListener> mFakeListener;
-    sp<FakeInputReaderPolicy> mFakePolicy;
-    sp<FakeEventHub> mFakeEventHub;
-    sp<InstrumentedInputReader> mReader;
-
-    virtual void SetUp() {
-        mFakeEventHub = new FakeEventHub();
-        mFakePolicy = new FakeInputReaderPolicy();
-        mFakeListener = new FakeInputListener();
-
-        mReader = new InstrumentedInputReader(mFakeEventHub, mFakePolicy, mFakeListener);
-    }
-
-    virtual void TearDown() {
-        mReader.clear();
-
-        mFakeListener.clear();
-        mFakePolicy.clear();
-        mFakeEventHub.clear();
-    }
-
-    void addDevice(int32_t deviceId, const String8& name, uint32_t classes,
-            const PropertyMap* configuration) {
-        mFakeEventHub->addDevice(deviceId, name, classes);
-
-        if (configuration) {
-            mFakeEventHub->addConfigurationMap(deviceId, configuration);
-        }
-        mFakeEventHub->finishDeviceScan();
-        mReader->loopOnce();
-        mReader->loopOnce();
-        mFakeEventHub->assertQueueIsEmpty();
-    }
-
-    FakeInputMapper* addDeviceWithFakeInputMapper(int32_t deviceId, int32_t controllerNumber,
-            const String8& name, uint32_t classes, uint32_t sources,
-            const PropertyMap* configuration) {
-        InputDevice* device = mReader->newDevice(deviceId, controllerNumber, name, classes);
-        FakeInputMapper* mapper = new FakeInputMapper(device, sources);
-        device->addMapper(mapper);
-        mReader->setNextDevice(device);
-        addDevice(deviceId, name, classes, configuration);
-        return mapper;
-    }
-};
-
-TEST_F(InputReaderTest, GetInputDevices) {
-    ASSERT_NO_FATAL_FAILURE(addDevice(1, String8("keyboard"),
-            INPUT_DEVICE_CLASS_KEYBOARD, NULL));
-    ASSERT_NO_FATAL_FAILURE(addDevice(2, String8("ignored"),
-            0, NULL)); // no classes so device will be ignored
-
-    Vector<InputDeviceInfo> inputDevices;
-    mReader->getInputDevices(inputDevices);
-
-    ASSERT_EQ(1U, inputDevices.size());
-    ASSERT_EQ(1, inputDevices[0].getId());
-    ASSERT_STREQ("keyboard", inputDevices[0].getIdentifier().name.string());
-    ASSERT_EQ(AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC, inputDevices[0].getKeyboardType());
-    ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, inputDevices[0].getSources());
-    ASSERT_EQ(size_t(0), inputDevices[0].getMotionRanges().size());
-
-    // Should also have received a notification describing the new input devices.
-    inputDevices = mFakePolicy->getInputDevices();
-    ASSERT_EQ(1U, inputDevices.size());
-    ASSERT_EQ(1, inputDevices[0].getId());
-    ASSERT_STREQ("keyboard", inputDevices[0].getIdentifier().name.string());
-    ASSERT_EQ(AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC, inputDevices[0].getKeyboardType());
-    ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, inputDevices[0].getSources());
-    ASSERT_EQ(size_t(0), inputDevices[0].getMotionRanges().size());
-}
-
-TEST_F(InputReaderTest, GetKeyCodeState_ForwardsRequestsToMappers) {
-    FakeInputMapper* mapper = NULL;
-    ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, 0, String8("fake"),
-            INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD, NULL));
-    mapper->setKeyCodeState(AKEYCODE_A, AKEY_STATE_DOWN);
-
-    ASSERT_EQ(AKEY_STATE_UNKNOWN, mReader->getKeyCodeState(0,
-            AINPUT_SOURCE_ANY, AKEYCODE_A))
-            << "Should return unknown when the device id is >= 0 but unknown.";
-
-    ASSERT_EQ(AKEY_STATE_UNKNOWN, mReader->getKeyCodeState(1,
-            AINPUT_SOURCE_TRACKBALL, AKEYCODE_A))
-            << "Should return unknown when the device id is valid but the sources are not supported by the device.";
-
-    ASSERT_EQ(AKEY_STATE_DOWN, mReader->getKeyCodeState(1,
-            AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TRACKBALL, AKEYCODE_A))
-            << "Should return value provided by mapper when device id is valid and the device supports some of the sources.";
-
-    ASSERT_EQ(AKEY_STATE_UNKNOWN, mReader->getKeyCodeState(-1,
-            AINPUT_SOURCE_TRACKBALL, AKEYCODE_A))
-            << "Should return unknown when the device id is < 0 but the sources are not supported by any device.";
-
-    ASSERT_EQ(AKEY_STATE_DOWN, mReader->getKeyCodeState(-1,
-            AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TRACKBALL, AKEYCODE_A))
-            << "Should return value provided by mapper when device id is < 0 and one of the devices supports some of the sources.";
-}
-
-TEST_F(InputReaderTest, GetScanCodeState_ForwardsRequestsToMappers) {
-    FakeInputMapper* mapper = NULL;
-    ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, 0, String8("fake"),
-            INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD, NULL));
-    mapper->setScanCodeState(KEY_A, AKEY_STATE_DOWN);
-
-    ASSERT_EQ(AKEY_STATE_UNKNOWN, mReader->getScanCodeState(0,
-            AINPUT_SOURCE_ANY, KEY_A))
-            << "Should return unknown when the device id is >= 0 but unknown.";
-
-    ASSERT_EQ(AKEY_STATE_UNKNOWN, mReader->getScanCodeState(1,
-            AINPUT_SOURCE_TRACKBALL, KEY_A))
-            << "Should return unknown when the device id is valid but the sources are not supported by the device.";
-
-    ASSERT_EQ(AKEY_STATE_DOWN, mReader->getScanCodeState(1,
-            AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TRACKBALL, KEY_A))
-            << "Should return value provided by mapper when device id is valid and the device supports some of the sources.";
-
-    ASSERT_EQ(AKEY_STATE_UNKNOWN, mReader->getScanCodeState(-1,
-            AINPUT_SOURCE_TRACKBALL, KEY_A))
-            << "Should return unknown when the device id is < 0 but the sources are not supported by any device.";
-
-    ASSERT_EQ(AKEY_STATE_DOWN, mReader->getScanCodeState(-1,
-            AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TRACKBALL, KEY_A))
-            << "Should return value provided by mapper when device id is < 0 and one of the devices supports some of the sources.";
-}
-
-TEST_F(InputReaderTest, GetSwitchState_ForwardsRequestsToMappers) {
-    FakeInputMapper* mapper = NULL;
-    ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, 0, String8("fake"),
-            INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD, NULL));
-    mapper->setSwitchState(SW_LID, AKEY_STATE_DOWN);
-
-    ASSERT_EQ(AKEY_STATE_UNKNOWN, mReader->getSwitchState(0,
-            AINPUT_SOURCE_ANY, SW_LID))
-            << "Should return unknown when the device id is >= 0 but unknown.";
-
-    ASSERT_EQ(AKEY_STATE_UNKNOWN, mReader->getSwitchState(1,
-            AINPUT_SOURCE_TRACKBALL, SW_LID))
-            << "Should return unknown when the device id is valid but the sources are not supported by the device.";
-
-    ASSERT_EQ(AKEY_STATE_DOWN, mReader->getSwitchState(1,
-            AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TRACKBALL, SW_LID))
-            << "Should return value provided by mapper when device id is valid and the device supports some of the sources.";
-
-    ASSERT_EQ(AKEY_STATE_UNKNOWN, mReader->getSwitchState(-1,
-            AINPUT_SOURCE_TRACKBALL, SW_LID))
-            << "Should return unknown when the device id is < 0 but the sources are not supported by any device.";
-
-    ASSERT_EQ(AKEY_STATE_DOWN, mReader->getSwitchState(-1,
-            AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TRACKBALL, SW_LID))
-            << "Should return value provided by mapper when device id is < 0 and one of the devices supports some of the sources.";
-}
-
-TEST_F(InputReaderTest, MarkSupportedKeyCodes_ForwardsRequestsToMappers) {
-    FakeInputMapper* mapper = NULL;
-    ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, 0, String8("fake"),
-            INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD, NULL));
-    mapper->addSupportedKeyCode(AKEYCODE_A);
-    mapper->addSupportedKeyCode(AKEYCODE_B);
-
-    const int32_t keyCodes[4] = { AKEYCODE_A, AKEYCODE_B, AKEYCODE_1, AKEYCODE_2 };
-    uint8_t flags[4] = { 0, 0, 0, 1 };
-
-    ASSERT_FALSE(mReader->hasKeys(0, AINPUT_SOURCE_ANY, 4, keyCodes, flags))
-            << "Should return false when device id is >= 0 but unknown.";
-    ASSERT_TRUE(!flags[0] && !flags[1] && !flags[2] && !flags[3]);
-
-    flags[3] = 1;
-    ASSERT_FALSE(mReader->hasKeys(1, AINPUT_SOURCE_TRACKBALL, 4, keyCodes, flags))
-            << "Should return false when device id is valid but the sources are not supported by the device.";
-    ASSERT_TRUE(!flags[0] && !flags[1] && !flags[2] && !flags[3]);
-
-    flags[3] = 1;
-    ASSERT_TRUE(mReader->hasKeys(1, AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TRACKBALL, 4, keyCodes, flags))
-            << "Should return value provided by mapper when device id is valid and the device supports some of the sources.";
-    ASSERT_TRUE(flags[0] && flags[1] && !flags[2] && !flags[3]);
-
-    flags[3] = 1;
-    ASSERT_FALSE(mReader->hasKeys(-1, AINPUT_SOURCE_TRACKBALL, 4, keyCodes, flags))
-            << "Should return false when the device id is < 0 but the sources are not supported by any device.";
-    ASSERT_TRUE(!flags[0] && !flags[1] && !flags[2] && !flags[3]);
-
-    flags[3] = 1;
-    ASSERT_TRUE(mReader->hasKeys(-1, AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TRACKBALL, 4, keyCodes, flags))
-            << "Should return value provided by mapper when device id is < 0 and one of the devices supports some of the sources.";
-    ASSERT_TRUE(flags[0] && flags[1] && !flags[2] && !flags[3]);
-}
-
-TEST_F(InputReaderTest, LoopOnce_WhenDeviceScanFinished_SendsConfigurationChanged) {
-    addDevice(1, String8("ignored"), INPUT_DEVICE_CLASS_KEYBOARD, NULL);
-
-    NotifyConfigurationChangedArgs args;
-
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyConfigurationChangedWasCalled(&args));
-    ASSERT_EQ(ARBITRARY_TIME, args.eventTime);
-}
-
-TEST_F(InputReaderTest, LoopOnce_ForwardsRawEventsToMappers) {
-    FakeInputMapper* mapper = NULL;
-    ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, 0, String8("fake"),
-            INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD, NULL));
-
-    mFakeEventHub->enqueueEvent(0, 1, EV_KEY, KEY_A, 1);
-    mReader->loopOnce();
-    ASSERT_NO_FATAL_FAILURE(mFakeEventHub->assertQueueIsEmpty());
-
-    RawEvent event;
-    ASSERT_NO_FATAL_FAILURE(mapper->assertProcessWasCalled(&event));
-    ASSERT_EQ(0, event.when);
-    ASSERT_EQ(1, event.deviceId);
-    ASSERT_EQ(EV_KEY, event.type);
-    ASSERT_EQ(KEY_A, event.code);
-    ASSERT_EQ(1, event.value);
-}
-
-
-// --- InputDeviceTest ---
-
-class InputDeviceTest : public testing::Test {
-protected:
-    static const char* DEVICE_NAME;
-    static const int32_t DEVICE_ID;
-    static const int32_t DEVICE_GENERATION;
-    static const int32_t DEVICE_CONTROLLER_NUMBER;
-    static const uint32_t DEVICE_CLASSES;
-
-    sp<FakeEventHub> mFakeEventHub;
-    sp<FakeInputReaderPolicy> mFakePolicy;
-    sp<FakeInputListener> mFakeListener;
-    FakeInputReaderContext* mFakeContext;
-
-    InputDevice* mDevice;
-
-    virtual void SetUp() {
-        mFakeEventHub = new FakeEventHub();
-        mFakePolicy = new FakeInputReaderPolicy();
-        mFakeListener = new FakeInputListener();
-        mFakeContext = new FakeInputReaderContext(mFakeEventHub, mFakePolicy, mFakeListener);
-
-        mFakeEventHub->addDevice(DEVICE_ID, String8(DEVICE_NAME), 0);
-        InputDeviceIdentifier identifier;
-        identifier.name = DEVICE_NAME;
-        mDevice = new InputDevice(mFakeContext, DEVICE_ID, DEVICE_GENERATION,
-                DEVICE_CONTROLLER_NUMBER, identifier, DEVICE_CLASSES);
-    }
-
-    virtual void TearDown() {
-        delete mDevice;
-
-        delete mFakeContext;
-        mFakeListener.clear();
-        mFakePolicy.clear();
-        mFakeEventHub.clear();
-    }
-};
-
-const char* InputDeviceTest::DEVICE_NAME = "device";
-const int32_t InputDeviceTest::DEVICE_ID = 1;
-const int32_t InputDeviceTest::DEVICE_GENERATION = 2;
-const int32_t InputDeviceTest::DEVICE_CONTROLLER_NUMBER = 0;
-const uint32_t InputDeviceTest::DEVICE_CLASSES = INPUT_DEVICE_CLASS_KEYBOARD
-        | INPUT_DEVICE_CLASS_TOUCH | INPUT_DEVICE_CLASS_JOYSTICK;
-
-TEST_F(InputDeviceTest, ImmutableProperties) {
-    ASSERT_EQ(DEVICE_ID, mDevice->getId());
-    ASSERT_STREQ(DEVICE_NAME, mDevice->getName());
-    ASSERT_EQ(DEVICE_CLASSES, mDevice->getClasses());
-}
-
-TEST_F(InputDeviceTest, WhenNoMappersAreRegistered_DeviceIsIgnored) {
-    // Configuration.
-    InputReaderConfiguration config;
-    mDevice->configure(ARBITRARY_TIME, &config, 0);
-
-    // Reset.
-    mDevice->reset(ARBITRARY_TIME);
-
-    NotifyDeviceResetArgs resetArgs;
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs));
-    ASSERT_EQ(ARBITRARY_TIME, resetArgs.eventTime);
-    ASSERT_EQ(DEVICE_ID, resetArgs.deviceId);
-
-    // Metadata.
-    ASSERT_TRUE(mDevice->isIgnored());
-    ASSERT_EQ(AINPUT_SOURCE_UNKNOWN, mDevice->getSources());
-
-    InputDeviceInfo info;
-    mDevice->getDeviceInfo(&info);
-    ASSERT_EQ(DEVICE_ID, info.getId());
-    ASSERT_STREQ(DEVICE_NAME, info.getIdentifier().name.string());
-    ASSERT_EQ(AINPUT_KEYBOARD_TYPE_NONE, info.getKeyboardType());
-    ASSERT_EQ(AINPUT_SOURCE_UNKNOWN, info.getSources());
-
-    // State queries.
-    ASSERT_EQ(0, mDevice->getMetaState());
-
-    ASSERT_EQ(AKEY_STATE_UNKNOWN, mDevice->getKeyCodeState(AINPUT_SOURCE_KEYBOARD, 0))
-            << "Ignored device should return unknown key code state.";
-    ASSERT_EQ(AKEY_STATE_UNKNOWN, mDevice->getScanCodeState(AINPUT_SOURCE_KEYBOARD, 0))
-            << "Ignored device should return unknown scan code state.";
-    ASSERT_EQ(AKEY_STATE_UNKNOWN, mDevice->getSwitchState(AINPUT_SOURCE_KEYBOARD, 0))
-            << "Ignored device should return unknown switch state.";
-
-    const int32_t keyCodes[2] = { AKEYCODE_A, AKEYCODE_B };
-    uint8_t flags[2] = { 0, 1 };
-    ASSERT_FALSE(mDevice->markSupportedKeyCodes(AINPUT_SOURCE_KEYBOARD, 2, keyCodes, flags))
-            << "Ignored device should never mark any key codes.";
-    ASSERT_EQ(0, flags[0]) << "Flag for unsupported key should be unchanged.";
-    ASSERT_EQ(1, flags[1]) << "Flag for unsupported key should be unchanged.";
-}
-
-TEST_F(InputDeviceTest, WhenMappersAreRegistered_DeviceIsNotIgnoredAndForwardsRequestsToMappers) {
-    // Configuration.
-    mFakeEventHub->addConfigurationProperty(DEVICE_ID, String8("key"), String8("value"));
-
-    FakeInputMapper* mapper1 = new FakeInputMapper(mDevice, AINPUT_SOURCE_KEYBOARD);
-    mapper1->setKeyboardType(AINPUT_KEYBOARD_TYPE_ALPHABETIC);
-    mapper1->setMetaState(AMETA_ALT_ON);
-    mapper1->addSupportedKeyCode(AKEYCODE_A);
-    mapper1->addSupportedKeyCode(AKEYCODE_B);
-    mapper1->setKeyCodeState(AKEYCODE_A, AKEY_STATE_DOWN);
-    mapper1->setKeyCodeState(AKEYCODE_B, AKEY_STATE_UP);
-    mapper1->setScanCodeState(2, AKEY_STATE_DOWN);
-    mapper1->setScanCodeState(3, AKEY_STATE_UP);
-    mapper1->setSwitchState(4, AKEY_STATE_DOWN);
-    mDevice->addMapper(mapper1);
-
-    FakeInputMapper* mapper2 = new FakeInputMapper(mDevice, AINPUT_SOURCE_TOUCHSCREEN);
-    mapper2->setMetaState(AMETA_SHIFT_ON);
-    mDevice->addMapper(mapper2);
-
-    InputReaderConfiguration config;
-    mDevice->configure(ARBITRARY_TIME, &config, 0);
-
-    String8 propertyValue;
-    ASSERT_TRUE(mDevice->getConfiguration().tryGetProperty(String8("key"), propertyValue))
-            << "Device should have read configuration during configuration phase.";
-    ASSERT_STREQ("value", propertyValue.string());
-
-    ASSERT_NO_FATAL_FAILURE(mapper1->assertConfigureWasCalled());
-    ASSERT_NO_FATAL_FAILURE(mapper2->assertConfigureWasCalled());
-
-    // Reset
-    mDevice->reset(ARBITRARY_TIME);
-    ASSERT_NO_FATAL_FAILURE(mapper1->assertResetWasCalled());
-    ASSERT_NO_FATAL_FAILURE(mapper2->assertResetWasCalled());
-
-    NotifyDeviceResetArgs resetArgs;
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs));
-    ASSERT_EQ(ARBITRARY_TIME, resetArgs.eventTime);
-    ASSERT_EQ(DEVICE_ID, resetArgs.deviceId);
-
-    // Metadata.
-    ASSERT_FALSE(mDevice->isIgnored());
-    ASSERT_EQ(uint32_t(AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TOUCHSCREEN), mDevice->getSources());
-
-    InputDeviceInfo info;
-    mDevice->getDeviceInfo(&info);
-    ASSERT_EQ(DEVICE_ID, info.getId());
-    ASSERT_STREQ(DEVICE_NAME, info.getIdentifier().name.string());
-    ASSERT_EQ(AINPUT_KEYBOARD_TYPE_ALPHABETIC, info.getKeyboardType());
-    ASSERT_EQ(uint32_t(AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TOUCHSCREEN), info.getSources());
-
-    // State queries.
-    ASSERT_EQ(AMETA_ALT_ON | AMETA_SHIFT_ON, mDevice->getMetaState())
-            << "Should query mappers and combine meta states.";
-
-    ASSERT_EQ(AKEY_STATE_UNKNOWN, mDevice->getKeyCodeState(AINPUT_SOURCE_TRACKBALL, AKEYCODE_A))
-            << "Should return unknown key code state when source not supported.";
-    ASSERT_EQ(AKEY_STATE_UNKNOWN, mDevice->getScanCodeState(AINPUT_SOURCE_TRACKBALL, AKEYCODE_A))
-            << "Should return unknown scan code state when source not supported.";
-    ASSERT_EQ(AKEY_STATE_UNKNOWN, mDevice->getSwitchState(AINPUT_SOURCE_TRACKBALL, AKEYCODE_A))
-            << "Should return unknown switch state when source not supported.";
-
-    ASSERT_EQ(AKEY_STATE_DOWN, mDevice->getKeyCodeState(AINPUT_SOURCE_KEYBOARD, AKEYCODE_A))
-            << "Should query mapper when source is supported.";
-    ASSERT_EQ(AKEY_STATE_UP, mDevice->getScanCodeState(AINPUT_SOURCE_KEYBOARD, 3))
-            << "Should query mapper when source is supported.";
-    ASSERT_EQ(AKEY_STATE_DOWN, mDevice->getSwitchState(AINPUT_SOURCE_KEYBOARD, 4))
-            << "Should query mapper when source is supported.";
-
-    const int32_t keyCodes[4] = { AKEYCODE_A, AKEYCODE_B, AKEYCODE_1, AKEYCODE_2 };
-    uint8_t flags[4] = { 0, 0, 0, 1 };
-    ASSERT_FALSE(mDevice->markSupportedKeyCodes(AINPUT_SOURCE_TRACKBALL, 4, keyCodes, flags))
-            << "Should do nothing when source is unsupported.";
-    ASSERT_EQ(0, flags[0]) << "Flag should be unchanged when source is unsupported.";
-    ASSERT_EQ(0, flags[1]) << "Flag should be unchanged when source is unsupported.";
-    ASSERT_EQ(0, flags[2]) << "Flag should be unchanged when source is unsupported.";
-    ASSERT_EQ(1, flags[3]) << "Flag should be unchanged when source is unsupported.";
-
-    ASSERT_TRUE(mDevice->markSupportedKeyCodes(AINPUT_SOURCE_KEYBOARD, 4, keyCodes, flags))
-            << "Should query mapper when source is supported.";
-    ASSERT_EQ(1, flags[0]) << "Flag for supported key should be set.";
-    ASSERT_EQ(1, flags[1]) << "Flag for supported key should be set.";
-    ASSERT_EQ(0, flags[2]) << "Flag for unsupported key should be unchanged.";
-    ASSERT_EQ(1, flags[3]) << "Flag for unsupported key should be unchanged.";
-
-    // Event handling.
-    RawEvent event;
-    mDevice->process(&event, 1);
-
-    ASSERT_NO_FATAL_FAILURE(mapper1->assertProcessWasCalled());
-    ASSERT_NO_FATAL_FAILURE(mapper2->assertProcessWasCalled());
-}
-
-
-// --- InputMapperTest ---
-
-class InputMapperTest : public testing::Test {
-protected:
-    static const char* DEVICE_NAME;
-    static const int32_t DEVICE_ID;
-    static const int32_t DEVICE_GENERATION;
-    static const int32_t DEVICE_CONTROLLER_NUMBER;
-    static const uint32_t DEVICE_CLASSES;
-
-    sp<FakeEventHub> mFakeEventHub;
-    sp<FakeInputReaderPolicy> mFakePolicy;
-    sp<FakeInputListener> mFakeListener;
-    FakeInputReaderContext* mFakeContext;
-    InputDevice* mDevice;
-
-    virtual void SetUp() {
-        mFakeEventHub = new FakeEventHub();
-        mFakePolicy = new FakeInputReaderPolicy();
-        mFakeListener = new FakeInputListener();
-        mFakeContext = new FakeInputReaderContext(mFakeEventHub, mFakePolicy, mFakeListener);
-        InputDeviceIdentifier identifier;
-        identifier.name = DEVICE_NAME;
-        mDevice = new InputDevice(mFakeContext, DEVICE_ID, DEVICE_GENERATION,
-                DEVICE_CONTROLLER_NUMBER, identifier, DEVICE_CLASSES);
-
-        mFakeEventHub->addDevice(DEVICE_ID, String8(DEVICE_NAME), 0);
-    }
-
-    virtual void TearDown() {
-        delete mDevice;
-        delete mFakeContext;
-        mFakeListener.clear();
-        mFakePolicy.clear();
-        mFakeEventHub.clear();
-    }
-
-    void addConfigurationProperty(const char* key, const char* value) {
-        mFakeEventHub->addConfigurationProperty(DEVICE_ID, String8(key), String8(value));
-    }
-
-    void addMapperAndConfigure(InputMapper* mapper) {
-        mDevice->addMapper(mapper);
-        mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), 0);
-        mDevice->reset(ARBITRARY_TIME);
-    }
-
-    void setDisplayInfoAndReconfigure(int32_t displayId, int32_t width, int32_t height,
-            int32_t orientation) {
-        mFakePolicy->setDisplayInfo(displayId, width, height, orientation);
-        mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
-                InputReaderConfiguration::CHANGE_DISPLAY_INFO);
-    }
-
-    static void process(InputMapper* mapper, nsecs_t when, int32_t deviceId, int32_t type,
-            int32_t code, int32_t value) {
-        RawEvent event;
-        event.when = when;
-        event.deviceId = deviceId;
-        event.type = type;
-        event.code = code;
-        event.value = value;
-        mapper->process(&event);
-    }
-
-    static void assertMotionRange(const InputDeviceInfo& info,
-            int32_t axis, uint32_t source, float min, float max, float flat, float fuzz) {
-        const InputDeviceInfo::MotionRange* range = info.getMotionRange(axis, source);
-        ASSERT_TRUE(range != NULL) << "Axis: " << axis << " Source: " << source;
-        ASSERT_EQ(axis, range->axis) << "Axis: " << axis << " Source: " << source;
-        ASSERT_EQ(source, range->source) << "Axis: " << axis << " Source: " << source;
-        ASSERT_NEAR(min, range->min, EPSILON) << "Axis: " << axis << " Source: " << source;
-        ASSERT_NEAR(max, range->max, EPSILON) << "Axis: " << axis << " Source: " << source;
-        ASSERT_NEAR(flat, range->flat, EPSILON) << "Axis: " << axis << " Source: " << source;
-        ASSERT_NEAR(fuzz, range->fuzz, EPSILON) << "Axis: " << axis << " Source: " << source;
-    }
-
-    static void assertPointerCoords(const PointerCoords& coords,
-            float x, float y, float pressure, float size,
-            float touchMajor, float touchMinor, float toolMajor, float toolMinor,
-            float orientation, float distance) {
-        ASSERT_NEAR(x, coords.getAxisValue(AMOTION_EVENT_AXIS_X), 1);
-        ASSERT_NEAR(y, coords.getAxisValue(AMOTION_EVENT_AXIS_Y), 1);
-        ASSERT_NEAR(pressure, coords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE), EPSILON);
-        ASSERT_NEAR(size, coords.getAxisValue(AMOTION_EVENT_AXIS_SIZE), EPSILON);
-        ASSERT_NEAR(touchMajor, coords.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR), 1);
-        ASSERT_NEAR(touchMinor, coords.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR), 1);
-        ASSERT_NEAR(toolMajor, coords.getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR), 1);
-        ASSERT_NEAR(toolMinor, coords.getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR), 1);
-        ASSERT_NEAR(orientation, coords.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION), EPSILON);
-        ASSERT_NEAR(distance, coords.getAxisValue(AMOTION_EVENT_AXIS_DISTANCE), EPSILON);
-    }
-
-    static void assertPosition(const sp<FakePointerController>& controller, float x, float y) {
-        float actualX, actualY;
-        controller->getPosition(&actualX, &actualY);
-        ASSERT_NEAR(x, actualX, 1);
-        ASSERT_NEAR(y, actualY, 1);
-    }
-};
-
-const char* InputMapperTest::DEVICE_NAME = "device";
-const int32_t InputMapperTest::DEVICE_ID = 1;
-const int32_t InputMapperTest::DEVICE_GENERATION = 2;
-const int32_t InputMapperTest::DEVICE_CONTROLLER_NUMBER = 0;
-const uint32_t InputMapperTest::DEVICE_CLASSES = 0; // not needed for current tests
-
-
-// --- SwitchInputMapperTest ---
-
-class SwitchInputMapperTest : public InputMapperTest {
-protected:
-};
-
-TEST_F(SwitchInputMapperTest, GetSources) {
-    SwitchInputMapper* mapper = new SwitchInputMapper(mDevice);
-    addMapperAndConfigure(mapper);
-
-    ASSERT_EQ(uint32_t(AINPUT_SOURCE_SWITCH), mapper->getSources());
-}
-
-TEST_F(SwitchInputMapperTest, GetSwitchState) {
-    SwitchInputMapper* mapper = new SwitchInputMapper(mDevice);
-    addMapperAndConfigure(mapper);
-
-    mFakeEventHub->setSwitchState(DEVICE_ID, SW_LID, 1);
-    ASSERT_EQ(1, mapper->getSwitchState(AINPUT_SOURCE_ANY, SW_LID));
-
-    mFakeEventHub->setSwitchState(DEVICE_ID, SW_LID, 0);
-    ASSERT_EQ(0, mapper->getSwitchState(AINPUT_SOURCE_ANY, SW_LID));
-}
-
-TEST_F(SwitchInputMapperTest, Process) {
-    SwitchInputMapper* mapper = new SwitchInputMapper(mDevice);
-    addMapperAndConfigure(mapper);
-
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SW, SW_LID, 1);
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SW, SW_JACK_PHYSICAL_INSERT, 1);
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SW, SW_HEADPHONE_INSERT, 0);
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0);
-
-    NotifySwitchArgs args;
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifySwitchWasCalled(&args));
-    ASSERT_EQ(ARBITRARY_TIME, args.eventTime);
-    ASSERT_EQ((1 << SW_LID) | (1 << SW_JACK_PHYSICAL_INSERT), args.switchValues);
-    ASSERT_EQ((1 << SW_LID) | (1 << SW_JACK_PHYSICAL_INSERT) | (1 << SW_HEADPHONE_INSERT),
-            args.switchMask);
-    ASSERT_EQ(uint32_t(0), args.policyFlags);
-}
-
-
-// --- KeyboardInputMapperTest ---
-
-class KeyboardInputMapperTest : public InputMapperTest {
-protected:
-    void testDPadKeyRotation(KeyboardInputMapper* mapper,
-            int32_t originalScanCode, int32_t originalKeyCode, int32_t rotatedKeyCode);
-};
-
-void KeyboardInputMapperTest::testDPadKeyRotation(KeyboardInputMapper* mapper,
-        int32_t originalScanCode, int32_t originalKeyCode, int32_t rotatedKeyCode) {
-    NotifyKeyArgs args;
-
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, originalScanCode, 1);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
-    ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, args.action);
-    ASSERT_EQ(originalScanCode, args.scanCode);
-    ASSERT_EQ(rotatedKeyCode, args.keyCode);
-
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, originalScanCode, 0);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
-    ASSERT_EQ(AKEY_EVENT_ACTION_UP, args.action);
-    ASSERT_EQ(originalScanCode, args.scanCode);
-    ASSERT_EQ(rotatedKeyCode, args.keyCode);
-}
-
-
-TEST_F(KeyboardInputMapperTest, GetSources) {
-    KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice,
-            AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC);
-    addMapperAndConfigure(mapper);
-
-    ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, mapper->getSources());
-}
-
-TEST_F(KeyboardInputMapperTest, Process_SimpleKeyPress) {
-    const int32_t USAGE_A = 0x070004;
-    const int32_t USAGE_UNKNOWN = 0x07ffff;
-    mFakeEventHub->addKey(DEVICE_ID, KEY_HOME, 0, AKEYCODE_HOME, POLICY_FLAG_WAKE);
-    mFakeEventHub->addKey(DEVICE_ID, 0, USAGE_A, AKEYCODE_A, POLICY_FLAG_WAKE);
-
-    KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice,
-            AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC);
-    addMapperAndConfigure(mapper);
-
-    // Key down by scan code.
-    process(mapper, ARBITRARY_TIME, DEVICE_ID,
-            EV_KEY, KEY_HOME, 1);
-    NotifyKeyArgs args;
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
-    ASSERT_EQ(DEVICE_ID, args.deviceId);
-    ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, args.source);
-    ASSERT_EQ(ARBITRARY_TIME, args.eventTime);
-    ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, args.action);
-    ASSERT_EQ(AKEYCODE_HOME, args.keyCode);
-    ASSERT_EQ(KEY_HOME, args.scanCode);
-    ASSERT_EQ(AMETA_NONE, args.metaState);
-    ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM, args.flags);
-    ASSERT_EQ(POLICY_FLAG_WAKE, args.policyFlags);
-    ASSERT_EQ(ARBITRARY_TIME, args.downTime);
-
-    // Key up by scan code.
-    process(mapper, ARBITRARY_TIME + 1, DEVICE_ID,
-            EV_KEY, KEY_HOME, 0);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
-    ASSERT_EQ(DEVICE_ID, args.deviceId);
-    ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, args.source);
-    ASSERT_EQ(ARBITRARY_TIME + 1, args.eventTime);
-    ASSERT_EQ(AKEY_EVENT_ACTION_UP, args.action);
-    ASSERT_EQ(AKEYCODE_HOME, args.keyCode);
-    ASSERT_EQ(KEY_HOME, args.scanCode);
-    ASSERT_EQ(AMETA_NONE, args.metaState);
-    ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM, args.flags);
-    ASSERT_EQ(POLICY_FLAG_WAKE, args.policyFlags);
-    ASSERT_EQ(ARBITRARY_TIME, args.downTime);
-
-    // Key down by usage code.
-    process(mapper, ARBITRARY_TIME, DEVICE_ID,
-            EV_MSC, MSC_SCAN, USAGE_A);
-    process(mapper, ARBITRARY_TIME, DEVICE_ID,
-            EV_KEY, 0, 1);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
-    ASSERT_EQ(DEVICE_ID, args.deviceId);
-    ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, args.source);
-    ASSERT_EQ(ARBITRARY_TIME, args.eventTime);
-    ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, args.action);
-    ASSERT_EQ(AKEYCODE_A, args.keyCode);
-    ASSERT_EQ(0, args.scanCode);
-    ASSERT_EQ(AMETA_NONE, args.metaState);
-    ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM, args.flags);
-    ASSERT_EQ(POLICY_FLAG_WAKE, args.policyFlags);
-    ASSERT_EQ(ARBITRARY_TIME, args.downTime);
-
-    // Key up by usage code.
-    process(mapper, ARBITRARY_TIME, DEVICE_ID,
-            EV_MSC, MSC_SCAN, USAGE_A);
-    process(mapper, ARBITRARY_TIME + 1, DEVICE_ID,
-            EV_KEY, 0, 0);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
-    ASSERT_EQ(DEVICE_ID, args.deviceId);
-    ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, args.source);
-    ASSERT_EQ(ARBITRARY_TIME + 1, args.eventTime);
-    ASSERT_EQ(AKEY_EVENT_ACTION_UP, args.action);
-    ASSERT_EQ(AKEYCODE_A, args.keyCode);
-    ASSERT_EQ(0, args.scanCode);
-    ASSERT_EQ(AMETA_NONE, args.metaState);
-    ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM, args.flags);
-    ASSERT_EQ(POLICY_FLAG_WAKE, args.policyFlags);
-    ASSERT_EQ(ARBITRARY_TIME, args.downTime);
-
-    // Key down with unknown scan code or usage code.
-    process(mapper, ARBITRARY_TIME, DEVICE_ID,
-            EV_MSC, MSC_SCAN, USAGE_UNKNOWN);
-    process(mapper, ARBITRARY_TIME, DEVICE_ID,
-            EV_KEY, KEY_UNKNOWN, 1);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
-    ASSERT_EQ(DEVICE_ID, args.deviceId);
-    ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, args.source);
-    ASSERT_EQ(ARBITRARY_TIME, args.eventTime);
-    ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, args.action);
-    ASSERT_EQ(0, args.keyCode);
-    ASSERT_EQ(KEY_UNKNOWN, args.scanCode);
-    ASSERT_EQ(AMETA_NONE, args.metaState);
-    ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM, args.flags);
-    ASSERT_EQ(0U, args.policyFlags);
-    ASSERT_EQ(ARBITRARY_TIME, args.downTime);
-
-    // Key up with unknown scan code or usage code.
-    process(mapper, ARBITRARY_TIME, DEVICE_ID,
-            EV_MSC, MSC_SCAN, USAGE_UNKNOWN);
-    process(mapper, ARBITRARY_TIME + 1, DEVICE_ID,
-            EV_KEY, KEY_UNKNOWN, 0);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
-    ASSERT_EQ(DEVICE_ID, args.deviceId);
-    ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, args.source);
-    ASSERT_EQ(ARBITRARY_TIME + 1, args.eventTime);
-    ASSERT_EQ(AKEY_EVENT_ACTION_UP, args.action);
-    ASSERT_EQ(0, args.keyCode);
-    ASSERT_EQ(KEY_UNKNOWN, args.scanCode);
-    ASSERT_EQ(AMETA_NONE, args.metaState);
-    ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM, args.flags);
-    ASSERT_EQ(0U, args.policyFlags);
-    ASSERT_EQ(ARBITRARY_TIME, args.downTime);
-}
-
-TEST_F(KeyboardInputMapperTest, Process_ShouldUpdateMetaState) {
-    mFakeEventHub->addKey(DEVICE_ID, KEY_LEFTSHIFT, 0, AKEYCODE_SHIFT_LEFT, 0);
-    mFakeEventHub->addKey(DEVICE_ID, KEY_A, 0, AKEYCODE_A, 0);
-
-    KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice,
-            AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC);
-    addMapperAndConfigure(mapper);
-
-    // Initial metastate.
-    ASSERT_EQ(AMETA_NONE, mapper->getMetaState());
-
-    // Metakey down.
-    process(mapper, ARBITRARY_TIME, DEVICE_ID,
-            EV_KEY, KEY_LEFTSHIFT, 1);
-    NotifyKeyArgs args;
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
-    ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, args.metaState);
-    ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, mapper->getMetaState());
-    ASSERT_NO_FATAL_FAILURE(mFakeContext->assertUpdateGlobalMetaStateWasCalled());
-
-    // Key down.
-    process(mapper, ARBITRARY_TIME + 1, DEVICE_ID,
-            EV_KEY, KEY_A, 1);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
-    ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, args.metaState);
-    ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, mapper->getMetaState());
-
-    // Key up.
-    process(mapper, ARBITRARY_TIME + 2, DEVICE_ID,
-            EV_KEY, KEY_A, 0);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
-    ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, args.metaState);
-    ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, mapper->getMetaState());
-
-    // Metakey up.
-    process(mapper, ARBITRARY_TIME + 3, DEVICE_ID,
-            EV_KEY, KEY_LEFTSHIFT, 0);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
-    ASSERT_EQ(AMETA_NONE, args.metaState);
-    ASSERT_EQ(AMETA_NONE, mapper->getMetaState());
-    ASSERT_NO_FATAL_FAILURE(mFakeContext->assertUpdateGlobalMetaStateWasCalled());
-}
-
-TEST_F(KeyboardInputMapperTest, Process_WhenNotOrientationAware_ShouldNotRotateDPad) {
-    mFakeEventHub->addKey(DEVICE_ID, KEY_UP, 0, AKEYCODE_DPAD_UP, 0);
-    mFakeEventHub->addKey(DEVICE_ID, KEY_RIGHT, 0, AKEYCODE_DPAD_RIGHT, 0);
-    mFakeEventHub->addKey(DEVICE_ID, KEY_DOWN, 0, AKEYCODE_DPAD_DOWN, 0);
-    mFakeEventHub->addKey(DEVICE_ID, KEY_LEFT, 0, AKEYCODE_DPAD_LEFT, 0);
-
-    KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice,
-            AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC);
-    addMapperAndConfigure(mapper);
-
-    setDisplayInfoAndReconfigure(DISPLAY_ID,
-            DISPLAY_WIDTH, DISPLAY_HEIGHT,
-            DISPLAY_ORIENTATION_90);
-    ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
-            KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_UP));
-    ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
-            KEY_RIGHT, AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_RIGHT));
-    ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
-            KEY_DOWN, AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_DOWN));
-    ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
-            KEY_LEFT, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_LEFT));
-}
-
-TEST_F(KeyboardInputMapperTest, Process_WhenOrientationAware_ShouldRotateDPad) {
-    mFakeEventHub->addKey(DEVICE_ID, KEY_UP, 0, AKEYCODE_DPAD_UP, 0);
-    mFakeEventHub->addKey(DEVICE_ID, KEY_RIGHT, 0, AKEYCODE_DPAD_RIGHT, 0);
-    mFakeEventHub->addKey(DEVICE_ID, KEY_DOWN, 0, AKEYCODE_DPAD_DOWN, 0);
-    mFakeEventHub->addKey(DEVICE_ID, KEY_LEFT, 0, AKEYCODE_DPAD_LEFT, 0);
-
-    KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice,
-            AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC);
-    addConfigurationProperty("keyboard.orientationAware", "1");
-    addMapperAndConfigure(mapper);
-
-    setDisplayInfoAndReconfigure(DISPLAY_ID,
-            DISPLAY_WIDTH, DISPLAY_HEIGHT,
-            DISPLAY_ORIENTATION_0);
-    ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
-            KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_UP));
-    ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
-            KEY_RIGHT, AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_RIGHT));
-    ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
-            KEY_DOWN, AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_DOWN));
-    ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
-            KEY_LEFT, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_LEFT));
-
-    setDisplayInfoAndReconfigure(DISPLAY_ID,
-            DISPLAY_WIDTH, DISPLAY_HEIGHT,
-            DISPLAY_ORIENTATION_90);
-    ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
-            KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_LEFT));
-    ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
-            KEY_RIGHT, AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_UP));
-    ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
-            KEY_DOWN, AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_RIGHT));
-    ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
-            KEY_LEFT, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_DOWN));
-
-    setDisplayInfoAndReconfigure(DISPLAY_ID,
-            DISPLAY_WIDTH, DISPLAY_HEIGHT,
-            DISPLAY_ORIENTATION_180);
-    ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
-            KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_DOWN));
-    ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
-            KEY_RIGHT, AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_LEFT));
-    ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
-            KEY_DOWN, AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_UP));
-    ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
-            KEY_LEFT, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_RIGHT));
-
-    setDisplayInfoAndReconfigure(DISPLAY_ID,
-            DISPLAY_WIDTH, DISPLAY_HEIGHT,
-            DISPLAY_ORIENTATION_270);
-    ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
-            KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_RIGHT));
-    ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
-            KEY_RIGHT, AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_DOWN));
-    ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
-            KEY_DOWN, AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_LEFT));
-    ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
-            KEY_LEFT, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_UP));
-
-    // Special case: if orientation changes while key is down, we still emit the same keycode
-    // in the key up as we did in the key down.
-    NotifyKeyArgs args;
-
-    setDisplayInfoAndReconfigure(DISPLAY_ID,
-            DISPLAY_WIDTH, DISPLAY_HEIGHT,
-            DISPLAY_ORIENTATION_270);
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, KEY_UP, 1);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
-    ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, args.action);
-    ASSERT_EQ(KEY_UP, args.scanCode);
-    ASSERT_EQ(AKEYCODE_DPAD_RIGHT, args.keyCode);
-
-    setDisplayInfoAndReconfigure(DISPLAY_ID,
-            DISPLAY_WIDTH, DISPLAY_HEIGHT,
-            DISPLAY_ORIENTATION_180);
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, KEY_UP, 0);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
-    ASSERT_EQ(AKEY_EVENT_ACTION_UP, args.action);
-    ASSERT_EQ(KEY_UP, args.scanCode);
-    ASSERT_EQ(AKEYCODE_DPAD_RIGHT, args.keyCode);
-}
-
-TEST_F(KeyboardInputMapperTest, GetKeyCodeState) {
-    KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice,
-            AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC);
-    addMapperAndConfigure(mapper);
-
-    mFakeEventHub->setKeyCodeState(DEVICE_ID, AKEYCODE_A, 1);
-    ASSERT_EQ(1, mapper->getKeyCodeState(AINPUT_SOURCE_ANY, AKEYCODE_A));
-
-    mFakeEventHub->setKeyCodeState(DEVICE_ID, AKEYCODE_A, 0);
-    ASSERT_EQ(0, mapper->getKeyCodeState(AINPUT_SOURCE_ANY, AKEYCODE_A));
-}
-
-TEST_F(KeyboardInputMapperTest, GetScanCodeState) {
-    KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice,
-            AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC);
-    addMapperAndConfigure(mapper);
-
-    mFakeEventHub->setScanCodeState(DEVICE_ID, KEY_A, 1);
-    ASSERT_EQ(1, mapper->getScanCodeState(AINPUT_SOURCE_ANY, KEY_A));
-
-    mFakeEventHub->setScanCodeState(DEVICE_ID, KEY_A, 0);
-    ASSERT_EQ(0, mapper->getScanCodeState(AINPUT_SOURCE_ANY, KEY_A));
-}
-
-TEST_F(KeyboardInputMapperTest, MarkSupportedKeyCodes) {
-    KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice,
-            AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC);
-    addMapperAndConfigure(mapper);
-
-    mFakeEventHub->addKey(DEVICE_ID, KEY_A, 0, AKEYCODE_A, 0);
-
-    const int32_t keyCodes[2] = { AKEYCODE_A, AKEYCODE_B };
-    uint8_t flags[2] = { 0, 0 };
-    ASSERT_TRUE(mapper->markSupportedKeyCodes(AINPUT_SOURCE_ANY, 1, keyCodes, flags));
-    ASSERT_TRUE(flags[0]);
-    ASSERT_FALSE(flags[1]);
-}
-
-TEST_F(KeyboardInputMapperTest, Process_LockedKeysShouldToggleMetaStateAndLeds) {
-    mFakeEventHub->addLed(DEVICE_ID, LED_CAPSL, true /*initially on*/);
-    mFakeEventHub->addLed(DEVICE_ID, LED_NUML, false /*initially off*/);
-    mFakeEventHub->addLed(DEVICE_ID, LED_SCROLLL, false /*initially off*/);
-    mFakeEventHub->addKey(DEVICE_ID, KEY_CAPSLOCK, 0, AKEYCODE_CAPS_LOCK, 0);
-    mFakeEventHub->addKey(DEVICE_ID, KEY_NUMLOCK, 0, AKEYCODE_NUM_LOCK, 0);
-    mFakeEventHub->addKey(DEVICE_ID, KEY_SCROLLLOCK, 0, AKEYCODE_SCROLL_LOCK, 0);
-
-    KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice,
-            AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC);
-    addMapperAndConfigure(mapper);
-
-    // Initialization should have turned all of the lights off.
-    ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_CAPSL));
-    ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_NUML));
-    ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_SCROLLL));
-
-    // Toggle caps lock on.
-    process(mapper, ARBITRARY_TIME, DEVICE_ID,
-            EV_KEY, KEY_CAPSLOCK, 1);
-    process(mapper, ARBITRARY_TIME, DEVICE_ID,
-            EV_KEY, KEY_CAPSLOCK, 0);
-    ASSERT_TRUE(mFakeEventHub->getLedState(DEVICE_ID, LED_CAPSL));
-    ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_NUML));
-    ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_SCROLLL));
-    ASSERT_EQ(AMETA_CAPS_LOCK_ON, mapper->getMetaState());
-
-    // Toggle num lock on.
-    process(mapper, ARBITRARY_TIME, DEVICE_ID,
-            EV_KEY, KEY_NUMLOCK, 1);
-    process(mapper, ARBITRARY_TIME, DEVICE_ID,
-            EV_KEY, KEY_NUMLOCK, 0);
-    ASSERT_TRUE(mFakeEventHub->getLedState(DEVICE_ID, LED_CAPSL));
-    ASSERT_TRUE(mFakeEventHub->getLedState(DEVICE_ID, LED_NUML));
-    ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_SCROLLL));
-    ASSERT_EQ(AMETA_CAPS_LOCK_ON | AMETA_NUM_LOCK_ON, mapper->getMetaState());
-
-    // Toggle caps lock off.
-    process(mapper, ARBITRARY_TIME, DEVICE_ID,
-            EV_KEY, KEY_CAPSLOCK, 1);
-    process(mapper, ARBITRARY_TIME, DEVICE_ID,
-            EV_KEY, KEY_CAPSLOCK, 0);
-    ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_CAPSL));
-    ASSERT_TRUE(mFakeEventHub->getLedState(DEVICE_ID, LED_NUML));
-    ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_SCROLLL));
-    ASSERT_EQ(AMETA_NUM_LOCK_ON, mapper->getMetaState());
-
-    // Toggle scroll lock on.
-    process(mapper, ARBITRARY_TIME, DEVICE_ID,
-            EV_KEY, KEY_SCROLLLOCK, 1);
-    process(mapper, ARBITRARY_TIME, DEVICE_ID,
-            EV_KEY, KEY_SCROLLLOCK, 0);
-    ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_CAPSL));
-    ASSERT_TRUE(mFakeEventHub->getLedState(DEVICE_ID, LED_NUML));
-    ASSERT_TRUE(mFakeEventHub->getLedState(DEVICE_ID, LED_SCROLLL));
-    ASSERT_EQ(AMETA_NUM_LOCK_ON | AMETA_SCROLL_LOCK_ON, mapper->getMetaState());
-
-    // Toggle num lock off.
-    process(mapper, ARBITRARY_TIME, DEVICE_ID,
-            EV_KEY, KEY_NUMLOCK, 1);
-    process(mapper, ARBITRARY_TIME, DEVICE_ID,
-            EV_KEY, KEY_NUMLOCK, 0);
-    ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_CAPSL));
-    ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_NUML));
-    ASSERT_TRUE(mFakeEventHub->getLedState(DEVICE_ID, LED_SCROLLL));
-    ASSERT_EQ(AMETA_SCROLL_LOCK_ON, mapper->getMetaState());
-
-    // Toggle scroll lock off.
-    process(mapper, ARBITRARY_TIME, DEVICE_ID,
-            EV_KEY, KEY_SCROLLLOCK, 1);
-    process(mapper, ARBITRARY_TIME, DEVICE_ID,
-            EV_KEY, KEY_SCROLLLOCK, 0);
-    ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_CAPSL));
-    ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_NUML));
-    ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_SCROLLL));
-    ASSERT_EQ(AMETA_NONE, mapper->getMetaState());
-}
-
-
-// --- CursorInputMapperTest ---
-
-class CursorInputMapperTest : public InputMapperTest {
-protected:
-    static const int32_t TRACKBALL_MOVEMENT_THRESHOLD;
-
-    sp<FakePointerController> mFakePointerController;
-
-    virtual void SetUp() {
-        InputMapperTest::SetUp();
-
-        mFakePointerController = new FakePointerController();
-        mFakePolicy->setPointerController(DEVICE_ID, mFakePointerController);
-    }
-
-    void testMotionRotation(CursorInputMapper* mapper,
-            int32_t originalX, int32_t originalY, int32_t rotatedX, int32_t rotatedY);
-};
-
-const int32_t CursorInputMapperTest::TRACKBALL_MOVEMENT_THRESHOLD = 6;
-
-void CursorInputMapperTest::testMotionRotation(CursorInputMapper* mapper,
-        int32_t originalX, int32_t originalY, int32_t rotatedX, int32_t rotatedY) {
-    NotifyMotionArgs args;
-
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_REL, REL_X, originalX);
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_REL, REL_Y, originalY);
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0],
-            float(rotatedX) / TRACKBALL_MOVEMENT_THRESHOLD,
-            float(rotatedY) / TRACKBALL_MOVEMENT_THRESHOLD,
-            0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f));
-}
-
-TEST_F(CursorInputMapperTest, WhenModeIsPointer_GetSources_ReturnsMouse) {
-    CursorInputMapper* mapper = new CursorInputMapper(mDevice);
-    addConfigurationProperty("cursor.mode", "pointer");
-    addMapperAndConfigure(mapper);
-
-    ASSERT_EQ(AINPUT_SOURCE_MOUSE, mapper->getSources());
-}
-
-TEST_F(CursorInputMapperTest, WhenModeIsNavigation_GetSources_ReturnsTrackball) {
-    CursorInputMapper* mapper = new CursorInputMapper(mDevice);
-    addConfigurationProperty("cursor.mode", "navigation");
-    addMapperAndConfigure(mapper);
-
-    ASSERT_EQ(AINPUT_SOURCE_TRACKBALL, mapper->getSources());
-}
-
-TEST_F(CursorInputMapperTest, WhenModeIsPointer_PopulateDeviceInfo_ReturnsRangeFromPointerController) {
-    CursorInputMapper* mapper = new CursorInputMapper(mDevice);
-    addConfigurationProperty("cursor.mode", "pointer");
-    addMapperAndConfigure(mapper);
-
-    InputDeviceInfo info;
-    mapper->populateDeviceInfo(&info);
-
-    // Initially there may not be a valid motion range.
-    ASSERT_EQ(NULL, info.getMotionRange(AINPUT_MOTION_RANGE_X, AINPUT_SOURCE_MOUSE));
-    ASSERT_EQ(NULL, info.getMotionRange(AINPUT_MOTION_RANGE_Y, AINPUT_SOURCE_MOUSE));
-    ASSERT_NO_FATAL_FAILURE(assertMotionRange(info,
-            AINPUT_MOTION_RANGE_PRESSURE, AINPUT_SOURCE_MOUSE, 0.0f, 1.0f, 0.0f, 0.0f));
-
-    // When the bounds are set, then there should be a valid motion range.
-    mFakePointerController->setBounds(1, 2, 800 - 1, 480 - 1);
-
-    InputDeviceInfo info2;
-    mapper->populateDeviceInfo(&info2);
-
-    ASSERT_NO_FATAL_FAILURE(assertMotionRange(info2,
-            AINPUT_MOTION_RANGE_X, AINPUT_SOURCE_MOUSE,
-            1, 800 - 1, 0.0f, 0.0f));
-    ASSERT_NO_FATAL_FAILURE(assertMotionRange(info2,
-            AINPUT_MOTION_RANGE_Y, AINPUT_SOURCE_MOUSE,
-            2, 480 - 1, 0.0f, 0.0f));
-    ASSERT_NO_FATAL_FAILURE(assertMotionRange(info2,
-            AINPUT_MOTION_RANGE_PRESSURE, AINPUT_SOURCE_MOUSE,
-            0.0f, 1.0f, 0.0f, 0.0f));
-}
-
-TEST_F(CursorInputMapperTest, WhenModeIsNavigation_PopulateDeviceInfo_ReturnsScaledRange) {
-    CursorInputMapper* mapper = new CursorInputMapper(mDevice);
-    addConfigurationProperty("cursor.mode", "navigation");
-    addMapperAndConfigure(mapper);
-
-    InputDeviceInfo info;
-    mapper->populateDeviceInfo(&info);
-
-    ASSERT_NO_FATAL_FAILURE(assertMotionRange(info,
-            AINPUT_MOTION_RANGE_X, AINPUT_SOURCE_TRACKBALL,
-            -1.0f, 1.0f, 0.0f, 1.0f / TRACKBALL_MOVEMENT_THRESHOLD));
-    ASSERT_NO_FATAL_FAILURE(assertMotionRange(info,
-            AINPUT_MOTION_RANGE_Y, AINPUT_SOURCE_TRACKBALL,
-            -1.0f, 1.0f, 0.0f, 1.0f / TRACKBALL_MOVEMENT_THRESHOLD));
-    ASSERT_NO_FATAL_FAILURE(assertMotionRange(info,
-            AINPUT_MOTION_RANGE_PRESSURE, AINPUT_SOURCE_TRACKBALL,
-            0.0f, 1.0f, 0.0f, 0.0f));
-}
-
-TEST_F(CursorInputMapperTest, Process_ShouldSetAllFieldsAndIncludeGlobalMetaState) {
-    CursorInputMapper* mapper = new CursorInputMapper(mDevice);
-    addConfigurationProperty("cursor.mode", "navigation");
-    addMapperAndConfigure(mapper);
-
-    mFakeContext->setGlobalMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON);
-
-    NotifyMotionArgs args;
-
-    // Button press.
-    // Mostly testing non x/y behavior here so we don't need to check again elsewhere.
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_MOUSE, 1);
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
-    ASSERT_EQ(ARBITRARY_TIME, args.eventTime);
-    ASSERT_EQ(DEVICE_ID, args.deviceId);
-    ASSERT_EQ(AINPUT_SOURCE_TRACKBALL, args.source);
-    ASSERT_EQ(uint32_t(0), args.policyFlags);
-    ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, args.action);
-    ASSERT_EQ(0, args.flags);
-    ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, args.metaState);
-    ASSERT_EQ(AMOTION_EVENT_BUTTON_PRIMARY, args.buttonState);
-    ASSERT_EQ(0, args.edgeFlags);
-    ASSERT_EQ(uint32_t(1), args.pointerCount);
-    ASSERT_EQ(0, args.pointerProperties[0].id);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_MOUSE, args.pointerProperties[0].toolType);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0],
-            0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f));
-    ASSERT_EQ(TRACKBALL_MOVEMENT_THRESHOLD, args.xPrecision);
-    ASSERT_EQ(TRACKBALL_MOVEMENT_THRESHOLD, args.yPrecision);
-    ASSERT_EQ(ARBITRARY_TIME, args.downTime);
-
-    // Button release.  Should have same down time.
-    process(mapper, ARBITRARY_TIME + 1, DEVICE_ID, EV_KEY, BTN_MOUSE, 0);
-    process(mapper, ARBITRARY_TIME + 1, DEVICE_ID, EV_SYN, SYN_REPORT, 0);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
-    ASSERT_EQ(ARBITRARY_TIME + 1, args.eventTime);
-    ASSERT_EQ(DEVICE_ID, args.deviceId);
-    ASSERT_EQ(AINPUT_SOURCE_TRACKBALL, args.source);
-    ASSERT_EQ(uint32_t(0), args.policyFlags);
-    ASSERT_EQ(AMOTION_EVENT_ACTION_UP, args.action);
-    ASSERT_EQ(0, args.flags);
-    ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, args.metaState);
-    ASSERT_EQ(0, args.buttonState);
-    ASSERT_EQ(0, args.edgeFlags);
-    ASSERT_EQ(uint32_t(1), args.pointerCount);
-    ASSERT_EQ(0, args.pointerProperties[0].id);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_MOUSE, args.pointerProperties[0].toolType);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0],
-            0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f));
-    ASSERT_EQ(TRACKBALL_MOVEMENT_THRESHOLD, args.xPrecision);
-    ASSERT_EQ(TRACKBALL_MOVEMENT_THRESHOLD, args.yPrecision);
-    ASSERT_EQ(ARBITRARY_TIME, args.downTime);
-}
-
-TEST_F(CursorInputMapperTest, Process_ShouldHandleIndependentXYUpdates) {
-    CursorInputMapper* mapper = new CursorInputMapper(mDevice);
-    addConfigurationProperty("cursor.mode", "navigation");
-    addMapperAndConfigure(mapper);
-
-    NotifyMotionArgs args;
-
-    // Motion in X but not Y.
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_REL, REL_X, 1);
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0],
-            1.0f / TRACKBALL_MOVEMENT_THRESHOLD, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f));
-
-    // Motion in Y but not X.
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_REL, REL_Y, -2);
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0],
-            0.0f, -2.0f / TRACKBALL_MOVEMENT_THRESHOLD, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f));
-}
-
-TEST_F(CursorInputMapperTest, Process_ShouldHandleIndependentButtonUpdates) {
-    CursorInputMapper* mapper = new CursorInputMapper(mDevice);
-    addConfigurationProperty("cursor.mode", "navigation");
-    addMapperAndConfigure(mapper);
-
-    NotifyMotionArgs args;
-
-    // Button press.
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_MOUSE, 1);
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, args.action);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0],
-            0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f));
-
-    // Button release.
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_MOUSE, 0);
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_UP, args.action);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0],
-            0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f));
-}
-
-TEST_F(CursorInputMapperTest, Process_ShouldHandleCombinedXYAndButtonUpdates) {
-    CursorInputMapper* mapper = new CursorInputMapper(mDevice);
-    addConfigurationProperty("cursor.mode", "navigation");
-    addMapperAndConfigure(mapper);
-
-    NotifyMotionArgs args;
-
-    // Combined X, Y and Button.
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_REL, REL_X, 1);
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_REL, REL_Y, -2);
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_MOUSE, 1);
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, args.action);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0],
-            1.0f / TRACKBALL_MOVEMENT_THRESHOLD, -2.0f / TRACKBALL_MOVEMENT_THRESHOLD,
-            1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f));
-
-    // Move X, Y a bit while pressed.
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_REL, REL_X, 2);
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_REL, REL_Y, 1);
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0],
-            2.0f / TRACKBALL_MOVEMENT_THRESHOLD, 1.0f / TRACKBALL_MOVEMENT_THRESHOLD,
-            1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f));
-
-    // Release Button.
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_MOUSE, 0);
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_UP, args.action);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0],
-            0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f));
-}
-
-TEST_F(CursorInputMapperTest, Process_WhenNotOrientationAware_ShouldNotRotateMotions) {
-    CursorInputMapper* mapper = new CursorInputMapper(mDevice);
-    addConfigurationProperty("cursor.mode", "navigation");
-    addMapperAndConfigure(mapper);
-
-    setDisplayInfoAndReconfigure(DISPLAY_ID,
-            DISPLAY_WIDTH, DISPLAY_HEIGHT,
-            DISPLAY_ORIENTATION_90);
-    ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper,  0,  1,  0,  1));
-    ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper,  1,  1,  1,  1));
-    ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper,  1,  0,  1,  0));
-    ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper,  1, -1,  1, -1));
-    ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper,  0, -1,  0, -1));
-    ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, -1, -1, -1));
-    ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1,  0, -1,  0));
-    ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1,  1, -1,  1));
-}
-
-TEST_F(CursorInputMapperTest, Process_WhenOrientationAware_ShouldRotateMotions) {
-    CursorInputMapper* mapper = new CursorInputMapper(mDevice);
-    addConfigurationProperty("cursor.mode", "navigation");
-    addConfigurationProperty("cursor.orientationAware", "1");
-    addMapperAndConfigure(mapper);
-
-    setDisplayInfoAndReconfigure(DISPLAY_ID,
-            DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_0);
-    ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper,  0,  1,  0,  1));
-    ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper,  1,  1,  1,  1));
-    ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper,  1,  0,  1,  0));
-    ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper,  1, -1,  1, -1));
-    ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper,  0, -1,  0, -1));
-    ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, -1, -1, -1));
-    ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1,  0, -1,  0));
-    ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1,  1, -1,  1));
-
-    setDisplayInfoAndReconfigure(DISPLAY_ID,
-            DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_90);
-    ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper,  0,  1,  1,  0));
-    ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper,  1,  1,  1, -1));
-    ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper,  1,  0,  0, -1));
-    ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper,  1, -1, -1, -1));
-    ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper,  0, -1, -1,  0));
-    ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, -1, -1,  1));
-    ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1,  0,  0,  1));
-    ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1,  1,  1,  1));
-
-    setDisplayInfoAndReconfigure(DISPLAY_ID,
-            DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_180);
-    ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper,  0,  1,  0, -1));
-    ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper,  1,  1, -1, -1));
-    ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper,  1,  0, -1,  0));
-    ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper,  1, -1, -1,  1));
-    ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper,  0, -1,  0,  1));
-    ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, -1,  1,  1));
-    ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1,  0,  1,  0));
-    ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1,  1,  1, -1));
-
-    setDisplayInfoAndReconfigure(DISPLAY_ID,
-            DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_270);
-    ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper,  0,  1, -1,  0));
-    ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper,  1,  1, -1,  1));
-    ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper,  1,  0,  0,  1));
-    ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper,  1, -1,  1,  1));
-    ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper,  0, -1,  1,  0));
-    ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, -1,  1, -1));
-    ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1,  0,  0, -1));
-    ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1,  1, -1, -1));
-}
-
-TEST_F(CursorInputMapperTest, Process_ShouldHandleAllButtons) {
-    CursorInputMapper* mapper = new CursorInputMapper(mDevice);
-    addConfigurationProperty("cursor.mode", "pointer");
-    addMapperAndConfigure(mapper);
-
-    mFakePointerController->setBounds(0, 0, 800 - 1, 480 - 1);
-    mFakePointerController->setPosition(100, 200);
-    mFakePointerController->setButtonState(0);
-
-    NotifyMotionArgs motionArgs;
-    NotifyKeyArgs keyArgs;
-
-    // press BTN_LEFT, release BTN_LEFT
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_LEFT, 1);
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action);
-    ASSERT_EQ(AMOTION_EVENT_BUTTON_PRIMARY, motionArgs.buttonState);
-    ASSERT_EQ(AMOTION_EVENT_BUTTON_PRIMARY, mFakePointerController->getButtonState());
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            100.0f, 200.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f));
-
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_LEFT, 0);
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(0, motionArgs.buttonState);
-    ASSERT_EQ(0, mFakePointerController->getButtonState());
-    ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            100.0f, 200.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f));
-
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(0, motionArgs.buttonState);
-    ASSERT_EQ(0, mFakePointerController->getButtonState());
-    ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            100.0f, 200.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f));
-
-    // press BTN_RIGHT + BTN_MIDDLE, release BTN_RIGHT, release BTN_MIDDLE
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_RIGHT, 1);
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_MIDDLE, 1);
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action);
-    ASSERT_EQ(AMOTION_EVENT_BUTTON_SECONDARY | AMOTION_EVENT_BUTTON_TERTIARY,
-            motionArgs.buttonState);
-    ASSERT_EQ(AMOTION_EVENT_BUTTON_SECONDARY | AMOTION_EVENT_BUTTON_TERTIARY,
-            mFakePointerController->getButtonState());
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            100.0f, 200.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f));
-
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_RIGHT, 0);
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_BUTTON_TERTIARY, motionArgs.buttonState);
-    ASSERT_EQ(AMOTION_EVENT_BUTTON_TERTIARY, mFakePointerController->getButtonState());
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            100.0f, 200.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f));
-
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_MIDDLE, 0);
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(0, motionArgs.buttonState);
-    ASSERT_EQ(0, mFakePointerController->getButtonState());
-    ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            100.0f, 200.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f));
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(0, motionArgs.buttonState);
-    ASSERT_EQ(0, mFakePointerController->getButtonState());
-    ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            100.0f, 200.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f));
-
-    // press BTN_BACK, release BTN_BACK
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_BACK, 1);
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs));
-    ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, keyArgs.action);
-    ASSERT_EQ(AKEYCODE_BACK, keyArgs.keyCode);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_BUTTON_BACK, motionArgs.buttonState);
-    ASSERT_EQ(AMOTION_EVENT_BUTTON_BACK, mFakePointerController->getButtonState());
-    ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            100.0f, 200.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f));
-
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_BACK, 0);
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(0, motionArgs.buttonState);
-    ASSERT_EQ(0, mFakePointerController->getButtonState());
-    ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            100.0f, 200.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f));
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs));
-    ASSERT_EQ(AKEY_EVENT_ACTION_UP, keyArgs.action);
-    ASSERT_EQ(AKEYCODE_BACK, keyArgs.keyCode);
-
-    // press BTN_SIDE, release BTN_SIDE
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_SIDE, 1);
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs));
-    ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, keyArgs.action);
-    ASSERT_EQ(AKEYCODE_BACK, keyArgs.keyCode);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_BUTTON_BACK, motionArgs.buttonState);
-    ASSERT_EQ(AMOTION_EVENT_BUTTON_BACK, mFakePointerController->getButtonState());
-    ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            100.0f, 200.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f));
-
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_SIDE, 0);
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(0, motionArgs.buttonState);
-    ASSERT_EQ(0, mFakePointerController->getButtonState());
-    ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            100.0f, 200.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f));
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs));
-    ASSERT_EQ(AKEY_EVENT_ACTION_UP, keyArgs.action);
-    ASSERT_EQ(AKEYCODE_BACK, keyArgs.keyCode);
-
-    // press BTN_FORWARD, release BTN_FORWARD
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_FORWARD, 1);
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs));
-    ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, keyArgs.action);
-    ASSERT_EQ(AKEYCODE_FORWARD, keyArgs.keyCode);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_BUTTON_FORWARD, motionArgs.buttonState);
-    ASSERT_EQ(AMOTION_EVENT_BUTTON_FORWARD, mFakePointerController->getButtonState());
-    ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            100.0f, 200.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f));
-
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_FORWARD, 0);
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(0, motionArgs.buttonState);
-    ASSERT_EQ(0, mFakePointerController->getButtonState());
-    ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            100.0f, 200.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f));
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs));
-    ASSERT_EQ(AKEY_EVENT_ACTION_UP, keyArgs.action);
-    ASSERT_EQ(AKEYCODE_FORWARD, keyArgs.keyCode);
-
-    // press BTN_EXTRA, release BTN_EXTRA
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_EXTRA, 1);
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs));
-    ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, keyArgs.action);
-    ASSERT_EQ(AKEYCODE_FORWARD, keyArgs.keyCode);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_BUTTON_FORWARD, motionArgs.buttonState);
-    ASSERT_EQ(AMOTION_EVENT_BUTTON_FORWARD, mFakePointerController->getButtonState());
-    ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            100.0f, 200.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f));
-
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_EXTRA, 0);
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(0, motionArgs.buttonState);
-    ASSERT_EQ(0, mFakePointerController->getButtonState());
-    ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            100.0f, 200.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f));
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs));
-    ASSERT_EQ(AKEY_EVENT_ACTION_UP, keyArgs.action);
-    ASSERT_EQ(AKEYCODE_FORWARD, keyArgs.keyCode);
-}
-
-TEST_F(CursorInputMapperTest, Process_WhenModeIsPointer_ShouldMoveThePointerAround) {
-    CursorInputMapper* mapper = new CursorInputMapper(mDevice);
-    addConfigurationProperty("cursor.mode", "pointer");
-    addMapperAndConfigure(mapper);
-
-    mFakePointerController->setBounds(0, 0, 800 - 1, 480 - 1);
-    mFakePointerController->setPosition(100, 200);
-    mFakePointerController->setButtonState(0);
-
-    NotifyMotionArgs args;
-
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_REL, REL_X, 10);
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_REL, REL_Y, 20);
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, args.action);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0],
-            110.0f, 220.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f));
-    ASSERT_NO_FATAL_FAILURE(assertPosition(mFakePointerController, 110.0f, 220.0f));
-}
-
-
-// --- TouchInputMapperTest ---
-
-class TouchInputMapperTest : public InputMapperTest {
-protected:
-    static const int32_t RAW_X_MIN;
-    static const int32_t RAW_X_MAX;
-    static const int32_t RAW_Y_MIN;
-    static const int32_t RAW_Y_MAX;
-    static const int32_t RAW_TOUCH_MIN;
-    static const int32_t RAW_TOUCH_MAX;
-    static const int32_t RAW_TOOL_MIN;
-    static const int32_t RAW_TOOL_MAX;
-    static const int32_t RAW_PRESSURE_MIN;
-    static const int32_t RAW_PRESSURE_MAX;
-    static const int32_t RAW_ORIENTATION_MIN;
-    static const int32_t RAW_ORIENTATION_MAX;
-    static const int32_t RAW_DISTANCE_MIN;
-    static const int32_t RAW_DISTANCE_MAX;
-    static const int32_t RAW_TILT_MIN;
-    static const int32_t RAW_TILT_MAX;
-    static const int32_t RAW_ID_MIN;
-    static const int32_t RAW_ID_MAX;
-    static const int32_t RAW_SLOT_MIN;
-    static const int32_t RAW_SLOT_MAX;
-    static const float X_PRECISION;
-    static const float Y_PRECISION;
-
-    static const float GEOMETRIC_SCALE;
-
-    static const VirtualKeyDefinition VIRTUAL_KEYS[2];
-
-    enum Axes {
-        POSITION = 1 << 0,
-        TOUCH = 1 << 1,
-        TOOL = 1 << 2,
-        PRESSURE = 1 << 3,
-        ORIENTATION = 1 << 4,
-        MINOR = 1 << 5,
-        ID = 1 << 6,
-        DISTANCE = 1 << 7,
-        TILT = 1 << 8,
-        SLOT = 1 << 9,
-        TOOL_TYPE = 1 << 10,
-    };
-
-    void prepareDisplay(int32_t orientation);
-    void prepareVirtualKeys();
-    int32_t toRawX(float displayX);
-    int32_t toRawY(float displayY);
-    float toDisplayX(int32_t rawX);
-    float toDisplayY(int32_t rawY);
-};
-
-const int32_t TouchInputMapperTest::RAW_X_MIN = 25;
-const int32_t TouchInputMapperTest::RAW_X_MAX = 1019;
-const int32_t TouchInputMapperTest::RAW_Y_MIN = 30;
-const int32_t TouchInputMapperTest::RAW_Y_MAX = 1009;
-const int32_t TouchInputMapperTest::RAW_TOUCH_MIN = 0;
-const int32_t TouchInputMapperTest::RAW_TOUCH_MAX = 31;
-const int32_t TouchInputMapperTest::RAW_TOOL_MIN = 0;
-const int32_t TouchInputMapperTest::RAW_TOOL_MAX = 15;
-const int32_t TouchInputMapperTest::RAW_PRESSURE_MIN = RAW_TOUCH_MIN;
-const int32_t TouchInputMapperTest::RAW_PRESSURE_MAX = RAW_TOUCH_MAX;
-const int32_t TouchInputMapperTest::RAW_ORIENTATION_MIN = -7;
-const int32_t TouchInputMapperTest::RAW_ORIENTATION_MAX = 7;
-const int32_t TouchInputMapperTest::RAW_DISTANCE_MIN = 0;
-const int32_t TouchInputMapperTest::RAW_DISTANCE_MAX = 7;
-const int32_t TouchInputMapperTest::RAW_TILT_MIN = 0;
-const int32_t TouchInputMapperTest::RAW_TILT_MAX = 150;
-const int32_t TouchInputMapperTest::RAW_ID_MIN = 0;
-const int32_t TouchInputMapperTest::RAW_ID_MAX = 9;
-const int32_t TouchInputMapperTest::RAW_SLOT_MIN = 0;
-const int32_t TouchInputMapperTest::RAW_SLOT_MAX = 9;
-const float TouchInputMapperTest::X_PRECISION = float(RAW_X_MAX - RAW_X_MIN + 1) / DISPLAY_WIDTH;
-const float TouchInputMapperTest::Y_PRECISION = float(RAW_Y_MAX - RAW_Y_MIN + 1) / DISPLAY_HEIGHT;
-
-const float TouchInputMapperTest::GEOMETRIC_SCALE =
-        avg(float(DISPLAY_WIDTH) / (RAW_X_MAX - RAW_X_MIN + 1),
-                float(DISPLAY_HEIGHT) / (RAW_Y_MAX - RAW_Y_MIN + 1));
-
-const VirtualKeyDefinition TouchInputMapperTest::VIRTUAL_KEYS[2] = {
-        { KEY_HOME, 60, DISPLAY_HEIGHT + 15, 20, 20 },
-        { KEY_MENU, DISPLAY_HEIGHT - 60, DISPLAY_WIDTH + 15, 20, 20 },
-};
-
-void TouchInputMapperTest::prepareDisplay(int32_t orientation) {
-    setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, orientation);
-}
-
-void TouchInputMapperTest::prepareVirtualKeys() {
-    mFakeEventHub->addVirtualKeyDefinition(DEVICE_ID, VIRTUAL_KEYS[0]);
-    mFakeEventHub->addVirtualKeyDefinition(DEVICE_ID, VIRTUAL_KEYS[1]);
-    mFakeEventHub->addKey(DEVICE_ID, KEY_HOME, 0, AKEYCODE_HOME, POLICY_FLAG_WAKE);
-    mFakeEventHub->addKey(DEVICE_ID, KEY_MENU, 0, AKEYCODE_MENU, POLICY_FLAG_WAKE);
-}
-
-int32_t TouchInputMapperTest::toRawX(float displayX) {
-    return int32_t(displayX * (RAW_X_MAX - RAW_X_MIN + 1) / DISPLAY_WIDTH + RAW_X_MIN);
-}
-
-int32_t TouchInputMapperTest::toRawY(float displayY) {
-    return int32_t(displayY * (RAW_Y_MAX - RAW_Y_MIN + 1) / DISPLAY_HEIGHT + RAW_Y_MIN);
-}
-
-float TouchInputMapperTest::toDisplayX(int32_t rawX) {
-    return float(rawX - RAW_X_MIN) * DISPLAY_WIDTH / (RAW_X_MAX - RAW_X_MIN + 1);
-}
-
-float TouchInputMapperTest::toDisplayY(int32_t rawY) {
-    return float(rawY - RAW_Y_MIN) * DISPLAY_HEIGHT / (RAW_Y_MAX - RAW_Y_MIN + 1);
-}
-
-
-// --- SingleTouchInputMapperTest ---
-
-class SingleTouchInputMapperTest : public TouchInputMapperTest {
-protected:
-    void prepareButtons();
-    void prepareAxes(int axes);
-
-    void processDown(SingleTouchInputMapper* mapper, int32_t x, int32_t y);
-    void processMove(SingleTouchInputMapper* mapper, int32_t x, int32_t y);
-    void processUp(SingleTouchInputMapper* mappery);
-    void processPressure(SingleTouchInputMapper* mapper, int32_t pressure);
-    void processToolMajor(SingleTouchInputMapper* mapper, int32_t toolMajor);
-    void processDistance(SingleTouchInputMapper* mapper, int32_t distance);
-    void processTilt(SingleTouchInputMapper* mapper, int32_t tiltX, int32_t tiltY);
-    void processKey(SingleTouchInputMapper* mapper, int32_t code, int32_t value);
-    void processSync(SingleTouchInputMapper* mapper);
-};
-
-void SingleTouchInputMapperTest::prepareButtons() {
-    mFakeEventHub->addKey(DEVICE_ID, BTN_TOUCH, 0, AKEYCODE_UNKNOWN, 0);
-}
-
-void SingleTouchInputMapperTest::prepareAxes(int axes) {
-    if (axes & POSITION) {
-        mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_X,
-                RAW_X_MIN, RAW_X_MAX, 0, 0);
-        mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_Y,
-                RAW_Y_MIN, RAW_Y_MAX, 0, 0);
-    }
-    if (axes & PRESSURE) {
-        mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_PRESSURE,
-                RAW_PRESSURE_MIN, RAW_PRESSURE_MAX, 0, 0);
-    }
-    if (axes & TOOL) {
-        mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_TOOL_WIDTH,
-                RAW_TOOL_MIN, RAW_TOOL_MAX, 0, 0);
-    }
-    if (axes & DISTANCE) {
-        mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_DISTANCE,
-                RAW_DISTANCE_MIN, RAW_DISTANCE_MAX, 0, 0);
-    }
-    if (axes & TILT) {
-        mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_TILT_X,
-                RAW_TILT_MIN, RAW_TILT_MAX, 0, 0);
-        mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_TILT_Y,
-                RAW_TILT_MIN, RAW_TILT_MAX, 0, 0);
-    }
-}
-
-void SingleTouchInputMapperTest::processDown(SingleTouchInputMapper* mapper, int32_t x, int32_t y) {
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_TOUCH, 1);
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_X, x);
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_Y, y);
-}
-
-void SingleTouchInputMapperTest::processMove(SingleTouchInputMapper* mapper, int32_t x, int32_t y) {
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_X, x);
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_Y, y);
-}
-
-void SingleTouchInputMapperTest::processUp(SingleTouchInputMapper* mapper) {
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_TOUCH, 0);
-}
-
-void SingleTouchInputMapperTest::processPressure(
-        SingleTouchInputMapper* mapper, int32_t pressure) {
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_PRESSURE, pressure);
-}
-
-void SingleTouchInputMapperTest::processToolMajor(
-        SingleTouchInputMapper* mapper, int32_t toolMajor) {
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_TOOL_WIDTH, toolMajor);
-}
-
-void SingleTouchInputMapperTest::processDistance(
-        SingleTouchInputMapper* mapper, int32_t distance) {
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_DISTANCE, distance);
-}
-
-void SingleTouchInputMapperTest::processTilt(
-        SingleTouchInputMapper* mapper, int32_t tiltX, int32_t tiltY) {
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_TILT_X, tiltX);
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_TILT_Y, tiltY);
-}
-
-void SingleTouchInputMapperTest::processKey(
-        SingleTouchInputMapper* mapper, int32_t code, int32_t value) {
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, code, value);
-}
-
-void SingleTouchInputMapperTest::processSync(SingleTouchInputMapper* mapper) {
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0);
-}
-
-
-TEST_F(SingleTouchInputMapperTest, GetSources_WhenDeviceTypeIsNotSpecifiedAndNotACursor_ReturnsPointer) {
-    SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
-    prepareButtons();
-    prepareAxes(POSITION);
-    addMapperAndConfigure(mapper);
-
-    ASSERT_EQ(AINPUT_SOURCE_MOUSE, mapper->getSources());
-}
-
-TEST_F(SingleTouchInputMapperTest, GetSources_WhenDeviceTypeIsNotSpecifiedAndIsACursor_ReturnsTouchPad) {
-    SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
-    mFakeEventHub->addRelativeAxis(DEVICE_ID, REL_X);
-    mFakeEventHub->addRelativeAxis(DEVICE_ID, REL_Y);
-    prepareButtons();
-    prepareAxes(POSITION);
-    addMapperAndConfigure(mapper);
-
-    ASSERT_EQ(AINPUT_SOURCE_TOUCHPAD, mapper->getSources());
-}
-
-TEST_F(SingleTouchInputMapperTest, GetSources_WhenDeviceTypeIsTouchPad_ReturnsTouchPad) {
-    SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
-    prepareButtons();
-    prepareAxes(POSITION);
-    addConfigurationProperty("touch.deviceType", "touchPad");
-    addMapperAndConfigure(mapper);
-
-    ASSERT_EQ(AINPUT_SOURCE_TOUCHPAD, mapper->getSources());
-}
-
-TEST_F(SingleTouchInputMapperTest, GetSources_WhenDeviceTypeIsTouchScreen_ReturnsTouchScreen) {
-    SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
-    prepareButtons();
-    prepareAxes(POSITION);
-    addConfigurationProperty("touch.deviceType", "touchScreen");
-    addMapperAndConfigure(mapper);
-
-    ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, mapper->getSources());
-}
-
-TEST_F(SingleTouchInputMapperTest, GetKeyCodeState) {
-    SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
-    addConfigurationProperty("touch.deviceType", "touchScreen");
-    prepareDisplay(DISPLAY_ORIENTATION_0);
-    prepareButtons();
-    prepareAxes(POSITION);
-    prepareVirtualKeys();
-    addMapperAndConfigure(mapper);
-
-    // Unknown key.
-    ASSERT_EQ(AKEY_STATE_UNKNOWN, mapper->getKeyCodeState(AINPUT_SOURCE_ANY, AKEYCODE_A));
-
-    // Virtual key is down.
-    int32_t x = toRawX(VIRTUAL_KEYS[0].centerX);
-    int32_t y = toRawY(VIRTUAL_KEYS[0].centerY);
-    processDown(mapper, x, y);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled());
-
-    ASSERT_EQ(AKEY_STATE_VIRTUAL, mapper->getKeyCodeState(AINPUT_SOURCE_ANY, AKEYCODE_HOME));
-
-    // Virtual key is up.
-    processUp(mapper);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled());
-
-    ASSERT_EQ(AKEY_STATE_UP, mapper->getKeyCodeState(AINPUT_SOURCE_ANY, AKEYCODE_HOME));
-}
-
-TEST_F(SingleTouchInputMapperTest, GetScanCodeState) {
-    SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
-    addConfigurationProperty("touch.deviceType", "touchScreen");
-    prepareDisplay(DISPLAY_ORIENTATION_0);
-    prepareButtons();
-    prepareAxes(POSITION);
-    prepareVirtualKeys();
-    addMapperAndConfigure(mapper);
-
-    // Unknown key.
-    ASSERT_EQ(AKEY_STATE_UNKNOWN, mapper->getScanCodeState(AINPUT_SOURCE_ANY, KEY_A));
-
-    // Virtual key is down.
-    int32_t x = toRawX(VIRTUAL_KEYS[0].centerX);
-    int32_t y = toRawY(VIRTUAL_KEYS[0].centerY);
-    processDown(mapper, x, y);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled());
-
-    ASSERT_EQ(AKEY_STATE_VIRTUAL, mapper->getScanCodeState(AINPUT_SOURCE_ANY, KEY_HOME));
-
-    // Virtual key is up.
-    processUp(mapper);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled());
-
-    ASSERT_EQ(AKEY_STATE_UP, mapper->getScanCodeState(AINPUT_SOURCE_ANY, KEY_HOME));
-}
-
-TEST_F(SingleTouchInputMapperTest, MarkSupportedKeyCodes) {
-    SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
-    addConfigurationProperty("touch.deviceType", "touchScreen");
-    prepareDisplay(DISPLAY_ORIENTATION_0);
-    prepareButtons();
-    prepareAxes(POSITION);
-    prepareVirtualKeys();
-    addMapperAndConfigure(mapper);
-
-    const int32_t keys[2] = { AKEYCODE_HOME, AKEYCODE_A };
-    uint8_t flags[2] = { 0, 0 };
-    ASSERT_TRUE(mapper->markSupportedKeyCodes(AINPUT_SOURCE_ANY, 2, keys, flags));
-    ASSERT_TRUE(flags[0]);
-    ASSERT_FALSE(flags[1]);
-}
-
-TEST_F(SingleTouchInputMapperTest, Process_WhenVirtualKeyIsPressedAndReleasedNormally_SendsKeyDownAndKeyUp) {
-    SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
-    addConfigurationProperty("touch.deviceType", "touchScreen");
-    prepareDisplay(DISPLAY_ORIENTATION_0);
-    prepareButtons();
-    prepareAxes(POSITION);
-    prepareVirtualKeys();
-    addMapperAndConfigure(mapper);
-
-    mFakeContext->setGlobalMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON);
-
-    NotifyKeyArgs args;
-
-    // Press virtual key.
-    int32_t x = toRawX(VIRTUAL_KEYS[0].centerX);
-    int32_t y = toRawY(VIRTUAL_KEYS[0].centerY);
-    processDown(mapper, x, y);
-    processSync(mapper);
-
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
-    ASSERT_EQ(ARBITRARY_TIME, args.eventTime);
-    ASSERT_EQ(DEVICE_ID, args.deviceId);
-    ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, args.source);
-    ASSERT_EQ(POLICY_FLAG_VIRTUAL, args.policyFlags);
-    ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, args.action);
-    ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY, args.flags);
-    ASSERT_EQ(AKEYCODE_HOME, args.keyCode);
-    ASSERT_EQ(KEY_HOME, args.scanCode);
-    ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, args.metaState);
-    ASSERT_EQ(ARBITRARY_TIME, args.downTime);
-
-    // Release virtual key.
-    processUp(mapper);
-    processSync(mapper);
-
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
-    ASSERT_EQ(ARBITRARY_TIME, args.eventTime);
-    ASSERT_EQ(DEVICE_ID, args.deviceId);
-    ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, args.source);
-    ASSERT_EQ(POLICY_FLAG_VIRTUAL, args.policyFlags);
-    ASSERT_EQ(AKEY_EVENT_ACTION_UP, args.action);
-    ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY, args.flags);
-    ASSERT_EQ(AKEYCODE_HOME, args.keyCode);
-    ASSERT_EQ(KEY_HOME, args.scanCode);
-    ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, args.metaState);
-    ASSERT_EQ(ARBITRARY_TIME, args.downTime);
-
-    // Should not have sent any motions.
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasNotCalled());
-}
-
-TEST_F(SingleTouchInputMapperTest, Process_WhenVirtualKeyIsPressedAndMovedOutOfBounds_SendsKeyDownAndKeyCancel) {
-    SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
-    addConfigurationProperty("touch.deviceType", "touchScreen");
-    prepareDisplay(DISPLAY_ORIENTATION_0);
-    prepareButtons();
-    prepareAxes(POSITION);
-    prepareVirtualKeys();
-    addMapperAndConfigure(mapper);
-
-    mFakeContext->setGlobalMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON);
-
-    NotifyKeyArgs keyArgs;
-
-    // Press virtual key.
-    int32_t x = toRawX(VIRTUAL_KEYS[0].centerX);
-    int32_t y = toRawY(VIRTUAL_KEYS[0].centerY);
-    processDown(mapper, x, y);
-    processSync(mapper);
-
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs));
-    ASSERT_EQ(ARBITRARY_TIME, keyArgs.eventTime);
-    ASSERT_EQ(DEVICE_ID, keyArgs.deviceId);
-    ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, keyArgs.source);
-    ASSERT_EQ(POLICY_FLAG_VIRTUAL, keyArgs.policyFlags);
-    ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, keyArgs.action);
-    ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY, keyArgs.flags);
-    ASSERT_EQ(AKEYCODE_HOME, keyArgs.keyCode);
-    ASSERT_EQ(KEY_HOME, keyArgs.scanCode);
-    ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, keyArgs.metaState);
-    ASSERT_EQ(ARBITRARY_TIME, keyArgs.downTime);
-
-    // Move out of bounds.  This should generate a cancel and a pointer down since we moved
-    // into the display area.
-    y -= 100;
-    processMove(mapper, x, y);
-    processSync(mapper);
-
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs));
-    ASSERT_EQ(ARBITRARY_TIME, keyArgs.eventTime);
-    ASSERT_EQ(DEVICE_ID, keyArgs.deviceId);
-    ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, keyArgs.source);
-    ASSERT_EQ(POLICY_FLAG_VIRTUAL, keyArgs.policyFlags);
-    ASSERT_EQ(AKEY_EVENT_ACTION_UP, keyArgs.action);
-    ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY
-            | AKEY_EVENT_FLAG_CANCELED, keyArgs.flags);
-    ASSERT_EQ(AKEYCODE_HOME, keyArgs.keyCode);
-    ASSERT_EQ(KEY_HOME, keyArgs.scanCode);
-    ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, keyArgs.metaState);
-    ASSERT_EQ(ARBITRARY_TIME, keyArgs.downTime);
-
-    NotifyMotionArgs motionArgs;
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime);
-    ASSERT_EQ(DEVICE_ID, motionArgs.deviceId);
-    ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source);
-    ASSERT_EQ(uint32_t(0), motionArgs.policyFlags);
-    ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action);
-    ASSERT_EQ(0, motionArgs.flags);
-    ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState);
-    ASSERT_EQ(0, motionArgs.buttonState);
-    ASSERT_EQ(0, motionArgs.edgeFlags);
-    ASSERT_EQ(size_t(1), motionArgs.pointerCount);
-    ASSERT_EQ(0, motionArgs.pointerProperties[0].id);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            toDisplayX(x), toDisplayY(y), 1, 0, 0, 0, 0, 0, 0, 0));
-    ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON);
-    ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON);
-    ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime);
-
-    // Keep moving out of bounds.  Should generate a pointer move.
-    y -= 50;
-    processMove(mapper, x, y);
-    processSync(mapper);
-
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime);
-    ASSERT_EQ(DEVICE_ID, motionArgs.deviceId);
-    ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source);
-    ASSERT_EQ(uint32_t(0), motionArgs.policyFlags);
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
-    ASSERT_EQ(0, motionArgs.flags);
-    ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState);
-    ASSERT_EQ(0, motionArgs.buttonState);
-    ASSERT_EQ(0, motionArgs.edgeFlags);
-    ASSERT_EQ(size_t(1), motionArgs.pointerCount);
-    ASSERT_EQ(0, motionArgs.pointerProperties[0].id);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            toDisplayX(x), toDisplayY(y), 1, 0, 0, 0, 0, 0, 0, 0));
-    ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON);
-    ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON);
-    ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime);
-
-    // Release out of bounds.  Should generate a pointer up.
-    processUp(mapper);
-    processSync(mapper);
-
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime);
-    ASSERT_EQ(DEVICE_ID, motionArgs.deviceId);
-    ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source);
-    ASSERT_EQ(uint32_t(0), motionArgs.policyFlags);
-    ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action);
-    ASSERT_EQ(0, motionArgs.flags);
-    ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState);
-    ASSERT_EQ(0, motionArgs.buttonState);
-    ASSERT_EQ(0, motionArgs.edgeFlags);
-    ASSERT_EQ(size_t(1), motionArgs.pointerCount);
-    ASSERT_EQ(0, motionArgs.pointerProperties[0].id);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            toDisplayX(x), toDisplayY(y), 1, 0, 0, 0, 0, 0, 0, 0));
-    ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON);
-    ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON);
-    ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime);
-
-    // Should not have sent any more keys or motions.
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasNotCalled());
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
-}
-
-TEST_F(SingleTouchInputMapperTest, Process_WhenTouchStartsOutsideDisplayAndMovesIn_SendsDownAsTouchEntersDisplay) {
-    SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
-    addConfigurationProperty("touch.deviceType", "touchScreen");
-    prepareDisplay(DISPLAY_ORIENTATION_0);
-    prepareButtons();
-    prepareAxes(POSITION);
-    prepareVirtualKeys();
-    addMapperAndConfigure(mapper);
-
-    mFakeContext->setGlobalMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON);
-
-    NotifyMotionArgs motionArgs;
-
-    // Initially go down out of bounds.
-    int32_t x = -10;
-    int32_t y = -10;
-    processDown(mapper, x, y);
-    processSync(mapper);
-
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
-
-    // Move into the display area.  Should generate a pointer down.
-    x = 50;
-    y = 75;
-    processMove(mapper, x, y);
-    processSync(mapper);
-
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime);
-    ASSERT_EQ(DEVICE_ID, motionArgs.deviceId);
-    ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source);
-    ASSERT_EQ(uint32_t(0), motionArgs.policyFlags);
-    ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action);
-    ASSERT_EQ(0, motionArgs.flags);
-    ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState);
-    ASSERT_EQ(0, motionArgs.buttonState);
-    ASSERT_EQ(0, motionArgs.edgeFlags);
-    ASSERT_EQ(size_t(1), motionArgs.pointerCount);
-    ASSERT_EQ(0, motionArgs.pointerProperties[0].id);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            toDisplayX(x), toDisplayY(y), 1, 0, 0, 0, 0, 0, 0, 0));
-    ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON);
-    ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON);
-    ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime);
-
-    // Release.  Should generate a pointer up.
-    processUp(mapper);
-    processSync(mapper);
-
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime);
-    ASSERT_EQ(DEVICE_ID, motionArgs.deviceId);
-    ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source);
-    ASSERT_EQ(uint32_t(0), motionArgs.policyFlags);
-    ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action);
-    ASSERT_EQ(0, motionArgs.flags);
-    ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState);
-    ASSERT_EQ(0, motionArgs.buttonState);
-    ASSERT_EQ(0, motionArgs.edgeFlags);
-    ASSERT_EQ(size_t(1), motionArgs.pointerCount);
-    ASSERT_EQ(0, motionArgs.pointerProperties[0].id);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            toDisplayX(x), toDisplayY(y), 1, 0, 0, 0, 0, 0, 0, 0));
-    ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON);
-    ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON);
-    ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime);
-
-    // Should not have sent any more keys or motions.
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasNotCalled());
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
-}
-
-TEST_F(SingleTouchInputMapperTest, Process_NormalSingleTouchGesture) {
-    SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
-    addConfigurationProperty("touch.deviceType", "touchScreen");
-    prepareDisplay(DISPLAY_ORIENTATION_0);
-    prepareButtons();
-    prepareAxes(POSITION);
-    prepareVirtualKeys();
-    addMapperAndConfigure(mapper);
-
-    mFakeContext->setGlobalMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON);
-
-    NotifyMotionArgs motionArgs;
-
-    // Down.
-    int32_t x = 100;
-    int32_t y = 125;
-    processDown(mapper, x, y);
-    processSync(mapper);
-
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime);
-    ASSERT_EQ(DEVICE_ID, motionArgs.deviceId);
-    ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source);
-    ASSERT_EQ(uint32_t(0), motionArgs.policyFlags);
-    ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action);
-    ASSERT_EQ(0, motionArgs.flags);
-    ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState);
-    ASSERT_EQ(0, motionArgs.buttonState);
-    ASSERT_EQ(0, motionArgs.edgeFlags);
-    ASSERT_EQ(size_t(1), motionArgs.pointerCount);
-    ASSERT_EQ(0, motionArgs.pointerProperties[0].id);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            toDisplayX(x), toDisplayY(y), 1, 0, 0, 0, 0, 0, 0, 0));
-    ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON);
-    ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON);
-    ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime);
-
-    // Move.
-    x += 50;
-    y += 75;
-    processMove(mapper, x, y);
-    processSync(mapper);
-
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime);
-    ASSERT_EQ(DEVICE_ID, motionArgs.deviceId);
-    ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source);
-    ASSERT_EQ(uint32_t(0), motionArgs.policyFlags);
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
-    ASSERT_EQ(0, motionArgs.flags);
-    ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState);
-    ASSERT_EQ(0, motionArgs.buttonState);
-    ASSERT_EQ(0, motionArgs.edgeFlags);
-    ASSERT_EQ(size_t(1), motionArgs.pointerCount);
-    ASSERT_EQ(0, motionArgs.pointerProperties[0].id);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            toDisplayX(x), toDisplayY(y), 1, 0, 0, 0, 0, 0, 0, 0));
-    ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON);
-    ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON);
-    ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime);
-
-    // Up.
-    processUp(mapper);
-    processSync(mapper);
-
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime);
-    ASSERT_EQ(DEVICE_ID, motionArgs.deviceId);
-    ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source);
-    ASSERT_EQ(uint32_t(0), motionArgs.policyFlags);
-    ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action);
-    ASSERT_EQ(0, motionArgs.flags);
-    ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState);
-    ASSERT_EQ(0, motionArgs.buttonState);
-    ASSERT_EQ(0, motionArgs.edgeFlags);
-    ASSERT_EQ(size_t(1), motionArgs.pointerCount);
-    ASSERT_EQ(0, motionArgs.pointerProperties[0].id);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            toDisplayX(x), toDisplayY(y), 1, 0, 0, 0, 0, 0, 0, 0));
-    ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON);
-    ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON);
-    ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime);
-
-    // Should not have sent any more keys or motions.
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasNotCalled());
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
-}
-
-TEST_F(SingleTouchInputMapperTest, Process_WhenNotOrientationAware_DoesNotRotateMotions) {
-    SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
-    addConfigurationProperty("touch.deviceType", "touchScreen");
-    prepareButtons();
-    prepareAxes(POSITION);
-    addConfigurationProperty("touch.orientationAware", "0");
-    addMapperAndConfigure(mapper);
-
-    NotifyMotionArgs args;
-
-    // Rotation 90.
-    prepareDisplay(DISPLAY_ORIENTATION_90);
-    processDown(mapper, toRawX(50), toRawY(75));
-    processSync(mapper);
-
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
-    ASSERT_NEAR(50, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X), 1);
-    ASSERT_NEAR(75, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y), 1);
-
-    processUp(mapper);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled());
-}
-
-TEST_F(SingleTouchInputMapperTest, Process_WhenOrientationAware_RotatesMotions) {
-    SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
-    addConfigurationProperty("touch.deviceType", "touchScreen");
-    prepareButtons();
-    prepareAxes(POSITION);
-    addMapperAndConfigure(mapper);
-
-    NotifyMotionArgs args;
-
-    // Rotation 0.
-    prepareDisplay(DISPLAY_ORIENTATION_0);
-    processDown(mapper, toRawX(50), toRawY(75));
-    processSync(mapper);
-
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
-    ASSERT_NEAR(50, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X), 1);
-    ASSERT_NEAR(75, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y), 1);
-
-    processUp(mapper);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled());
-
-    // Rotation 90.
-    prepareDisplay(DISPLAY_ORIENTATION_90);
-    processDown(mapper, RAW_X_MAX - toRawX(75) + RAW_X_MIN, toRawY(50));
-    processSync(mapper);
-
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
-    ASSERT_NEAR(50, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X), 1);
-    ASSERT_NEAR(75, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y), 1);
-
-    processUp(mapper);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled());
-
-    // Rotation 180.
-    prepareDisplay(DISPLAY_ORIENTATION_180);
-    processDown(mapper, RAW_X_MAX - toRawX(50) + RAW_X_MIN, RAW_Y_MAX - toRawY(75) + RAW_Y_MIN);
-    processSync(mapper);
-
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
-    ASSERT_NEAR(50, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X), 1);
-    ASSERT_NEAR(75, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y), 1);
-
-    processUp(mapper);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled());
-
-    // Rotation 270.
-    prepareDisplay(DISPLAY_ORIENTATION_270);
-    processDown(mapper, toRawX(75), RAW_Y_MAX - toRawY(50) + RAW_Y_MIN);
-    processSync(mapper);
-
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
-    ASSERT_NEAR(50, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X), 1);
-    ASSERT_NEAR(75, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y), 1);
-
-    processUp(mapper);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled());
-}
-
-TEST_F(SingleTouchInputMapperTest, Process_AllAxes_DefaultCalibration) {
-    SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
-    addConfigurationProperty("touch.deviceType", "touchScreen");
-    prepareDisplay(DISPLAY_ORIENTATION_0);
-    prepareButtons();
-    prepareAxes(POSITION | PRESSURE | TOOL | DISTANCE | TILT);
-    addMapperAndConfigure(mapper);
-
-    // These calculations are based on the input device calibration documentation.
-    int32_t rawX = 100;
-    int32_t rawY = 200;
-    int32_t rawPressure = 10;
-    int32_t rawToolMajor = 12;
-    int32_t rawDistance = 2;
-    int32_t rawTiltX = 30;
-    int32_t rawTiltY = 110;
-
-    float x = toDisplayX(rawX);
-    float y = toDisplayY(rawY);
-    float pressure = float(rawPressure) / RAW_PRESSURE_MAX;
-    float size = float(rawToolMajor) / RAW_TOOL_MAX;
-    float tool = float(rawToolMajor) * GEOMETRIC_SCALE;
-    float distance = float(rawDistance);
-
-    float tiltCenter = (RAW_TILT_MAX + RAW_TILT_MIN) * 0.5f;
-    float tiltScale = M_PI / 180;
-    float tiltXAngle = (rawTiltX - tiltCenter) * tiltScale;
-    float tiltYAngle = (rawTiltY - tiltCenter) * tiltScale;
-    float orientation = atan2f(-sinf(tiltXAngle), sinf(tiltYAngle));
-    float tilt = acosf(cosf(tiltXAngle) * cosf(tiltYAngle));
-
-    processDown(mapper, rawX, rawY);
-    processPressure(mapper, rawPressure);
-    processToolMajor(mapper, rawToolMajor);
-    processDistance(mapper, rawDistance);
-    processTilt(mapper, rawTiltX, rawTiltY);
-    processSync(mapper);
-
-    NotifyMotionArgs args;
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0],
-            x, y, pressure, size, tool, tool, tool, tool, orientation, distance));
-    ASSERT_EQ(tilt, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_TILT));
-}
-
-TEST_F(SingleTouchInputMapperTest, Process_ShouldHandleAllButtons) {
-    SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
-    addConfigurationProperty("touch.deviceType", "touchScreen");
-    prepareDisplay(DISPLAY_ORIENTATION_0);
-    prepareButtons();
-    prepareAxes(POSITION);
-    addMapperAndConfigure(mapper);
-
-    NotifyMotionArgs motionArgs;
-    NotifyKeyArgs keyArgs;
-
-    processDown(mapper, 100, 200);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action);
-    ASSERT_EQ(0, motionArgs.buttonState);
-
-    // press BTN_LEFT, release BTN_LEFT
-    processKey(mapper, BTN_LEFT, 1);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
-    ASSERT_EQ(AMOTION_EVENT_BUTTON_PRIMARY, motionArgs.buttonState);
-
-    processKey(mapper, BTN_LEFT, 0);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(0, motionArgs.buttonState);
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
-
-    // press BTN_RIGHT + BTN_MIDDLE, release BTN_RIGHT, release BTN_MIDDLE
-    processKey(mapper, BTN_RIGHT, 1);
-    processKey(mapper, BTN_MIDDLE, 1);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
-    ASSERT_EQ(AMOTION_EVENT_BUTTON_SECONDARY | AMOTION_EVENT_BUTTON_TERTIARY,
-            motionArgs.buttonState);
-
-    processKey(mapper, BTN_RIGHT, 0);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_BUTTON_TERTIARY, motionArgs.buttonState);
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
-
-    processKey(mapper, BTN_MIDDLE, 0);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(0, motionArgs.buttonState);
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
-
-    // press BTN_BACK, release BTN_BACK
-    processKey(mapper, BTN_BACK, 1);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs));
-    ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, keyArgs.action);
-    ASSERT_EQ(AKEYCODE_BACK, keyArgs.keyCode);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_BUTTON_BACK, motionArgs.buttonState);
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
-
-    processKey(mapper, BTN_BACK, 0);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(0, motionArgs.buttonState);
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs));
-    ASSERT_EQ(AKEY_EVENT_ACTION_UP, keyArgs.action);
-    ASSERT_EQ(AKEYCODE_BACK, keyArgs.keyCode);
-
-    // press BTN_SIDE, release BTN_SIDE
-    processKey(mapper, BTN_SIDE, 1);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs));
-    ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, keyArgs.action);
-    ASSERT_EQ(AKEYCODE_BACK, keyArgs.keyCode);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_BUTTON_BACK, motionArgs.buttonState);
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
-
-    processKey(mapper, BTN_SIDE, 0);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(0, motionArgs.buttonState);
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs));
-    ASSERT_EQ(AKEY_EVENT_ACTION_UP, keyArgs.action);
-    ASSERT_EQ(AKEYCODE_BACK, keyArgs.keyCode);
-
-    // press BTN_FORWARD, release BTN_FORWARD
-    processKey(mapper, BTN_FORWARD, 1);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs));
-    ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, keyArgs.action);
-    ASSERT_EQ(AKEYCODE_FORWARD, keyArgs.keyCode);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_BUTTON_FORWARD, motionArgs.buttonState);
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
-
-    processKey(mapper, BTN_FORWARD, 0);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(0, motionArgs.buttonState);
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs));
-    ASSERT_EQ(AKEY_EVENT_ACTION_UP, keyArgs.action);
-    ASSERT_EQ(AKEYCODE_FORWARD, keyArgs.keyCode);
-
-    // press BTN_EXTRA, release BTN_EXTRA
-    processKey(mapper, BTN_EXTRA, 1);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs));
-    ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, keyArgs.action);
-    ASSERT_EQ(AKEYCODE_FORWARD, keyArgs.keyCode);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_BUTTON_FORWARD, motionArgs.buttonState);
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
-
-    processKey(mapper, BTN_EXTRA, 0);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(0, motionArgs.buttonState);
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs));
-    ASSERT_EQ(AKEY_EVENT_ACTION_UP, keyArgs.action);
-    ASSERT_EQ(AKEYCODE_FORWARD, keyArgs.keyCode);
-
-    // press BTN_STYLUS, release BTN_STYLUS
-    processKey(mapper, BTN_STYLUS, 1);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
-    ASSERT_EQ(AMOTION_EVENT_BUTTON_SECONDARY, motionArgs.buttonState);
-
-    processKey(mapper, BTN_STYLUS, 0);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(0, motionArgs.buttonState);
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
-
-    // press BTN_STYLUS2, release BTN_STYLUS2
-    processKey(mapper, BTN_STYLUS2, 1);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
-    ASSERT_EQ(AMOTION_EVENT_BUTTON_TERTIARY, motionArgs.buttonState);
-
-    processKey(mapper, BTN_STYLUS2, 0);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(0, motionArgs.buttonState);
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
-
-    // release touch
-    processUp(mapper);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action);
-    ASSERT_EQ(0, motionArgs.buttonState);
-}
-
-TEST_F(SingleTouchInputMapperTest, Process_ShouldHandleAllToolTypes) {
-    SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
-    addConfigurationProperty("touch.deviceType", "touchScreen");
-    prepareDisplay(DISPLAY_ORIENTATION_0);
-    prepareButtons();
-    prepareAxes(POSITION);
-    addMapperAndConfigure(mapper);
-
-    NotifyMotionArgs motionArgs;
-
-    // default tool type is finger
-    processDown(mapper, 100, 200);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
-
-    // eraser
-    processKey(mapper, BTN_TOOL_RUBBER, 1);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_ERASER, motionArgs.pointerProperties[0].toolType);
-
-    // stylus
-    processKey(mapper, BTN_TOOL_RUBBER, 0);
-    processKey(mapper, BTN_TOOL_PEN, 1);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_STYLUS, motionArgs.pointerProperties[0].toolType);
-
-    // brush
-    processKey(mapper, BTN_TOOL_PEN, 0);
-    processKey(mapper, BTN_TOOL_BRUSH, 1);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_STYLUS, motionArgs.pointerProperties[0].toolType);
-
-    // pencil
-    processKey(mapper, BTN_TOOL_BRUSH, 0);
-    processKey(mapper, BTN_TOOL_PENCIL, 1);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_STYLUS, motionArgs.pointerProperties[0].toolType);
-
-    // airbrush
-    processKey(mapper, BTN_TOOL_PENCIL, 0);
-    processKey(mapper, BTN_TOOL_AIRBRUSH, 1);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_STYLUS, motionArgs.pointerProperties[0].toolType);
-
-    // mouse
-    processKey(mapper, BTN_TOOL_AIRBRUSH, 0);
-    processKey(mapper, BTN_TOOL_MOUSE, 1);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_MOUSE, motionArgs.pointerProperties[0].toolType);
-
-    // lens
-    processKey(mapper, BTN_TOOL_MOUSE, 0);
-    processKey(mapper, BTN_TOOL_LENS, 1);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_MOUSE, motionArgs.pointerProperties[0].toolType);
-
-    // double-tap
-    processKey(mapper, BTN_TOOL_LENS, 0);
-    processKey(mapper, BTN_TOOL_DOUBLETAP, 1);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
-
-    // triple-tap
-    processKey(mapper, BTN_TOOL_DOUBLETAP, 0);
-    processKey(mapper, BTN_TOOL_TRIPLETAP, 1);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
-
-    // quad-tap
-    processKey(mapper, BTN_TOOL_TRIPLETAP, 0);
-    processKey(mapper, BTN_TOOL_QUADTAP, 1);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
-
-    // finger
-    processKey(mapper, BTN_TOOL_QUADTAP, 0);
-    processKey(mapper, BTN_TOOL_FINGER, 1);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
-
-    // stylus trumps finger
-    processKey(mapper, BTN_TOOL_PEN, 1);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_STYLUS, motionArgs.pointerProperties[0].toolType);
-
-    // eraser trumps stylus
-    processKey(mapper, BTN_TOOL_RUBBER, 1);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_ERASER, motionArgs.pointerProperties[0].toolType);
-
-    // mouse trumps eraser
-    processKey(mapper, BTN_TOOL_MOUSE, 1);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_MOUSE, motionArgs.pointerProperties[0].toolType);
-
-    // back to default tool type
-    processKey(mapper, BTN_TOOL_MOUSE, 0);
-    processKey(mapper, BTN_TOOL_RUBBER, 0);
-    processKey(mapper, BTN_TOOL_PEN, 0);
-    processKey(mapper, BTN_TOOL_FINGER, 0);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
-}
-
-TEST_F(SingleTouchInputMapperTest, Process_WhenBtnTouchPresent_HoversIfItsValueIsZero) {
-    SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
-    addConfigurationProperty("touch.deviceType", "touchScreen");
-    prepareDisplay(DISPLAY_ORIENTATION_0);
-    prepareButtons();
-    prepareAxes(POSITION);
-    mFakeEventHub->addKey(DEVICE_ID, BTN_TOOL_FINGER, 0, AKEYCODE_UNKNOWN, 0);
-    addMapperAndConfigure(mapper);
-
-    NotifyMotionArgs motionArgs;
-
-    // initially hovering because BTN_TOUCH not sent yet, pressure defaults to 0
-    processKey(mapper, BTN_TOOL_FINGER, 1);
-    processMove(mapper, 100, 200);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_ENTER, motionArgs.action);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            toDisplayX(100), toDisplayY(200), 0, 0, 0, 0, 0, 0, 0, 0));
-
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            toDisplayX(100), toDisplayY(200), 0, 0, 0, 0, 0, 0, 0, 0));
-
-    // move a little
-    processMove(mapper, 150, 250);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0));
-
-    // down when BTN_TOUCH is pressed, pressure defaults to 1
-    processKey(mapper, BTN_TOUCH, 1);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_EXIT, motionArgs.action);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0));
-
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            toDisplayX(150), toDisplayY(250), 1, 0, 0, 0, 0, 0, 0, 0));
-
-    // up when BTN_TOUCH is released, hover restored
-    processKey(mapper, BTN_TOUCH, 0);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            toDisplayX(150), toDisplayY(250), 1, 0, 0, 0, 0, 0, 0, 0));
-
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_ENTER, motionArgs.action);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0));
-
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0));
-
-    // exit hover when pointer goes away
-    processKey(mapper, BTN_TOOL_FINGER, 0);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_EXIT, motionArgs.action);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0));
-}
-
-TEST_F(SingleTouchInputMapperTest, Process_WhenAbsPressureIsPresent_HoversIfItsValueIsZero) {
-    SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
-    addConfigurationProperty("touch.deviceType", "touchScreen");
-    prepareDisplay(DISPLAY_ORIENTATION_0);
-    prepareButtons();
-    prepareAxes(POSITION | PRESSURE);
-    addMapperAndConfigure(mapper);
-
-    NotifyMotionArgs motionArgs;
-
-    // initially hovering because pressure is 0
-    processDown(mapper, 100, 200);
-    processPressure(mapper, 0);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_ENTER, motionArgs.action);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            toDisplayX(100), toDisplayY(200), 0, 0, 0, 0, 0, 0, 0, 0));
-
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            toDisplayX(100), toDisplayY(200), 0, 0, 0, 0, 0, 0, 0, 0));
-
-    // move a little
-    processMove(mapper, 150, 250);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0));
-
-    // down when pressure is non-zero
-    processPressure(mapper, RAW_PRESSURE_MAX);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_EXIT, motionArgs.action);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0));
-
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            toDisplayX(150), toDisplayY(250), 1, 0, 0, 0, 0, 0, 0, 0));
-
-    // up when pressure becomes 0, hover restored
-    processPressure(mapper, 0);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            toDisplayX(150), toDisplayY(250), 1, 0, 0, 0, 0, 0, 0, 0));
-
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_ENTER, motionArgs.action);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0));
-
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0));
-
-    // exit hover when pointer goes away
-    processUp(mapper);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_EXIT, motionArgs.action);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0));
-}
-
-
-// --- MultiTouchInputMapperTest ---
-
-class MultiTouchInputMapperTest : public TouchInputMapperTest {
-protected:
-    void prepareAxes(int axes);
-
-    void processPosition(MultiTouchInputMapper* mapper, int32_t x, int32_t y);
-    void processTouchMajor(MultiTouchInputMapper* mapper, int32_t touchMajor);
-    void processTouchMinor(MultiTouchInputMapper* mapper, int32_t touchMinor);
-    void processToolMajor(MultiTouchInputMapper* mapper, int32_t toolMajor);
-    void processToolMinor(MultiTouchInputMapper* mapper, int32_t toolMinor);
-    void processOrientation(MultiTouchInputMapper* mapper, int32_t orientation);
-    void processPressure(MultiTouchInputMapper* mapper, int32_t pressure);
-    void processDistance(MultiTouchInputMapper* mapper, int32_t distance);
-    void processId(MultiTouchInputMapper* mapper, int32_t id);
-    void processSlot(MultiTouchInputMapper* mapper, int32_t slot);
-    void processToolType(MultiTouchInputMapper* mapper, int32_t toolType);
-    void processKey(MultiTouchInputMapper* mapper, int32_t code, int32_t value);
-    void processMTSync(MultiTouchInputMapper* mapper);
-    void processSync(MultiTouchInputMapper* mapper);
-};
-
-void MultiTouchInputMapperTest::prepareAxes(int axes) {
-    if (axes & POSITION) {
-        mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_POSITION_X,
-                RAW_X_MIN, RAW_X_MAX, 0, 0);
-        mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_POSITION_Y,
-                RAW_Y_MIN, RAW_Y_MAX, 0, 0);
-    }
-    if (axes & TOUCH) {
-        mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_TOUCH_MAJOR,
-                RAW_TOUCH_MIN, RAW_TOUCH_MAX, 0, 0);
-        if (axes & MINOR) {
-            mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_TOUCH_MINOR,
-                    RAW_TOUCH_MIN, RAW_TOUCH_MAX, 0, 0);
-        }
-    }
-    if (axes & TOOL) {
-        mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_WIDTH_MAJOR,
-                RAW_TOOL_MIN, RAW_TOOL_MAX, 0, 0);
-        if (axes & MINOR) {
-            mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_WIDTH_MINOR,
-                    RAW_TOOL_MAX, RAW_TOOL_MAX, 0, 0);
-        }
-    }
-    if (axes & ORIENTATION) {
-        mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_ORIENTATION,
-                RAW_ORIENTATION_MIN, RAW_ORIENTATION_MAX, 0, 0);
-    }
-    if (axes & PRESSURE) {
-        mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_PRESSURE,
-                RAW_PRESSURE_MIN, RAW_PRESSURE_MAX, 0, 0);
-    }
-    if (axes & DISTANCE) {
-        mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_DISTANCE,
-                RAW_DISTANCE_MIN, RAW_DISTANCE_MAX, 0, 0);
-    }
-    if (axes & ID) {
-        mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_TRACKING_ID,
-                RAW_ID_MIN, RAW_ID_MAX, 0, 0);
-    }
-    if (axes & SLOT) {
-        mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_SLOT,
-                RAW_SLOT_MIN, RAW_SLOT_MAX, 0, 0);
-        mFakeEventHub->setAbsoluteAxisValue(DEVICE_ID, ABS_MT_SLOT, 0);
-    }
-    if (axes & TOOL_TYPE) {
-        mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_TOOL_TYPE,
-                0, MT_TOOL_MAX, 0, 0);
-    }
-}
-
-void MultiTouchInputMapperTest::processPosition(
-        MultiTouchInputMapper* mapper, int32_t x, int32_t y) {
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_POSITION_X, x);
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_POSITION_Y, y);
-}
-
-void MultiTouchInputMapperTest::processTouchMajor(
-        MultiTouchInputMapper* mapper, int32_t touchMajor) {
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_TOUCH_MAJOR, touchMajor);
-}
-
-void MultiTouchInputMapperTest::processTouchMinor(
-        MultiTouchInputMapper* mapper, int32_t touchMinor) {
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_TOUCH_MINOR, touchMinor);
-}
-
-void MultiTouchInputMapperTest::processToolMajor(
-        MultiTouchInputMapper* mapper, int32_t toolMajor) {
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_WIDTH_MAJOR, toolMajor);
-}
-
-void MultiTouchInputMapperTest::processToolMinor(
-        MultiTouchInputMapper* mapper, int32_t toolMinor) {
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_WIDTH_MINOR, toolMinor);
-}
-
-void MultiTouchInputMapperTest::processOrientation(
-        MultiTouchInputMapper* mapper, int32_t orientation) {
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_ORIENTATION, orientation);
-}
-
-void MultiTouchInputMapperTest::processPressure(
-        MultiTouchInputMapper* mapper, int32_t pressure) {
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_PRESSURE, pressure);
-}
-
-void MultiTouchInputMapperTest::processDistance(
-        MultiTouchInputMapper* mapper, int32_t distance) {
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_DISTANCE, distance);
-}
-
-void MultiTouchInputMapperTest::processId(
-        MultiTouchInputMapper* mapper, int32_t id) {
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_TRACKING_ID, id);
-}
-
-void MultiTouchInputMapperTest::processSlot(
-        MultiTouchInputMapper* mapper, int32_t slot) {
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_SLOT, slot);
-}
-
-void MultiTouchInputMapperTest::processToolType(
-        MultiTouchInputMapper* mapper, int32_t toolType) {
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_TOOL_TYPE, toolType);
-}
-
-void MultiTouchInputMapperTest::processKey(
-        MultiTouchInputMapper* mapper, int32_t code, int32_t value) {
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, code, value);
-}
-
-void MultiTouchInputMapperTest::processMTSync(MultiTouchInputMapper* mapper) {
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_MT_REPORT, 0);
-}
-
-void MultiTouchInputMapperTest::processSync(MultiTouchInputMapper* mapper) {
-    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0);
-}
-
-
-TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithoutTrackingIds) {
-    MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
-    addConfigurationProperty("touch.deviceType", "touchScreen");
-    prepareDisplay(DISPLAY_ORIENTATION_0);
-    prepareAxes(POSITION);
-    prepareVirtualKeys();
-    addMapperAndConfigure(mapper);
-
-    mFakeContext->setGlobalMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON);
-
-    NotifyMotionArgs motionArgs;
-
-    // Two fingers down at once.
-    int32_t x1 = 100, y1 = 125, x2 = 300, y2 = 500;
-    processPosition(mapper, x1, y1);
-    processMTSync(mapper);
-    processPosition(mapper, x2, y2);
-    processMTSync(mapper);
-    processSync(mapper);
-
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime);
-    ASSERT_EQ(DEVICE_ID, motionArgs.deviceId);
-    ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source);
-    ASSERT_EQ(uint32_t(0), motionArgs.policyFlags);
-    ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action);
-    ASSERT_EQ(0, motionArgs.flags);
-    ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState);
-    ASSERT_EQ(0, motionArgs.buttonState);
-    ASSERT_EQ(0, motionArgs.edgeFlags);
-    ASSERT_EQ(size_t(1), motionArgs.pointerCount);
-    ASSERT_EQ(0, motionArgs.pointerProperties[0].id);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0, 0));
-    ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON);
-    ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON);
-    ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime);
-
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime);
-    ASSERT_EQ(DEVICE_ID, motionArgs.deviceId);
-    ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source);
-    ASSERT_EQ(uint32_t(0), motionArgs.policyFlags);
-    ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
-            motionArgs.action);
-    ASSERT_EQ(0, motionArgs.flags);
-    ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState);
-    ASSERT_EQ(0, motionArgs.buttonState);
-    ASSERT_EQ(0, motionArgs.edgeFlags);
-    ASSERT_EQ(size_t(2), motionArgs.pointerCount);
-    ASSERT_EQ(0, motionArgs.pointerProperties[0].id);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
-    ASSERT_EQ(1, motionArgs.pointerProperties[1].id);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0, 0));
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1],
-            toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0));
-    ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON);
-    ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON);
-    ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime);
-
-    // Move.
-    x1 += 10; y1 += 15; x2 += 5; y2 -= 10;
-    processPosition(mapper, x1, y1);
-    processMTSync(mapper);
-    processPosition(mapper, x2, y2);
-    processMTSync(mapper);
-    processSync(mapper);
-
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime);
-    ASSERT_EQ(DEVICE_ID, motionArgs.deviceId);
-    ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source);
-    ASSERT_EQ(uint32_t(0), motionArgs.policyFlags);
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
-    ASSERT_EQ(0, motionArgs.flags);
-    ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState);
-    ASSERT_EQ(0, motionArgs.buttonState);
-    ASSERT_EQ(0, motionArgs.edgeFlags);
-    ASSERT_EQ(size_t(2), motionArgs.pointerCount);
-    ASSERT_EQ(0, motionArgs.pointerProperties[0].id);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
-    ASSERT_EQ(1, motionArgs.pointerProperties[1].id);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0, 0));
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1],
-            toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0));
-    ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON);
-    ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON);
-    ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime);
-
-    // First finger up.
-    x2 += 15; y2 -= 20;
-    processPosition(mapper, x2, y2);
-    processMTSync(mapper);
-    processSync(mapper);
-
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime);
-    ASSERT_EQ(DEVICE_ID, motionArgs.deviceId);
-    ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source);
-    ASSERT_EQ(uint32_t(0), motionArgs.policyFlags);
-    ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
-            motionArgs.action);
-    ASSERT_EQ(0, motionArgs.flags);
-    ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState);
-    ASSERT_EQ(0, motionArgs.buttonState);
-    ASSERT_EQ(0, motionArgs.edgeFlags);
-    ASSERT_EQ(size_t(2), motionArgs.pointerCount);
-    ASSERT_EQ(0, motionArgs.pointerProperties[0].id);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
-    ASSERT_EQ(1, motionArgs.pointerProperties[1].id);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0, 0));
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1],
-            toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0));
-    ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON);
-    ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON);
-    ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime);
-
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime);
-    ASSERT_EQ(DEVICE_ID, motionArgs.deviceId);
-    ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source);
-    ASSERT_EQ(uint32_t(0), motionArgs.policyFlags);
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
-    ASSERT_EQ(0, motionArgs.flags);
-    ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState);
-    ASSERT_EQ(0, motionArgs.buttonState);
-    ASSERT_EQ(0, motionArgs.edgeFlags);
-    ASSERT_EQ(size_t(1), motionArgs.pointerCount);
-    ASSERT_EQ(1, motionArgs.pointerProperties[0].id);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0));
-    ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON);
-    ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON);
-    ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime);
-
-    // Move.
-    x2 += 20; y2 -= 25;
-    processPosition(mapper, x2, y2);
-    processMTSync(mapper);
-    processSync(mapper);
-
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime);
-    ASSERT_EQ(DEVICE_ID, motionArgs.deviceId);
-    ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source);
-    ASSERT_EQ(uint32_t(0), motionArgs.policyFlags);
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
-    ASSERT_EQ(0, motionArgs.flags);
-    ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState);
-    ASSERT_EQ(0, motionArgs.buttonState);
-    ASSERT_EQ(0, motionArgs.edgeFlags);
-    ASSERT_EQ(size_t(1), motionArgs.pointerCount);
-    ASSERT_EQ(1, motionArgs.pointerProperties[0].id);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0));
-    ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON);
-    ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON);
-    ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime);
-
-    // New finger down.
-    int32_t x3 = 700, y3 = 300;
-    processPosition(mapper, x2, y2);
-    processMTSync(mapper);
-    processPosition(mapper, x3, y3);
-    processMTSync(mapper);
-    processSync(mapper);
-
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime);
-    ASSERT_EQ(DEVICE_ID, motionArgs.deviceId);
-    ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source);
-    ASSERT_EQ(uint32_t(0), motionArgs.policyFlags);
-    ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
-            motionArgs.action);
-    ASSERT_EQ(0, motionArgs.flags);
-    ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState);
-    ASSERT_EQ(0, motionArgs.buttonState);
-    ASSERT_EQ(0, motionArgs.edgeFlags);
-    ASSERT_EQ(size_t(2), motionArgs.pointerCount);
-    ASSERT_EQ(0, motionArgs.pointerProperties[0].id);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
-    ASSERT_EQ(1, motionArgs.pointerProperties[1].id);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0, 0));
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1],
-            toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0));
-    ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON);
-    ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON);
-    ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime);
-
-    // Second finger up.
-    x3 += 30; y3 -= 20;
-    processPosition(mapper, x3, y3);
-    processMTSync(mapper);
-    processSync(mapper);
-
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime);
-    ASSERT_EQ(DEVICE_ID, motionArgs.deviceId);
-    ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source);
-    ASSERT_EQ(uint32_t(0), motionArgs.policyFlags);
-    ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
-            motionArgs.action);
-    ASSERT_EQ(0, motionArgs.flags);
-    ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState);
-    ASSERT_EQ(0, motionArgs.buttonState);
-    ASSERT_EQ(0, motionArgs.edgeFlags);
-    ASSERT_EQ(size_t(2), motionArgs.pointerCount);
-    ASSERT_EQ(0, motionArgs.pointerProperties[0].id);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
-    ASSERT_EQ(1, motionArgs.pointerProperties[1].id);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0, 0));
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1],
-            toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0));
-    ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON);
-    ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON);
-    ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime);
-
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime);
-    ASSERT_EQ(DEVICE_ID, motionArgs.deviceId);
-    ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source);
-    ASSERT_EQ(uint32_t(0), motionArgs.policyFlags);
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
-    ASSERT_EQ(0, motionArgs.flags);
-    ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState);
-    ASSERT_EQ(0, motionArgs.buttonState);
-    ASSERT_EQ(0, motionArgs.edgeFlags);
-    ASSERT_EQ(size_t(1), motionArgs.pointerCount);
-    ASSERT_EQ(0, motionArgs.pointerProperties[0].id);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0, 0));
-    ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON);
-    ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON);
-    ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime);
-
-    // Last finger up.
-    processMTSync(mapper);
-    processSync(mapper);
-
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime);
-    ASSERT_EQ(DEVICE_ID, motionArgs.deviceId);
-    ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source);
-    ASSERT_EQ(uint32_t(0), motionArgs.policyFlags);
-    ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action);
-    ASSERT_EQ(0, motionArgs.flags);
-    ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState);
-    ASSERT_EQ(0, motionArgs.buttonState);
-    ASSERT_EQ(0, motionArgs.edgeFlags);
-    ASSERT_EQ(size_t(1), motionArgs.pointerCount);
-    ASSERT_EQ(0, motionArgs.pointerProperties[0].id);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0, 0));
-    ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON);
-    ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON);
-    ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime);
-
-    // Should not have sent any more keys or motions.
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasNotCalled());
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
-}
-
-TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithTrackingIds) {
-    MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
-    addConfigurationProperty("touch.deviceType", "touchScreen");
-    prepareDisplay(DISPLAY_ORIENTATION_0);
-    prepareAxes(POSITION | ID);
-    prepareVirtualKeys();
-    addMapperAndConfigure(mapper);
-
-    mFakeContext->setGlobalMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON);
-
-    NotifyMotionArgs motionArgs;
-
-    // Two fingers down at once.
-    int32_t x1 = 100, y1 = 125, x2 = 300, y2 = 500;
-    processPosition(mapper, x1, y1);
-    processId(mapper, 1);
-    processMTSync(mapper);
-    processPosition(mapper, x2, y2);
-    processId(mapper, 2);
-    processMTSync(mapper);
-    processSync(mapper);
-
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action);
-    ASSERT_EQ(size_t(1), motionArgs.pointerCount);
-    ASSERT_EQ(0, motionArgs.pointerProperties[0].id);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0, 0));
-
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
-            motionArgs.action);
-    ASSERT_EQ(size_t(2), motionArgs.pointerCount);
-    ASSERT_EQ(0, motionArgs.pointerProperties[0].id);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
-    ASSERT_EQ(1, motionArgs.pointerProperties[1].id);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0, 0));
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1],
-            toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0));
-
-    // Move.
-    x1 += 10; y1 += 15; x2 += 5; y2 -= 10;
-    processPosition(mapper, x1, y1);
-    processId(mapper, 1);
-    processMTSync(mapper);
-    processPosition(mapper, x2, y2);
-    processId(mapper, 2);
-    processMTSync(mapper);
-    processSync(mapper);
-
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
-    ASSERT_EQ(size_t(2), motionArgs.pointerCount);
-    ASSERT_EQ(0, motionArgs.pointerProperties[0].id);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
-    ASSERT_EQ(1, motionArgs.pointerProperties[1].id);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0, 0));
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1],
-            toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0));
-
-    // First finger up.
-    x2 += 15; y2 -= 20;
-    processPosition(mapper, x2, y2);
-    processId(mapper, 2);
-    processMTSync(mapper);
-    processSync(mapper);
-
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
-            motionArgs.action);
-    ASSERT_EQ(size_t(2), motionArgs.pointerCount);
-    ASSERT_EQ(0, motionArgs.pointerProperties[0].id);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
-    ASSERT_EQ(1, motionArgs.pointerProperties[1].id);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0, 0));
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1],
-            toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0));
-
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
-    ASSERT_EQ(size_t(1), motionArgs.pointerCount);
-    ASSERT_EQ(1, motionArgs.pointerProperties[0].id);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0));
-
-    // Move.
-    x2 += 20; y2 -= 25;
-    processPosition(mapper, x2, y2);
-    processId(mapper, 2);
-    processMTSync(mapper);
-    processSync(mapper);
-
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
-    ASSERT_EQ(size_t(1), motionArgs.pointerCount);
-    ASSERT_EQ(1, motionArgs.pointerProperties[0].id);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0));
-
-    // New finger down.
-    int32_t x3 = 700, y3 = 300;
-    processPosition(mapper, x2, y2);
-    processId(mapper, 2);
-    processMTSync(mapper);
-    processPosition(mapper, x3, y3);
-    processId(mapper, 3);
-    processMTSync(mapper);
-    processSync(mapper);
-
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
-            motionArgs.action);
-    ASSERT_EQ(size_t(2), motionArgs.pointerCount);
-    ASSERT_EQ(0, motionArgs.pointerProperties[0].id);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
-    ASSERT_EQ(1, motionArgs.pointerProperties[1].id);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0, 0));
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1],
-            toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0));
-
-    // Second finger up.
-    x3 += 30; y3 -= 20;
-    processPosition(mapper, x3, y3);
-    processId(mapper, 3);
-    processMTSync(mapper);
-    processSync(mapper);
-
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
-            motionArgs.action);
-    ASSERT_EQ(size_t(2), motionArgs.pointerCount);
-    ASSERT_EQ(0, motionArgs.pointerProperties[0].id);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
-    ASSERT_EQ(1, motionArgs.pointerProperties[1].id);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0, 0));
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1],
-            toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0));
-
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
-    ASSERT_EQ(size_t(1), motionArgs.pointerCount);
-    ASSERT_EQ(0, motionArgs.pointerProperties[0].id);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0, 0));
-
-    // Last finger up.
-    processMTSync(mapper);
-    processSync(mapper);
-
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action);
-    ASSERT_EQ(size_t(1), motionArgs.pointerCount);
-    ASSERT_EQ(0, motionArgs.pointerProperties[0].id);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0, 0));
-
-    // Should not have sent any more keys or motions.
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasNotCalled());
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
-}
-
-TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithSlots) {
-    MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
-    addConfigurationProperty("touch.deviceType", "touchScreen");
-    prepareDisplay(DISPLAY_ORIENTATION_0);
-    prepareAxes(POSITION | ID | SLOT);
-    prepareVirtualKeys();
-    addMapperAndConfigure(mapper);
-
-    mFakeContext->setGlobalMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON);
-
-    NotifyMotionArgs motionArgs;
-
-    // Two fingers down at once.
-    int32_t x1 = 100, y1 = 125, x2 = 300, y2 = 500;
-    processPosition(mapper, x1, y1);
-    processId(mapper, 1);
-    processSlot(mapper, 1);
-    processPosition(mapper, x2, y2);
-    processId(mapper, 2);
-    processSync(mapper);
-
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action);
-    ASSERT_EQ(size_t(1), motionArgs.pointerCount);
-    ASSERT_EQ(0, motionArgs.pointerProperties[0].id);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0, 0));
-
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
-            motionArgs.action);
-    ASSERT_EQ(size_t(2), motionArgs.pointerCount);
-    ASSERT_EQ(0, motionArgs.pointerProperties[0].id);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
-    ASSERT_EQ(1, motionArgs.pointerProperties[1].id);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0, 0));
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1],
-            toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0));
-
-    // Move.
-    x1 += 10; y1 += 15; x2 += 5; y2 -= 10;
-    processSlot(mapper, 0);
-    processPosition(mapper, x1, y1);
-    processSlot(mapper, 1);
-    processPosition(mapper, x2, y2);
-    processSync(mapper);
-
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
-    ASSERT_EQ(size_t(2), motionArgs.pointerCount);
-    ASSERT_EQ(0, motionArgs.pointerProperties[0].id);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
-    ASSERT_EQ(1, motionArgs.pointerProperties[1].id);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0, 0));
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1],
-            toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0));
-
-    // First finger up.
-    x2 += 15; y2 -= 20;
-    processSlot(mapper, 0);
-    processId(mapper, -1);
-    processSlot(mapper, 1);
-    processPosition(mapper, x2, y2);
-    processSync(mapper);
-
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
-            motionArgs.action);
-    ASSERT_EQ(size_t(2), motionArgs.pointerCount);
-    ASSERT_EQ(0, motionArgs.pointerProperties[0].id);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
-    ASSERT_EQ(1, motionArgs.pointerProperties[1].id);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0, 0));
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1],
-            toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0));
-
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
-    ASSERT_EQ(size_t(1), motionArgs.pointerCount);
-    ASSERT_EQ(1, motionArgs.pointerProperties[0].id);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0));
-
-    // Move.
-    x2 += 20; y2 -= 25;
-    processPosition(mapper, x2, y2);
-    processSync(mapper);
-
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
-    ASSERT_EQ(size_t(1), motionArgs.pointerCount);
-    ASSERT_EQ(1, motionArgs.pointerProperties[0].id);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0));
-
-    // New finger down.
-    int32_t x3 = 700, y3 = 300;
-    processPosition(mapper, x2, y2);
-    processSlot(mapper, 0);
-    processId(mapper, 3);
-    processPosition(mapper, x3, y3);
-    processSync(mapper);
-
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
-            motionArgs.action);
-    ASSERT_EQ(size_t(2), motionArgs.pointerCount);
-    ASSERT_EQ(0, motionArgs.pointerProperties[0].id);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
-    ASSERT_EQ(1, motionArgs.pointerProperties[1].id);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0, 0));
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1],
-            toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0));
-
-    // Second finger up.
-    x3 += 30; y3 -= 20;
-    processSlot(mapper, 1);
-    processId(mapper, -1);
-    processSlot(mapper, 0);
-    processPosition(mapper, x3, y3);
-    processSync(mapper);
-
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
-            motionArgs.action);
-    ASSERT_EQ(size_t(2), motionArgs.pointerCount);
-    ASSERT_EQ(0, motionArgs.pointerProperties[0].id);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
-    ASSERT_EQ(1, motionArgs.pointerProperties[1].id);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0, 0));
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1],
-            toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0));
-
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
-    ASSERT_EQ(size_t(1), motionArgs.pointerCount);
-    ASSERT_EQ(0, motionArgs.pointerProperties[0].id);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0, 0));
-
-    // Last finger up.
-    processId(mapper, -1);
-    processSync(mapper);
-
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action);
-    ASSERT_EQ(size_t(1), motionArgs.pointerCount);
-    ASSERT_EQ(0, motionArgs.pointerProperties[0].id);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0, 0));
-
-    // Should not have sent any more keys or motions.
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasNotCalled());
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
-}
-
-TEST_F(MultiTouchInputMapperTest, Process_AllAxes_WithDefaultCalibration) {
-    MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
-    addConfigurationProperty("touch.deviceType", "touchScreen");
-    prepareDisplay(DISPLAY_ORIENTATION_0);
-    prepareAxes(POSITION | TOUCH | TOOL | PRESSURE | ORIENTATION | ID | MINOR | DISTANCE);
-    addMapperAndConfigure(mapper);
-
-    // These calculations are based on the input device calibration documentation.
-    int32_t rawX = 100;
-    int32_t rawY = 200;
-    int32_t rawTouchMajor = 7;
-    int32_t rawTouchMinor = 6;
-    int32_t rawToolMajor = 9;
-    int32_t rawToolMinor = 8;
-    int32_t rawPressure = 11;
-    int32_t rawDistance = 0;
-    int32_t rawOrientation = 3;
-    int32_t id = 5;
-
-    float x = toDisplayX(rawX);
-    float y = toDisplayY(rawY);
-    float pressure = float(rawPressure) / RAW_PRESSURE_MAX;
-    float size = avg(rawTouchMajor, rawTouchMinor) / RAW_TOUCH_MAX;
-    float toolMajor = float(rawToolMajor) * GEOMETRIC_SCALE;
-    float toolMinor = float(rawToolMinor) * GEOMETRIC_SCALE;
-    float touchMajor = float(rawTouchMajor) * GEOMETRIC_SCALE;
-    float touchMinor = float(rawTouchMinor) * GEOMETRIC_SCALE;
-    float orientation = float(rawOrientation) / RAW_ORIENTATION_MAX * M_PI_2;
-    float distance = float(rawDistance);
-
-    processPosition(mapper, rawX, rawY);
-    processTouchMajor(mapper, rawTouchMajor);
-    processTouchMinor(mapper, rawTouchMinor);
-    processToolMajor(mapper, rawToolMajor);
-    processToolMinor(mapper, rawToolMinor);
-    processPressure(mapper, rawPressure);
-    processOrientation(mapper, rawOrientation);
-    processDistance(mapper, rawDistance);
-    processId(mapper, id);
-    processMTSync(mapper);
-    processSync(mapper);
-
-    NotifyMotionArgs args;
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
-    ASSERT_EQ(0, args.pointerProperties[0].id);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0],
-            x, y, pressure, size, touchMajor, touchMinor, toolMajor, toolMinor,
-            orientation, distance));
-}
-
-TEST_F(MultiTouchInputMapperTest, Process_TouchAndToolAxes_GeometricCalibration) {
-    MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
-    addConfigurationProperty("touch.deviceType", "touchScreen");
-    prepareDisplay(DISPLAY_ORIENTATION_0);
-    prepareAxes(POSITION | TOUCH | TOOL | MINOR);
-    addConfigurationProperty("touch.size.calibration", "geometric");
-    addMapperAndConfigure(mapper);
-
-    // These calculations are based on the input device calibration documentation.
-    int32_t rawX = 100;
-    int32_t rawY = 200;
-    int32_t rawTouchMajor = 140;
-    int32_t rawTouchMinor = 120;
-    int32_t rawToolMajor = 180;
-    int32_t rawToolMinor = 160;
-
-    float x = toDisplayX(rawX);
-    float y = toDisplayY(rawY);
-    float size = avg(rawTouchMajor, rawTouchMinor) / RAW_TOUCH_MAX;
-    float toolMajor = float(rawToolMajor) * GEOMETRIC_SCALE;
-    float toolMinor = float(rawToolMinor) * GEOMETRIC_SCALE;
-    float touchMajor = float(rawTouchMajor) * GEOMETRIC_SCALE;
-    float touchMinor = float(rawTouchMinor) * GEOMETRIC_SCALE;
-
-    processPosition(mapper, rawX, rawY);
-    processTouchMajor(mapper, rawTouchMajor);
-    processTouchMinor(mapper, rawTouchMinor);
-    processToolMajor(mapper, rawToolMajor);
-    processToolMinor(mapper, rawToolMinor);
-    processMTSync(mapper);
-    processSync(mapper);
-
-    NotifyMotionArgs args;
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0],
-            x, y, 1.0f, size, touchMajor, touchMinor, toolMajor, toolMinor, 0, 0));
-}
-
-TEST_F(MultiTouchInputMapperTest, Process_TouchAndToolAxes_SummedLinearCalibration) {
-    MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
-    addConfigurationProperty("touch.deviceType", "touchScreen");
-    prepareDisplay(DISPLAY_ORIENTATION_0);
-    prepareAxes(POSITION | TOUCH | TOOL);
-    addConfigurationProperty("touch.size.calibration", "diameter");
-    addConfigurationProperty("touch.size.scale", "10");
-    addConfigurationProperty("touch.size.bias", "160");
-    addConfigurationProperty("touch.size.isSummed", "1");
-    addMapperAndConfigure(mapper);
-
-    // These calculations are based on the input device calibration documentation.
-    // Note: We only provide a single common touch/tool value because the device is assumed
-    //       not to emit separate values for each pointer (isSummed = 1).
-    int32_t rawX = 100;
-    int32_t rawY = 200;
-    int32_t rawX2 = 150;
-    int32_t rawY2 = 250;
-    int32_t rawTouchMajor = 5;
-    int32_t rawToolMajor = 8;
-
-    float x = toDisplayX(rawX);
-    float y = toDisplayY(rawY);
-    float x2 = toDisplayX(rawX2);
-    float y2 = toDisplayY(rawY2);
-    float size = float(rawTouchMajor) / 2 / RAW_TOUCH_MAX;
-    float touch = float(rawTouchMajor) / 2 * 10.0f + 160.0f;
-    float tool = float(rawToolMajor) / 2 * 10.0f + 160.0f;
-
-    processPosition(mapper, rawX, rawY);
-    processTouchMajor(mapper, rawTouchMajor);
-    processToolMajor(mapper, rawToolMajor);
-    processMTSync(mapper);
-    processPosition(mapper, rawX2, rawY2);
-    processTouchMajor(mapper, rawTouchMajor);
-    processToolMajor(mapper, rawToolMajor);
-    processMTSync(mapper);
-    processSync(mapper);
-
-    NotifyMotionArgs args;
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, args.action);
-
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
-            args.action);
-    ASSERT_EQ(size_t(2), args.pointerCount);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0],
-            x, y, 1.0f, size, touch, touch, tool, tool, 0, 0));
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[1],
-            x2, y2, 1.0f, size, touch, touch, tool, tool, 0, 0));
-}
-
-TEST_F(MultiTouchInputMapperTest, Process_TouchAndToolAxes_AreaCalibration) {
-    MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
-    addConfigurationProperty("touch.deviceType", "touchScreen");
-    prepareDisplay(DISPLAY_ORIENTATION_0);
-    prepareAxes(POSITION | TOUCH | TOOL);
-    addConfigurationProperty("touch.size.calibration", "area");
-    addConfigurationProperty("touch.size.scale", "43");
-    addConfigurationProperty("touch.size.bias", "3");
-    addMapperAndConfigure(mapper);
-
-    // These calculations are based on the input device calibration documentation.
-    int32_t rawX = 100;
-    int32_t rawY = 200;
-    int32_t rawTouchMajor = 5;
-    int32_t rawToolMajor = 8;
-
-    float x = toDisplayX(rawX);
-    float y = toDisplayY(rawY);
-    float size = float(rawTouchMajor) / RAW_TOUCH_MAX;
-    float touch = sqrtf(rawTouchMajor) * 43.0f + 3.0f;
-    float tool = sqrtf(rawToolMajor) * 43.0f + 3.0f;
-
-    processPosition(mapper, rawX, rawY);
-    processTouchMajor(mapper, rawTouchMajor);
-    processToolMajor(mapper, rawToolMajor);
-    processMTSync(mapper);
-    processSync(mapper);
-
-    NotifyMotionArgs args;
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0],
-            x, y, 1.0f, size, touch, touch, tool, tool, 0, 0));
-}
-
-TEST_F(MultiTouchInputMapperTest, Process_PressureAxis_AmplitudeCalibration) {
-    MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
-    addConfigurationProperty("touch.deviceType", "touchScreen");
-    prepareDisplay(DISPLAY_ORIENTATION_0);
-    prepareAxes(POSITION | PRESSURE);
-    addConfigurationProperty("touch.pressure.calibration", "amplitude");
-    addConfigurationProperty("touch.pressure.scale", "0.01");
-    addMapperAndConfigure(mapper);
-
-    // These calculations are based on the input device calibration documentation.
-    int32_t rawX = 100;
-    int32_t rawY = 200;
-    int32_t rawPressure = 60;
-
-    float x = toDisplayX(rawX);
-    float y = toDisplayY(rawY);
-    float pressure = float(rawPressure) * 0.01f;
-
-    processPosition(mapper, rawX, rawY);
-    processPressure(mapper, rawPressure);
-    processMTSync(mapper);
-    processSync(mapper);
-
-    NotifyMotionArgs args;
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0],
-            x, y, pressure, 0, 0, 0, 0, 0, 0, 0));
-}
-
-TEST_F(MultiTouchInputMapperTest, Process_ShouldHandleAllButtons) {
-    MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
-    addConfigurationProperty("touch.deviceType", "touchScreen");
-    prepareDisplay(DISPLAY_ORIENTATION_0);
-    prepareAxes(POSITION | ID | SLOT);
-    addMapperAndConfigure(mapper);
-
-    NotifyMotionArgs motionArgs;
-    NotifyKeyArgs keyArgs;
-
-    processId(mapper, 1);
-    processPosition(mapper, 100, 200);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action);
-    ASSERT_EQ(0, motionArgs.buttonState);
-
-    // press BTN_LEFT, release BTN_LEFT
-    processKey(mapper, BTN_LEFT, 1);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
-    ASSERT_EQ(AMOTION_EVENT_BUTTON_PRIMARY, motionArgs.buttonState);
-
-    processKey(mapper, BTN_LEFT, 0);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(0, motionArgs.buttonState);
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
-
-    // press BTN_RIGHT + BTN_MIDDLE, release BTN_RIGHT, release BTN_MIDDLE
-    processKey(mapper, BTN_RIGHT, 1);
-    processKey(mapper, BTN_MIDDLE, 1);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
-    ASSERT_EQ(AMOTION_EVENT_BUTTON_SECONDARY | AMOTION_EVENT_BUTTON_TERTIARY,
-            motionArgs.buttonState);
-
-    processKey(mapper, BTN_RIGHT, 0);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_BUTTON_TERTIARY, motionArgs.buttonState);
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
-
-    processKey(mapper, BTN_MIDDLE, 0);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(0, motionArgs.buttonState);
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
-
-    // press BTN_BACK, release BTN_BACK
-    processKey(mapper, BTN_BACK, 1);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs));
-    ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, keyArgs.action);
-    ASSERT_EQ(AKEYCODE_BACK, keyArgs.keyCode);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_BUTTON_BACK, motionArgs.buttonState);
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
-
-    processKey(mapper, BTN_BACK, 0);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(0, motionArgs.buttonState);
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs));
-    ASSERT_EQ(AKEY_EVENT_ACTION_UP, keyArgs.action);
-    ASSERT_EQ(AKEYCODE_BACK, keyArgs.keyCode);
-
-    // press BTN_SIDE, release BTN_SIDE
-    processKey(mapper, BTN_SIDE, 1);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs));
-    ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, keyArgs.action);
-    ASSERT_EQ(AKEYCODE_BACK, keyArgs.keyCode);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_BUTTON_BACK, motionArgs.buttonState);
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
-
-    processKey(mapper, BTN_SIDE, 0);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(0, motionArgs.buttonState);
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs));
-    ASSERT_EQ(AKEY_EVENT_ACTION_UP, keyArgs.action);
-    ASSERT_EQ(AKEYCODE_BACK, keyArgs.keyCode);
-
-    // press BTN_FORWARD, release BTN_FORWARD
-    processKey(mapper, BTN_FORWARD, 1);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs));
-    ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, keyArgs.action);
-    ASSERT_EQ(AKEYCODE_FORWARD, keyArgs.keyCode);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_BUTTON_FORWARD, motionArgs.buttonState);
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
-
-    processKey(mapper, BTN_FORWARD, 0);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(0, motionArgs.buttonState);
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs));
-    ASSERT_EQ(AKEY_EVENT_ACTION_UP, keyArgs.action);
-    ASSERT_EQ(AKEYCODE_FORWARD, keyArgs.keyCode);
-
-    // press BTN_EXTRA, release BTN_EXTRA
-    processKey(mapper, BTN_EXTRA, 1);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs));
-    ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, keyArgs.action);
-    ASSERT_EQ(AKEYCODE_FORWARD, keyArgs.keyCode);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_BUTTON_FORWARD, motionArgs.buttonState);
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
-
-    processKey(mapper, BTN_EXTRA, 0);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(0, motionArgs.buttonState);
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs));
-    ASSERT_EQ(AKEY_EVENT_ACTION_UP, keyArgs.action);
-    ASSERT_EQ(AKEYCODE_FORWARD, keyArgs.keyCode);
-
-    // press BTN_STYLUS, release BTN_STYLUS
-    processKey(mapper, BTN_STYLUS, 1);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
-    ASSERT_EQ(AMOTION_EVENT_BUTTON_SECONDARY, motionArgs.buttonState);
-
-    processKey(mapper, BTN_STYLUS, 0);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(0, motionArgs.buttonState);
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
-
-    // press BTN_STYLUS2, release BTN_STYLUS2
-    processKey(mapper, BTN_STYLUS2, 1);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
-    ASSERT_EQ(AMOTION_EVENT_BUTTON_TERTIARY, motionArgs.buttonState);
-
-    processKey(mapper, BTN_STYLUS2, 0);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(0, motionArgs.buttonState);
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
-
-    // release touch
-    processId(mapper, -1);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action);
-    ASSERT_EQ(0, motionArgs.buttonState);
-}
-
-TEST_F(MultiTouchInputMapperTest, Process_ShouldHandleAllToolTypes) {
-    MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
-    addConfigurationProperty("touch.deviceType", "touchScreen");
-    prepareDisplay(DISPLAY_ORIENTATION_0);
-    prepareAxes(POSITION | ID | SLOT | TOOL_TYPE);
-    addMapperAndConfigure(mapper);
-
-    NotifyMotionArgs motionArgs;
-
-    // default tool type is finger
-    processId(mapper, 1);
-    processPosition(mapper, 100, 200);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
-
-    // eraser
-    processKey(mapper, BTN_TOOL_RUBBER, 1);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_ERASER, motionArgs.pointerProperties[0].toolType);
-
-    // stylus
-    processKey(mapper, BTN_TOOL_RUBBER, 0);
-    processKey(mapper, BTN_TOOL_PEN, 1);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_STYLUS, motionArgs.pointerProperties[0].toolType);
-
-    // brush
-    processKey(mapper, BTN_TOOL_PEN, 0);
-    processKey(mapper, BTN_TOOL_BRUSH, 1);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_STYLUS, motionArgs.pointerProperties[0].toolType);
-
-    // pencil
-    processKey(mapper, BTN_TOOL_BRUSH, 0);
-    processKey(mapper, BTN_TOOL_PENCIL, 1);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_STYLUS, motionArgs.pointerProperties[0].toolType);
-
-    // airbrush
-    processKey(mapper, BTN_TOOL_PENCIL, 0);
-    processKey(mapper, BTN_TOOL_AIRBRUSH, 1);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_STYLUS, motionArgs.pointerProperties[0].toolType);
-
-    // mouse
-    processKey(mapper, BTN_TOOL_AIRBRUSH, 0);
-    processKey(mapper, BTN_TOOL_MOUSE, 1);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_MOUSE, motionArgs.pointerProperties[0].toolType);
-
-    // lens
-    processKey(mapper, BTN_TOOL_MOUSE, 0);
-    processKey(mapper, BTN_TOOL_LENS, 1);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_MOUSE, motionArgs.pointerProperties[0].toolType);
-
-    // double-tap
-    processKey(mapper, BTN_TOOL_LENS, 0);
-    processKey(mapper, BTN_TOOL_DOUBLETAP, 1);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
-
-    // triple-tap
-    processKey(mapper, BTN_TOOL_DOUBLETAP, 0);
-    processKey(mapper, BTN_TOOL_TRIPLETAP, 1);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
-
-    // quad-tap
-    processKey(mapper, BTN_TOOL_TRIPLETAP, 0);
-    processKey(mapper, BTN_TOOL_QUADTAP, 1);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
-
-    // finger
-    processKey(mapper, BTN_TOOL_QUADTAP, 0);
-    processKey(mapper, BTN_TOOL_FINGER, 1);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
-
-    // stylus trumps finger
-    processKey(mapper, BTN_TOOL_PEN, 1);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_STYLUS, motionArgs.pointerProperties[0].toolType);
-
-    // eraser trumps stylus
-    processKey(mapper, BTN_TOOL_RUBBER, 1);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_ERASER, motionArgs.pointerProperties[0].toolType);
-
-    // mouse trumps eraser
-    processKey(mapper, BTN_TOOL_MOUSE, 1);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_MOUSE, motionArgs.pointerProperties[0].toolType);
-
-    // MT tool type trumps BTN tool types: MT_TOOL_FINGER
-    processToolType(mapper, MT_TOOL_FINGER); // this is the first time we send MT_TOOL_TYPE
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
-
-    // MT tool type trumps BTN tool types: MT_TOOL_PEN
-    processToolType(mapper, MT_TOOL_PEN);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_STYLUS, motionArgs.pointerProperties[0].toolType);
-
-    // back to default tool type
-    processToolType(mapper, -1); // use a deliberately undefined tool type, for testing
-    processKey(mapper, BTN_TOOL_MOUSE, 0);
-    processKey(mapper, BTN_TOOL_RUBBER, 0);
-    processKey(mapper, BTN_TOOL_PEN, 0);
-    processKey(mapper, BTN_TOOL_FINGER, 0);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
-    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
-}
-
-TEST_F(MultiTouchInputMapperTest, Process_WhenBtnTouchPresent_HoversIfItsValueIsZero) {
-    MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
-    addConfigurationProperty("touch.deviceType", "touchScreen");
-    prepareDisplay(DISPLAY_ORIENTATION_0);
-    prepareAxes(POSITION | ID | SLOT);
-    mFakeEventHub->addKey(DEVICE_ID, BTN_TOUCH, 0, AKEYCODE_UNKNOWN, 0);
-    addMapperAndConfigure(mapper);
-
-    NotifyMotionArgs motionArgs;
-
-    // initially hovering because BTN_TOUCH not sent yet, pressure defaults to 0
-    processId(mapper, 1);
-    processPosition(mapper, 100, 200);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_ENTER, motionArgs.action);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            toDisplayX(100), toDisplayY(200), 0, 0, 0, 0, 0, 0, 0, 0));
-
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            toDisplayX(100), toDisplayY(200), 0, 0, 0, 0, 0, 0, 0, 0));
-
-    // move a little
-    processPosition(mapper, 150, 250);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0));
-
-    // down when BTN_TOUCH is pressed, pressure defaults to 1
-    processKey(mapper, BTN_TOUCH, 1);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_EXIT, motionArgs.action);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0));
-
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            toDisplayX(150), toDisplayY(250), 1, 0, 0, 0, 0, 0, 0, 0));
-
-    // up when BTN_TOUCH is released, hover restored
-    processKey(mapper, BTN_TOUCH, 0);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            toDisplayX(150), toDisplayY(250), 1, 0, 0, 0, 0, 0, 0, 0));
-
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_ENTER, motionArgs.action);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0));
-
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0));
-
-    // exit hover when pointer goes away
-    processId(mapper, -1);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_EXIT, motionArgs.action);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0));
-}
-
-TEST_F(MultiTouchInputMapperTest, Process_WhenAbsMTPressureIsPresent_HoversIfItsValueIsZero) {
-    MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
-    addConfigurationProperty("touch.deviceType", "touchScreen");
-    prepareDisplay(DISPLAY_ORIENTATION_0);
-    prepareAxes(POSITION | ID | SLOT | PRESSURE);
-    addMapperAndConfigure(mapper);
-
-    NotifyMotionArgs motionArgs;
-
-    // initially hovering because pressure is 0
-    processId(mapper, 1);
-    processPosition(mapper, 100, 200);
-    processPressure(mapper, 0);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_ENTER, motionArgs.action);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            toDisplayX(100), toDisplayY(200), 0, 0, 0, 0, 0, 0, 0, 0));
-
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            toDisplayX(100), toDisplayY(200), 0, 0, 0, 0, 0, 0, 0, 0));
-
-    // move a little
-    processPosition(mapper, 150, 250);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0));
-
-    // down when pressure becomes non-zero
-    processPressure(mapper, RAW_PRESSURE_MAX);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_EXIT, motionArgs.action);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0));
-
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            toDisplayX(150), toDisplayY(250), 1, 0, 0, 0, 0, 0, 0, 0));
-
-    // up when pressure becomes 0, hover restored
-    processPressure(mapper, 0);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            toDisplayX(150), toDisplayY(250), 1, 0, 0, 0, 0, 0, 0, 0));
-
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_ENTER, motionArgs.action);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0));
-
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0));
-
-    // exit hover when pointer goes away
-    processId(mapper, -1);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_EXIT, motionArgs.action);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
-            toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0));
-}
-
-
-} // namespace android
diff --git a/media/java/android/media/IMediaHTTPConnection.aidl b/media/java/android/media/IMediaHTTPConnection.aidl
new file mode 100644
index 0000000..300211b
--- /dev/null
+++ b/media/java/android/media/IMediaHTTPConnection.aidl
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import android.os.IBinder;
+
+/** MUST STAY IN SYNC WITH NATIVE CODE at libmedia/IMediaHTTPConnection.{cpp,h} */
+
+/** @hide */
+interface IMediaHTTPConnection
+{
+    IBinder connect(in String uri, in String headers);
+    void disconnect();
+
+    int readAt(long offset, int size);
+    long getSize();
+    String getMIMEType();
+}
+
diff --git a/media/java/android/media/IMediaHTTPService.aidl b/media/java/android/media/IMediaHTTPService.aidl
new file mode 100644
index 0000000..8aaf6b3
--- /dev/null
+++ b/media/java/android/media/IMediaHTTPService.aidl
@@ -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 android.media;
+
+import android.media.IMediaHTTPConnection;
+
+/** MUST STAY IN SYNC WITH NATIVE CODE at libmedia/IMediaHTTPService.{cpp,h} */
+
+/** @hide */
+interface IMediaHTTPService
+{
+    IMediaHTTPConnection makeHTTPConnection();
+}
diff --git a/media/java/android/media/MediaExtractor.java b/media/java/android/media/MediaExtractor.java
index c3e5035..f2753ee 100644
--- a/media/java/android/media/MediaExtractor.java
+++ b/media/java/android/media/MediaExtractor.java
@@ -21,7 +21,9 @@
 import android.content.res.AssetFileDescriptor;
 import android.media.MediaCodec;
 import android.media.MediaFormat;
+import android.media.MediaHTTPService;
 import android.net.Uri;
+import android.os.IBinder;
 
 import java.io.FileDescriptor;
 import java.io.IOException;
@@ -137,11 +139,19 @@
                 ++i;
             }
         }
-        setDataSource(path, keys, values);
+
+        nativeSetDataSource(
+                MediaHTTPService.createHttpServiceBinderIfNecessary(path),
+                path,
+                keys,
+                values);
     }
 
-    private native final void setDataSource(
-            String path, String[] keys, String[] values) throws IOException;
+    private native final void nativeSetDataSource(
+            IBinder httpServiceBinder,
+            String path,
+            String[] keys,
+            String[] values) throws IOException;
 
     /**
      * Sets the data source (file-path or http URL) to use.
@@ -156,7 +166,11 @@
      * and then use the file descriptor form {@link #setDataSource(FileDescriptor)}.
      */
     public final void setDataSource(String path) throws IOException {
-        setDataSource(path, null, null);
+        nativeSetDataSource(
+                MediaHTTPService.createHttpServiceBinderIfNecessary(path),
+                path,
+                null,
+                null);
     }
 
     /**
diff --git a/media/java/android/media/MediaHTTPConnection.java b/media/java/android/media/MediaHTTPConnection.java
new file mode 100644
index 0000000..2732fbc
--- /dev/null
+++ b/media/java/android/media/MediaHTTPConnection.java
@@ -0,0 +1,263 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import android.net.Uri;
+import android.os.IBinder;
+import android.os.StrictMode;
+import android.util.Log;
+
+import java.io.BufferedInputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.net.CookieHandler;
+import java.net.CookieManager;
+import java.net.URL;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.util.HashMap;
+import java.util.Map;
+
+/** @hide */
+public class MediaHTTPConnection extends IMediaHTTPConnection.Stub {
+    private static final String TAG = "MediaHTTPConnection";
+    private static final boolean VERBOSE = false;
+
+    private long mCurrentOffset = -1;
+    private URL mURL = null;
+    private Map<String, String> mHeaders = null;
+    private HttpURLConnection mConnection = null;
+    private long mTotalSize = -1;
+    private InputStream mInputStream = null;
+
+    public MediaHTTPConnection() {
+        if (CookieHandler.getDefault() == null) {
+            CookieHandler.setDefault(new CookieManager());
+        }
+
+        native_setup();
+    }
+
+    public IBinder connect(String uri, String headers) {
+        if (VERBOSE) {
+            Log.d(TAG, "connect: uri=" + uri + ", headers=" + headers);
+        }
+
+        try {
+            disconnect();
+            mURL = new URL(uri);
+            mHeaders = convertHeaderStringToMap(headers);
+        } catch (MalformedURLException e) {
+            return null;
+        }
+
+        return native_getIMemory();
+    }
+
+    private Map<String, String> convertHeaderStringToMap(String headers) {
+        HashMap<String, String> map = new HashMap<String, String>();
+
+        String[] pairs = headers.split("\r\n");
+        for (String pair : pairs) {
+            int colonPos = pair.indexOf(":");
+            if (colonPos >= 0) {
+                String key = pair.substring(0, colonPos);
+                String val = pair.substring(colonPos + 1);
+
+                map.put(key, val);
+            }
+        }
+
+        return map;
+    }
+
+    public void disconnect() {
+        teardownConnection();
+        mHeaders = null;
+        mURL = null;
+    }
+
+    private void teardownConnection() {
+        if (mConnection != null) {
+            mInputStream = null;
+
+            mConnection.disconnect();
+            mConnection = null;
+
+            mCurrentOffset = -1;
+        }
+    }
+
+    private void seekTo(long offset) throws IOException {
+        teardownConnection();
+
+        try {
+            mConnection = (HttpURLConnection)mURL.openConnection();
+
+            if (mHeaders != null) {
+                for (Map.Entry<String, String> entry : mHeaders.entrySet()) {
+                    mConnection.setRequestProperty(
+                            entry.getKey(), entry.getValue());
+                }
+            }
+
+            if (offset > 0) {
+                mConnection.setRequestProperty(
+                        "Range", "bytes=" + offset + "-");
+            }
+
+            if (mConnection.getResponseCode() == HttpURLConnection.HTTP_PARTIAL) {
+                // Partial content, we cannot just use getContentLength
+                // because what we want is not just the length of the range
+                // returned but the size of the full content if available.
+
+                String contentRange =
+                    mConnection.getHeaderField("Content-Range");
+
+                mTotalSize = -1;
+                if (contentRange != null) {
+                    // format is "bytes xxx-yyy/zzz
+                    // where "zzz" is the total number of bytes of the
+                    // content or '*' if unknown.
+
+                    int lastSlashPos = contentRange.lastIndexOf('/');
+                    if (lastSlashPos >= 0) {
+                        String total =
+                            contentRange.substring(lastSlashPos + 1);
+
+                        try {
+                            mTotalSize = Long.parseLong(total);
+                        } catch (NumberFormatException e) {
+                        }
+                    }
+                }
+            } else if (mConnection.getResponseCode()
+                    != HttpURLConnection.HTTP_OK) {
+                throw new IOException();
+            } else {
+                mTotalSize = mConnection.getContentLength();
+            }
+
+            if (offset > 0
+                    && mConnection.getResponseCode()
+                            != HttpURLConnection.HTTP_PARTIAL) {
+                // Some servers simply ignore "Range" requests and serve
+                // data from the start of the content.
+                throw new IOException();
+            }
+
+            mInputStream =
+                new BufferedInputStream(mConnection.getInputStream());
+
+            mCurrentOffset = offset;
+        } catch (IOException e) {
+            mTotalSize = -1;
+            mInputStream = null;
+            mConnection = null;
+            mCurrentOffset = -1;
+
+            throw e;
+        }
+    }
+
+    public int readAt(long offset, int size) {
+        return native_readAt(offset, size);
+    }
+
+    private int readAt(long offset, byte[] data, int size) {
+        StrictMode.ThreadPolicy policy =
+            new StrictMode.ThreadPolicy.Builder().permitAll().build();
+
+        StrictMode.setThreadPolicy(policy);
+
+        try {
+            if (offset != mCurrentOffset) {
+                seekTo(offset);
+            }
+
+            int n = mInputStream.read(data, 0, size);
+
+            if (n == -1) {
+                // InputStream signals EOS using a -1 result, our semantics
+                // are to return a 0-length read.
+                n = 0;
+            }
+
+            mCurrentOffset += n;
+
+            if (VERBOSE) {
+                Log.d(TAG, "readAt " + offset + " / " + size + " => " + n);
+            }
+
+            return n;
+        } catch (IOException e) {
+            if (VERBOSE) {
+                Log.d(TAG, "readAt " + offset + " / " + size + " => -1");
+            }
+            return -1;
+        } catch (Exception e) {
+            if (VERBOSE) {
+                Log.d(TAG, "unknown exception " + e);
+                Log.d(TAG, "readAt " + offset + " / " + size + " => -1");
+            }
+            return -1;
+        }
+    }
+
+    public long getSize() {
+        if (mConnection == null) {
+            try {
+                seekTo(0);
+            } catch (IOException e) {
+                return -1;
+            }
+        }
+
+        return mTotalSize;
+    }
+
+    public String getMIMEType() {
+        if (mConnection == null) {
+            try {
+                seekTo(0);
+            } catch (IOException e) {
+                return "application/octet-stream";
+            }
+        }
+
+        return mConnection.getContentType();
+    }
+
+    @Override
+    protected void finalize() {
+        native_finalize();
+    }
+
+    private static native final void native_init();
+    private native final void native_setup();
+    private native final void native_finalize();
+
+    private native final IBinder native_getIMemory();
+    private native final int native_readAt(long offset, int size);
+
+    static {
+        System.loadLibrary("media_jni");
+        native_init();
+    }
+
+    private int mNativeContext;
+}
diff --git a/media/java/android/media/MediaHTTPService.java b/media/java/android/media/MediaHTTPService.java
new file mode 100644
index 0000000..3b4703d
--- /dev/null
+++ b/media/java/android/media/MediaHTTPService.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import android.os.Binder;
+import android.os.IBinder;
+import android.util.Log;
+
+/** @hide */
+public class MediaHTTPService extends IMediaHTTPService.Stub {
+    private static final String TAG = "MediaHTTPService";
+
+    public MediaHTTPService() {
+    }
+
+    public IMediaHTTPConnection makeHTTPConnection() {
+        return new MediaHTTPConnection();
+    }
+
+    /* package private */static IBinder createHttpServiceBinderIfNecessary(
+            String path) {
+        if (path.startsWith("http://")
+                || path.startsWith("https://")
+                || path.startsWith("widevine://")) {
+            return (new MediaHTTPService()).asBinder();
+        }
+
+        return null;
+    }
+}
diff --git a/media/java/android/media/MediaMetadataRetriever.java b/media/java/android/media/MediaMetadataRetriever.java
index db27d09..9a69c06 100644
--- a/media/java/android/media/MediaMetadataRetriever.java
+++ b/media/java/android/media/MediaMetadataRetriever.java
@@ -21,6 +21,7 @@
 import android.content.res.AssetFileDescriptor;
 import android.graphics.Bitmap;
 import android.net.Uri;
+import android.os.IBinder;
 
 import java.io.FileDescriptor;
 import java.io.FileInputStream;
@@ -100,11 +101,16 @@
             values[i] = entry.getValue();
             ++i;
         }
-        _setDataSource(uri, keys, values);
+
+        _setDataSource(
+                MediaHTTPService.createHttpServiceBinderIfNecessary(uri),
+                uri,
+                keys,
+                values);
     }
 
     private native void _setDataSource(
-        String uri, String[] keys, String[] values)
+        IBinder httpServiceBinder, String uri, String[] keys, String[] values)
         throws IllegalArgumentException;
 
     /**
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 3cceb03..2806bff 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -22,11 +22,10 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.res.AssetFileDescriptor;
-import android.net.Proxy;
-import android.net.ProxyProperties;
 import android.net.Uri;
 import android.os.Handler;
 import android.os.HandlerThread;
+import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
 import android.os.Parcel;
@@ -881,8 +880,6 @@
      */
     public void setDataSource(Context context, Uri uri, Map<String, String> headers)
         throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {
-        disableProxyListener();
-
         String scheme = uri.getScheme();
         if(scheme == null || scheme.equals("file")) {
             setDataSource(uri.getPath());
@@ -916,11 +913,6 @@
         Log.d(TAG, "Couldn't open file on client side, trying server side");
 
         setDataSource(uri.toString(), headers);
-
-        if (scheme.equalsIgnoreCase("http")
-                || scheme.equalsIgnoreCase("https")) {
-            setupProxyListener(context);
-        }
     }
 
     /**
@@ -971,8 +963,6 @@
 
     private void setDataSource(String path, String[] keys, String[] values)
             throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {
-        disableProxyListener();
-
         final Uri uri = Uri.parse(path);
         if ("file".equals(uri.getScheme())) {
             path = uri.getPath();
@@ -989,8 +979,18 @@
         }
     }
 
-    private native void _setDataSource(
+    private void _setDataSource(
         String path, String[] keys, String[] values)
+        throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {
+        nativeSetDataSource(
+                MediaHTTPService.createHttpServiceBinderIfNecessary(path),
+                path,
+                keys,
+                values);
+    }
+
+    private native void nativeSetDataSource(
+        IBinder httpServiceBinder, String path, String[] keys, String[] values)
         throws IOException, IllegalArgumentException, SecurityException, IllegalStateException;
 
     /**
@@ -1018,7 +1018,6 @@
      */
     public void setDataSource(FileDescriptor fd, long offset, long length)
             throws IOException, IllegalArgumentException, IllegalStateException {
-        disableProxyListener();
         _setDataSource(fd, offset, length);
     }
 
@@ -1390,8 +1389,6 @@
         if (mEventHandler != null) {
             mEventHandler.removeCallbacksAndMessages(null);
         }
-
-        disableProxyListener();
     }
 
     private native void _reset();
@@ -2739,59 +2736,6 @@
                 mode == VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING);
     }
 
-    private Context mProxyContext = null;
-    private ProxyReceiver mProxyReceiver = null;
-
-    private void setupProxyListener(Context context) {
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(Proxy.PROXY_CHANGE_ACTION);
-        mProxyReceiver = new ProxyReceiver();
-        mProxyContext = context;
-
-        Intent currentProxy =
-            context.getApplicationContext().registerReceiver(mProxyReceiver, filter);
-
-        if (currentProxy != null) {
-            handleProxyBroadcast(currentProxy);
-        }
-    }
-
-    private void disableProxyListener() {
-        if (mProxyReceiver == null) {
-            return;
-        }
-
-        Context appContext = mProxyContext.getApplicationContext();
-        if (appContext != null) {
-            appContext.unregisterReceiver(mProxyReceiver);
-        }
-
-        mProxyReceiver = null;
-        mProxyContext = null;
-    }
-
-    private void handleProxyBroadcast(Intent intent) {
-        ProxyProperties props =
-            (ProxyProperties)intent.getExtra(Proxy.EXTRA_PROXY_INFO);
-
-        if (props == null || props.getHost() == null) {
-            updateProxyConfig(null);
-        } else {
-            updateProxyConfig(props);
-        }
-    }
-
-    private class ProxyReceiver extends BroadcastReceiver {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            if (intent.getAction().equals(Proxy.PROXY_CHANGE_ACTION)) {
-                handleProxyBroadcast(intent);
-            }
-        }
-    }
-
-    private native void updateProxyConfig(ProxyProperties props);
-
     /** @hide */
     static class TimeProvider implements MediaPlayer.OnSeekCompleteListener,
             MediaTimeProvider {
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index 53835e2..01485b8 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -55,6 +55,7 @@
 import java.io.IOException;
 import java.io.InputStreamReader;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.Locale;
@@ -1400,27 +1401,60 @@
         return false;
     }
 
-    public static boolean isNoMediaPath(String path) {
-        if (path == null) return false;
+    private static HashMap<String,String> mNoMediaPaths = new HashMap<String,String>();
+    private static HashMap<String,String> mMediaPaths = new HashMap<String,String>();
 
-        // return true if file or any parent directory has name starting with a dot
-        if (path.indexOf("/.") >= 0) return true;
-
-        // now check to see if any parent directories have a ".nomedia" file
-        // start from 1 so we don't bother checking in the root directory
-        int offset = 1;
-        while (offset >= 0) {
-            int slashIndex = path.indexOf('/', offset);
-            if (slashIndex > offset) {
-                slashIndex++; // move past slash
-                File file = new File(path.substring(0, slashIndex) + ".nomedia");
-                if (file.exists()) {
-                    // we have a .nomedia in one of the parent directories
-                    return true;
-                }
+    /* MediaProvider calls this when a .nomedia file is added or removed */
+    public static void clearMediaPathCache(boolean clearMediaPaths, boolean clearNoMediaPaths) {
+        synchronized (MediaScanner.class) {
+            if (clearMediaPaths) {
+                mMediaPaths.clear();
             }
-            offset = slashIndex;
+            if (clearNoMediaPaths) {
+                mNoMediaPaths.clear();
+            }
         }
+    }
+
+    public static boolean isNoMediaPath(String path) {
+        if (path == null) {
+            return false;
+        }
+        // return true if file or any parent directory has name starting with a dot
+        if (path.indexOf("/.") >= 0) {
+            return true;
+        }
+
+        int firstSlash = path.lastIndexOf('/');
+        if (firstSlash == 0) {
+            return false;
+        }
+        String parent = path.substring(0,  firstSlash);
+
+        synchronized (MediaScanner.class) {
+            if (mNoMediaPaths.containsKey(parent)) {
+                return true;
+            } else if (!mMediaPaths.containsKey(parent)) {
+                // check to see if any parent directories have a ".nomedia" file
+                // start from 1 so we don't bother checking in the root directory
+                int offset = 1;
+                while (offset >= 0) {
+                    int slashIndex = path.indexOf('/', offset);
+                    if (slashIndex > offset) {
+                        slashIndex++; // move past slash
+                        File file = new File(path.substring(0, slashIndex) + ".nomedia");
+                        if (file.exists()) {
+                            // we have a .nomedia in one of the parent directories
+                            mNoMediaPaths.put(parent, "");
+                            return true;
+                        }
+                    }
+                    offset = slashIndex;
+                }
+                mMediaPaths.put(parent, "");
+            }
+        }
+
         return isNoMediaFile(path);
     }
 
diff --git a/media/jni/Android.mk b/media/jni/Android.mk
index dea971e..51fccd4 100644
--- a/media/jni/Android.mk
+++ b/media/jni/Android.mk
@@ -8,6 +8,7 @@
     android_media_MediaCodecList.cpp \
     android_media_MediaDrm.cpp \
     android_media_MediaExtractor.cpp \
+    android_media_MediaHTTPConnection.cpp \
     android_media_MediaMuxer.cpp \
     android_media_MediaPlayer.cpp \
     android_media_MediaRecorder.cpp \
diff --git a/media/jni/android_media_MediaExtractor.cpp b/media/jni/android_media_MediaExtractor.cpp
index 705de88..d3a8b22 100644
--- a/media/jni/android_media_MediaExtractor.cpp
+++ b/media/jni/android_media_MediaExtractor.cpp
@@ -26,6 +26,7 @@
 #include "jni.h"
 #include "JNIHelp.h"
 
+#include <media/IMediaHTTPService.h>
 #include <media/hardware/CryptoAPI.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
@@ -35,6 +36,8 @@
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/NuMediaExtractor.h>
 
+#include "android_util_Binder.h"
+
 namespace android {
 
 struct fields_t {
@@ -135,8 +138,10 @@
 }
 
 status_t JMediaExtractor::setDataSource(
-        const char *path, const KeyedVector<String8, String8> *headers) {
-    return mImpl->setDataSource(path, headers);
+        const sp<IMediaHTTPService> &httpService,
+        const char *path,
+        const KeyedVector<String8, String8> *headers) {
+    return mImpl->setDataSource(httpService, path, headers);
 }
 
 status_t JMediaExtractor::setDataSource(int fd, off64_t offset, off64_t size) {
@@ -661,7 +666,10 @@
 
 static void android_media_MediaExtractor_setDataSource(
         JNIEnv *env, jobject thiz,
-        jstring pathObj, jobjectArray keysArray, jobjectArray valuesArray) {
+        jobject httpServiceBinderObj,
+        jstring pathObj,
+        jobjectArray keysArray,
+        jobjectArray valuesArray) {
     sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
 
     if (extractor == NULL) {
@@ -686,7 +694,13 @@
         return;
     }
 
-    status_t err = extractor->setDataSource(path, &headers);
+    sp<IMediaHTTPService> httpService;
+    if (httpServiceBinderObj != NULL) {
+        sp<IBinder> binder = ibinderForJavaObject(env, httpServiceBinderObj);
+        httpService = interface_cast<IMediaHTTPService>(binder);
+    }
+
+    status_t err = extractor->setDataSource(httpService, path, &headers);
 
     env->ReleaseStringUTFChars(pathObj, path);
     path = NULL;
@@ -839,8 +853,9 @@
     { "native_finalize", "()V",
       (void *)android_media_MediaExtractor_native_finalize },
 
-    { "setDataSource", "(Ljava/lang/String;[Ljava/lang/String;"
-                       "[Ljava/lang/String;)V",
+    { "nativeSetDataSource",
+        "(Landroid/os/IBinder;Ljava/lang/String;[Ljava/lang/String;"
+        "[Ljava/lang/String;)V",
       (void *)android_media_MediaExtractor_setDataSource },
 
     { "setDataSource", "(Ljava/io/FileDescriptor;JJ)V",
diff --git a/media/jni/android_media_MediaExtractor.h b/media/jni/android_media_MediaExtractor.h
index ccbad8c..e5a0c16e 100644
--- a/media/jni/android_media_MediaExtractor.h
+++ b/media/jni/android_media_MediaExtractor.h
@@ -29,6 +29,7 @@
 
 namespace android {
 
+struct IMediaHTTPService;
 struct MetaData;
 struct NuMediaExtractor;
 
@@ -36,6 +37,7 @@
     JMediaExtractor(JNIEnv *env, jobject thiz);
 
     status_t setDataSource(
+            const sp<IMediaHTTPService> &httpService,
             const char *path,
             const KeyedVector<String8, String8> *headers);
 
diff --git a/media/jni/android_media_MediaHTTPConnection.cpp b/media/jni/android_media_MediaHTTPConnection.cpp
new file mode 100644
index 0000000..c48af11
--- /dev/null
+++ b/media/jni/android_media_MediaHTTPConnection.cpp
@@ -0,0 +1,179 @@
+/*
+ * Copyright 2013, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "MediaHTTPConnection-JNI"
+#include <utils/Log.h>
+
+#include <binder/MemoryDealer.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <nativehelper/ScopedLocalRef.h>
+
+#include "android_media_MediaHTTPConnection.h"
+#include "android_util_Binder.h"
+
+#include "android_runtime/AndroidRuntime.h"
+#include "jni.h"
+#include "JNIHelp.h"
+
+namespace android {
+
+JMediaHTTPConnection::JMediaHTTPConnection(JNIEnv *env, jobject thiz)
+    : mClass(NULL),
+      mObject(NULL),
+      mByteArrayObj(NULL) {
+    jclass clazz = env->GetObjectClass(thiz);
+    CHECK(clazz != NULL);
+
+    mClass = (jclass)env->NewGlobalRef(clazz);
+    mObject = env->NewWeakGlobalRef(thiz);
+
+    mDealer = new MemoryDealer(kBufferSize, "MediaHTTPConnection");
+    mMemory = mDealer->allocate(kBufferSize);
+
+    ScopedLocalRef<jbyteArray> tmp(
+            env, env->NewByteArray(JMediaHTTPConnection::kBufferSize));
+
+    mByteArrayObj = (jbyteArray)env->NewGlobalRef(tmp.get());
+}
+
+JMediaHTTPConnection::~JMediaHTTPConnection() {
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+
+    env->DeleteGlobalRef(mByteArrayObj);
+    mByteArrayObj = NULL;
+    env->DeleteWeakGlobalRef(mObject);
+    mObject = NULL;
+    env->DeleteGlobalRef(mClass);
+    mClass = NULL;
+}
+
+sp<IMemory> JMediaHTTPConnection::getIMemory() {
+    return mMemory;
+}
+
+jbyteArray JMediaHTTPConnection::getByteArrayObj() {
+    return mByteArrayObj;
+}
+
+}  // namespace android
+
+using namespace android;
+
+struct fields_t {
+    jfieldID context;
+
+    jmethodID readAtMethodID;
+};
+
+static fields_t gFields;
+
+static sp<JMediaHTTPConnection> setObject(
+        JNIEnv *env, jobject thiz, const sp<JMediaHTTPConnection> &conn) {
+    sp<JMediaHTTPConnection> old =
+        (JMediaHTTPConnection *)env->GetIntField(thiz, gFields.context);
+
+    if (conn != NULL) {
+        conn->incStrong(thiz);
+    }
+    if (old != NULL) {
+        old->decStrong(thiz);
+    }
+    env->SetIntField(thiz, gFields.context, (int)conn.get());
+
+    return old;
+}
+
+static sp<JMediaHTTPConnection> getObject(JNIEnv *env, jobject thiz) {
+    return (JMediaHTTPConnection *)env->GetIntField(thiz, gFields.context);
+}
+
+static void android_media_MediaHTTPConnection_native_init(JNIEnv *env) {
+    ScopedLocalRef<jclass> clazz(
+            env, env->FindClass("android/media/MediaHTTPConnection"));
+    CHECK(clazz.get() != NULL);
+
+    gFields.context = env->GetFieldID(clazz.get(), "mNativeContext", "I");
+    CHECK(gFields.context != NULL);
+
+    gFields.readAtMethodID = env->GetMethodID(clazz.get(), "readAt", "(J[BI)I");
+}
+
+static void android_media_MediaHTTPConnection_native_setup(
+        JNIEnv *env, jobject thiz) {
+    sp<JMediaHTTPConnection> conn = new JMediaHTTPConnection(env, thiz);
+
+    setObject(env, thiz, conn);
+}
+
+static void android_media_MediaHTTPConnection_native_finalize(
+        JNIEnv *env, jobject thiz) {
+    setObject(env, thiz, NULL);
+}
+
+static jobject android_media_MediaHTTPConnection_native_getIMemory(
+        JNIEnv *env, jobject thiz) {
+    sp<JMediaHTTPConnection> conn = getObject(env, thiz);
+
+    return javaObjectForIBinder(env, conn->getIMemory()->asBinder());
+}
+
+static jint android_media_MediaHTTPConnection_native_readAt(
+        JNIEnv *env, jobject thiz, jlong offset, jint size) {
+    sp<JMediaHTTPConnection> conn = getObject(env, thiz);
+
+    if (size > JMediaHTTPConnection::kBufferSize) {
+        size = JMediaHTTPConnection::kBufferSize;
+    }
+
+    jbyteArray byteArrayObj = conn->getByteArrayObj();
+
+    jint n = env->CallIntMethod(
+            thiz, gFields.readAtMethodID, offset, byteArrayObj, size);
+
+    if (n > 0) {
+        env->GetByteArrayRegion(
+                byteArrayObj,
+                0,
+                n,
+                (jbyte *)conn->getIMemory()->pointer());
+    }
+
+    return n;
+}
+
+static JNINativeMethod gMethods[] = {
+    { "native_getIMemory", "()Landroid/os/IBinder;",
+      (void *)android_media_MediaHTTPConnection_native_getIMemory },
+
+    { "native_readAt", "(JI)I",
+      (void *)android_media_MediaHTTPConnection_native_readAt },
+
+    { "native_init", "()V",
+      (void *)android_media_MediaHTTPConnection_native_init },
+
+    { "native_setup", "()V",
+      (void *)android_media_MediaHTTPConnection_native_setup },
+
+    { "native_finalize", "()V",
+      (void *)android_media_MediaHTTPConnection_native_finalize },
+};
+
+int register_android_media_MediaHTTPConnection(JNIEnv *env) {
+    return AndroidRuntime::registerNativeMethods(env,
+                "android/media/MediaHTTPConnection", gMethods, NELEM(gMethods));
+}
+
diff --git a/media/jni/android_media_MediaHTTPConnection.h b/media/jni/android_media_MediaHTTPConnection.h
new file mode 100644
index 0000000..62ff678
--- /dev/null
+++ b/media/jni/android_media_MediaHTTPConnection.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2013, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _ANDROID_MEDIA_MEDIAHTTPCONNECTION_H_
+#define _ANDROID_MEDIA_MEDIAHTTPCONNECTION_H_
+
+#include "jni.h"
+
+#include <media/stagefright/foundation/ABase.h>
+#include <utils/RefBase.h>
+
+namespace android {
+
+struct IMemory;
+struct MemoryDealer;
+
+struct JMediaHTTPConnection : public RefBase {
+    enum {
+        kBufferSize = 32768,
+    };
+
+    JMediaHTTPConnection(JNIEnv *env, jobject thiz);
+
+    sp<IMemory> getIMemory();
+
+    jbyteArray getByteArrayObj();
+
+protected:
+    virtual ~JMediaHTTPConnection();
+
+private:
+    jclass mClass;
+    jweak mObject;
+    jbyteArray mByteArrayObj;
+
+    sp<MemoryDealer> mDealer;
+    sp<IMemory> mMemory;
+
+    DISALLOW_EVIL_CONSTRUCTORS(JMediaHTTPConnection);
+};
+
+}  // namespace android
+
+#endif  // _ANDROID_MEDIA_MEDIAHTTPCONNECTION_H_
diff --git a/media/jni/android_media_MediaMetadataRetriever.cpp b/media/jni/android_media_MediaMetadataRetriever.cpp
index a52b24d..f17209f 100644
--- a/media/jni/android_media_MediaMetadataRetriever.cpp
+++ b/media/jni/android_media_MediaMetadataRetriever.cpp
@@ -22,6 +22,7 @@
 #include <utils/Log.h>
 #include <utils/threads.h>
 #include <core/SkBitmap.h>
+#include <media/IMediaHTTPService.h>
 #include <media/mediametadataretriever.h>
 #include <private/media/VideoFrame.h>
 
@@ -29,6 +30,7 @@
 #include "JNIHelp.h"
 #include "android_runtime/AndroidRuntime.h"
 #include "android_media_Utils.h"
+#include "android_util_Binder.h"
 
 
 using namespace android;
@@ -80,7 +82,7 @@
 
 static void
 android_media_MediaMetadataRetriever_setDataSourceAndHeaders(
-        JNIEnv *env, jobject thiz, jstring path,
+        JNIEnv *env, jobject thiz, jobject httpServiceBinderObj, jstring path,
         jobjectArray keys, jobjectArray values) {
 
     ALOGV("setDataSource");
@@ -122,10 +124,19 @@
             env, keys, values, &headersVector)) {
         return;
     }
+
+    sp<IMediaHTTPService> httpService;
+    if (httpServiceBinderObj != NULL) {
+        sp<IBinder> binder = ibinderForJavaObject(env, httpServiceBinderObj);
+        httpService = interface_cast<IMediaHTTPService>(binder);
+    }
+
     process_media_retriever_call(
             env,
             retriever->setDataSource(
-                pathStr.string(), headersVector.size() > 0 ? &headersVector : NULL),
+                httpService,
+                pathStr.string(),
+                headersVector.size() > 0 ? &headersVector : NULL),
 
             "java/lang/RuntimeException",
             "setDataSource failed");
@@ -442,7 +453,7 @@
 static JNINativeMethod nativeMethods[] = {
         {
             "_setDataSource",
-            "(Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;)V",
+            "(Landroid/os/IBinder;Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;)V",
             (void *)android_media_MediaMetadataRetriever_setDataSourceAndHeaders
         },
 
diff --git a/media/jni/android_media_MediaMuxer.cpp b/media/jni/android_media_MediaMuxer.cpp
index 2c16a05..3fef446f 100644
--- a/media/jni/android_media_MediaMuxer.cpp
+++ b/media/jni/android_media_MediaMuxer.cpp
@@ -132,7 +132,7 @@
 }
 
 // Constructor counterpart.
-static jint android_media_MediaMuxer_native_setup(
+static jlong android_media_MediaMuxer_native_setup(
         JNIEnv *env, jclass clazz, jobject fileDescriptor,
         jint format) {
     int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
@@ -142,7 +142,7 @@
         static_cast<MediaMuxer::OutputFormat>(format);
     sp<MediaMuxer> muxer = new MediaMuxer(fd, fileFormat);
     muxer->incStrong(clazz);
-    return int(muxer.get());
+    return reinterpret_cast<jlong>(muxer.get());
 }
 
 static void android_media_MediaMuxer_setOrientationHint(
@@ -164,7 +164,7 @@
 }
 
 static void android_media_MediaMuxer_setLocation(
-        JNIEnv *env, jclass clazz, jint nativeObject, jint latitude, jint longitude) {
+        JNIEnv *env, jclass clazz, jlong nativeObject, jint latitude, jint longitude) {
     MediaMuxer* muxer = reinterpret_cast<MediaMuxer *>(nativeObject);
 
     status_t res = muxer->setLocation(latitude, longitude);
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index 9d0d5a6..dc3ae5b 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -20,6 +20,7 @@
 #include "utils/Log.h"
 
 #include <media/mediaplayer.h>
+#include <media/IMediaHTTPService.h>
 #include <media/MediaPlayerInterface.h>
 #include <stdio.h>
 #include <assert.h>
@@ -45,6 +46,7 @@
 #include <binder/IPCThreadState.h>
 #include <binder/IServiceManager.h>
 
+#include "android_util_Binder.h"
 // ----------------------------------------------------------------------------
 
 using namespace android;
@@ -183,7 +185,7 @@
 
 static void
 android_media_MediaPlayer_setDataSourceAndHeaders(
-        JNIEnv *env, jobject thiz, jstring path,
+        JNIEnv *env, jobject thiz, jobject httpServiceBinderObj, jstring path,
         jobjectArray keys, jobjectArray values) {
 
     sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
@@ -214,8 +216,15 @@
         return;
     }
 
+    sp<IMediaHTTPService> httpService;
+    if (httpServiceBinderObj != NULL) {
+        sp<IBinder> binder = ibinderForJavaObject(env, httpServiceBinderObj);
+        httpService = interface_cast<IMediaHTTPService>(binder);
+    }
+
     status_t opStatus =
         mp->setDataSource(
+                httpService,
                 pathStr,
                 headersVector.size() > 0? &headersVector : NULL);
 
@@ -726,7 +735,8 @@
 }
 
 static jint
-android_media_MediaPlayer_pullBatteryData(JNIEnv *env, jobject thiz, jobject java_reply)
+android_media_MediaPlayer_pullBatteryData(
+        JNIEnv *env, jobject /* thiz */, jobject java_reply)
 {
     sp<IBinder> binder = defaultServiceManager()->getService(String16("media.player"));
     sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder);
@@ -806,58 +816,13 @@
     ;
 }
 
-static void
-android_media_MediaPlayer_updateProxyConfig(
-        JNIEnv *env, jobject thiz, jobject proxyProps)
-{
-    ALOGV("updateProxyConfig");
-    sp<MediaPlayer> thisplayer = getMediaPlayer(env, thiz);
-    if (thisplayer == NULL) {
-        return;
-    }
-
-    if (proxyProps == NULL) {
-        thisplayer->updateProxyConfig(
-                NULL /* host */, 0 /* port */, NULL /* exclusionList */);
-    } else {
-        jstring hostObj = (jstring)env->CallObjectMethod(
-                proxyProps, fields.proxyConfigGetHost);
-
-        const char *host = env->GetStringUTFChars(hostObj, NULL);
-
-        int port = env->CallIntMethod(proxyProps, fields.proxyConfigGetPort);
-
-        jstring exclusionListObj = (jstring)env->CallObjectMethod(
-                proxyProps, fields.proxyConfigGetExclusionList);
-
-        if (host != NULL && exclusionListObj != NULL) {
-            const char *exclusionList = env->GetStringUTFChars(exclusionListObj, NULL);
-
-            if (exclusionList != NULL) {
-                thisplayer->updateProxyConfig(host, port, exclusionList);
-
-                env->ReleaseStringUTFChars(exclusionListObj, exclusionList);
-                exclusionList = NULL;
-            } else {
-                thisplayer->updateProxyConfig(host, port, "");
-            }
-        } else if (host != NULL) {
-            thisplayer->updateProxyConfig(host, port, "");
-        }
-
-        if (host != NULL) {
-            env->ReleaseStringUTFChars(hostObj, host);
-            host = NULL;
-        }
-    }
-}
-
 // ----------------------------------------------------------------------------
 
 static JNINativeMethod gMethods[] = {
     {
-        "_setDataSource",
-        "(Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;)V",
+        "nativeSetDataSource",
+        "(Landroid/os/IBinder;Ljava/lang/String;[Ljava/lang/String;"
+        "[Ljava/lang/String;)V",
         (void *)android_media_MediaPlayer_setDataSourceAndHeaders
     },
 
@@ -893,7 +858,6 @@
     {"native_pullBatteryData", "(Landroid/os/Parcel;)I",        (void *)android_media_MediaPlayer_pullBatteryData},
     {"native_setRetransmitEndpoint", "(Ljava/lang/String;I)I",  (void *)android_media_MediaPlayer_setRetransmitEndpoint},
     {"setNextMediaPlayer",  "(Landroid/media/MediaPlayer;)V",   (void *)android_media_MediaPlayer_setNextMediaPlayer},
-    {"updateProxyConfig", "(Landroid/net/ProxyProperties;)V", (void *)android_media_MediaPlayer_updateProxyConfig},
 };
 
 static const char* const kClassPathName = "android/media/MediaPlayer";
@@ -911,6 +875,7 @@
 extern int register_android_media_MediaCodec(JNIEnv *env);
 extern int register_android_media_MediaExtractor(JNIEnv *env);
 extern int register_android_media_MediaCodecList(JNIEnv *env);
+extern int register_android_media_MediaHTTPConnection(JNIEnv *env);
 extern int register_android_media_MediaMetadataRetriever(JNIEnv *env);
 extern int register_android_media_MediaMuxer(JNIEnv *env);
 extern int register_android_media_MediaRecorder(JNIEnv *env);
@@ -922,7 +887,7 @@
 extern int register_android_mtp_MtpDevice(JNIEnv *env);
 extern int register_android_mtp_MtpServer(JNIEnv *env);
 
-jint JNI_OnLoad(JavaVM* vm, void* reserved)
+jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
 {
     JNIEnv* env = NULL;
     jint result = -1;
@@ -1018,6 +983,11 @@
         goto bail;
     }
 
+    if (register_android_media_MediaHTTPConnection(env) < 0) {
+        ALOGE("ERROR: MediaHTTPConnection native registration failed");
+        goto bail;
+    }
+
     /* success -- return valid version number */
     result = JNI_VERSION_1_4;
 
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java
index ee867ff..d01f4ec 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java
@@ -137,6 +137,8 @@
     public static final String INVALD_VIDEO_PATH =
             "/sdcard/media_api/filepathdoesnotexist" + "/filepathdoesnotexist/temp.3gp";
 
+    public static final String RECORDED_SURFACE_3GP = "/sdcard/surface.3gp";
+
     public static final long RECORDED_TIME = 5000;
     public static final long VALID_VIDEO_DURATION = 2000;
 
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaProfileReader.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaProfileReader.java
index abe8b8c..54c8add 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaProfileReader.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaProfileReader.java
@@ -88,7 +88,8 @@
         if (audioEncoder != MediaRecorder.AudioEncoder.AMR_NB &&
             audioEncoder != MediaRecorder.AudioEncoder.AMR_WB &&
             audioEncoder != MediaRecorder.AudioEncoder.AAC &&
-            audioEncoder != MediaRecorder.AudioEncoder.HE_AAC) {
+            audioEncoder != MediaRecorder.AudioEncoder.HE_AAC &&
+            audioEncoder != MediaRecorder.AudioEncoder.AAC_ELD) {
             throw new IllegalArgumentException("Unsupported audio encodeer " + audioEncoder);
         }
         return audioEncoderMap.get(audioEncoder);
@@ -128,5 +129,6 @@
         audioEncoderMap.put(MediaRecorder.AudioEncoder.AMR_WB, "amrwb");
         audioEncoderMap.put(MediaRecorder.AudioEncoder.AAC, "aac");
         audioEncoderMap.put(MediaRecorder.AudioEncoder.HE_AAC, "heaac");
+        audioEncoderMap.put(MediaRecorder.AudioEncoder.AAC_ELD, "aaceld");
     }
 }
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/mediarecorder/MediaRecorderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/mediarecorder/MediaRecorderTest.java
index 8e6d5cb..599522b 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/mediarecorder/MediaRecorderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/mediarecorder/MediaRecorderTest.java
@@ -22,6 +22,10 @@
 import java.io.*;
 
 import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Typeface;
 import android.hardware.Camera;
 import android.media.MediaPlayer;
 import android.media.MediaRecorder;
@@ -30,6 +34,7 @@
 import android.media.EncoderCapabilities.AudioEncoderCap;
 import android.test.ActivityInstrumentationTestCase2;
 import android.util.Log;
+import android.view.Surface;
 import android.view.SurfaceHolder;
 import android.view.SurfaceView;
 import com.android.mediaframeworktest.MediaProfileReader;
@@ -41,14 +46,14 @@
 
 
 /**
- * Junit / Instrumentation test case for the media recorder api 
- */  
+ * Junit / Instrumentation test case for the media recorder api
+ */
 public class MediaRecorderTest extends ActivityInstrumentationTestCase2<MediaFrameworkTest> {
     private String TAG = "MediaRecorderTest";
     private int mOutputDuration =0;
     private int mOutputVideoWidth = 0;
     private int mOutputVideoHeight= 0 ;
-    
+
     private SurfaceHolder mSurfaceHolder = null;
     private MediaRecorder mRecorder;
 
@@ -58,10 +63,10 @@
 
     Context mContext;
     Camera mCamera;
-  
+
     public MediaRecorderTest() {
-        super("com.android.mediaframeworktest", MediaFrameworkTest.class);
-       
+        super(MediaFrameworkTest.class);
+
     }
 
     protected void setUp() throws Exception {
@@ -69,8 +74,8 @@
         mRecorder = new MediaRecorder();
         super.setUp();
     }
- 
-    private void recordVideo(int frameRate, int width, int height, 
+
+    private void recordVideo(int frameRate, int width, int height,
             int videoFormat, int outFormat, String outFile, boolean videoOnly) {
         Log.v(TAG,"startPreviewAndPrepareRecording");
         try {
@@ -80,7 +85,7 @@
             }
             mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
             mRecorder.setOutputFormat(outFormat);
-            Log.v(TAG, "output format " + outFormat);          
+            Log.v(TAG, "output format " + outFormat);
             mRecorder.setOutputFile(outFile);
             mRecorder.setVideoFrameRate(frameRate);
             mRecorder.setVideoSize(width, height);
@@ -105,7 +110,180 @@
             mRecorder.release();
         }
     }
-    
+
+    private boolean validateGetSurface(boolean useSurface) {
+        Log.v(TAG,"validateGetSurface, useSurface=" + useSurface);
+        MediaRecorder recorder = new MediaRecorder();
+        Surface surface;
+        boolean success = true;
+        try {
+            /* initialization */
+            if (!useSurface) {
+                mCamera = Camera.open(CAMERA_ID);
+                Camera.Parameters parameters = mCamera.getParameters();
+                parameters.setPreviewSize(352, 288);
+                parameters.set("orientation", "portrait");
+                mCamera.setParameters(parameters);
+                mCamera.unlock();
+                recorder.setCamera(mCamera);
+                mSurfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder();
+                recorder.setPreviewDisplay(mSurfaceHolder.getSurface());
+            }
+
+            recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
+            int videoSource = useSurface ?
+                    MediaRecorder.VideoSource.SURFACE :
+                    MediaRecorder.VideoSource.CAMERA;
+            recorder.setVideoSource(videoSource);
+            recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
+            recorder.setOutputFile(MediaNames.RECORDED_SURFACE_3GP);
+            recorder.setVideoFrameRate(30);
+            recorder.setVideoSize(352, 288);
+            recorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
+            recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
+
+            /* Test: getSurface() before prepare()
+             * should throw IllegalStateException
+             */
+            try {
+                surface = recorder.getSurface();
+                throw new Exception("getSurface failed to throw IllegalStateException");
+            } catch (IllegalStateException e) {
+                // OK
+            }
+
+            recorder.prepare();
+
+            /* Test: getSurface() after prepare()
+             * should succeed for surface source
+             * should fail for camera source
+             */
+            try {
+                surface = recorder.getSurface();
+                if (!useSurface) {
+                    throw new Exception("getSurface failed to throw IllegalStateException");
+                }
+            } catch (IllegalStateException e) {
+                if (useSurface) {
+                    throw new Exception("getSurface failed to throw IllegalStateException");
+                }
+            }
+
+            recorder.start();
+
+            /* Test: getSurface() after start()
+             * should succeed for surface source
+             * should fail for camera source
+             */
+            try {
+                surface = recorder.getSurface();
+                if (!useSurface) {
+                    throw new Exception("getSurface failed to throw IllegalStateException");
+                }
+            } catch (IllegalStateException e) {
+                if (useSurface) {
+                    throw new Exception("getSurface failed to throw IllegalStateException");
+                }
+            }
+
+            try {
+                recorder.stop();
+            } catch (Exception e) {
+                // stop() could fail if the recording is empty, as we didn't render anything.
+                // ignore any failure in stop, we just want it stopped.
+            }
+
+            /* Test: getSurface() after stop()
+             * should throw IllegalStateException
+             */
+            try {
+                surface = recorder.getSurface();
+                throw new Exception("getSurface failed to throw IllegalStateException");
+            } catch (IllegalStateException e) {
+                // OK
+            }
+        } catch (Exception e) {
+            // fail
+            success = false;
+        }
+
+        try {
+            if (mCamera != null) {
+                mCamera.lock();
+                mCamera.release();
+                mCamera = null;
+            }
+            recorder.release();
+        } catch (Exception e) {
+            success = false;
+        }
+
+        return success;
+    }
+
+    private boolean recordVideoFromSurface(int frameRate, int width, int height,
+            int videoFormat, int outFormat, String outFile, boolean videoOnly) {
+        Log.v(TAG,"recordVideoFromSurface");
+        MediaRecorder recorder = new MediaRecorder();
+        try {
+            if (!videoOnly) {
+                recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
+            }
+            recorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
+            recorder.setOutputFormat(outFormat);
+            recorder.setOutputFile(outFile);
+            recorder.setVideoFrameRate(frameRate);
+            recorder.setVideoSize(width, height);
+            recorder.setVideoEncoder(videoFormat);
+            if (!videoOnly) {
+                recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
+            }
+            recorder.prepare();
+            Surface surface = recorder.getSurface();
+
+            Paint paint = new Paint();
+            paint.setTextSize(16);
+            paint.setColor(Color.RED);
+            int i;
+
+            /* Test: draw 10 frames at 30fps before start
+             * these should be dropped and not causing malformed stream.
+             */
+            for(i = 0; i < 10; i++) {
+                Canvas canvas = surface.lockCanvas(null);
+                int background = (i * 255 / 99);
+                canvas.drawARGB(255, background, background, background);
+                String text = "Frame #" + i;
+                canvas.drawText(text, 100, 100, paint);
+                surface.unlockCanvasAndPost(canvas);
+                Thread.sleep(33);
+            }
+
+            Log.v(TAG, "start");
+            recorder.start();
+
+            /* Test: draw another 90 frames at 30fps after start */
+            for(i = 10; i < 100; i++) {
+                Canvas canvas = surface.lockCanvas(null);
+                int background = (i * 255 / 99);
+                canvas.drawARGB(255, background, background, background);
+                String text = "Frame #" + i;
+                canvas.drawText(text, 100, 100, paint);
+                surface.unlockCanvasAndPost(canvas);
+                Thread.sleep(33);
+            }
+
+            Log.v(TAG, "stop");
+            recorder.stop();
+            recorder.release();
+        } catch (Exception e) {
+            Log.v("record video failed ", e.toString());
+            recorder.release();
+            return false;
+        }
+        return true;
+    }
+
     private boolean recordVideoWithPara(VideoEncoderCap videoCap, AudioEncoderCap audioCap, boolean highQuality){
         boolean recordSuccess = false;
         int videoEncoder = videoCap.mCodec;
@@ -171,7 +349,7 @@
         return recordSuccess;
     }
 
-    private boolean invalidRecordSetting(int frameRate, int width, int height, 
+    private boolean invalidRecordSetting(int frameRate, int width, int height,
             int videoFormat, int outFormat, String outFile, boolean videoOnly) {
         try {
             if (!videoOnly) {
@@ -180,7 +358,7 @@
             }
             mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
             mRecorder.setOutputFormat(outFormat);
-            Log.v(TAG, "output format " + outFormat);          
+            Log.v(TAG, "output format " + outFormat);
             mRecorder.setOutputFile(outFile);
             mRecorder.setVideoFrameRate(frameRate);
             mRecorder.setVideoSize(width, height);
@@ -208,7 +386,7 @@
         }
         return false;
     }
-    
+
     private void getOutputVideoProperty(String outputFilePath) {
         MediaPlayer mediaPlayer = new MediaPlayer();
         try {
@@ -223,13 +401,13 @@
             Thread.sleep(1000);
             mOutputVideoHeight = mediaPlayer.getVideoHeight();
             mOutputVideoWidth = mediaPlayer.getVideoWidth();
-            mediaPlayer.release();    
+            mediaPlayer.release();
         } catch (Exception e) {
             Log.v(TAG, e.toString());
             mediaPlayer.release();
-        }       
+        }
     }
-    
+
     private boolean validateVideo(String filePath, int width, int height) {
         boolean validVideo = false;
         getOutputVideoProperty(filePath);
@@ -260,7 +438,7 @@
             int codec = MediaRecorder.VideoEncoder.H263;
             int frameRate = MediaProfileReader.getMaxFrameRateForCodec(codec);
             recordVideo(frameRate, 352, 288, codec,
-                    MediaRecorder.OutputFormat.THREE_GPP, 
+                    MediaRecorder.OutputFormat.THREE_GPP,
                     MediaNames.RECORDED_PORTRAIT_H263, true);
             mCamera.lock();
             mCamera.release();
@@ -271,15 +449,15 @@
         }
         assertTrue("PortraitH263", videoRecordedResult);
     }
-    
+
     @LargeTest
-    public void testInvalidVideoPath() throws Exception {       
+    public void testInvalidVideoPath() throws Exception {
         boolean isTestInvalidVideoPathSuccessful = false;
-        isTestInvalidVideoPathSuccessful = invalidRecordSetting(15, 176, 144, MediaRecorder.VideoEncoder.H263, 
-               MediaRecorder.OutputFormat.THREE_GPP, MediaNames.INVALD_VIDEO_PATH, false);      
+        isTestInvalidVideoPathSuccessful = invalidRecordSetting(15, 176, 144, MediaRecorder.VideoEncoder.H263,
+               MediaRecorder.OutputFormat.THREE_GPP, MediaNames.INVALD_VIDEO_PATH, false);
         assertTrue("Invalid outputFile Path", isTestInvalidVideoPathSuccessful);
     }
-    
+
     @LargeTest
     //test cases for the new codec
     public void testDeviceSpecificCodec() throws Exception {
@@ -309,4 +487,49 @@
             assertTrue("testDeviceSpecificCodec", false);
         }
     }
+
+    // Test MediaRecorder.getSurface() api with surface or camera source
+    public void testGetSurfaceApi() {
+        boolean success = false;
+        int noOfFailure = 0;
+        try {
+            for (int k = 0; k < 2; k++) {
+                success = validateGetSurface(
+                        k == 0 ? true : false /* useSurface */);
+                if (!success) {
+                    noOfFailure++;
+                }
+            }
+        } catch (Exception e) {
+            Log.v(TAG, e.toString());
+        }
+        assertTrue("testGetSurfaceApi", noOfFailure == 0);
+    }
+
+    // Test recording from surface source with/without audio
+    public void testSurfaceRecording() {
+        boolean success = false;
+        int noOfFailure = 0;
+        try {
+            int codec = MediaRecorder.VideoEncoder.H264;
+            int frameRate = MediaProfileReader.getMaxFrameRateForCodec(codec);
+            for (int k = 0; k < 2; k++) {
+                String filename = "/sdcard/surface_" +
+                            (k==0?"video_only":"with_audio") + ".3gp";
+
+                success = recordVideoFromSurface(frameRate, 352, 288, codec,
+                        MediaRecorder.OutputFormat.THREE_GPP, filename,
+                        k == 0 ? true : false /* videoOnly */);
+                if (success) {
+                    success = validateVideo(filename, 352, 288);
+                }
+                if (!success) {
+                    noOfFailure++;
+                }
+            }
+        } catch (Exception e) {
+            Log.v(TAG, e.toString());
+        }
+        assertTrue("testSurfaceRecording", noOfFailure == 0);
+    }
 }
diff --git a/media/tests/players/invoke_mock_media_player.cpp b/media/tests/players/invoke_mock_media_player.cpp
index a94fedb..d1fed7bb 100644
--- a/media/tests/players/invoke_mock_media_player.cpp
+++ b/media/tests/players/invoke_mock_media_player.cpp
@@ -27,6 +27,7 @@
 using android::INVALID_OPERATION;
 using android::Surface;
 using android::IGraphicBufferProducer;
+using android::IMediaHTTPService;
 using android::MediaPlayerBase;
 using android::OK;
 using android::Parcel;
@@ -57,6 +58,7 @@
     virtual bool        hardwareOutput() {return true;}
 
     virtual status_t    setDataSource(
+            const sp<IMediaHTTPService> &httpService,
             const char *url,
             const KeyedVector<String8, String8> *) {
         ALOGV("setDataSource %s", url);
diff --git a/opengl/java/com/google/android/gles_jni/EGLConfigImpl.java b/opengl/java/com/google/android/gles_jni/EGLConfigImpl.java
index c2f4400..1902a40 100644
--- a/opengl/java/com/google/android/gles_jni/EGLConfigImpl.java
+++ b/opengl/java/com/google/android/gles_jni/EGLConfigImpl.java
@@ -19,13 +19,13 @@
 import javax.microedition.khronos.egl.*;
 
 public class EGLConfigImpl extends EGLConfig {
-    private int mEGLConfig;
+    private long mEGLConfig;
 
-    EGLConfigImpl(int config) {
+    EGLConfigImpl(long config) {
         mEGLConfig = config;
     }
     
-    int get() {
+    long get() {
         return mEGLConfig;
     }
 }
diff --git a/opengl/java/com/google/android/gles_jni/EGLContextImpl.java b/opengl/java/com/google/android/gles_jni/EGLContextImpl.java
index cd36099..47369ac 100644
--- a/opengl/java/com/google/android/gles_jni/EGLContextImpl.java
+++ b/opengl/java/com/google/android/gles_jni/EGLContextImpl.java
@@ -21,13 +21,13 @@
 
 public class EGLContextImpl extends EGLContext {
     private GLImpl mGLContext;
-    int mEGLContext;
-    
-    public EGLContextImpl(int ctx) {
+    long mEGLContext;
+
+    public EGLContextImpl(long ctx) {
         mEGLContext = ctx;
         mGLContext = new GLImpl();
     }
- 
+
     @Override
     public GL getGL() {
         return mGLContext;
@@ -45,6 +45,12 @@
 
     @Override
     public int hashCode() {
-        return mEGLContext;
+        /*
+         * Based on the algorithm suggested in
+         * http://developer.android.com/reference/java/lang/Object.html
+         */
+        int result = 17;
+        result = 31 * result + (int) (mEGLContext ^ (mEGLContext >>> 32));
+        return result;
     }
 }
diff --git a/opengl/java/com/google/android/gles_jni/EGLDisplayImpl.java b/opengl/java/com/google/android/gles_jni/EGLDisplayImpl.java
index e6c9817..9b932fc 100644
--- a/opengl/java/com/google/android/gles_jni/EGLDisplayImpl.java
+++ b/opengl/java/com/google/android/gles_jni/EGLDisplayImpl.java
@@ -19,9 +19,9 @@
 import javax.microedition.khronos.egl.*;
 
 public class EGLDisplayImpl extends EGLDisplay {
-    int mEGLDisplay;
+    long mEGLDisplay;
 
-    public EGLDisplayImpl(int dpy) {
+    public EGLDisplayImpl(long dpy) {
         mEGLDisplay = dpy;
     }
 
@@ -38,6 +38,12 @@
 
     @Override
     public int hashCode() {
-        return mEGLDisplay;
+        /*
+         * Based on the algorithm suggested in
+         * http://developer.android.com/reference/java/lang/Object.html
+         */
+        int result = 17;
+        result = 31 * result + (int) (mEGLDisplay ^ (mEGLDisplay >>> 32));
+        return result;
     }
 }
diff --git a/opengl/java/com/google/android/gles_jni/EGLImpl.java b/opengl/java/com/google/android/gles_jni/EGLImpl.java
index 64a54c2..41fb072 100644
--- a/opengl/java/com/google/android/gles_jni/EGLImpl.java
+++ b/opengl/java/com/google/android/gles_jni/EGLImpl.java
@@ -51,7 +51,7 @@
     public static native int  getInitCount(EGLDisplay display);
 
     public EGLContext eglCreateContext(EGLDisplay display, EGLConfig config, EGLContext share_context, int[] attrib_list) {
-        int eglContextId = _eglCreateContext(display, config, share_context, attrib_list);
+        long eglContextId = _eglCreateContext(display, config, share_context, attrib_list);
         if (eglContextId == 0) {
             return EGL10.EGL_NO_CONTEXT;
         }
@@ -59,7 +59,7 @@
     }
 
     public EGLSurface eglCreatePbufferSurface(EGLDisplay display, EGLConfig config, int[] attrib_list) {
-        int eglSurfaceId = _eglCreatePbufferSurface(display, config, attrib_list);
+        long eglSurfaceId = _eglCreatePbufferSurface(display, config, attrib_list);
         if (eglSurfaceId == 0) {
             return EGL10.EGL_NO_SURFACE;
         }
@@ -87,7 +87,7 @@
             sur = (Surface) native_window;
         }
 
-        int eglSurfaceId;
+        long eglSurfaceId;
         if (sur != null) {
             eglSurfaceId = _eglCreateWindowSurface(display, config, sur, attrib_list);
         } else if (native_window instanceof SurfaceTexture) {
@@ -106,7 +106,7 @@
     }
 
     public synchronized EGLDisplay eglGetDisplay(Object native_display) {
-        int value = _eglGetDisplay(native_display);
+        long value = _eglGetDisplay(native_display);
         if (value == 0) {
             return EGL10.EGL_NO_DISPLAY;
         }
@@ -116,7 +116,7 @@
     }
 
     public synchronized EGLContext eglGetCurrentContext() {
-        int value = _eglGetCurrentContext();
+        long value = _eglGetCurrentContext();
         if (value == 0) {
             return EGL10.EGL_NO_CONTEXT;
         }
@@ -126,7 +126,7 @@
     }
 
     public synchronized EGLDisplay eglGetCurrentDisplay() {
-        int value = _eglGetCurrentDisplay();
+        long value = _eglGetCurrentDisplay();
         if (value == 0) {
             return EGL10.EGL_NO_DISPLAY;
         }
@@ -136,7 +136,7 @@
     }
 
     public synchronized EGLSurface eglGetCurrentSurface(int readdraw) {
-        int value = _eglGetCurrentSurface(readdraw);
+        long value = _eglGetCurrentSurface(readdraw);
         if (value == 0) {
             return EGL10.EGL_NO_SURFACE;
         }
@@ -145,15 +145,15 @@
         return mSurface;
     }
 
-    private native int _eglCreateContext(EGLDisplay display, EGLConfig config, EGLContext share_context, int[] attrib_list);
-    private native int _eglCreatePbufferSurface(EGLDisplay display, EGLConfig config, int[] attrib_list);
+    private native long _eglCreateContext(EGLDisplay display, EGLConfig config, EGLContext share_context, int[] attrib_list);
+    private native long _eglCreatePbufferSurface(EGLDisplay display, EGLConfig config, int[] attrib_list);
     private native void _eglCreatePixmapSurface(EGLSurface sur, EGLDisplay display, EGLConfig config, Object native_pixmap, int[] attrib_list);
-    private native int _eglCreateWindowSurface(EGLDisplay display, EGLConfig config, Object native_window, int[] attrib_list);
-    private native int _eglCreateWindowSurfaceTexture(EGLDisplay display, EGLConfig config, Object native_window, int[] attrib_list);
-    private native int _eglGetDisplay(Object native_display);
-    private native int _eglGetCurrentContext();
-    private native int _eglGetCurrentDisplay();
-    private native int _eglGetCurrentSurface(int readdraw);
+    private native long _eglCreateWindowSurface(EGLDisplay display, EGLConfig config, Object native_window, int[] attrib_list);
+    private native long _eglCreateWindowSurfaceTexture(EGLDisplay display, EGLConfig config, Object native_window, int[] attrib_list);
+    private native long _eglGetDisplay(Object native_display);
+    private native long _eglGetCurrentContext();
+    private native long _eglGetCurrentDisplay();
+    private native long _eglGetCurrentSurface(int readdraw);
 
     native private static void _nativeClassInit();
     static { _nativeClassInit(); }
diff --git a/opengl/java/com/google/android/gles_jni/EGLSurfaceImpl.java b/opengl/java/com/google/android/gles_jni/EGLSurfaceImpl.java
index e7f15dc..7a3ed24 100644
--- a/opengl/java/com/google/android/gles_jni/EGLSurfaceImpl.java
+++ b/opengl/java/com/google/android/gles_jni/EGLSurfaceImpl.java
@@ -19,13 +19,13 @@
 import javax.microedition.khronos.egl.*;
 
 public class EGLSurfaceImpl extends EGLSurface {
-    int mEGLSurface;
-    private int mNativePixelRef;
+    long mEGLSurface;
+    private long mNativePixelRef;
     public EGLSurfaceImpl() {
         mEGLSurface = 0;
         mNativePixelRef = 0;
     }
-    public EGLSurfaceImpl(int surface) {
+    public EGLSurfaceImpl(long surface) {
         mEGLSurface = surface;
         mNativePixelRef = 0;
     }
@@ -43,6 +43,12 @@
 
     @Override
     public int hashCode() {
-        return mEGLSurface;
+        /*
+         * Based on the algorithm suggested in
+         * http://developer.android.com/reference/java/lang/Object.html
+         */
+        int result = 17;
+        result = 31 * result + (int) (mEGLSurface ^ (mEGLSurface >>> 32));
+        return result;
     }
 }
diff --git a/packages/Keyguard/Android.mk b/packages/Keyguard/Android.mk
index f6f441d..1f2b5fb 100644
--- a/packages/Keyguard/Android.mk
+++ b/packages/Keyguard/Android.mk
@@ -18,8 +18,6 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-subdir-Iaidl-files)
 
-LOCAL_JAVA_LIBRARIES := services
-
 LOCAL_PACKAGE_NAME := Keyguard
 
 LOCAL_CERTIFICATE := platform
diff --git a/packages/Keyguard/res/layout-port/keyguard_simple_host_view.xml b/packages/Keyguard/res/layout-port/keyguard_simple_host_view.xml
new file mode 100644
index 0000000..cba7667
--- /dev/null
+++ b/packages/Keyguard/res/layout-port/keyguard_simple_host_view.xml
@@ -0,0 +1,49 @@
+<?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.
+*/
+-->
+
+<!-- This is the host view that generally contains two sub views: the widget view
+    and the security view. -->
+<com.android.keyguard.KeyguardSimpleHostView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/res/com.android.keyguard"
+    android:id="@+id/keyguard_host_view"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <com.android.keyguard.KeyguardSecurityContainer
+        android:id="@+id/keyguard_security_container"
+        android:layout_width="wrap_content"
+        android:layout_height="@dimen/keyguard_security_height"
+        android:clipChildren="false"
+        android:clipToPadding="false"
+        android:padding="0dp"
+        android:layout_gravity="center">
+        <com.android.keyguard.KeyguardSecurityViewFlipper
+            android:id="@+id/view_flipper"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:clipChildren="false"
+            android:clipToPadding="false"
+            android:paddingTop="@dimen/keyguard_security_view_margin"
+            android:gravity="center">
+        </com.android.keyguard.KeyguardSecurityViewFlipper>
+    </com.android.keyguard.KeyguardSecurityContainer>
+
+</com.android.keyguard.KeyguardSimpleHostView>
+
diff --git a/packages/Keyguard/res/values-de/strings.xml b/packages/Keyguard/res/values-de/strings.xml
index 4ece6d9..edbbffd 100644
--- a/packages/Keyguard/res/values-de/strings.xml
+++ b/packages/Keyguard/res/values-de/strings.xml
@@ -86,7 +86,7 @@
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Löschen"</string>
     <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Fertig"</string>
     <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Modusänderung"</string>
-    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Umschalttaste"</string>
+    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Eingabetaste"</string>
     <string name="description_target_unlock" msgid="2228524900439801453">"Entsperren"</string>
     <string name="description_target_camera" msgid="969071997552486814">"Kamera"</string>
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java
index 1548dee..7ac94bd 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java
@@ -17,15 +17,14 @@
 package com.android.keyguard;
 
 import android.nfc.NfcUnlock;
+
 import com.android.internal.widget.LockPatternUtils;
-import com.android.keyguard.KeyguardSecurityContainer.SecurityCallback;
 import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
 import com.android.keyguard.KeyguardUpdateMonitor.DisplayClientState;
 
 import android.app.Activity;
 import android.app.ActivityManager;
 import android.app.ActivityOptions;
-import android.app.AlertDialog;
 import android.app.SearchManager;
 import android.app.admin.DevicePolicyManager;
 import android.appwidget.AppWidgetHost;
@@ -39,9 +38,9 @@
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.UserInfo;
 import android.content.res.Resources;
-import android.graphics.Canvas;
 import android.graphics.Rect;
 import android.media.RemoteControlClient;
+import android.os.Bundle;
 import android.os.Looper;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -51,12 +50,9 @@
 import android.provider.Settings;
 import android.util.AttributeSet;
 import android.util.Log;
-import android.util.Slog;
-
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
-import android.view.WindowManager;
 import android.widget.RemoteViews.OnClickHandler;
 
 import java.io.File;
@@ -65,6 +61,8 @@
 
 public class KeyguardHostView extends KeyguardViewBase {
     private static final String TAG = "KeyguardHostView";
+    public static boolean DEBUG = KeyguardViewMediator.DEBUG;
+    public static boolean DEBUGXPORT = true; // debug music transport control
 
     // Transport control states.
     static final int TRANSPORT_GONE = 0;
@@ -73,13 +71,8 @@
 
     private int mTransportState = TRANSPORT_GONE;
 
-    // Use this to debug all of keyguard
-    public static boolean DEBUG = KeyguardViewMediator.DEBUG;
-    public static boolean DEBUGXPORT = true; // debug music transport control
-
     // Found in KeyguardAppWidgetPickActivity.java
     static final int APPWIDGET_HOST_ID = 0x4B455947;
-
     private final int MAX_WIDGETS = 5;
 
     private AppWidgetHost mAppWidgetHost;
@@ -89,18 +82,13 @@
     private int mAppWidgetToShow;
 
     protected int mFailedAttempts;
-    private LockPatternUtils mLockPatternUtils;
 
     private KeyguardViewStateManager mViewStateManager;
 
     private Rect mTempRect = new Rect();
-
     private int mDisabledFeatures;
-
     private boolean mCameraDisabled;
-
     private boolean mSafeModeEnabled;
-
     private boolean mUserSetupCompleted;
 
     // User for whom this host view was created.  Final because we should never change the
@@ -119,8 +107,6 @@
 
     private Runnable mPostBootCompletedRunnable;
 
-    private OnDismissAction mDismissAction;
-
     /*package*/ interface UserSwitcherCallback {
         void hideSecurityView(int duration);
         void showSecurityView();
@@ -309,27 +295,18 @@
 
     private SlidingChallengeLayout mSlidingChallengeLayout;
     private MultiPaneChallengeLayout mMultiPaneChallengeLayout;
-    private KeyguardSecurityContainer mSecurityContainer;
 
     @Override
     public boolean onTouchEvent(MotionEvent ev) {
         boolean result = super.onTouchEvent(ev);
         mTempRect.set(0, 0, 0, 0);
-        offsetRectIntoDescendantCoords(mSecurityContainer, mTempRect);
+        offsetRectIntoDescendantCoords(getSecurityContainer(), mTempRect);
         ev.offsetLocation(mTempRect.left, mTempRect.top);
-        result = mSecurityContainer.dispatchTouchEvent(ev) || result;
+        result = getSecurityContainer().dispatchTouchEvent(ev) || result;
         ev.offsetLocation(-mTempRect.left, -mTempRect.top);
         return result;
     }
 
-    @Override
-    protected void dispatchDraw(Canvas canvas) {
-        super.dispatchDraw(canvas);
-        if (mViewMediatorCallback != null) {
-            mViewMediatorCallback.keyguardDoneDrawing();
-        }
-    }
-
     private int getWidgetPosition(int id) {
         final KeyguardWidgetPager appWidgetContainer = mAppWidgetContainer;
         final int children = appWidgetContainer.getChildCount();
@@ -347,6 +324,8 @@
 
     @Override
     protected void onFinishInflate() {
+        super.onFinishInflate();
+
         // Grab instances of and make any necessary changes to the main layouts. Create
         // view state manager and wire up necessary listeners / callbacks.
         View deleteDropTarget = findViewById(R.id.keyguard_widget_pager_delete_target);
@@ -372,49 +351,7 @@
         mViewStateManager.setPagedView(mAppWidgetContainer);
         mViewStateManager.setChallengeLayout(challenge);
 
-        mSecurityContainer =
-                (KeyguardSecurityContainer) findViewById(R.id.keyguard_security_container);
-        mSecurityContainer.setLockPatternUtils(mLockPatternUtils);
-        mSecurityContainer.setSecurityCallback(new SecurityCallback() {
-            @Override
-            public void userActivity(long timeout) {
-                if (mViewMediatorCallback != null) {
-                    mViewMediatorCallback.userActivity(timeout);
-                }
-            }
-
-            @Override
-            public void dismiss(boolean authenticated) {
-                KeyguardHostView.this.dismiss(authenticated);
-            }
-
-            @Override
-            public void finish() {
-
-                // If the alternate unlock was suppressed, it can now be safely
-                // enabled because the user has left keyguard.
-                KeyguardUpdateMonitor.getInstance(mContext).setAlternateUnlockEnabled(true);
-
-                // If there's a pending runnable because the user interacted with a widget
-                // and we're leaving keyguard, then run it.
-                boolean deferKeyguardDone = false;
-                if (mDismissAction != null) {
-                    deferKeyguardDone = mDismissAction.onDismiss();
-                    mDismissAction = null;
-                }
-                if (mViewMediatorCallback != null) {
-                    if (deferKeyguardDone) {
-                        mViewMediatorCallback.keyguardDonePending();
-                    } else {
-                        mViewMediatorCallback.keyguardDone(true);
-                    }
-                }
-            }
-        });
-
-        mViewStateManager.setSecurityViewContainer(mSecurityContainer);
-
-        setBackButtonEnabled(false);
+        mViewStateManager.setSecurityViewContainer(getSecurityContainer());
 
         if (KeyguardUpdateMonitor.getInstance(mContext).hasBootCompleted()) {
             updateAndAddWidgets();
@@ -429,8 +366,7 @@
             };
         }
 
-        mSecurityContainer.showPrimarySecurityScreen(false);
-        mSecurityContainer.updateSecurityViews(mViewStateManager.isBouncing());
+        getSecurityContainer().updateSecurityViews(mViewStateManager.isBouncing());
         enableUserSelectorIfNecessary();
     }
 
@@ -459,17 +395,37 @@
         }
     }
 
-    private void setBackButtonEnabled(boolean enabled) {
-        if (mContext instanceof Activity) return;  // always enabled in activity mode
-        setSystemUiVisibility(enabled ?
-                getSystemUiVisibility() & ~View.STATUS_BAR_DISABLE_BACK :
-                getSystemUiVisibility() | View.STATUS_BAR_DISABLE_BACK);
-    }
-
     private boolean shouldEnableAddWidget() {
         return numWidgets() < MAX_WIDGETS && mUserSetupCompleted;
     }
 
+    @Override
+    public boolean dismiss(boolean authenticated) {
+        boolean finished = super.dismiss(authenticated);
+        if (!finished) {
+            mViewStateManager.showBouncer(true);
+
+            // Enter full screen mode if we're in SIM or Account screen
+            SecurityMode securityMode = getSecurityContainer().getSecurityMode();
+            boolean isFullScreen = getResources().getBoolean(R.bool.kg_sim_puk_account_full_screen);
+            boolean isSimOrAccount = securityMode == SecurityMode.SimPin
+                    || securityMode == SecurityMode.SimPuk
+                    || securityMode == SecurityMode.Account;
+            mAppWidgetContainer.setVisibility(
+                    isSimOrAccount && isFullScreen ? View.GONE : View.VISIBLE);
+
+            // Don't show camera or search in navbar when SIM or Account screen is showing
+            setSystemUiVisibility(isSimOrAccount ?
+                    (getSystemUiVisibility() | View.STATUS_BAR_DISABLE_SEARCH)
+                    : (getSystemUiVisibility() & ~View.STATUS_BAR_DISABLE_SEARCH));
+
+            if (mSlidingChallengeLayout != null) {
+                mSlidingChallengeLayout.setChallengeInteractive(!isFullScreen);
+            }
+        }
+        return finished;
+    }
+
     private int getDisabledFeatures(DevicePolicyManager dpm) {
         int disabledFeatures = DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_NONE;
         if (dpm != null) {
@@ -492,10 +448,10 @@
                 || (mDisabledFeatures & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA) != 0;
     }
 
-    void setLockPatternUtils(LockPatternUtils utils) {
-        mLockPatternUtils = utils;
-        mSecurityContainer.setLockPatternUtils(utils);
-        mSecurityContainer.updateSecurityViews(mViewStateManager.isBouncing());
+    @Override
+    protected void setLockPatternUtils(LockPatternUtils utils) {
+        super.setLockPatternUtils(utils);
+        getSecurityContainer().updateSecurityViews(mViewStateManager.isBouncing());
     }
 
     @Override
@@ -554,7 +510,8 @@
         }
     };
 
-    public void initializeSwitchingUserState(boolean switching) {
+    @Override
+    public void onUserSwitching(boolean switching) {
         if (!switching && mKeyguardMultiUserSelectorView != null) {
             mKeyguardMultiUserSelectorView.finalizeActiveUserView(false);
         }
@@ -582,8 +539,6 @@
         return -1;
     }
 
-
-
     private static class MyOnClickHandler extends OnClickHandler {
 
         // weak reference to the hostView to avoid keeping a live reference
@@ -641,75 +596,31 @@
 
     @Override
     public void onScreenTurnedOn() {
-        if (DEBUG) Log.d(TAG, "screen on, instance " + Integer.toHexString(hashCode()));
-        mSecurityContainer.showPrimarySecurityScreen(false);
-        mSecurityContainer.onResume(KeyguardSecurityView.SCREEN_ON);
-
-        // This is a an attempt to fix bug 7137389 where the device comes back on but the entire
-        // layout is blank but forcing a layout causes it to reappear (e.g. with with
-        // hierarchyviewer).
-        requestLayout();
-
+        super.onScreenTurnedOn();
         if (mViewStateManager != null) {
             mViewStateManager.showUsabilityHints();
         }
-
-        requestFocus();
     }
 
     @Override
     public void onScreenTurnedOff() {
-        if (DEBUG) Log.d(TAG, String.format("screen off, instance %s at %s",
-                Integer.toHexString(hashCode()), SystemClock.uptimeMillis()));
-        // Once the screen turns off, we no longer consider this to be first boot and we want the
-        // biometric unlock to start next time keyguard is shown.
-        KeyguardUpdateMonitor.getInstance(mContext).setAlternateUnlockEnabled(true);
+        super.onScreenTurnedOff();
         // We use mAppWidgetToShow to show a particular widget after you add it-- once the screen
         // turns off we reset that behavior
         clearAppWidgetToShow();
         if (KeyguardUpdateMonitor.getInstance(mContext).hasBootCompleted()) {
             checkAppWidgetConsistency();
         }
-        mSecurityContainer.showPrimarySecurityScreen(true);
-        mSecurityContainer.onPause();
         CameraWidgetFrame cameraPage = findCameraPage();
         if (cameraPage != null) {
             cameraPage.onScreenTurnedOff();
         }
-
-        clearFocus();
     }
 
     public void clearAppWidgetToShow() {
         mAppWidgetToShow = AppWidgetManager.INVALID_APPWIDGET_ID;
     }
 
-    @Override
-    public void show() {
-        if (DEBUG) Log.d(TAG, "show()");
-        mSecurityContainer.showPrimarySecurityScreen(false);
-    }
-
-    @Override
-    public void verifyUnlock() {
-        SecurityMode securityMode = mSecurityContainer.getSecurityMode();
-        if (securityMode == KeyguardSecurityModel.SecurityMode.None) {
-            if (mViewMediatorCallback != null) {
-                mViewMediatorCallback.keyguardDone(true);
-            }
-        } else if (securityMode != KeyguardSecurityModel.SecurityMode.Pattern
-                && securityMode != KeyguardSecurityModel.SecurityMode.PIN
-                && securityMode != KeyguardSecurityModel.SecurityMode.Password) {
-            // can only verify unlock when in pattern/password mode
-            if (mViewMediatorCallback != null) {
-                mViewMediatorCallback.keyguardDone(false);
-            }
-        } else {
-            // otherwise, go to the unlock screen, see if they can verify it
-            mSecurityContainer.verifyUnlock();
-        }
-    }
-
     private boolean addWidget(int appId, int pageIndex, boolean updateDbIfFailed) {
         AppWidgetProviderInfo appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(appId);
         if (appWidgetInfo != null) {
@@ -757,28 +668,6 @@
             }
         };
 
-    private final KeyguardActivityLauncher mActivityLauncher = new KeyguardActivityLauncher() {
-        @Override
-        Context getContext() {
-            return mContext;
-        }
-
-        @Override
-        void setOnDismissAction(OnDismissAction action) {
-            mDismissAction = action;
-        }
-
-        @Override
-        LockPatternUtils getLockPatternUtils() {
-            return mLockPatternUtils;
-        }
-
-        @Override
-        void requestDismissKeyguard() {
-            KeyguardHostView.this.dismiss(false);
-        }
-    };
-
     private int numWidgets() {
         final int childCount = mAppWidgetContainer.getChildCount();
         int widgetCount = 0;
@@ -800,7 +689,7 @@
                 @Override
                 public void onClick(View v) {
                     // Pass in an invalid widget id... the picker will allocate an ID for us
-                    mActivityLauncher.launchWidgetPicker(AppWidgetManager.INVALID_APPWIDGET_ID);
+                    getActivityLauncher().launchWidgetPicker(AppWidgetManager.INVALID_APPWIDGET_ID);
                 }
             });
         }
@@ -810,8 +699,8 @@
         // inflate system-provided camera?
         if (!mSafeModeEnabled && !cameraDisabledByDpm() && mUserSetupCompleted
                 && mContext.getResources().getBoolean(R.bool.kg_enable_camera_default_widget)) {
-            View cameraWidget =
-                    CameraWidgetFrame.create(mContext, mCameraWidgetCallbacks, mActivityLauncher);
+            View cameraWidget = CameraWidgetFrame.create(mContext, mCameraWidgetCallbacks,
+                    getActivityLauncher());
             if (cameraWidget != null) {
                 mAppWidgetContainer.addWidget(cameraWidget);
             }
@@ -1198,18 +1087,18 @@
                 UserSwitcherCallback callback = new UserSwitcherCallback() {
                     @Override
                     public void hideSecurityView(int duration) {
-                        mSecurityContainer.animate().alpha(0).setDuration(duration);
+                        getSecurityContainer().animate().alpha(0).setDuration(duration);
                     }
 
                     @Override
                     public void showSecurityView() {
-                        mSecurityContainer.setAlpha(1.0f);
+                        getSecurityContainer().setAlpha(1.0f);
                     }
 
                     @Override
                     public void showUnlockHint() {
-                        if (mSecurityContainer != null) {
-                            mSecurityContainer.showUsabilityHint();
+                        if (getSecurityContainer() != null) {
+                            getSecurityContainer().showUsabilityHint();
                         }
                     }
 
@@ -1244,124 +1133,31 @@
         }
     }
 
-    /**
-     * In general, we enable unlocking the insecure keyguard with the menu key. However, there are
-     * some cases where we wish to disable it, notably when the menu button placement or technology
-     * is prone to false positives.
-     *
-     * @return true if the menu key should be enabled
-     */
-    private static final String ENABLE_MENU_KEY_FILE = "/data/local/enable_menu_key";
-    private boolean shouldEnableMenuKey() {
-        final Resources res = getResources();
-        final boolean configDisabled = res.getBoolean(R.bool.config_disableMenuKeyInLockScreen);
-        final boolean isTestHarness = ActivityManager.isRunningInTestHarness();
-        final boolean fileOverride = (new File(ENABLE_MENU_KEY_FILE)).exists();
-        return !configDisabled || isTestHarness || fileOverride;
-    }
-
     public void goToWidget(int appWidgetId) {
         mAppWidgetToShow = appWidgetId;
         mSwitchPageRunnable.run();
     }
 
-    public boolean handleMenuKey() {
-        // The following enables the MENU key to work for testing automation
-        if (shouldEnableMenuKey()) {
-            dismiss();
-            return true;
-        }
-        return false;
+    @Override
+    protected void showBouncer(boolean show) {
+        super.showBouncer(show);
+        mViewStateManager.showBouncer(show);
     }
 
-    public boolean handleBackKey() {
-        if (mSecurityContainer.getCurrentSecuritySelection() == SecurityMode.Account) {
-            // go back to primary screen and re-disable back
-            setBackButtonEnabled(false);
-            mSecurityContainer.showPrimarySecurityScreen(false /*turningOff*/);
-            return true;
-        }
-        if (mSecurityContainer.getCurrentSecuritySelection() != SecurityMode.None) {
-            mSecurityContainer.dismiss(false);
-            return true;
-        }
-        return false;
-    }
-
-    /**
-     *  Dismisses the keyguard by going to the next screen or making it gone.
-     */
-    public void dismiss() {
-        dismiss(false);
-    }
-
-    private void dismiss(boolean authenticated) {
-        boolean finished = mSecurityContainer.showNextSecurityScreenOrFinish(authenticated);
-        if (!finished) {
-            updateAfterSecuritySelection();
-            mViewStateManager.showBouncer(true);
-        }
-    }
-
-    void setOnDismissAction(OnDismissAction action) {
-        mDismissAction = action;
-    }
-
-    public void announceCurrentSecurityMethod() {
-        mSecurityContainer.announceCurrentSecurityMethod();
-    }
-
-    private void updateAfterSecuritySelection() {
-        // Enable or disable the back button based on security mode
-        if (mSecurityContainer.getSecurityMode() == SecurityMode.Account
-                && !mLockPatternUtils.isPermanentlyLocked()) {
-            // we're showing account as a backup, provide a way to get back to primary
-            setBackButtonEnabled(true);
-        }
-
-        // Enter full screen mode if we're in SIM or Account screen
-        SecurityMode securityMode = mSecurityContainer.getSecurityMode();
-        boolean isFullScreen = getResources().getBoolean(R.bool.kg_sim_puk_account_full_screen);
-        boolean isSimOrAccount = securityMode == SecurityMode.SimPin
-                || securityMode == SecurityMode.SimPuk
-                || securityMode == SecurityMode.Account;
-        mAppWidgetContainer.setVisibility(
-                isSimOrAccount && isFullScreen ? View.GONE : View.VISIBLE);
-
-        // Don't show camera or search in navbar when SIM or Account screen is showing
-        setSystemUiVisibility(isSimOrAccount ?
-                (getSystemUiVisibility() | View.STATUS_BAR_DISABLE_SEARCH)
-                : (getSystemUiVisibility() & ~View.STATUS_BAR_DISABLE_SEARCH));
-
-        if (mSlidingChallengeLayout != null) {
-            mSlidingChallengeLayout.setChallengeInteractive(!isFullScreen);
-        }
-
-        if (mViewMediatorCallback != null) {
-            mViewMediatorCallback.setNeedsInput(mSecurityContainer.needsInput());
-        }
-    }
-
-    public void showAssistant() {
-        final Intent intent = ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE))
-          .getAssistIntent(mContext, true, UserHandle.USER_CURRENT);
-
-        if (intent == null) return;
-
-        final ActivityOptions opts = ActivityOptions.makeCustomAnimation(mContext,
-                R.anim.keyguard_action_assist_enter, R.anim.keyguard_action_assist_exit,
-                getHandler(), null);
-
-        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        mActivityLauncher.launchActivityWithAnimation(intent, false, opts.toBundle(), null, null);
-    }
-
-    public void dispatch(MotionEvent event) {
+    @Override
+    public void onExternalMotionEvent(MotionEvent event) {
         mAppWidgetContainer.handleExternalCameraEvent(event);
     }
 
-    public void launchCamera() {
-        mActivityLauncher.launchCamera(getHandler(), null);
+    @Override
+    protected void onCreateOptions(Bundle options) {
+        if (options != null) {
+            int widgetToShow = options.getInt(LockPatternUtils.KEYGUARD_SHOW_APPWIDGET,
+                    AppWidgetManager.INVALID_APPWIDGET_ID);
+            if (widgetToShow != AppWidgetManager.INVALID_APPWIDGET_ID) {
+                goToWidget(widgetToShow);
+            }
+        }
     }
 
 }
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
index ea92b649..0f62100 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -44,8 +44,9 @@
 
     // Used to notify the container when something interesting happens.
     public interface SecurityCallback {
-        public void dismiss(boolean authenticated);
+        public boolean dismiss(boolean authenticated);
         public void userActivity(long timeout);
+        public void onSecurityModeChanged(SecurityMode securityMode, boolean needsInput);
         public void finish();
     }
 
@@ -293,18 +294,12 @@
         showSecurityScreen(backup);
     }
 
-    private boolean showNextSecurityScreenIfPresent() {
-        SecurityMode securityMode = mSecurityModel.getSecurityMode();
-        // Allow an alternate, such as biometric unlock
-        securityMode = mSecurityModel.getAlternateFor(securityMode);
-        if (SecurityMode.None == securityMode) {
-            return false;
-        } else {
-            showSecurityScreen(securityMode); // switch to the alternate security view
-            return true;
-        }
-    }
-
+    /**
+     * Shows the next security screen if there is one.
+     * @param authenticated true if the user entered the correct authentication
+     * @param authenticated
+     * @return true if keyguard is done
+     */
     boolean showNextSecurityScreenOrFinish(boolean authenticated) {
         if (DEBUG) Log.d(TAG, "showNextSecurityScreenOrFinish(" + authenticated + ")");
         boolean finish = false;
@@ -386,6 +381,7 @@
         }
 
         mCurrentSecuritySelection = securityMode;
+        mSecurityCallback.onSecurityModeChanged(securityMode, newView.needsInput());
     }
 
     private KeyguardSecurityViewFlipper getFlipper() {
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityModel.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityModel.java
index 4129e33..9f5768a 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityModel.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityModel.java
@@ -105,7 +105,7 @@
                     break;
 
                 default:
-                    throw new IllegalStateException("Unknown unlock mode:" + mode);
+                    throw new IllegalStateException("Unknown security quality:" + security);
             }
         }
         return mode;
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSimpleHostView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSimpleHostView.java
new file mode 100644
index 0000000..cf983cb
--- /dev/null
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSimpleHostView.java
@@ -0,0 +1,70 @@
+/*
+ * 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.keyguard;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+
+public class KeyguardSimpleHostView extends KeyguardViewBase {
+
+    public KeyguardSimpleHostView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    protected void showBouncer(boolean show) {
+        super.showBouncer(show);
+        if (show) {
+            getSecurityContainer().showBouncer(250);
+        } else {
+            getSecurityContainer().hideBouncer(250);
+        }
+    }
+
+    @Override
+    public void verifyUnlock() {
+        // TODO Auto-generated method stub
+    }
+
+    @Override
+    public void cleanUp() {
+        // TODO Auto-generated method stub
+    }
+
+    @Override
+    public long getUserActivityTimeout() {
+        return -1; // not used
+    }
+
+    @Override
+    protected void onUserSwitching(boolean switching) {
+        // TODO Auto-generated method stub
+    }
+
+    @Override
+    protected void onCreateOptions(Bundle options) {
+        // TODO Auto-generated method stub
+    }
+
+    @Override
+    protected void onExternalMotionEvent(MotionEvent event) {
+        // TODO Auto-generated method stub
+    }
+
+}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardViewBase.java b/packages/Keyguard/src/com/android/keyguard/KeyguardViewBase.java
index bff1f93..78f4506 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardViewBase.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardViewBase.java
@@ -17,18 +17,36 @@
 package com.android.keyguard;
 
 import android.app.Activity;
+import android.app.ActivityManager;
+import android.app.ActivityOptions;
+import android.app.SearchManager;
 import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.graphics.Canvas;
 import android.media.AudioManager;
 import android.media.IAudioService;
+import android.os.Bundle;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.SystemClock;
+import android.os.UserHandle;
 import android.telephony.TelephonyManager;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.Slog;
 import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.View;
 import android.widget.FrameLayout;
 
+import com.android.internal.widget.LockPatternUtils;
+import com.android.keyguard.KeyguardHostView.OnDismissAction;
+import com.android.keyguard.KeyguardSecurityContainer.SecurityCallback;
+import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
+
+import java.io.File;
+
 /**
  * Base class for keyguard view.  {@link #reset} is where you should
  * reset the state of your view.  Use the {@link KeyguardViewCallback} via
@@ -38,16 +56,22 @@
  * Handles intercepting of media keys that still work when the keyguard is
  * showing.
  */
-public abstract class KeyguardViewBase extends FrameLayout {
+public abstract class KeyguardViewBase extends FrameLayout implements SecurityCallback {
 
     private AudioManager mAudioManager;
     private TelephonyManager mTelephonyManager = null;
     protected KeyguardViewMediator.ViewMediatorCallback mViewMediatorCallback;
+    protected LockPatternUtils mLockPatternUtils;
+    private OnDismissAction mDismissAction;
 
     // Whether the volume keys should be handled by keyguard. If true, then
     // they will be handled here for specific media types such as music, otherwise
     // the audio service will bring up the volume dialog.
     private static final boolean KEYGUARD_MANAGES_VOLUME = true;
+    private static final boolean DEBUG = false;
+    private static final String TAG = "KeyguardViewBase";
+
+    private KeyguardSecurityContainer mSecurityContainer;
 
     public KeyguardViewBase(Context context) {
         this(context, null);
@@ -57,20 +81,181 @@
         super(context, attrs);
     }
 
-    /**
-     * Called when the screen turned off.
-     */
-    abstract public void onScreenTurnedOff();
+    @Override
+    protected void dispatchDraw(Canvas canvas) {
+        super.dispatchDraw(canvas);
+        if (mViewMediatorCallback != null) {
+            mViewMediatorCallback.keyguardDoneDrawing();
+        }
+    }
 
     /**
-     * Called when the screen turned on.
+     * Sets an action to run when keyguard finishes.
+     *
+     * @param action
      */
-    abstract public void onScreenTurnedOn();
+    public void setOnDismissAction(OnDismissAction action) {
+        mDismissAction = action;
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        mSecurityContainer =
+                (KeyguardSecurityContainer) findViewById(R.id.keyguard_security_container);
+        mLockPatternUtils = new LockPatternUtils(mContext);
+        mSecurityContainer.setLockPatternUtils(mLockPatternUtils);
+        mSecurityContainer.setSecurityCallback(this);
+        mSecurityContainer.showPrimarySecurityScreen(false);
+        // mSecurityContainer.updateSecurityViews(false /* not bouncing */);
+        setBackButtonEnabled(false);
+    }
 
     /**
      * Called when the view needs to be shown.
      */
-    abstract public void show();
+    public void show() {
+        if (DEBUG) Log.d(TAG, "show()");
+        mSecurityContainer.showPrimarySecurityScreen(false);
+    }
+
+    /**
+     *  Dismisses the keyguard by going to the next screen or making it gone.
+     */
+    public void dismiss() {
+        dismiss(false);
+    }
+
+    private void setBackButtonEnabled(boolean enabled) {
+        setSystemUiVisibility(enabled ?
+                getSystemUiVisibility() & ~View.STATUS_BAR_DISABLE_BACK :
+                getSystemUiVisibility() | View.STATUS_BAR_DISABLE_BACK);
+    }
+
+    protected void showBouncer(boolean show) {
+        CharSequence what = getContext().getResources().getText(
+                show ? R.string.keyguard_accessibility_show_bouncer
+                        : R.string.keyguard_accessibility_hide_bouncer);
+        announceForAccessibility(what);
+        announceCurrentSecurityMethod();
+    }
+
+    public boolean handleBackKey() {
+        if (mSecurityContainer.getCurrentSecuritySelection() == SecurityMode.Account) {
+            // go back to primary screen and re-disable back
+            setBackButtonEnabled(false);
+            mSecurityContainer.showPrimarySecurityScreen(false /*turningOff*/);
+            return true;
+        }
+        if (mSecurityContainer.getCurrentSecuritySelection() != SecurityMode.None) {
+            mSecurityContainer.dismiss(false);
+            return true;
+        }
+        return false;
+    }
+
+    protected void announceCurrentSecurityMethod() {
+        mSecurityContainer.announceCurrentSecurityMethod();
+    }
+
+    protected KeyguardSecurityContainer getSecurityContainer() {
+        return mSecurityContainer;
+    }
+
+    /**
+     * Extend display timeout
+     * @param timeout duration to delay timeout, in ms.
+     */
+    @Override
+    public void userActivity(long timeout) {
+        if (mViewMediatorCallback != null) {
+            mViewMediatorCallback.userActivity(timeout);
+        }
+    }
+
+    @Override
+    public boolean dismiss(boolean authenticated) {
+        return mSecurityContainer.showNextSecurityScreenOrFinish(authenticated);
+    }
+
+    /**
+     * Authentication has happened and it's time to dismiss keyguard. This function
+     * should clean up and inform KeyguardViewMediator.
+     */
+    @Override
+    public void finish() {
+        // If the alternate unlock was suppressed, it can now be safely
+        // enabled because the user has left keyguard.
+        KeyguardUpdateMonitor.getInstance(mContext).setAlternateUnlockEnabled(true);
+
+        // If there's a pending runnable because the user interacted with a widget
+        // and we're leaving keyguard, then run it.
+        boolean deferKeyguardDone = false;
+        if (mDismissAction != null) {
+            deferKeyguardDone = mDismissAction.onDismiss();
+            mDismissAction = null;
+        }
+        if (mViewMediatorCallback != null) {
+            if (deferKeyguardDone) {
+                mViewMediatorCallback.keyguardDonePending();
+            } else {
+                mViewMediatorCallback.keyguardDone(true);
+            }
+        }
+    }
+
+    @Override
+    public void onSecurityModeChanged(SecurityMode securityMode, boolean needsInput) {
+        // Enable or disable the back button based on security mode
+        if (securityMode == SecurityMode.Account && !mLockPatternUtils.isPermanentlyLocked()) {
+            // we're showing account as a backup, provide a way to get back to primary
+            setBackButtonEnabled(true);
+        }
+
+        if (mViewMediatorCallback != null) {
+            mViewMediatorCallback.setNeedsInput(needsInput);
+        }
+    }
+
+    public void userActivity() {
+        if (mViewMediatorCallback != null) {
+            mViewMediatorCallback.userActivity();
+        }
+    }
+
+    protected void onUserActivityTimeoutChanged() {
+        if (mViewMediatorCallback != null) {
+            mViewMediatorCallback.onUserActivityTimeoutChanged();
+        }
+    }
+
+    /**
+     * Called when the screen turned off.
+     */
+    protected void onScreenTurnedOff() {
+        if (DEBUG) Log.d(TAG, String.format("screen off, instance %s at %s",
+                Integer.toHexString(hashCode()), SystemClock.uptimeMillis()));
+        // Once the screen turns off, we no longer consider this to be first boot and we want the
+        // biometric unlock to start next time keyguard is shown.
+        KeyguardUpdateMonitor.getInstance(mContext).setAlternateUnlockEnabled(true);
+        mSecurityContainer.showPrimarySecurityScreen(true);
+        mSecurityContainer.onPause();
+        clearFocus();
+    }
+
+    /**
+     * Called when the screen turned on.
+     */
+    protected void onScreenTurnedOn() {
+        if (DEBUG) Log.d(TAG, "screen on, instance " + Integer.toHexString(hashCode()));
+        mSecurityContainer.showPrimarySecurityScreen(false);
+        mSecurityContainer.onResume(KeyguardSecurityView.SCREEN_ON);
+
+        // This is a an attempt to fix bug 7137389 where the device comes back on but the entire
+        // layout is blank but forcing a layout causes it to reappear (e.g. with with
+        // hierarchyviewer).
+        requestLayout();
+        requestFocus();
+    }
 
     /**
      * Verify that the user can get past the keyguard securely.  This is called,
@@ -79,7 +264,24 @@
      *
      * The result will be propogated back via {@link KeyguardViewCallback#keyguardDone(boolean)}
      */
-    abstract public void verifyUnlock();
+    public void verifyUnlock() {
+        SecurityMode securityMode = mSecurityContainer.getSecurityMode();
+        if (securityMode == KeyguardSecurityModel.SecurityMode.None) {
+            if (mViewMediatorCallback != null) {
+                mViewMediatorCallback.keyguardDone(true);
+            }
+        } else if (securityMode != KeyguardSecurityModel.SecurityMode.Pattern
+                && securityMode != KeyguardSecurityModel.SecurityMode.PIN
+                && securityMode != KeyguardSecurityModel.SecurityMode.Password) {
+            // can only verify unlock when in pattern/password mode
+            if (mViewMediatorCallback != null) {
+                mViewMediatorCallback.keyguardDone(false);
+            }
+        } else {
+            // otherwise, go to the unlock screen, see if they can verify it
+            mSecurityContainer.verifyUnlock();
+        }
+    }
 
     /**
      * Called before this view is being removed.
@@ -183,7 +385,7 @@
         return false;
     }
 
-    void handleMediaKeyEvent(KeyEvent keyEvent) {
+    private void handleMediaKeyEvent(KeyEvent keyEvent) {
         IAudioService audioService = IAudioService.Stub.asInterface(
                 ServiceManager.checkService(Context.AUDIO_SERVICE));
         if (audioService != null) {
@@ -206,8 +408,91 @@
         }
     }
 
+    /**
+     * In general, we enable unlocking the insecure keyguard with the menu key. However, there are
+     * some cases where we wish to disable it, notably when the menu button placement or technology
+     * is prone to false positives.
+     *
+     * @return true if the menu key should be enabled
+     */
+    private static final String ENABLE_MENU_KEY_FILE = "/data/local/enable_menu_key";
+    private boolean shouldEnableMenuKey() {
+        final Resources res = getResources();
+        final boolean configDisabled = res.getBoolean(R.bool.config_disableMenuKeyInLockScreen);
+        final boolean isTestHarness = ActivityManager.isRunningInTestHarness();
+        final boolean fileOverride = (new File(ENABLE_MENU_KEY_FILE)).exists();
+        return !configDisabled || isTestHarness || fileOverride;
+    }
+
+    public boolean handleMenuKey() {
+        // The following enables the MENU key to work for testing automation
+        if (shouldEnableMenuKey()) {
+            dismiss();
+            return true;
+        }
+        return false;
+    }
+
     public void setViewMediatorCallback(
             KeyguardViewMediator.ViewMediatorCallback viewMediatorCallback) {
         mViewMediatorCallback = viewMediatorCallback;
+        // Update ViewMediator with the current input method requirements
+        mViewMediatorCallback.setNeedsInput(mSecurityContainer.needsInput());
     }
+
+    protected KeyguardActivityLauncher getActivityLauncher() {
+        return mActivityLauncher;
+    }
+
+    private final KeyguardActivityLauncher mActivityLauncher = new KeyguardActivityLauncher() {
+        @Override
+        Context getContext() {
+            return mContext;
+        }
+
+        @Override
+        void setOnDismissAction(OnDismissAction action) {
+            KeyguardViewBase.this.setOnDismissAction(action);
+        }
+
+        @Override
+        LockPatternUtils getLockPatternUtils() {
+            return mLockPatternUtils;
+        }
+
+        @Override
+        void requestDismissKeyguard() {
+            KeyguardViewBase.this.dismiss(false);
+        }
+    };
+
+    public void showAssistant() {
+        final Intent intent = ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE))
+          .getAssistIntent(mContext, true, UserHandle.USER_CURRENT);
+
+        if (intent == null) return;
+
+        final ActivityOptions opts = ActivityOptions.makeCustomAnimation(mContext,
+                R.anim.keyguard_action_assist_enter, R.anim.keyguard_action_assist_exit,
+                getHandler(), null);
+
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        mActivityLauncher.launchActivityWithAnimation(intent, false, opts.toBundle(), null, null);
+    }
+
+    public void launchCamera() {
+        mActivityLauncher.launchCamera(getHandler(), null);
+    }
+
+    protected void setLockPatternUtils(LockPatternUtils utils) {
+        mLockPatternUtils = utils;
+        mSecurityContainer.setLockPatternUtils(utils);
+    }
+
+    protected abstract void onUserSwitching(boolean switching);
+
+    protected abstract void onCreateOptions(Bundle options);
+
+    protected abstract void onExternalMotionEvent(MotionEvent event);
+
 }
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardViewManager.java b/packages/Keyguard/src/com/android/keyguard/KeyguardViewManager.java
index f2853c8..baf520e 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardViewManager.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardViewManager.java
@@ -18,11 +18,15 @@
 
 import android.graphics.Bitmap;
 import android.graphics.drawable.BitmapDrawable;
+
 import com.android.internal.policy.IKeyguardShowCallback;
 import com.android.internal.widget.LockPatternUtils;
 
+import org.xmlpull.v1.XmlPullParser;
+
 import android.app.ActivityManager;
 import android.appwidget.AppWidgetManager;
+import android.content.ContentResolver;
 import android.content.Context;
 import android.content.pm.ActivityInfo;
 import android.content.res.Configuration;
@@ -38,6 +42,7 @@
 import android.os.Parcelable;
 import android.os.RemoteException;
 import android.os.SystemProperties;
+import android.provider.Settings;
 import android.util.Log;
 import android.util.Slog;
 import android.util.SparseArray;
@@ -75,7 +80,7 @@
     private boolean mNeedsInput = false;
 
     private ViewManagerHost mKeyguardHost;
-    private KeyguardHostView mKeyguardView;
+    private KeyguardViewBase mKeyguardView;
 
     private boolean mScreenOn = false;
     private LockPatternUtils mLockPatternUtils;
@@ -259,6 +264,7 @@
     }
 
     SparseArray<Parcelable> mStateContainer = new SparseArray<Parcelable>();
+    private int mCurrentLayout;
 
     private void maybeCreateKeyguardLocked(boolean enableScreenRotation, boolean force,
             Bundle options) {
@@ -306,7 +312,14 @@
         if (force || mKeyguardView == null) {
             mKeyguardHost.setCustomBackground(null);
             mKeyguardHost.removeAllViews();
-            inflateKeyguardView(options);
+            int layout = allowNotificationsOnSecureKeyguard()
+                    ? R.layout.keyguard_simple_host_view
+                    : R.layout.keyguard_host_view;
+            if (mCurrentLayout != layout) {
+                mStateContainer.clear(); // don't restore to the wrong view hierarchy
+                mCurrentLayout = layout;
+            }
+            mKeyguardView = inflateKeyguardView(options, layout);
             mKeyguardView.requestFocus();
         }
         updateUserActivityTimeoutInWindowLayoutParams();
@@ -315,38 +328,24 @@
         mKeyguardHost.restoreHierarchyState(mStateContainer);
     }
 
-    private void inflateKeyguardView(Bundle options) {
+    private boolean allowNotificationsOnSecureKeyguard() {
+        ContentResolver cr = mContext.getContentResolver();
+        return Settings.Secure.getInt(cr, Settings.Secure.LOCK_SCREEN_ALLOW_NOTIFICATIONS, 0) == 1;
+    }
+
+    private KeyguardViewBase inflateKeyguardView(Bundle options, int layoutId) {
         View v = mKeyguardHost.findViewById(R.id.keyguard_host_view);
         if (v != null) {
             mKeyguardHost.removeView(v);
         }
         final LayoutInflater inflater = LayoutInflater.from(mContext);
-        View view = inflater.inflate(R.layout.keyguard_host_view, mKeyguardHost, true);
-        mKeyguardView = (KeyguardHostView) view.findViewById(R.id.keyguard_host_view);
-        mKeyguardView.setLockPatternUtils(mLockPatternUtils);
-        mKeyguardView.setViewMediatorCallback(mViewMediatorCallback);
-        mKeyguardView.initializeSwitchingUserState(options != null &&
-                options.getBoolean(IS_SWITCHING_USER));
-
-        // HACK
-        // The keyguard view will have set up window flags in onFinishInflate before we set
-        // the view mediator callback. Make sure it knows the correct IME state.
-        if (mViewMediatorCallback != null) {
-            KeyguardPasswordView kpv = (KeyguardPasswordView) mKeyguardView.findViewById(
-                    R.id.keyguard_password_view);
-
-            if (kpv != null) {
-                mViewMediatorCallback.setNeedsInput(kpv.needsInput());
-            }
-        }
-
-        if (options != null) {
-            int widgetToShow = options.getInt(LockPatternUtils.KEYGUARD_SHOW_APPWIDGET,
-                    AppWidgetManager.INVALID_APPWIDGET_ID);
-            if (widgetToShow != AppWidgetManager.INVALID_APPWIDGET_ID) {
-                mKeyguardView.goToWidget(widgetToShow);
-            }
-        }
+        View view = inflater.inflate(layoutId, mKeyguardHost, true);
+        KeyguardViewBase keyguard = (KeyguardViewBase) view.findViewById(R.id.keyguard_host_view);
+        keyguard.setLockPatternUtils(mLockPatternUtils);
+        keyguard.setViewMediatorCallback(mViewMediatorCallback);
+        keyguard.onUserSwitching(options != null && options.getBoolean(IS_SWITCHING_USER));
+        keyguard.onCreateOptions(options);
+        return keyguard;
     }
 
     public void updateUserActivityTimeout() {
@@ -541,7 +540,7 @@
 
     public void dispatch(MotionEvent event) {
         if (mKeyguardView != null) {
-            mKeyguardView.dispatch(event);
+            mKeyguardView.onExternalMotionEvent(event);
         }
     }
 
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardViewStateManager.java b/packages/Keyguard/src/com/android/keyguard/KeyguardViewStateManager.java
index a7b72e2..e47edf3 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardViewStateManager.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardViewStateManager.java
@@ -105,11 +105,6 @@
     }
 
     public void showBouncer(boolean show) {
-        CharSequence what = mKeyguardHostView.getContext().getResources().getText(
-                show ? R.string.keyguard_accessibility_show_bouncer
-                        : R.string.keyguard_accessibility_hide_bouncer);
-        mKeyguardHostView.announceForAccessibility(what);
-        mKeyguardHostView.announceCurrentSecurityMethod();
         mChallengeLayout.showBouncer();
     }
 
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_battery.xml b/packages/SystemUI/res/layout/quick_settings_tile_battery.xml
index f3b894c..1f39aef 100644
--- a/packages/SystemUI/res/layout/quick_settings_tile_battery.xml
+++ b/packages/SystemUI/res/layout/quick_settings_tile_battery.xml
@@ -15,6 +15,7 @@
 -->
 <LinearLayout
         xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:layout_gravity="top"
@@ -27,6 +28,7 @@
             android:layout_height="32dp"
             android:padding="3dp"
             android:layout_gravity="top|center_horizontal"
+            systemui:frameColor="@color/qs_batterymeter_frame_color"
             />
     <TextView
             style="@style/TextAppearance.QuickSettings.TileView"
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 70b30e6..5d6368e 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -192,7 +192,7 @@
     <string name="quick_settings_location_off_label" msgid="7464544086507331459">"Localisation désactivée"</string>
     <string name="quick_settings_media_device_label" msgid="1302906836372603762">"Appareil multimédia"</string>
     <string name="quick_settings_rssi_label" msgid="7725671335550695589">"RSSI"</string>
-    <string name="quick_settings_rssi_emergency_only" msgid="2713774041672886750">"Appels d\'urgence uniquement"</string>
+    <string name="quick_settings_rssi_emergency_only" msgid="2713774041672886750">"Appels d\'urgence"</string>
     <string name="quick_settings_settings_label" msgid="5326556592578065401">"Paramètres"</string>
     <string name="quick_settings_time_label" msgid="4635969182239736408">"Heure"</string>
     <string name="quick_settings_user_label" msgid="5238995632130897840">"Moi"</string>
@@ -200,7 +200,7 @@
     <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Non connecté"</string>
     <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Aucun réseau"</string>
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi désactivé"</string>
-    <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Écran sur lequel l\'affichage est diffusé"</string>
+    <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Caster l\'écran"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Luminosité"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMATIQUE"</string>
     <string name="quick_settings_inversion_label" msgid="1666358784283020762">"Mode d\'inversion des couleurs"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index ac5f7ff..59c64b5 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -198,7 +198,7 @@
     <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Niet verbonden"</string>
     <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Geen netwerk"</string>
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wifi uit"</string>
-    <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Scherm sturen"</string>
+    <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Scherm casten"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Helderheid"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMATISCH"</string>
     <string name="quick_settings_inversion_label" msgid="1666358784283020762">"Modus voor kleurinversie"</string>
diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml
index 047570f..734abdc 100644
--- a/packages/SystemUI/res/values/attrs.xml
+++ b/packages/SystemUI/res/values/attrs.xml
@@ -42,7 +42,9 @@
         <attr name="decayTime" format="integer" />
         <attr name="orientation" />
     </declare-styleable>
-
+    <declare-styleable name="BatteryMeterView">
+        <attr name="frameColor" format="color" />
+    </declare-styleable>
     <attr name="orientation">
         <enum name="horizontal" value="0" />
         <enum name="vertical" value="1" />
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 9301618..e525fbb 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -35,6 +35,7 @@
     <color name="batterymeter_frame_color">#66FFFFFF</color><!-- 40% white -->
     <color name="batterymeter_charge_color">#FFFFFFFF</color>
     <color name="batterymeter_bolt_color">#FFFFFFFF</color>
+    <color name="qs_batterymeter_frame_color">#FF404040</color>
     <color name="status_bar_clock_color">#FFFFFFFF</color>
     <drawable name="notification_item_background_color">#ff111111</drawable>
     <drawable name="notification_item_background_color_pressed">#ff454545</drawable>
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
index 5579e19..19d06be 100755
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
@@ -68,6 +68,7 @@
 
     private final Path mShapePath = new Path();
     private final Path mClipPath = new Path();
+    private final Path mTextPath = new Path();
 
     private class BatteryTracker extends BroadcastReceiver {
         public static final int UNKNOWN_LEVEL = -1;
@@ -177,6 +178,10 @@
         super(context, attrs, defStyle);
 
         final Resources res = context.getResources();
+        TypedArray atts = context.obtainStyledAttributes(attrs, R.styleable.BatteryMeterView,
+                defStyle, 0);
+        final int frameColor = atts.getColor(R.styleable.BatteryMeterView_frameColor,
+                res.getColor(R.color.batterymeter_frame_color));
         TypedArray levels = res.obtainTypedArray(R.array.batterymeter_color_levels);
         TypedArray colors = res.obtainTypedArray(R.array.batterymeter_color_values);
 
@@ -188,15 +193,13 @@
         }
         levels.recycle();
         colors.recycle();
+        atts.recycle();
         mShowPercent = ENABLE_PERCENT && 0 != Settings.System.getInt(
                 context.getContentResolver(), "status_bar_show_battery_percent", 0);
-        if (mShowPercent) {
-            setLayerType(View.LAYER_TYPE_SOFTWARE, null);
-        }
         mWarningString = context.getString(R.string.battery_meter_very_low_overlay_symbol);
 
         mFramePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
-        mFramePaint.setColor(res.getColor(R.color.batterymeter_frame_color));
+        mFramePaint.setColor(frameColor);
         mFramePaint.setDither(true);
         mFramePaint.setStrokeWidth(0);
         mFramePaint.setStyle(Paint.Style.FILL_AND_STROKE);
@@ -353,6 +356,29 @@
             }
         }
 
+        // compute percentage text
+        boolean pctOpaque = false;
+        float pctX = 0, pctY = 0;
+        String pctText = null;
+        if (!tracker.plugged && level > EMPTY && mShowPercent
+                && !(tracker.level == 100 && !SHOW_100_PERCENT)) {
+            mTextPaint.setColor(getColorForLevel(level));
+            mTextPaint.setTextSize(height *
+                    (SINGLE_DIGIT_PERCENT ? 0.75f
+                            : (tracker.level == 100 ? 0.38f : 0.5f)));
+            mTextHeight = -mTextPaint.getFontMetrics().ascent;
+            pctText = String.valueOf(SINGLE_DIGIT_PERCENT ? (level/10) : level);
+            pctX = mWidth * 0.5f;
+            pctY = (mHeight + mTextHeight) * 0.47f;
+            pctOpaque = levelTop > pctY;
+            if (!pctOpaque) {
+                mTextPath.reset();
+                mTextPaint.getTextPath(pctText, 0, pctText.length(), pctX, pctY, mTextPath);
+                // cut the percentage text out of the overall shape
+                mShapePath.op(mTextPath, Path.Op.DIFFERENCE);
+            }
+        }
+
         // draw the battery shape background
         c.drawPath(mShapePath, mFramePaint);
 
@@ -369,29 +395,9 @@
                 final float x = mWidth * 0.5f;
                 final float y = (mHeight + mWarningTextHeight) * 0.48f;
                 c.drawText(mWarningString, x, y, mWarningTextPaint);
-            } else if (mShowPercent && !(tracker.level == 100 && !SHOW_100_PERCENT)) {
+            } else if (pctOpaque) {
                 // draw the percentage text
-                mTextPaint.setColor(getColorForLevel(level));
-                mTextPaint.setTextSize(height *
-                        (SINGLE_DIGIT_PERCENT ? 0.75f
-                                : (tracker.level == 100 ? 0.38f : 0.5f)));
-                mTextHeight = -mTextPaint.getFontMetrics().ascent;
-
-                final String str = String.valueOf(SINGLE_DIGIT_PERCENT ? (level/10) : level);
-                final float x = mWidth * 0.5f;
-                final float y = (mHeight + mTextHeight) * 0.47f;
-
-                boolean opaque = levelTop > y;
-                if (opaque) {
-                    mTextPaint.setXfermode(null);
-                } else {
-                    mTextPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
-                }
-
-                c.drawText(str,
-                        x,
-                        y,
-                        mTextPaint);
+                c.drawText(pctText, pctX, pctY, mTextPaint);
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index b72c25d..44e7dac 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -1914,7 +1914,7 @@
             }
             if (sbModeChanged || nbModeChanged) {
                 // update transient bar autohide
-                if (sbMode == MODE_SEMI_TRANSPARENT || nbMode == MODE_SEMI_TRANSPARENT) {
+                if (mStatusBarMode == MODE_SEMI_TRANSPARENT || mNavigationBarMode == MODE_SEMI_TRANSPARENT) {
                     scheduleAutohide();
                 } else {
                     cancelAutohide();
diff --git a/policy/src/com/android/internal/policy/impl/BarController.java b/policy/src/com/android/internal/policy/impl/BarController.java
index 0ce4b12..fc49a569 100644
--- a/policy/src/com/android/internal/policy/impl/BarController.java
+++ b/policy/src/com/android/internal/policy/impl/BarController.java
@@ -108,7 +108,7 @@
         if (mWin != null) {
             if (win != null && (win.getAttrs().privateFlags
                     & WindowManager.LayoutParams.PRIVATE_FLAG_INHERIT_TRANSLUCENT_DECOR) == 0) {
-                if ((win.getAttrs().flags & mTranslucentWmFlag) != 0) {
+                if ((PolicyControl.getWindowFlags(win, null) & mTranslucentWmFlag) != 0) {
                     vis |= mTranslucentFlag;
                 } else {
                     vis &= ~mTranslucentFlag;
diff --git a/policy/src/com/android/internal/policy/impl/ImmersiveModeConfirmation.java b/policy/src/com/android/internal/policy/impl/ImmersiveModeConfirmation.java
index b734c41..507d385 100644
--- a/policy/src/com/android/internal/policy/impl/ImmersiveModeConfirmation.java
+++ b/policy/src/com/android/internal/policy/impl/ImmersiveModeConfirmation.java
@@ -117,7 +117,7 @@
     }
 
     public void immersiveModeChanged(String pkg, boolean isImmersiveMode) {
-        if (pkg == null) {
+        if (pkg == null || PolicyControl.disableImmersiveConfirmation(pkg)) {
             return;
         }
         mHandler.removeMessages(H.SHOW);
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index a0ea53c..c73d90a 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -22,6 +22,8 @@
 import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
 import static android.view.WindowManager.LayoutParams.*;
 
+import android.animation.Animator;
+import android.animation.ObjectAnimator;
 import android.app.ActivityOptions;
 import android.transition.Scene;
 import android.transition.Transition;
@@ -88,6 +90,7 @@
 import android.view.ViewParent;
 import android.view.ViewRootImpl;
 import android.view.ViewStub;
+import android.view.ViewTreeObserver;
 import android.view.Window;
 import android.view.WindowManager;
 import android.view.accessibility.AccessibilityEvent;
@@ -114,6 +117,8 @@
     private final static String TAG = "PhoneWindow";
 
     private final static boolean SWEEP_OPEN_MENU = false;
+    private static final long MAX_TRANSITION_START_WAIT = 500;
+    private static final long MAX_TRANSITION_FINISH_WAIT = 1000;
 
     /**
      * Simple callback used by the context menu and its submenus. The options
@@ -136,22 +141,21 @@
     private ViewGroup mContentParent;
 
     SurfaceHolder.Callback2 mTakeSurfaceCallback;
-    
+
     InputQueue.Callback mTakeInputQueueCallback;
-    
+
     private boolean mIsFloating;
 
     private LayoutInflater mLayoutInflater;
 
     private TextView mTitleView;
-    
+
     private ActionBarView mActionBar;
     private ActionMenuPresenterCallback mActionMenuPresenterCallback;
     private PanelMenuPresenterCallback mPanelMenuPresenterCallback;
 
     private TransitionManager mTransitionManager;
     private Scene mContentScene;
-    private Bundle mTransitionOptions;
 
     // The icon resource has been explicitly set elsewhere
     // and should not be overwritten with a default.
@@ -233,6 +237,10 @@
         }
     };
 
+    private ActivityOptions mActivityOptions;
+    private SceneTransitionListener mSceneTransitionListener;
+    private boolean mFadeEarly = true;
+
     static class WindowManagerHolder {
         static final IWindowManager sWindowManager = IWindowManager.Stub.asInterface(
                 ServiceManager.getService("window"));
@@ -303,11 +311,6 @@
     }
 
     @Override
-    public void setTransitionOptions(Bundle options) {
-        mTransitionOptions = options;
-    }
-
-    @Override
     public void setContentView(int layoutResID) {
         // Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window
         // decor, when theme attributes and the like are crystalized. Do not check the feature
@@ -378,26 +381,11 @@
     }
 
     private void transitionTo(Scene scene) {
-        Transition selected = null;
-        if (mTransitionOptions != null) {
-            final ActivityOptions opts = new ActivityOptions(mTransitionOptions);
-            mTransitionOptions = null;
-
-            String selectedName = null;
-            for (String sceneName : opts.getDestSceneNames()) {
-                final Transition t = mTransitionManager.getNamedTransition(sceneName, scene);
-                if (t != null) {
-                    // TODO handle args/state; inject into t/clone with params
-                    selected = t;
-                    selectedName = sceneName;
-                    break;
-                }
+        if (mContentScene == null) {
+            scene.enter();
+            if (mActivityOptions != null) {
+                new EnterScene().start();
             }
-            opts.dispatchSceneTransitionStarted(selectedName);
-        }
-
-        if (selected != null) {
-            TransitionManager.go(scene, selected);
         } else {
             mTransitionManager.transitionTo(scene);
         }
@@ -413,11 +401,11 @@
     public void takeSurface(SurfaceHolder.Callback2 callback) {
         mTakeSurfaceCallback = callback;
     }
-    
+
     public void takeInputQueue(InputQueue.Callback callback) {
         mTakeInputQueueCallback = callback;
     }
-    
+
     @Override
     public boolean isFloating() {
         return mIsFloating;
@@ -3553,6 +3541,12 @@
         return mVolumeControlStreamType;
     }
 
+    private boolean isTranslucent() {
+        TypedArray a = getWindowStyle();
+        return a.getBoolean(a.getResourceId(
+                com.android.internal.R.styleable.Window_windowIsTranslucent, 0), false);
+    }
+
     private static final class DrawableFeatureState {
         DrawableFeatureState(int _featureId) {
             featureId = _featureId;
@@ -3986,4 +3980,218 @@
     void sendCloseSystemWindows(String reason) {
         PhoneWindowManager.sendCloseSystemWindows(getContext(), reason);
     }
+
+    @Override
+    public void setTransitionOptions(ActivityOptions options, SceneTransitionListener listener) {
+        mSceneTransitionListener = listener;
+        mActivityOptions = options;
+    }
+
+    @Override
+    public void setEarlyBackgroundTransition(boolean fadeEarly) {
+        mFadeEarly = fadeEarly;
+    }
+
+    @Override
+    public void startExitTransition(ActivityOptions activityOptions) {
+        Transition transition = mTransitionManager.getNamedTransition(getContentScene(), "null");
+        if (transition == null) {
+            transition = TransitionManager.getDefaultTransition().clone();
+        }
+        activityOptions.setExitTransition(transition, new ActivityOptions.SharedElementSource() {
+            @Override
+            public int getTextureId() {
+                // TODO: move shared elements to a layer and return the texture id
+                recurseHideExitingSharedElements(mContentParent);
+                return 0;
+            }
+        });
+        ViewGroup sceneRoot = getContentScene().getSceneRoot();
+        TransitionManager.beginDelayedTransition(sceneRoot, transition);
+        recurseExitNonSharedElements(mContentParent);
+    }
+
+    private static void recurseExitNonSharedElements(ViewGroup viewGroup) {
+        int numChildren = viewGroup.getChildCount();
+        for (int i = 0; i < numChildren; i++) {
+            View child = viewGroup.getChildAt(i);
+            if (child.getSharedElementName() != null || (child.getVisibility() != View.VISIBLE)) {
+                continue;
+            }
+            if (child instanceof ViewGroup && !((ViewGroup)child).isTransitionGroup()) {
+                recurseExitNonSharedElements((ViewGroup) child);
+            } else {
+                child.setVisibility(View.INVISIBLE);
+            }
+        }
+    }
+
+    private static void recurseHideViews(ViewGroup viewGroup, ArrayList<View> nonSharedElements,
+            ArrayList<View> sharedElements) {
+        int numChildren = viewGroup.getChildCount();
+        for (int i = 0; i < numChildren; i++) {
+            View child = viewGroup.getChildAt(i);
+            if (child.getVisibility() != View.VISIBLE) {
+                continue;
+            }
+            if (child.getSharedElementName() != null) {
+                sharedElements.add(child);
+                child.setVisibility(View.INVISIBLE);
+            } else if (child instanceof ViewGroup && !((ViewGroup)child).isTransitionGroup()) {
+                recurseHideViews((ViewGroup) child, nonSharedElements, sharedElements);
+            } else {
+                nonSharedElements.add(child);
+                child.setVisibility(View.INVISIBLE);
+            }
+        }
+    }
+
+    private static void recurseHideExitingSharedElements(ViewGroup viewGroup) {
+        int numChildren = viewGroup.getChildCount();
+        for (int i = 0; i < numChildren; i++) {
+            View child = viewGroup.getChildAt(i);
+            if (child.getVisibility() != View.VISIBLE) {
+                continue;
+            }
+            if (child.getSharedElementName() != null) {
+                child.setVisibility(View.INVISIBLE);
+            } else if (child instanceof ViewGroup) {
+                ViewGroup childViewGroup = (ViewGroup) child;
+                recurseHideExitingSharedElements(childViewGroup);
+            }
+        }
+    }
+
+    /**
+     * Provides code for handling the Activity transition entering scene.
+     * When the first scene is laid out (onPreDraw), it makes views invisible.
+     * It then starts the entering transition by making non-shared elements visible. When
+     * the entering transition is started, the calling Activity is notified that
+     * this Activity is ready to receive the shared element. When the calling Activity notifies
+     * that the shared element is ready, this Activity is notified through the
+     * SceneTransitionListener.
+     *
+     * This class also takes into account fading the background -- either waiting until the
+     * shared element is ready or the calling Activity's exit transition is complete.
+     */
+    private class EnterScene implements ViewTreeObserver.OnPreDrawListener, Runnable,
+            ActivityOptions.ActivityTransitionTarget, Animator.AnimatorListener {
+        private boolean mSharedElementReadyReceived;
+        private boolean mAllDone;
+        private Handler mHandler = new Handler();
+        private boolean mEnterTransitionStarted;
+        private ArrayList<View> mSharedElements = new ArrayList<View>();
+
+        public EnterScene() {
+            mSceneTransitionListener.nullPendingTransition();
+            Drawable background = getDecorView().getBackground();
+            if (background != null) {
+                setBackgroundDrawable(null);
+                background.setAlpha(0);
+                setBackgroundDrawable(background);
+            }
+            mSceneTransitionListener.convertToTranslucent();
+        }
+
+        @Override
+        public boolean onPreDraw() {
+            ViewTreeObserver observer = mContentParent.getViewTreeObserver();
+            observer.removeOnPreDrawListener(this);
+            if (!mEnterTransitionStarted && mSceneTransitionListener != null) {
+                mEnterTransitionStarted = true;
+                ArrayList<View> enteringViews = new ArrayList<View>();
+                recurseHideViews(mContentParent, enteringViews, mSharedElements);
+                Transition transition = getTransitionManager().getNamedTransition("null",
+                        mContentScene);
+                if (transition == null) {
+                    transition = TransitionManager.getDefaultTransition().clone();
+                }
+                TransitionManager.beginDelayedTransition(mContentParent, transition);
+                for (View hidden : enteringViews) {
+                    hidden.setVisibility(View.VISIBLE);
+                }
+                observer.addOnPreDrawListener(this);
+            } else {
+                mHandler.postDelayed(this, MAX_TRANSITION_START_WAIT);
+                mActivityOptions.dispatchSceneTransitionStarted(this);
+            }
+            return true;
+        }
+
+        public void start() {
+            ViewTreeObserver observer = mContentParent.getViewTreeObserver();
+            observer.addOnPreDrawListener(this);
+        }
+
+        @Override
+        public void run() {
+            exitTransitionComplete();
+        }
+
+        @Override
+        public void sharedElementTransitionComplete() {
+            if (!mSharedElementReadyReceived) {
+                mSharedElementReadyReceived = true;
+                mHandler.removeCallbacks(this);
+                mHandler.postDelayed(this, MAX_TRANSITION_FINISH_WAIT);
+                for (View sharedElement: mSharedElements) {
+                    sharedElement.setVisibility(View.VISIBLE);
+                }
+                mSharedElements.clear();
+                mContentParent.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
+                    @Override
+                    public boolean onPreDraw() {
+                        mContentParent.getViewTreeObserver().removeOnPreDrawListener(this);
+                        mSceneTransitionListener.enterSharedElement(
+                                mActivityOptions.getSceneTransitionArgs());
+                        return false;
+                    }
+                });
+                if (mFadeEarly) {
+                    fadeInBackground();
+                }
+            }
+        }
+
+        private void fadeInBackground() {
+            Drawable background = getDecorView().getBackground();
+            if (background == null) {
+                mSceneTransitionListener.convertFromTranslucent();
+            } else {
+                ObjectAnimator animator = ObjectAnimator.ofInt(background, "alpha", 255);
+                animator.addListener(this);
+                animator.start();
+            }
+        }
+
+        @Override
+        public void exitTransitionComplete() {
+            if (mAllDone) {
+                return;
+            }
+            mAllDone = true;
+            sharedElementTransitionComplete();
+            mHandler.removeCallbacks(this);
+            if (!mFadeEarly) {
+                fadeInBackground();
+            }
+        }
+
+        @Override
+        public void onAnimationStart(Animator animation) {
+        }
+
+        @Override
+        public void onAnimationEnd(Animator animation) {
+            mSceneTransitionListener.convertFromTranslucent();
+        }
+
+        @Override
+        public void onAnimationCancel(Animator animation) {
+        }
+
+        @Override
+        public void onAnimationRepeat(Animator animation) {
+        }
+    }
 }
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index ce6166a..b6a4052 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -526,6 +526,9 @@
             resolver.registerContentObserver(Settings.System.getUriFor(
                     Settings.Secure.IMMERSIVE_MODE_CONFIRMATIONS), false, this,
                     UserHandle.USER_ALL);
+            resolver.registerContentObserver(Settings.Global.getUriFor(
+                    Settings.Global.POLICY_CONTROL), false, this,
+                    UserHandle.USER_ALL);
             updateSettings();
         }
 
@@ -1167,6 +1170,7 @@
             if (mImmersiveModeConfirmation != null) {
                 mImmersiveModeConfirmation.loadSetting();
             }
+            PolicyControl.reloadFromSetting(mContext);
         }
         if (updateRotation) {
             updateRotation(true);
@@ -2564,7 +2568,7 @@
 
     @Override
     public void getContentInsetHintLw(WindowManager.LayoutParams attrs, Rect contentInset) {
-        final int fl = attrs.flags;
+        final int fl = PolicyControl.getWindowFlags(null, attrs);
         final int systemUiVisibility = (attrs.systemUiVisibility|attrs.subtreeSystemUiVisibility);
 
         if ((fl & (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR))
@@ -2737,7 +2741,8 @@
                         // We currently want to hide the navigation UI.
                         mNavigationBarController.setBarShowingLw(false);
                     }
-                    if (navVisible && !navTranslucent && !mNavigationBar.isAnimatingLw()
+                    if (navVisible && !navTranslucent && !navAllowedHidden
+                            && !mNavigationBar.isAnimatingLw()
                             && !mNavigationBarController.wasRecentlyTranslucent()) {
                         // If the opaque nav bar is currently requested to be visible,
                         // and not in the process of animating on or off, then
@@ -2946,9 +2951,9 @@
             offsetInputMethodWindowLw(mLastInputMethodWindow);
         }
 
-        final int fl = attrs.flags;
+        final int fl = PolicyControl.getWindowFlags(win, attrs);
         final int sim = attrs.softInputMode;
-        final int sysUiFl = win.getSystemUiVisibility();
+        final int sysUiFl = PolicyControl.getSystemUiVisibility(win);
 
         final Rect pf = mTmpParentFrame;
         final Rect df = mTmpDisplayFrame;
@@ -3366,6 +3371,7 @@
                                 WindowManager.LayoutParams attrs) {
         if (DEBUG_LAYOUT) Slog.i(TAG, "Win " + win + ": isVisibleOrBehindKeyguardLw="
                 + win.isVisibleOrBehindKeyguardLw());
+        final int fl = PolicyControl.getWindowFlags(win, attrs);
         if (mTopFullscreenOpaqueWindowState == null
                 && win.isVisibleLw() && attrs.type == TYPE_INPUT_METHOD) {
             mForcingShowNavBar = true;
@@ -3373,7 +3379,7 @@
         }
         if (mTopFullscreenOpaqueWindowState == null &&
                 win.isVisibleOrBehindKeyguardLw() && !win.isGoneForLayoutLw()) {
-            if ((attrs.flags & FLAG_FORCE_NOT_FULLSCREEN) != 0) {
+            if ((fl & FLAG_FORCE_NOT_FULLSCREEN) != 0) {
                 if (attrs.type == TYPE_KEYGUARD) {
                     mForceStatusBarFromKeyguard = true;
                 } else {
@@ -3400,12 +3406,12 @@
                     && attrs.height == WindowManager.LayoutParams.MATCH_PARENT) {
                 if (DEBUG_LAYOUT) Slog.v(TAG, "Fullscreen window: " + win);
                 mTopFullscreenOpaqueWindowState = win;
-                if ((attrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0) {
+                if ((fl & FLAG_SHOW_WHEN_LOCKED) != 0) {
                     if (DEBUG_LAYOUT) Slog.v(TAG, "Setting mHideLockScreen to true by win " + win);
                     mHideLockScreen = true;
                     mForceStatusBarFromKeyguard = false;
                 }
-                if ((attrs.flags & FLAG_DISMISS_KEYGUARD) != 0
+                if ((fl & FLAG_DISMISS_KEYGUARD) != 0
                         && mDismissKeyguard == DISMISS_KEYGUARD_NONE) {
                     if (DEBUG_LAYOUT) Slog.v(TAG, "Setting mDismissKeyguard true by win " + win);
                     mDismissKeyguard = mWinDismissingKeyguard == win ?
@@ -3413,7 +3419,7 @@
                     mWinDismissingKeyguard = win;
                     mForceStatusBarFromKeyguard = mShowingLockscreen && isKeyguardSecure();
                 }
-                if ((attrs.flags & FLAG_ALLOW_LOCK_WHILE_SCREEN_ON) != 0) {
+                if ((fl & FLAG_ALLOW_LOCK_WHILE_SCREEN_ON) != 0) {
                     mAllowLockscreenWhenOn = true;
                 }
             }
@@ -3455,13 +3461,14 @@
                             mLastSystemUiFlags, mLastSystemUiFlags);
                 }
             } else if (mTopFullscreenOpaqueWindowState != null) {
+                final int fl = PolicyControl.getWindowFlags(null, lp);
                 if (localLOGV) {
                     Slog.d(TAG, "frame: " + mTopFullscreenOpaqueWindowState.getFrameLw()
                             + " shown frame: " + mTopFullscreenOpaqueWindowState.getShownFrameLw());
                     Slog.d(TAG, "attr: " + mTopFullscreenOpaqueWindowState.getAttrs()
-                            + " lp.flags=0x" + Integer.toHexString(lp.flags));
+                            + " lp.flags=0x" + Integer.toHexString(fl));
                 }
-                topIsFullscreen = (lp.flags & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0
+                topIsFullscreen = (fl & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0
                         || (mLastSystemUiFlags & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0;
                 // The subtle difference between the window for mTopFullscreenOpaqueWindowState
                 // and mTopIsFullscreen is that that mTopIsFullscreen is set only if the window
@@ -5061,11 +5068,11 @@
             return 0;
         }
 
-        int tmpVisibility = win.getSystemUiVisibility()
+        int tmpVisibility = PolicyControl.getSystemUiVisibility(win)
                 & ~mResettingSystemUiFlags
                 & ~mForceClearedSystemUiFlags;
         if (mForcingShowNavBar && win.getSurfaceLayer() < mForcingShowNavBarLayer) {
-            tmpVisibility &= ~View.SYSTEM_UI_CLEARABLE_FLAGS;
+            tmpVisibility &= ~PolicyControl.adjustClearableFlags(win, View.SYSTEM_UI_CLEARABLE_FLAGS);
         }
         final int visibility = updateSystemBarsLw(win, mLastSystemUiFlags, tmpVisibility);
         final int diff = visibility ^ mLastSystemUiFlags;
@@ -5124,7 +5131,7 @@
                 (vis & View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0;
         boolean hideStatusBarWM =
                 mTopFullscreenOpaqueWindowState != null &&
-                (mTopFullscreenOpaqueWindowState.getAttrs().flags
+                (PolicyControl.getWindowFlags(mTopFullscreenOpaqueWindowState, null)
                         & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0;
         boolean hideStatusBarSysui =
                 (vis & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0;
@@ -5412,5 +5419,6 @@
         pw.print(prefix); pw.print("mUndockedHdmiRotation="); pw.println(mUndockedHdmiRotation);
         mStatusBarController.dump(pw, prefix);
         mNavigationBarController.dump(pw, prefix);
+        PolicyControl.dump(prefix, pw);
     }
 }
diff --git a/policy/src/com/android/internal/policy/impl/PolicyControl.java b/policy/src/com/android/internal/policy/impl/PolicyControl.java
new file mode 100644
index 0000000..4f355dd
--- /dev/null
+++ b/policy/src/com/android/internal/policy/impl/PolicyControl.java
@@ -0,0 +1,255 @@
+/*
+ * 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.policy.impl;
+
+import android.content.Context;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.util.ArraySet;
+import android.util.Slog;
+import android.view.View;
+import android.view.WindowManager;
+import android.view.WindowManager.LayoutParams;
+import android.view.WindowManagerPolicy.WindowState;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+/**
+ * Runtime adjustments applied to the global window policy.
+ *
+ * This includes forcing immersive mode behavior for one or both system bars (based on a package
+ * list) and permanently disabling immersive mode confirmations for specific packages.
+ *
+ * Control by setting {@link Settings.Global.POLICY_CONTROL} to one or more name-value pairs.
+ * e.g.
+ *   to force immersive mode everywhere:
+ *     "immersive.full=*"
+ *   to force transient status for all apps except a specific package:
+ *     "immersive.status=apps,-com.package"
+ *   to disable the immersive mode confirmations for specific packages:
+ *     "immersive.preconfirms=com.package.one,com.package.two"
+ *
+ * Separate multiple name-value pairs with ':'
+ *   e.g. "immersive.status=apps:immersive.preconfirms=*"
+ */
+public class PolicyControl {
+    private static String TAG = "PolicyControl";
+    private static boolean DEBUG = false;
+
+    private static final String NAME_IMMERSIVE_FULL = "immersive.full";
+    private static final String NAME_IMMERSIVE_STATUS = "immersive.status";
+    private static final String NAME_IMMERSIVE_NAVIGATION = "immersive.navigation";
+    private static final String NAME_IMMERSIVE_PRECONFIRMATIONS = "immersive.preconfirms";
+
+    private static String sSettingValue;
+    private static Filter sImmersivePreconfirmationsFilter;
+    private static Filter sImmersiveStatusFilter;
+    private static Filter sImmersiveNavigationFilter;
+
+    public static int getSystemUiVisibility(WindowState win) {
+        int vis = win.getSystemUiVisibility();
+        if (sImmersiveStatusFilter != null && sImmersiveStatusFilter.matches(win)) {
+            vis |= View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
+                    | View.SYSTEM_UI_FLAG_FULLSCREEN
+                    | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
+            vis &= ~(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+                    | View.STATUS_BAR_TRANSLUCENT);
+        }
+        if (sImmersiveNavigationFilter != null && sImmersiveNavigationFilter.matches(win)) {
+            vis |= View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
+                    | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+                    | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
+            vis &= ~(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+                    | View.NAVIGATION_BAR_TRANSLUCENT);
+        }
+        return vis;
+    }
+
+    public static int getWindowFlags(WindowState win, LayoutParams attrs) {
+        int flags = (attrs != null ? attrs : win.getAttrs()).flags;
+        if (sImmersiveStatusFilter != null && sImmersiveStatusFilter.matches(win)) {
+            flags |= WindowManager.LayoutParams.FLAG_FULLSCREEN;
+            flags &= ~(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
+                    | WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
+        }
+        if (sImmersiveNavigationFilter != null && sImmersiveNavigationFilter.matches(win)) {
+            flags &= ~WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
+        }
+        return flags;
+    }
+
+    public static int adjustClearableFlags(WindowState win, int clearableFlags) {
+        if (sImmersiveStatusFilter != null && sImmersiveStatusFilter.matches(win)) {
+            clearableFlags &= ~View.SYSTEM_UI_FLAG_FULLSCREEN;
+        }
+        return clearableFlags;
+    }
+
+    public static boolean disableImmersiveConfirmation(String pkg) {
+        return sImmersivePreconfirmationsFilter != null
+                && sImmersivePreconfirmationsFilter.matches(pkg);
+    }
+
+    public static void reloadFromSetting(Context context) {
+        if (DEBUG) Slog.d(TAG, "reloadFromSetting()");
+        String value = null;
+        try {
+            value = Settings.Global.getStringForUser(context.getContentResolver(),
+                    Settings.Global.POLICY_CONTROL,
+                    UserHandle.USER_CURRENT);
+            if (sSettingValue != null && sSettingValue.equals(value)) return;
+            setFilters(value);
+            sSettingValue = value;
+        } catch (Throwable t) {
+            Slog.w(TAG, "Error loading policy control, value=" + value, t);
+        }
+    }
+
+    public static void dump(String prefix, PrintWriter pw) {
+        dump("sImmersiveStatusFilter", sImmersiveStatusFilter, prefix, pw);
+        dump("sImmersiveNavigationFilter", sImmersiveNavigationFilter, prefix, pw);
+        dump("sImmersivePreconfirmationsFilter", sImmersivePreconfirmationsFilter, prefix, pw);
+    }
+
+    private static void dump(String name, Filter filter, String prefix, PrintWriter pw) {
+        pw.print(prefix); pw.print("PolicyControl."); pw.print(name); pw.print('=');
+        if (filter == null) {
+            pw.println("null");
+        } else {
+            filter.dump(pw); pw.println();
+        }
+    }
+
+    private static void setFilters(String value) {
+        if (DEBUG) Slog.d(TAG, "setFilters: " + value);
+        sImmersiveStatusFilter = null;
+        sImmersiveNavigationFilter = null;
+        sImmersivePreconfirmationsFilter = null;
+        if (value != null) {
+            String[] nvps = value.split(":");
+            for (String nvp : nvps) {
+                int i = nvp.indexOf('=');
+                if (i == -1) continue;
+                String n = nvp.substring(0, i);
+                String v = nvp.substring(i + 1);
+                if (n.equals(NAME_IMMERSIVE_FULL)) {
+                    Filter f = Filter.parse(v);
+                    sImmersiveStatusFilter = sImmersiveNavigationFilter = f;
+                    if (sImmersivePreconfirmationsFilter == null) {
+                        sImmersivePreconfirmationsFilter = f;
+                    }
+                } else if (n.equals(NAME_IMMERSIVE_STATUS)) {
+                    Filter f = Filter.parse(v);
+                    sImmersiveStatusFilter = f;
+                } else if (n.equals(NAME_IMMERSIVE_NAVIGATION)) {
+                    Filter f = Filter.parse(v);
+                    sImmersiveNavigationFilter = f;
+                    if (sImmersivePreconfirmationsFilter == null) {
+                        sImmersivePreconfirmationsFilter = f;
+                    }
+                } else if (n.equals(NAME_IMMERSIVE_PRECONFIRMATIONS)) {
+                    Filter f = Filter.parse(v);
+                    sImmersivePreconfirmationsFilter = f;
+                }
+            }
+        }
+        if (DEBUG) {
+            Slog.d(TAG, "immersiveStatusFilter: " + sImmersiveStatusFilter);
+            Slog.d(TAG, "immersiveNavigationFilter: " + sImmersiveNavigationFilter);
+            Slog.d(TAG, "immersivePreconfirmationsFilter: " + sImmersivePreconfirmationsFilter);
+        }
+    }
+
+    private static class Filter {
+        private static final String ALL = "*";
+        private static final String APPS = "apps";
+
+        private final ArraySet<String> mWhitelist;
+        private final ArraySet<String> mBlacklist;
+
+        private Filter(ArraySet<String> whitelist, ArraySet<String> blacklist) {
+            mWhitelist = whitelist;
+            mBlacklist = blacklist;
+        }
+
+        boolean matches(WindowState win) {
+            if (win == null) return false;
+            LayoutParams attrs = win.getAttrs();
+            if (attrs == null) return false;
+            boolean isApp = attrs.type >= WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW
+                    && attrs.type <= WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
+            if (isApp && mBlacklist.contains(APPS)) return false;
+            if (onBlacklist(attrs.packageName)) return false;
+            if (isApp && mWhitelist.contains(APPS)) return true;
+            return onWhitelist(attrs.packageName);
+        }
+
+        boolean matches(String packageName) {
+            return !onBlacklist(packageName) && onWhitelist(packageName);
+        }
+
+        private boolean onBlacklist(String packageName) {
+            return mBlacklist.contains(packageName) || mBlacklist.contains(ALL);
+        }
+
+        private boolean onWhitelist(String packageName) {
+            return mWhitelist.contains(ALL) || mWhitelist.contains(packageName);
+        }
+
+        void dump(PrintWriter pw) {
+            pw.print("Filter[");
+            dump("whitelist", mWhitelist, pw); pw.print(',');
+            dump("blacklist", mBlacklist, pw); pw.print(']');
+        }
+
+        private void dump(String name, ArraySet<String> set, PrintWriter pw) {
+            pw.print(name); pw.print("=(");
+            final int n = set.size();
+            for (int i = 0; i < n; i++) {
+                if (i > 0) pw.print(',');
+                pw.print(set.valueAt(i));
+            }
+            pw.print(')');
+        }
+
+        @Override
+        public String toString() {
+            StringWriter sw = new StringWriter();
+            dump(new PrintWriter(sw, true));
+            return sw.toString();
+        }
+
+        // value = comma-delimited list of tokens, where token = (package name|apps|*)
+        // e.g. "com.package1", or "apps, com.android.keyguard" or "*"
+        static Filter parse(String value) {
+            if (value == null) return null;
+            ArraySet<String> whitelist = new ArraySet<String>();
+            ArraySet<String> blacklist = new ArraySet<String>();
+            for (String token : value.split(",")) {
+                token = token.trim();
+                if (token.startsWith("-") && token.length() > 1) {
+                    token = token.substring(1);
+                    blacklist.add(token);
+                } else {
+                    whitelist.add(token);
+                }
+            }
+            return new Filter(whitelist, blacklist);
+        }
+    }
+}
diff --git a/rs/java/android/renderscript/BaseObj.java b/rs/java/android/renderscript/BaseObj.java
index eee4936..842aa23 100644
--- a/rs/java/android/renderscript/BaseObj.java
+++ b/rs/java/android/renderscript/BaseObj.java
@@ -32,7 +32,7 @@
         mDestroyed = false;
     }
 
-    void setID(int id) {
+    void setID(long id) {
         if (mID != 0) {
             throw new RSRuntimeException("Internal Error, reset of object ID.");
         }
diff --git a/rs/java/android/renderscript/FileA3D.java b/rs/java/android/renderscript/FileA3D.java
index f0acb56..4164810 100644
--- a/rs/java/android/renderscript/FileA3D.java
+++ b/rs/java/android/renderscript/FileA3D.java
@@ -136,7 +136,7 @@
                 return null;
             }
 
-            int objectID = rs.nFileA3DGetEntryByIndex(entry.mID, entry.mIndex);
+            long objectID = rs.nFileA3DGetEntryByIndex(entry.mID, entry.mIndex);
             if(objectID == 0) {
                 return null;
             }
@@ -292,7 +292,7 @@
 
         long fileId = 0;
         if (is instanceof AssetManager.AssetInputStream) {
-            int asset = ((AssetManager.AssetInputStream) is).getAssetInt();
+            long asset = ((AssetManager.AssetInputStream) is).getNativeAsset();
             fileId = rs.nFileA3DCreateFromAssetStream(asset);
         } else {
             throw new RSRuntimeException("Unsupported asset stream");
diff --git a/rs/java/android/renderscript/Font.java b/rs/java/android/renderscript/Font.java
index 4cd89db..b22aeb7 100644
--- a/rs/java/android/renderscript/Font.java
+++ b/rs/java/android/renderscript/Font.java
@@ -148,7 +148,7 @@
         return "DroidSans.ttf";
     }
 
-    Font(int id, RenderScript rs) {
+    Font(long id, RenderScript rs) {
         super(id, rs);
     }
 
@@ -159,7 +159,7 @@
     static public Font createFromFile(RenderScript rs, Resources res, String path, float pointSize) {
         rs.validate();
         int dpi = res.getDisplayMetrics().densityDpi;
-        int fontId = rs.nFontCreateFromFile(path, pointSize, dpi);
+        long fontId = rs.nFontCreateFromFile(path, pointSize, dpi);
 
         if(fontId == 0) {
             throw new RSRuntimeException("Unable to create font from file " + path);
@@ -184,7 +184,7 @@
         AssetManager mgr = res.getAssets();
         int dpi = res.getDisplayMetrics().densityDpi;
 
-        int fontId = rs.nFontCreateFromAsset(mgr, path, pointSize, dpi);
+        long fontId = rs.nFontCreateFromAsset(mgr, path, pointSize, dpi);
         if(fontId == 0) {
             throw new RSRuntimeException("Unable to create font from asset " + path);
         }
@@ -208,9 +208,9 @@
 
         int dpi = res.getDisplayMetrics().densityDpi;
 
-        int fontId = 0;
+        long fontId = 0;
         if (is instanceof AssetManager.AssetInputStream) {
-            int asset = ((AssetManager.AssetInputStream) is).getAssetInt();
+            long asset = ((AssetManager.AssetInputStream) is).getNativeAsset();
             fontId = rs.nFontCreateFromAssetStream(name, pointSize, dpi, asset);
         } else {
             throw new RSRuntimeException("Unsupported asset stream created");
diff --git a/rs/java/android/renderscript/Long4.java b/rs/java/android/renderscript/Long4.java
index 757b910..1a1ad74 100644
--- a/rs/java/android/renderscript/Long4.java
+++ b/rs/java/android/renderscript/Long4.java
@@ -505,7 +505,7 @@
      * @param data
      * @param offset
      */
-    public void copyTo(Long[] data, int offset) {
+    public void copyTo(long[] data, int offset) {
         data[offset] = (long)(x);
         data[offset + 1] = (long)(y);
         data[offset + 2] = (long)(z);
diff --git a/rs/java/android/renderscript/ProgramStore.java b/rs/java/android/renderscript/ProgramStore.java
index 730c51b..c0fa9c4 100644
--- a/rs/java/android/renderscript/ProgramStore.java
+++ b/rs/java/android/renderscript/ProgramStore.java
@@ -143,7 +143,7 @@
     BlendDstFunc mBlendDst;
     boolean mDither;
 
-    ProgramStore(int id, RenderScript rs) {
+    ProgramStore(long id, RenderScript rs) {
         super(id, rs);
     }
 
@@ -418,7 +418,7 @@
         */
         public ProgramStore create() {
             mRS.validate();
-            int id = mRS.nProgramStoreCreate(mColorMaskR, mColorMaskG, mColorMaskB, mColorMaskA,
+            long id = mRS.nProgramStoreCreate(mColorMaskR, mColorMaskG, mColorMaskB, mColorMaskA,
                                              mDepthMask, mDither,
                                              mBlendSrc.mID, mBlendDst.mID, mDepthFunc.mID);
             ProgramStore programStore = new ProgramStore(id, mRS);
diff --git a/rs/java/android/renderscript/RenderScript.java b/rs/java/android/renderscript/RenderScript.java
index b0ef156..a4a9070 100644
--- a/rs/java/android/renderscript/RenderScript.java
+++ b/rs/java/android/renderscript/RenderScript.java
@@ -502,8 +502,8 @@
         rsnAllocationResize1D(mContext, id, dimX);
     }
 
-    native long rsnFileA3DCreateFromAssetStream(long con, int assetStream);
-    synchronized long nFileA3DCreateFromAssetStream(int assetStream) {
+    native long rsnFileA3DCreateFromAssetStream(long con, long assetStream);
+    synchronized long nFileA3DCreateFromAssetStream(long assetStream) {
         validate();
         return rsnFileA3DCreateFromAssetStream(mContext, assetStream);
     }
@@ -527,24 +527,24 @@
         validate();
         rsnFileA3DGetIndexEntries(mContext, fileA3D, numEntries, IDs, names);
     }
-    native int  rsnFileA3DGetEntryByIndex(long con, long fileA3D, int index);
-    synchronized int nFileA3DGetEntryByIndex(long fileA3D, int index) {
+    native long rsnFileA3DGetEntryByIndex(long con, long fileA3D, int index);
+    synchronized long nFileA3DGetEntryByIndex(long fileA3D, int index) {
         validate();
         return rsnFileA3DGetEntryByIndex(mContext, fileA3D, index);
     }
 
-    native int  rsnFontCreateFromFile(long con, String fileName, float size, int dpi);
-    synchronized int nFontCreateFromFile(String fileName, float size, int dpi) {
+    native long rsnFontCreateFromFile(long con, String fileName, float size, int dpi);
+    synchronized long nFontCreateFromFile(String fileName, float size, int dpi) {
         validate();
         return rsnFontCreateFromFile(mContext, fileName, size, dpi);
     }
-    native int  rsnFontCreateFromAssetStream(long con, String name, float size, int dpi, int assetStream);
-    synchronized int nFontCreateFromAssetStream(String name, float size, int dpi, int assetStream) {
+    native long rsnFontCreateFromAssetStream(long con, String name, float size, int dpi, long assetStream);
+    synchronized long nFontCreateFromAssetStream(String name, float size, int dpi, long assetStream) {
         validate();
         return rsnFontCreateFromAssetStream(mContext, name, size, dpi, assetStream);
     }
-    native int  rsnFontCreateFromAsset(long con, AssetManager mgr, String path, float size, int dpi);
-    synchronized int nFontCreateFromAsset(AssetManager mgr, String path, float size, int dpi) {
+    native long rsnFontCreateFromAsset(long con, AssetManager mgr, String path, float size, int dpi);
+    synchronized long nFontCreateFromAsset(AssetManager mgr, String path, float size, int dpi) {
         validate();
         return rsnFontCreateFromAsset(mContext, mgr, path, size, dpi);
     }
@@ -661,9 +661,9 @@
         rsnScriptSetVarObj(mContext, id, slot, val);
     }
 
-    native int  rsnScriptCCreate(long con, String resName, String cacheDir,
+    native long rsnScriptCCreate(long con, String resName, String cacheDir,
                                  byte[] script, int length);
-    synchronized int nScriptCCreate(String resName, String cacheDir, byte[] script, int length) {
+    synchronized long nScriptCCreate(String resName, String cacheDir, byte[] script, int length) {
         validate();
         return rsnScriptCCreate(mContext, resName, cacheDir, script, length);
     }
@@ -710,18 +710,18 @@
         rsnScriptGroupExecute(mContext, group);
     }
 
-    native int  rsnSamplerCreate(long con, int magFilter, int minFilter,
+    native long  rsnSamplerCreate(long con, int magFilter, int minFilter,
                                  int wrapS, int wrapT, int wrapR, float aniso);
-    synchronized int nSamplerCreate(int magFilter, int minFilter,
+    synchronized long nSamplerCreate(int magFilter, int minFilter,
                                  int wrapS, int wrapT, int wrapR, float aniso) {
         validate();
         return rsnSamplerCreate(mContext, magFilter, minFilter, wrapS, wrapT, wrapR, aniso);
     }
 
-    native int  rsnProgramStoreCreate(long con, boolean r, boolean g, boolean b, boolean a,
+    native long rsnProgramStoreCreate(long con, boolean r, boolean g, boolean b, boolean a,
                                       boolean depthMask, boolean dither,
                                       int srcMode, int dstMode, int depthFunc);
-    synchronized int nProgramStoreCreate(boolean r, boolean g, boolean b, boolean a,
+    synchronized long nProgramStoreCreate(boolean r, boolean g, boolean b, boolean a,
                                          boolean depthMask, boolean dither,
                                          int srcMode, int dstMode, int depthFunc) {
         validate();
@@ -787,8 +787,8 @@
         rsnMeshGetIndices(mContext, id, idxIds, primitives, vtxIdCount);
     }
 
-    native long rsnPathCreate(long con, int prim, boolean isStatic, long vtx, int loop, float q);
-    synchronized long nPathCreate(int prim, boolean isStatic, long vtx, int loop, float q) {
+    native long rsnPathCreate(long con, int prim, boolean isStatic, long vtx, long loop, float q);
+    synchronized long nPathCreate(int prim, boolean isStatic, long vtx, long loop, float q) {
         validate();
         return rsnPathCreate(mContext, prim, isStatic, vtx, loop, q);
     }
diff --git a/rs/java/android/renderscript/Sampler.java b/rs/java/android/renderscript/Sampler.java
index 39b867b..a4edbb5 100644
--- a/rs/java/android/renderscript/Sampler.java
+++ b/rs/java/android/renderscript/Sampler.java
@@ -49,7 +49,7 @@
     Value mWrapR;
     float mAniso;
 
-    Sampler(int id, RenderScript rs) {
+    Sampler(long id, RenderScript rs) {
         super(id, rs);
     }
 
@@ -336,7 +336,7 @@
 
         public Sampler create() {
             mRS.validate();
-            int id = mRS.nSamplerCreate(mMag.mID, mMin.mID,
+            long id = mRS.nSamplerCreate(mMag.mID, mMin.mID,
                                         mWrapS.mID, mWrapT.mID, mWrapR.mID, mAniso);
             Sampler sampler = new Sampler(id, mRS);
             sampler.mMin = mMin;
diff --git a/rs/java/android/renderscript/ScriptC.java b/rs/java/android/renderscript/ScriptC.java
index c7979f6..9e76f52 100644
--- a/rs/java/android/renderscript/ScriptC.java
+++ b/rs/java/android/renderscript/ScriptC.java
@@ -38,7 +38,17 @@
     protected ScriptC(int id, RenderScript rs) {
         super(id, rs);
     }
-
+    /**
+     * Only intended for use by the generated derived classes.
+     *
+     * @param id
+     * @param rs
+     *
+     * @hide
+     */
+    protected ScriptC(long id, RenderScript rs) {
+        super(id, rs);
+    }
     /**
      * Only intended for use by the generated derived classes.
      *
@@ -49,7 +59,7 @@
      */
     protected ScriptC(RenderScript rs, Resources resources, int resourceID) {
         super(0, rs);
-        int id = internalCreate(rs, resources, resourceID);
+        long id = internalCreate(rs, resources, resourceID);
         if (id == 0) {
             throw new RSRuntimeException("Loading of ScriptC script failed.");
         }
@@ -63,7 +73,7 @@
 
     static String mCachePath;
 
-    private static synchronized int internalCreate(RenderScript rs, Resources resources, int resourceID) {
+    private static synchronized long internalCreate(RenderScript rs, Resources resources, int resourceID) {
         byte[] pgm;
         int pgmLength;
         InputStream is = resources.openRawResource(resourceID);
diff --git a/rs/jni/android_renderscript_RenderScript.cpp b/rs/jni/android_renderscript_RenderScript.cpp
index 024d0c3..80a5da2 100644
--- a/rs/jni/android_renderscript_RenderScript.cpp
+++ b/rs/jni/android_renderscript_RenderScript.cpp
@@ -220,7 +220,7 @@
 nDeviceCreate(JNIEnv *_env, jobject _this)
 {
     LOG_API("nDeviceCreate");
-    return (jint)rsDeviceCreate();
+    return (jlong)rsDeviceCreate();
 }
 
 static void
@@ -241,17 +241,17 @@
 nContextCreate(JNIEnv *_env, jobject _this, jlong dev, jint ver, jint sdkVer, jint ct)
 {
     LOG_API("nContextCreate");
-    return (jint)rsContextCreate((RsDevice)dev, ver, sdkVer, (RsContextType)ct, 0);
+    return (jlong)rsContextCreate((RsDevice)dev, ver, sdkVer, (RsContextType)ct, 0);
 }
 
 static jlong
 nContextCreateGL(JNIEnv *_env, jobject _this, jlong dev, jint ver, jint sdkVer,
-                 int colorMin, int colorPref,
-                 int alphaMin, int alphaPref,
-                 int depthMin, int depthPref,
-                 int stencilMin, int stencilPref,
-                 int samplesMin, int samplesPref, float samplesQ,
-                 int dpi)
+                 jint colorMin, jint colorPref,
+                 jint alphaMin, jint alphaPref,
+                 jint depthMin, jint depthPref,
+                 jint stencilMin, jint stencilPref,
+                 jint samplesMin, jint samplesPref, jfloat samplesQ,
+                 jint dpi)
 {
     RsSurfaceConfig sc;
     sc.alphaMin = alphaMin;
@@ -265,7 +265,7 @@
     sc.samplesQ = samplesQ;
 
     LOG_API("nContextCreateGL");
-    return (jint)rsContextCreateGL((RsDevice)dev, ver, sdkVer, sc, dpi);
+    return (jlong)rsContextCreateGL((RsDevice)dev, ver, sdkVer, sc, dpi);
 }
 
 static void
@@ -355,7 +355,7 @@
         ALOGV("message receive buffer too small.  %i", receiveLen);
     }
     _env->ReleaseIntArrayElements(data, ptr, 0);
-    return id;
+    return (jint)id;
 }
 
 static jint
@@ -370,7 +370,7 @@
     auxDataPtr[0] = (jint)subID;
     auxDataPtr[1] = (jint)receiveLen;
     _env->ReleaseIntArrayElements(auxData, auxDataPtr, 0);
-    return id;
+    return (jint)id;
 }
 
 static void nContextInitToClient(JNIEnv *_env, jobject _this, jlong con)
@@ -432,7 +432,7 @@
 
     _env->ReleaseIntArrayElements(_ids, ids, JNI_ABORT);
     _env->ReleaseIntArrayElements(_arraySizes, arraySizes, JNI_ABORT);
-    return (jint)id;
+    return (jlong)id;
 }
 
 static void
@@ -499,7 +499,7 @@
     int elementCount = _env->GetArrayLength(_typeData);
 
     assert(elementCount == 6);
-    LOG_API("nTypeCreate, con(%p)", (RsContext)con);
+    LOG_API("nTypeGetNativeData, con(%p)", (RsContext)con);
 
     uint32_t typeData[6];
     rsaTypeGetNativeData((RsContext)con, (RsType)id, typeData, 6);
@@ -515,7 +515,7 @@
 nAllocationCreateTyped(JNIEnv *_env, jobject _this, jlong con, jlong type, jint mips, jint usage, jint pointer)
 {
     LOG_API("nAllocationCreateTyped, con(%p), type(%p), mip(%i), usage(%i), ptr(%p)", (RsContext)con, (RsElement)type, mips, usage, (void *)pointer);
-    return (jint) rsAllocationCreateTyped((RsContext)con, (RsType)type, (RsAllocationMipmapControl)mips, (uint32_t)usage, (uint32_t)pointer);
+    return (jlong) rsAllocationCreateTyped((RsContext)con, (RsType)type, (RsAllocationMipmapControl)mips, (uint32_t)usage, (uint32_t)pointer);
 }
 
 static void
@@ -662,7 +662,7 @@
 
 static void
 nAllocationData1D(JNIEnv *_env, jobject _this, jlong con, jlong _alloc, jint offset, jint lod,
-                  jint count, jobject data, int sizeBytes, int dataType)
+                  jint count, jobject data, jint sizeBytes, jint dataType)
 {
     RsAllocation *alloc = (RsAllocation *)_alloc;
     LOG_API("nAllocation1DData, con(%p), adapter(%p), offset(%i), count(%i), sizeBytes(%i), dataType(%i)",
@@ -671,8 +671,8 @@
 }
 
 static void
-//    native void rsnAllocationElementData1D(int con, int id, int xoff, int compIdx, byte[] d, int sizeBytes);
-nAllocationElementData1D(JNIEnv *_env, jobject _this, jlong con, jlong alloc, jint offset, jint lod, jint compIdx, jbyteArray data, int sizeBytes)
+//    native void rsnAllocationElementData1D(long con, long id, int xoff, int compIdx, byte[] d, int sizeBytes);
+nAllocationElementData1D(JNIEnv *_env, jobject _this, jlong con, jlong alloc, jint offset, jint lod, jint compIdx, jbyteArray data, jint sizeBytes)
 {
     jint len = _env->GetArrayLength(data);
     LOG_API("nAllocationElementData1D, con(%p), alloc(%p), offset(%i), comp(%i), len(%i), sizeBytes(%i)", (RsContext)con, (RsAllocation)alloc, offset, compIdx, len, sizeBytes);
@@ -683,7 +683,7 @@
 
 static void
 nAllocationData2D(JNIEnv *_env, jobject _this, jlong con, jlong _alloc, jint xoff, jint yoff, jint lod, jint _face,
-                  jint w, jint h, jobject data, int sizeBytes, int dataType)
+                  jint w, jint h, jobject data, jint sizeBytes, jint dataType)
 {
     RsAllocation *alloc = (RsAllocation *)_alloc;
     RsAllocationCubemapFace face = (RsAllocationCubemapFace)_face;
@@ -797,9 +797,8 @@
 static jlong
 nFileA3DCreateFromAssetStream(JNIEnv *_env, jobject _this, jlong con, jlong native_asset)
 {
-    ALOGV("______nFileA3D %u", (uint32_t) native_asset);
-
     Asset* asset = reinterpret_cast<Asset*>(native_asset);
+    ALOGV("______nFileA3D %p", asset);
 
     jlong id = (jlong)rsaFileA3DCreateFromMemory((RsContext)con, asset->getBuffer(false), asset->getLength());
     return id;
@@ -837,13 +836,13 @@
 {
     int32_t numEntries = 0;
     rsaFileA3DGetNumIndexEntries((RsContext)con, &numEntries, (RsFile)fileA3D);
-    return numEntries;
+    return (jint)numEntries;
 }
 
 static void
 nFileA3DGetIndexEntries(JNIEnv *_env, jobject _this, jlong con, jlong fileA3D, jint numEntries, jintArray _ids, jobjectArray _entries)
 {
-    ALOGV("______nFileA3D %u", (uint32_t) fileA3D);
+    ALOGV("______nFileA3D %p", (RsFile) fileA3D);
     RsFileIndexEntry *fileEntries = (RsFileIndexEntry*)malloc((uint32_t)numEntries * sizeof(RsFileIndexEntry));
 
     rsaFileA3DGetIndexEntries((RsContext)con, fileEntries, (uint32_t)numEntries, (RsFile)fileA3D);
@@ -856,43 +855,43 @@
     free(fileEntries);
 }
 
-static int
+static jlong
 nFileA3DGetEntryByIndex(JNIEnv *_env, jobject _this, jlong con, jlong fileA3D, jint index)
 {
-    ALOGV("______nFileA3D %u", (uint32_t) fileA3D);
-    jint id = (jint)rsaFileA3DGetEntryByIndex((RsContext)con, (uint32_t)index, (RsFile)fileA3D);
+    ALOGV("______nFileA3D %p", (RsFile) fileA3D);
+    jlong id = (jlong)rsaFileA3DGetEntryByIndex((RsContext)con, (uint32_t)index, (RsFile)fileA3D);
     return id;
 }
 
 // -----------------------------------
 
-static int
+static jlong
 nFontCreateFromFile(JNIEnv *_env, jobject _this, jlong con,
                     jstring fileName, jfloat fontSize, jint dpi)
 {
     AutoJavaStringToUTF8 fileNameUTF(_env, fileName);
-    jint id = (jint)rsFontCreateFromFile((RsContext)con,
+    jlong id = (jlong)rsFontCreateFromFile((RsContext)con,
                                          fileNameUTF.c_str(), fileNameUTF.length(),
                                          fontSize, dpi);
 
     return id;
 }
 
-static int
+static jlong
 nFontCreateFromAssetStream(JNIEnv *_env, jobject _this, jlong con,
-                           jstring name, jfloat fontSize, jint dpi, jint native_asset)
+                           jstring name, jfloat fontSize, jint dpi, jlong native_asset)
 {
     Asset* asset = reinterpret_cast<Asset*>(native_asset);
     AutoJavaStringToUTF8 nameUTF(_env, name);
 
-    jint id = (jint)rsFontCreateFromMemory((RsContext)con,
+    jlong id = (jlong)rsFontCreateFromMemory((RsContext)con,
                                            nameUTF.c_str(), nameUTF.length(),
                                            fontSize, dpi,
                                            asset->getBuffer(false), asset->getLength());
     return id;
 }
 
-static int
+static jlong
 nFontCreateFromAsset(JNIEnv *_env, jobject _this, jlong con, jobject _assetMgr, jstring _path,
                      jfloat fontSize, jint dpi)
 {
@@ -907,7 +906,7 @@
         return 0;
     }
 
-    jint id = (jint)rsFontCreateFromMemory((RsContext)con,
+    jlong id = (jlong)rsFontCreateFromMemory((RsContext)con,
                                            str.c_str(), str.length(),
                                            fontSize, dpi,
                                            asset->getBuffer(false), asset->getLength());
@@ -1126,7 +1125,7 @@
 
 // -----------------------------------
 
-static jint
+static jlong
 nScriptCCreate(JNIEnv *_env, jobject _this, jlong con,
                jstring resName, jstring cacheDir,
                jbyteArray scriptRef, jint length)
@@ -1135,7 +1134,7 @@
 
     AutoJavaStringToUTF8 resNameUTF(_env, resName);
     AutoJavaStringToUTF8 cacheDirUTF(_env, cacheDir);
-    jint ret = 0;
+    jlong ret = 0;
     jbyte* script_ptr = NULL;
     jint _exception = 0;
     jint remaining;
@@ -1161,7 +1160,7 @@
 
     //rsScriptCSetText((RsContext)con, (const char *)script_ptr, length);
 
-    ret = (jint)rsScriptCCreate((RsContext)con,
+    ret = (jlong)rsScriptCCreate((RsContext)con,
                                 resNameUTF.c_str(), resNameUTF.length(),
                                 cacheDirUTF.c_str(), cacheDirUTF.length(),
                                 (const char *)script_ptr, length);
@@ -1172,7 +1171,7 @@
                 _exception ? JNI_ABORT: 0);
     }
 
-    return ret;
+    return (jlong)ret;
 }
 
 static jlong
@@ -1186,14 +1185,14 @@
 nScriptKernelIDCreate(JNIEnv *_env, jobject _this, jlong con, jlong sid, jint slot, jint sig)
 {
     LOG_API("nScriptKernelIDCreate, con(%p) script(%p), slot(%i), sig(%i)", (RsContext)con, (void *)sid, slot, sig);
-    return (jint)rsScriptKernelIDCreate((RsContext)con, (RsScript)sid, slot, sig);
+    return (jlong)rsScriptKernelIDCreate((RsContext)con, (RsScript)sid, slot, sig);
 }
 
 static jlong
 nScriptFieldIDCreate(JNIEnv *_env, jobject _this, jlong con, jlong sid, jint slot)
 {
     LOG_API("nScriptFieldIDCreate, con(%p) script(%p), slot(%i)", (RsContext)con, (void *)sid, slot);
-    return (jint)rsScriptFieldIDCreate((RsContext)con, (RsScript)sid, slot);
+    return (jlong)rsScriptFieldIDCreate((RsContext)con, (RsScript)sid, slot);
 }
 
 static jlong
@@ -1253,7 +1252,7 @@
 
 // ---------------------------------------------------------------------------
 
-static jint
+static jlong
 nProgramStoreCreate(JNIEnv *_env, jobject _this, jlong con,
                     jboolean colorMaskR, jboolean colorMaskG, jboolean colorMaskB, jboolean colorMaskA,
                     jboolean depthMask, jboolean ditherEnable,
@@ -1261,7 +1260,7 @@
                     jint depthFunc)
 {
     LOG_API("nProgramStoreCreate, con(%p)", (RsContext)con);
-    return (jint)rsProgramStoreCreate((RsContext)con, colorMaskR, colorMaskG, colorMaskB, colorMaskA,
+    return (jlong)rsProgramStoreCreate((RsContext)con, colorMaskR, colorMaskG, colorMaskB, colorMaskA,
                                       depthMask, ditherEnable, (RsBlendSrcFunc)srcFunc,
                                       (RsBlendDstFunc)destFunc, (RsDepthFunc)depthFunc);
 }
@@ -1346,7 +1345,7 @@
 nProgramRasterCreate(JNIEnv *_env, jobject _this, jlong con, jboolean pointSprite, jint cull)
 {
     LOG_API("nProgramRasterCreate, con(%p), pointSprite(%i), cull(%i)", (RsContext)con, pointSprite, cull);
-    return (jint)rsProgramRasterCreate((RsContext)con, pointSprite, (RsCullMode)cull);
+    return (jlong)rsProgramRasterCreate((RsContext)con, pointSprite, (RsCullMode)cull);
 }
 
 
@@ -1390,12 +1389,12 @@
 
 // ---------------------------------------------------------------------------
 
-static jint
+static jlong
 nSamplerCreate(JNIEnv *_env, jobject _this, jlong con, jint magFilter, jint minFilter,
                jint wrapS, jint wrapT, jint wrapR, jfloat aniso)
 {
     LOG_API("nSamplerCreate, con(%p)", (RsContext)con);
-    return (jint)rsSamplerCreate((RsContext)con,
+    return (jlong)rsSamplerCreate((RsContext)con,
                                  (RsSamplerValue)magFilter,
                                  (RsSamplerValue)minFilter,
                                  (RsSamplerValue)wrapS,
@@ -1407,7 +1406,7 @@
 // ---------------------------------------------------------------------------
 
 static jlong
-nPathCreate(JNIEnv *_env, jobject _this, jlong con, jint prim, jboolean isStatic, jlong _vtx, jint _loop, jfloat q) {
+nPathCreate(JNIEnv *_env, jobject _this, jlong con, jint prim, jboolean isStatic, jlong _vtx, jlong _loop, jfloat q) {
     LOG_API("nPathCreate, con(%p)", (RsContext)con);
 
     jlong id = (jlong)rsPathCreate((RsContext)con, (RsPathPrimitive)prim, isStatic,
@@ -1526,15 +1525,15 @@
 {"rsnObjDestroy",                    "(JJ)V",                                 (void*)nObjDestroy },
 
 {"rsnFileA3DCreateFromFile",         "(JLjava/lang/String;)J",                (void*)nFileA3DCreateFromFile },
-{"rsnFileA3DCreateFromAssetStream",  "(JI)J",                                 (void*)nFileA3DCreateFromAssetStream },
+{"rsnFileA3DCreateFromAssetStream",  "(JJ)J",                                 (void*)nFileA3DCreateFromAssetStream },
 {"rsnFileA3DCreateFromAsset",        "(JLandroid/content/res/AssetManager;Ljava/lang/String;)J",            (void*)nFileA3DCreateFromAsset },
 {"rsnFileA3DGetNumIndexEntries",     "(JJ)I",                                 (void*)nFileA3DGetNumIndexEntries },
 {"rsnFileA3DGetIndexEntries",        "(JJI[I[Ljava/lang/String;)V",           (void*)nFileA3DGetIndexEntries },
-{"rsnFileA3DGetEntryByIndex",        "(JJI)I",                                (void*)nFileA3DGetEntryByIndex },
+{"rsnFileA3DGetEntryByIndex",        "(JJI)J",                                (void*)nFileA3DGetEntryByIndex },
 
-{"rsnFontCreateFromFile",            "(JLjava/lang/String;FI)I",              (void*)nFontCreateFromFile },
-{"rsnFontCreateFromAssetStream",     "(JLjava/lang/String;FII)I",             (void*)nFontCreateFromAssetStream },
-{"rsnFontCreateFromAsset",        "(JLandroid/content/res/AssetManager;Ljava/lang/String;FI)I",            (void*)nFontCreateFromAsset },
+{"rsnFontCreateFromFile",            "(JLjava/lang/String;FI)J",              (void*)nFontCreateFromFile },
+{"rsnFontCreateFromAssetStream",     "(JLjava/lang/String;FIJ)J",             (void*)nFontCreateFromAssetStream },
+{"rsnFontCreateFromAsset",        "(JLandroid/content/res/AssetManager;Ljava/lang/String;FI)J",            (void*)nFontCreateFromAsset },
 
 {"rsnElementCreate",                 "(JJIZI)J",                              (void*)nElementCreate },
 {"rsnElementCreate2",                "(J[I[Ljava/lang/String;[I)J",           (void*)nElementCreate2 },
@@ -1591,7 +1590,7 @@
 {"rsnScriptSetVarVE",                "(JJI[BJ[I)V",                           (void*)nScriptSetVarVE },
 {"rsnScriptSetVarObj",               "(JJIJ)V",                               (void*)nScriptSetVarObj },
 
-{"rsnScriptCCreate",                 "(JLjava/lang/String;Ljava/lang/String;[BI)I",  (void*)nScriptCCreate },
+{"rsnScriptCCreate",                 "(JLjava/lang/String;Ljava/lang/String;[BI)J",  (void*)nScriptCCreate },
 {"rsnScriptIntrinsicCreate",         "(JIJ)J",                                (void*)nScriptIntrinsicCreate },
 {"rsnScriptKernelIDCreate",          "(JJII)J",                               (void*)nScriptKernelIDCreate },
 {"rsnScriptFieldIDCreate",           "(JJI)J",                                (void*)nScriptFieldIDCreate },
@@ -1600,7 +1599,7 @@
 {"rsnScriptGroupSetOutput",          "(JJJJ)V",                               (void*)nScriptGroupSetOutput },
 {"rsnScriptGroupExecute",            "(JJ)V",                                 (void*)nScriptGroupExecute },
 
-{"rsnProgramStoreCreate",            "(JZZZZZZIII)I",                         (void*)nProgramStoreCreate },
+{"rsnProgramStoreCreate",            "(JZZZZZZIII)J",                         (void*)nProgramStoreCreate },
 
 {"rsnProgramBindConstants",          "(JJIJ)V",                               (void*)nProgramBindConstants },
 {"rsnProgramBindTexture",            "(JJIJ)V",                               (void*)nProgramBindTexture },
@@ -1616,9 +1615,9 @@
 {"rsnContextBindProgramVertex",      "(JI)V",                                 (void*)nContextBindProgramVertex },
 {"rsnContextBindProgramRaster",      "(JI)V",                                 (void*)nContextBindProgramRaster },
 
-{"rsnSamplerCreate",                 "(JIIIIIF)I",                            (void*)nSamplerCreate },
+{"rsnSamplerCreate",                 "(JIIIIIF)J",                            (void*)nSamplerCreate },
 
-{"rsnPathCreate",                    "(JIZJIF)J",                             (void*)nPathCreate },
+{"rsnPathCreate",                    "(JIZJJF)J",                             (void*)nPathCreate },
 {"rsnMeshCreate",                    "(J[I[I[I)J",                            (void*)nMeshCreate },
 
 {"rsnMeshGetVertexBufferCount",      "(JJ)I",                                 (void*)nMeshGetVertexBufferCount },
@@ -1648,7 +1647,7 @@
     assert(env != NULL);
 
     if (registerFuncs(env) < 0) {
-        ALOGE("ERROR: MediaPlayer native registration failed\n");
+        ALOGE("ERROR: Renderscript native registration failed\n");
         goto bail;
     }
 
diff --git a/services/Android.mk b/services/Android.mk
index 80fd35a..a8881b6 100644
--- a/services/Android.mk
+++ b/services/Android.mk
@@ -1,27 +1,23 @@
 LOCAL_PATH:= $(call my-dir)
 
-# the java library
+# merge all required services into one jar
 # ============================================================
 include $(CLEAR_VARS)
 
-LOCAL_SRC_FILES :=
+LOCAL_MODULE := services
 
-# TODO: Move this to the product makefiles
-REQUIRED_SERVICES := core accessibility appwidget backup devicepolicy print
+LOCAL_SRC_FILES := $(call all-java-files-under,java)
 
-include $(patsubst %,$(LOCAL_PATH)/%/java/service.mk,$(REQUIRED_SERVICES))
-
-LOCAL_MODULE:= services
-
-LOCAL_JAVA_LIBRARIES := android.policy conscrypt telephony-common
-
-#LOCAL_PROGUARD_ENABLED := full
-#LOCAL_PROGUARD_FLAG_FILES := proguard.flags
+LOCAL_STATIC_JAVA_LIBRARIES := \
+    services.core \
+    services.accessibility \
+    services.appwidget \
+    services.backup \
+    services.devicepolicy \
+    services.print
 
 include $(BUILD_JAVA_LIBRARY)
 
-include $(BUILD_DROIDDOC)
-
 # native library
 # =============================================================
 
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/accessibility/java/service.mk b/services/accessibility/java/service.mk
deleted file mode 100644
index 5e8f375..0000000
--- a/services/accessibility/java/service.mk
+++ /dev/null
@@ -1,11 +0,0 @@
-# Include only if the service is required
-ifneq ($(findstring accessibility,$(REQUIRED_SERVICES)),)
-
-SUB_DIR := accessibility/java
-
-LOCAL_SRC_FILES += \
-      $(call all-java-files-under,$(SUB_DIR))
-
-#DEFINED_SERVICES += com.android.server.accessibility.AccessibilityManagerService
-
-endif
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
index 3378e3d..e208677 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetService.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetService.java
@@ -53,13 +53,13 @@
 
     static final String TAG = "AppWidgetService";
 
-    Context mContext;
-    Handler mSaveStateHandler;
+    final Context mContext;
+    final Handler mSaveStateHandler;
 
-    SparseArray<AppWidgetServiceImpl> mAppWidgetServices;
+    final SparseArray<AppWidgetServiceImpl> mAppWidgetServices;
 
-    @Override
-    public void onCreate(Context context) {
+    public AppWidgetService(Context context) {
+        super(context);
         mContext = context;
 
         mSaveStateHandler = BackgroundThread.getHandler();
diff --git a/services/appwidget/java/service.mk b/services/appwidget/java/service.mk
deleted file mode 100644
index 0e33446..0000000
--- a/services/appwidget/java/service.mk
+++ /dev/null
@@ -1,11 +0,0 @@
-# Include only if the service is required
-ifneq ($(findstring appwidget,$(REQUIRED_SERVICES)),)
-
-SUB_DIR := appwidget/java
-
-LOCAL_SRC_FILES += \
-      $(call all-java-files-under,$(SUB_DIR))
-
-#DEFINED_SERVICES += com.android.server.appwidget.AppWidgetService
-
-endif
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/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 1e7c18a..186ae1b 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -83,6 +83,7 @@
 import com.android.internal.backup.IBackupTransport;
 import com.android.internal.backup.IObbBackupService;
 import com.android.server.EventLogTags;
+import com.android.server.SystemService;
 import com.android.server.backup.PackageManagerBackupAgent.Metadata;
 
 import java.io.BufferedInputStream;
@@ -277,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);
diff --git a/services/backup/java/com/android/server/backup/BackupManagerSystemService.java b/services/backup/java/com/android/server/backup/BackupManagerSystemService.java
deleted file mode 100644
index db2c94a..0000000
--- a/services/backup/java/com/android/server/backup/BackupManagerSystemService.java
+++ /dev/null
@@ -1,36 +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.backup;
-
-import android.content.Context;
-
-import com.android.server.SystemService;
-
-public class BackupManagerSystemService extends SystemService {
-    private BackupManagerService mBackupManagerImpl;
-
-    @Override
-    public void onCreate(Context context) {
-        mBackupManagerImpl = new BackupManagerService(context);
-    }
-
-    @Override
-    public void onStart() {
-        publishBinderService(Context.BACKUP_SERVICE, mBackupManagerImpl);
-    }
-}
-
diff --git a/services/backup/java/service.mk b/services/backup/java/service.mk
deleted file mode 100644
index bd22b95..0000000
--- a/services/backup/java/service.mk
+++ /dev/null
@@ -1,11 +0,0 @@
-# Include only if the service is required
-ifneq ($(findstring backup,$(REQUIRED_SERVICES)),)
-
-SUB_DIR := backup/java
-
-LOCAL_SRC_FILES += \
-      $(call all-java-files-under,$(SUB_DIR))
-
-#DEFINED_SERVICES += com.android.server.backup.BackupManagerService
-
-endif
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/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index cb5ae96..5d86b38 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -39,8 +39,10 @@
 import android.os.UserHandle;
 import android.os.WorkSource;
 import android.text.TextUtils;
+import android.util.ArrayMap;
 import android.util.Pair;
 import android.util.Slog;
+import android.util.SparseArray;
 import android.util.TimeUtils;
 
 import java.io.ByteArrayOutputStream;
@@ -53,9 +55,7 @@
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.Date;
-import java.util.HashMap;
 import java.util.LinkedList;
-import java.util.Map;
 import java.util.TimeZone;
 
 import static android.app.AlarmManager.RTC_WAKEUP;
@@ -313,12 +313,31 @@
             return 0;
         }
     }
-    
+
+    final Comparator<Alarm> mAlarmDispatchComparator = new Comparator<Alarm>() {
+        @Override
+        public int compare(Alarm lhs, Alarm rhs) {
+            if (lhs.wakeup != rhs.wakeup) {
+                return lhs.wakeup ? -1 : 1;
+            }
+            if (lhs.whenElapsed < rhs.whenElapsed) {
+                return -1;
+            } else if (lhs.whenElapsed > rhs.whenElapsed) {
+                return 1;
+            }
+            return 0;
+        }
+    };
+
     // minimum recurrence period or alarm futurity for us to be able to fuzz it
     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);
         if (isRtc) {
@@ -442,6 +461,7 @@
     }
     
     static final class BroadcastStats {
+        final int mUid;
         final String mPackageName;
 
         long aggregateTime;
@@ -449,16 +469,17 @@
         int numWakeup;
         long startTime;
         int nesting;
-        final HashMap<Pair<String, ComponentName>, FilterStats> filterStats
-                = new HashMap<Pair<String, ComponentName>, FilterStats>();
+        final ArrayMap<Pair<String, ComponentName>, FilterStats> filterStats
+                = new ArrayMap<Pair<String, ComponentName>, FilterStats>();
 
-        BroadcastStats(String packageName) {
+        BroadcastStats(int uid, String packageName) {
+            mUid = uid;
             mPackageName = packageName;
         }
     }
     
-    final HashMap<String, BroadcastStats> mBroadcastStats
-            = new HashMap<String, BroadcastStats>();
+    final SparseArray<ArrayMap<String, BroadcastStats>> mBroadcastStats
+            = new SparseArray<ArrayMap<String, BroadcastStats>>();
     
     @Override
     public void onStart() {
@@ -470,7 +491,7 @@
         setTimeZoneImpl(SystemProperties.get(TIMEZONE_PROPERTY));
 
         PowerManager pm = (PowerManager) getContext().getSystemService(Context.POWER_SERVICE);
-        mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
+        mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*alarm*");
         
         mTimeTickSender = PendingIntent.getBroadcastAsUser(getContext(), 0,
                 new Intent(Intent.ACTION_TIME_TICK).addFlags(
@@ -743,24 +764,26 @@
                 }
             };
             int len = 0;
-            for (Map.Entry<String, BroadcastStats> be : mBroadcastStats.entrySet()) {
-                BroadcastStats bs = be.getValue();
-                for (Map.Entry<Pair<String, ComponentName>, FilterStats> fe
-                        : bs.filterStats.entrySet()) {
-                    FilterStats fs = fe.getValue();
-                    int pos = len > 0
-                            ? Arrays.binarySearch(topFilters, 0, len, fs, comparator) : 0;
-                    if (pos < 0) {
-                        pos = -pos - 1;
-                    }
-                    if (pos < topFilters.length) {
-                        int copylen = topFilters.length - pos - 1;
-                        if (copylen > 0) {
-                            System.arraycopy(topFilters, pos, topFilters, pos+1, copylen);
+            for (int iu=0; iu<mBroadcastStats.size(); iu++) {
+                ArrayMap<String, BroadcastStats> uidStats = mBroadcastStats.valueAt(iu);
+                for (int ip=0; ip<uidStats.size(); ip++) {
+                    BroadcastStats bs = uidStats.valueAt(ip);
+                    for (int is=0; is<bs.filterStats.size(); is++) {
+                        FilterStats fs = bs.filterStats.valueAt(is);
+                        int pos = len > 0
+                                ? Arrays.binarySearch(topFilters, 0, len, fs, comparator) : 0;
+                        if (pos < 0) {
+                            pos = -pos - 1;
                         }
-                        topFilters[pos] = fs;
-                        if (len < topFilters.length) {
-                            len++;
+                        if (pos < topFilters.length) {
+                            int copylen = topFilters.length - pos - 1;
+                            if (copylen > 0) {
+                                System.arraycopy(topFilters, pos, topFilters, pos+1, copylen);
+                            }
+                            topFilters[pos] = fs;
+                            if (len < topFilters.length) {
+                                len++;
+                            }
                         }
                     }
                 }
@@ -774,7 +797,8 @@
                     TimeUtils.formatDuration(fs.aggregateTime, pw);
                     pw.print(" running, "); pw.print(fs.numWakeup);
                     pw.print(" wakeups, "); pw.print(fs.count);
-                    pw.print(" alarms: "); pw.print(fs.mBroadcastStats.mPackageName);
+                    pw.print(" alarms: "); UserHandle.formatUid(pw, fs.mBroadcastStats.mUid);
+                    pw.print(":"); pw.print(fs.mBroadcastStats.mPackageName);
                     pw.println();
                     pw.print("      ");
                     if (fs.mTarget.first != null) {
@@ -790,35 +814,39 @@
             pw.println(" ");
             pw.println("  Alarm Stats:");
             final ArrayList<FilterStats> tmpFilters = new ArrayList<FilterStats>();
-            for (Map.Entry<String, BroadcastStats> be : mBroadcastStats.entrySet()) {
-                BroadcastStats bs = be.getValue();
-                pw.print("  ");
-                if (bs.nesting > 0) pw.print("*ACTIVE* ");
-                pw.print(be.getKey());
-                pw.print(" "); TimeUtils.formatDuration(bs.aggregateTime, pw);
-                        pw.print(" running, "); pw.print(bs.numWakeup);
-                        pw.println(" wakeups:");
-                tmpFilters.clear();
-                for (Map.Entry<Pair<String, ComponentName>, FilterStats> fe
-                        : bs.filterStats.entrySet()) {
-                    tmpFilters.add(fe.getValue());
-                }
-                Collections.sort(tmpFilters, comparator);
-                for (int i=0; i<tmpFilters.size(); i++) {
-                    FilterStats fs = tmpFilters.get(i);
-                    pw.print("    ");
-                            if (fs.nesting > 0) pw.print("*ACTIVE* ");
-                            TimeUtils.formatDuration(fs.aggregateTime, pw);
-                            pw.print(" "); pw.print(fs.numWakeup);
-                            pw.print(" wakes " ); pw.print(fs.count);
-                            pw.print(" alarms:");
-                            if (fs.mTarget.first != null) {
-                                pw.print(" act="); pw.print(fs.mTarget.first);
-                            }
-                            if (fs.mTarget.second != null) {
-                                pw.print(" cmp="); pw.print(fs.mTarget.second.toShortString());
-                            }
-                            pw.println();
+            for (int iu=0; iu<mBroadcastStats.size(); iu++) {
+                ArrayMap<String, BroadcastStats> uidStats = mBroadcastStats.valueAt(iu);
+                for (int ip=0; ip<uidStats.size(); ip++) {
+                    BroadcastStats bs = uidStats.valueAt(ip);
+                    pw.print("  ");
+                    if (bs.nesting > 0) pw.print("*ACTIVE* ");
+                    UserHandle.formatUid(pw, bs.mUid);
+                    pw.print(":");
+                    pw.print(bs.mPackageName);
+                    pw.print(" "); TimeUtils.formatDuration(bs.aggregateTime, pw);
+                            pw.print(" running, "); pw.print(bs.numWakeup);
+                            pw.println(" wakeups:");
+                    tmpFilters.clear();
+                    for (int is=0; is<bs.filterStats.size(); is++) {
+                        tmpFilters.add(bs.filterStats.valueAt(is));
+                    }
+                    Collections.sort(tmpFilters, comparator);
+                    for (int i=0; i<tmpFilters.size(); i++) {
+                        FilterStats fs = tmpFilters.get(i);
+                        pw.print("    ");
+                                if (fs.nesting > 0) pw.print("*ACTIVE* ");
+                                TimeUtils.formatDuration(fs.aggregateTime, pw);
+                                pw.print(" "); pw.print(fs.numWakeup);
+                                pw.print(" wakes " ); pw.print(fs.count);
+                                pw.print(" alarms:");
+                                if (fs.mTarget.first != null) {
+                                    pw.print(" act="); pw.print(fs.mTarget.first);
+                                }
+                                if (fs.mTarget.second != null) {
+                                    pw.print(" cmp="); pw.print(fs.mTarget.second.toShortString());
+                                }
+                                pw.println();
+                    }
                 }
             }
 
@@ -1037,7 +1065,8 @@
     private native int waitForAlarm(long nativeData);
     private native int setKernelTimezone(long nativeData, int minuteswest);
 
-    void triggerAlarmsLocked(ArrayList<Alarm> triggerList, long nowELAPSED, long nowRTC) {
+    void triggerAlarmsLocked(ArrayList<Alarm> triggerList, final long nowELAPSED,
+            final 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
@@ -1076,6 +1105,14 @@
 
             }
         }
+
+        Collections.sort(triggerList, mAlarmDispatchComparator);
+
+        if (localLOGV) {
+            for (int i=0; i<triggerList.size(); i++) {
+                Slog.v(TAG, "Triggering alarm #" + i + ": " + triggerList.get(i));
+            }
+        }
     }
 
     /**
@@ -1096,7 +1133,8 @@
     }
     
     private static class Alarm {
-        public int type;
+        public final int type;
+        public final boolean wakeup;
         public int count;
         public long when;
         public long windowLength;
@@ -1109,6 +1147,8 @@
         public Alarm(int _type, long _when, long _whenElapsed, long _windowLength, long _maxWhen,
                 long _interval, PendingIntent _op, WorkSource _ws) {
             type = _type;
+            wakeup = _type == AlarmManager.ELAPSED_REALTIME_WAKEUP
+                    || _type == AlarmManager.RTC_WAKEUP;
             when = _when;
             whenElapsed = _whenElapsed;
             windowLength = _windowLength;
@@ -1126,6 +1166,8 @@
             sb.append(Integer.toHexString(System.identityHashCode(this)));
             sb.append(" type ");
             sb.append(type);
+            sb.append(" when ");
+            sb.append(when);
             sb.append(" ");
             sb.append(operation.getTargetPackage());
             sb.append('}');
@@ -1231,6 +1273,15 @@
                             // we have an active broadcast so stay awake.
                             if (mBroadcastRefCount == 0) {
                                 setWakelockWorkSource(alarm.operation, alarm.workSource);
+                                mWakeLock.setUnimportantForLogging(
+                                        alarm.operation == mTimeTickSender);
+                                // XXX debugging
+                                /*
+                                Intent intent = alarm.operation.getIntent();
+                                mWakeLock.setTag(intent.getAction() != null ? intent.getAction()
+                                        : (intent.getComponent() != null
+                                                ? intent.getComponent().toShortString() : TAG));
+                                */
                                 mWakeLock.acquire();
                             }
                             final InFlight inflight = new InFlight(AlarmManagerService.this,
@@ -1450,7 +1501,14 @@
                 if (pkgList != null && (pkgList.length > 0)) {
                     for (String pkg : pkgList) {
                         removeLocked(pkg);
-                        mBroadcastStats.remove(pkg);
+                        for (int i=mBroadcastStats.size()-1; i>=0; i--) {
+                            ArrayMap<String, BroadcastStats> uidStats = mBroadcastStats.valueAt(i);
+                            if (uidStats.remove(pkg) != null) {
+                                if (uidStats.size() <= 0) {
+                                    mBroadcastStats.removeAt(i);
+                                }
+                            }
+                        }
                     }
                 }
             }
@@ -1458,11 +1516,17 @@
     }
     
     private final BroadcastStats getStatsLocked(PendingIntent pi) {
-        String pkg = pi.getTargetPackage();
-        BroadcastStats bs = mBroadcastStats.get(pkg);
+        String pkg = pi.getCreatorPackage();
+        int uid = pi.getCreatorUid();
+        ArrayMap<String, BroadcastStats> uidStats = mBroadcastStats.get(uid);
+        if (uidStats == null) {
+            uidStats = new ArrayMap<String, BroadcastStats>();
+            mBroadcastStats.put(uid, uidStats);
+        }
+        BroadcastStats bs = uidStats.get(pkg);
         if (bs == null) {
-            bs = new BroadcastStats(pkg);
-            mBroadcastStats.put(pkg, bs);
+            bs = new BroadcastStats(uid, pkg);
+            uidStats.put(pkg, bs);
         }
         return bs;
     }
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 015185f..9349730 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -169,9 +169,9 @@
     private static final String TAG = "ConnectivityService";
 
     private static final boolean DBG = true;
-    private static final boolean VDBG = false;
+    private static final boolean VDBG = true;
 
-    private static final boolean LOGD_RULES = false;
+    private static final boolean LOGD_RULES = true;
 
     // TODO: create better separation between radio types and network types
 
@@ -4495,11 +4495,16 @@
          * @param seconds
          */
         private static void sleep(int seconds) {
-            try {
-                Thread.sleep(seconds * 1000);
-            } catch (InterruptedException e) {
-                e.printStackTrace();
+            log("XXXXX sleeping for " + seconds + " sec");
+            long stopTime = System.nanoTime() + (seconds * 1000000000);
+            long sleepTime;
+            while ((sleepTime = stopTime - System.nanoTime()) > 0) {
+                try {
+                    Thread.sleep(sleepTime / 1000000);
+                } catch (InterruptedException ignored) {
+                }
             }
+            log("XXXXX returning from sleep");
         }
 
         private static void log(String s) {
diff --git a/services/core/java/com/android/server/ConsumerIrService.java b/services/core/java/com/android/server/ConsumerIrService.java
index 066a9c4..ea6812d 100644
--- a/services/core/java/com/android/server/ConsumerIrService.java
+++ b/services/core/java/com/android/server/ConsumerIrService.java
@@ -29,13 +29,13 @@
 
     private static final int MAX_XMIT_TIME = 2000000; /* in microseconds */
 
-    private static native int halOpen();
-    private static native int halTransmit(int halObject, int carrierFrequency, int[] pattern);
-    private static native int[] halGetCarrierFrequencies(int halObject);
+    private static native long halOpen();
+    private static native int halTransmit(long halObject, int carrierFrequency, int[] pattern);
+    private static native int[] halGetCarrierFrequencies(long halObject);
 
     private final Context mContext;
     private final PowerManager.WakeLock mWakeLock;
-    private final int mHal;
+    private final long mNativeHal;
     private final Object mHalLock = new Object();
 
     ConsumerIrService(Context context) {
@@ -45,23 +45,23 @@
         mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
         mWakeLock.setReferenceCounted(true);
 
-        mHal = halOpen();
+        mNativeHal = halOpen();
         if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CONSUMER_IR)) {
-            if (mHal == 0) {
+            if (mNativeHal == 0) {
                 throw new RuntimeException("FEATURE_CONSUMER_IR present, but no IR HAL loaded!");
             }
-        } else if (mHal != 0) {
+        } else if (mNativeHal != 0) {
             throw new RuntimeException("IR HAL present, but FEATURE_CONSUMER_IR is not set!");
         }
     }
 
     @Override
     public boolean hasIrEmitter() {
-        return mHal != 0;
+        return mNativeHal != 0;
     }
 
     private void throwIfNoIrEmitter() {
-        if (mHal == 0) {
+        if (mNativeHal == 0) {
             throw new UnsupportedOperationException("IR emitter not available");
         }
     }
@@ -91,7 +91,7 @@
 
         // Right now there is no mechanism to ensure fair queing of IR requests
         synchronized (mHalLock) {
-            int err = halTransmit(mHal, carrierFrequency, pattern);
+            int err = halTransmit(mNativeHal, carrierFrequency, pattern);
 
             if (err < 0) {
                 Slog.e(TAG, "Error transmitting: " + err);
@@ -109,7 +109,7 @@
         throwIfNoIrEmitter();
 
         synchronized(mHalLock) {
-            return halGetCarrierFrequencies(mHal);
+            return halGetCarrierFrequencies(mNativeHal);
         }
     }
 }
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index de912dc..ad693d0 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -88,6 +88,10 @@
 
     private PowerManager.WakeLock mWakeLock;
 
+    public UiModeManagerService(Context context) {
+        super(context);
+    }
+
     private static Intent buildHomeIntent(String category) {
         Intent intent = new Intent(Intent.ACTION_MAIN);
         intent.addCategory(category);
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 17bb3e0..be2df04 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -28,6 +28,7 @@
 import android.os.Looper;
 import android.os.SystemProperties;
 import android.util.ArrayMap;
+import com.android.internal.app.ProcessMap;
 import com.android.internal.app.ProcessStats;
 import com.android.internal.os.BatteryStatsImpl;
 import com.android.internal.os.TransferPipe;
@@ -595,12 +596,7 @@
                 break;
             }
         }
-        if (anyForeground != proc.foregroundServices) {
-            proc.foregroundServices = anyForeground;
-            if (oomAdj) {
-                mAm.updateOomAdjLocked();
-            }
-        }
+        mAm.updateProcessForegroundLocked(proc, anyForeground, oomAdj);
     }
 
     private boolean updateServiceClientActivitiesLocked(ProcessRecord proc,
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index a21157f..7b2fc50 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -51,7 +51,6 @@
 import com.android.server.AttributeCache;
 import com.android.server.IntentResolver;
 import com.android.server.ServiceThread;
-import com.android.server.SystemServer;
 import com.android.server.SystemService;
 import com.android.server.Watchdog;
 import com.android.server.am.ActivityStack.ActivityState;
@@ -922,11 +921,25 @@
     long mLowRamTimeSinceLastIdle = 0;
 
     /**
-     * If RAM is currently low, when that horrible situatin started.
+     * If RAM is currently low, when that horrible situation started.
      */
     long mLowRamStartTime = 0;
 
     /**
+     * For reporting to battery stats the current top application.
+     */
+    private String mCurResumedPackage = null;
+    private int mCurResumedUid = -1;
+
+    /**
+     * For reporting to battery stats the apps currently running foreground
+     * service.  The ProcessMap is package/uid tuples; each of these contain
+     * an array of the currently foreground processes.
+     */
+    final ProcessMap<ArrayList<ProcessRecord>> mForegroundPackages
+            = new ProcessMap<ArrayList<ProcessRecord>>();
+
+    /**
      * This is set if we had to do a delayed dexopt of an app before launching
      * it, to increasing the ANR timeouts in that case.
      */
@@ -1868,11 +1881,11 @@
         }
     }
 
-    public static class Lifecycle extends SystemService {
-        private ActivityManagerService mService;
+    public static final class Lifecycle extends SystemService {
+        private final ActivityManagerService mService;
 
-        @Override
-        public void onCreate(Context context) {
+        public Lifecycle(Context context) {
+            super(context);
             mService = new ActivityManagerService(context);
         }
 
@@ -2768,7 +2781,7 @@
                 mHandler.sendMessageDelayed(msg, startResult.usingWrapper
                         ? PROC_START_TIMEOUT_WITH_WRAPPER : PROC_START_TIMEOUT);
             }
-            mBatteryStatsService.noteEvent(BatteryStats.HistoryItem.EVENT_PROC_STARTED,
+            mBatteryStatsService.noteEvent(BatteryStats.HistoryItem.EVENT_PROC_START,
                     app.processName, app.info.uid);
             if (app.isolated) {
                 mBatteryStatsService.addIsolatedUid(app.uid, app.info.uid);
@@ -3125,7 +3138,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;
     }
 
@@ -3237,7 +3250,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);
@@ -3245,7 +3259,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, null, options, userId, container);
         return ret;
     }
 
@@ -4727,7 +4741,7 @@
                 mPidsSelfLocked.remove(pid);
                 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
             }
-            mBatteryStatsService.noteEvent(BatteryStats.HistoryItem.EVENT_PROC_FINISHED,
+            mBatteryStatsService.noteEvent(BatteryStats.HistoryItem.EVENT_PROC_FINISH,
                     app.processName, app.info.uid);
             if (app.isolated) {
                 mBatteryStatsService.removeIsolatedUid(app.uid, app.info.uid);
@@ -4772,7 +4786,7 @@
                         mHeavyWeightProcess.userId, 0));
                 mHeavyWeightProcess = null;
             }
-            mBatteryStatsService.noteEvent(BatteryStats.HistoryItem.EVENT_PROC_FINISHED,
+            mBatteryStatsService.noteEvent(BatteryStats.HistoryItem.EVENT_PROC_FINISH,
                     app.processName, app.info.uid);
             if (app.isolated) {
                 mBatteryStatsService.removeIsolatedUid(app.uid, app.info.uid);
@@ -4861,7 +4875,7 @@
         app.curAdj = app.setAdj = -100;
         app.curSchedGroup = app.setSchedGroup = Process.THREAD_GROUP_DEFAULT;
         app.forcingToForeground = null;
-        app.foregroundServices = false;
+        updateProcessForegroundLocked(app, false, false);
         app.hasShownUi = false;
         app.debugging = false;
         app.cached = false;
@@ -5564,7 +5578,7 @@
                     return;
                 }
                 pr.forcingToForeground = null;
-                pr.foregroundServices = false;
+                updateProcessForegroundLocked(pr, false, false);
             }
             updateOomAdjLocked();
         }
@@ -7741,22 +7755,27 @@
      */
     public void removeContentProvider(IBinder connection, boolean stable) {
         enforceNotIsolatedCaller("removeContentProvider");
-        synchronized (this) {
-            ContentProviderConnection conn;
-            try {
-                conn = (ContentProviderConnection)connection;
-            } catch (ClassCastException e) {
-                String msg ="removeContentProvider: " + connection
-                        + " not a ContentProviderConnection";
-                Slog.w(TAG, msg);
-                throw new IllegalArgumentException(msg);
+        long ident = Binder.clearCallingIdentity();
+        try {
+            synchronized (this) {
+                ContentProviderConnection conn;
+                try {
+                    conn = (ContentProviderConnection)connection;
+                } catch (ClassCastException e) {
+                    String msg ="removeContentProvider: " + connection
+                            + " not a ContentProviderConnection";
+                    Slog.w(TAG, msg);
+                    throw new IllegalArgumentException(msg);
+                }
+                if (conn == null) {
+                    throw new NullPointerException("connection is null");
+                }
+                if (decProviderCountLocked(conn, null, null, stable)) {
+                    updateOomAdjLocked();
+                }
             }
-            if (conn == null) {
-                throw new NullPointerException("connection is null");
-            }
-            if (decProviderCountLocked(conn, null, null, stable)) {
-                updateOomAdjLocked();
-            }
+        } finally {
+            Binder.restoreCallingIdentity(ident);
         }
     }
 
@@ -12115,7 +12134,25 @@
             if (!brief) {
                 if (!isCompact) {
                     pw.print("Total RAM: "); pw.print(memInfo.getTotalSizeKb());
-                    pw.println(" kB");
+                    pw.print(" kB (status ");
+                    switch (mLastMemoryLevel) {
+                        case ProcessStats.ADJ_MEM_FACTOR_NORMAL:
+                            pw.println("normal)");
+                            break;
+                        case ProcessStats.ADJ_MEM_FACTOR_MODERATE:
+                            pw.println("moderate)");
+                            break;
+                        case ProcessStats.ADJ_MEM_FACTOR_LOW:
+                            pw.println("low)");
+                            break;
+                        case ProcessStats.ADJ_MEM_FACTOR_CRITICAL:
+                            pw.println("critical)");
+                            break;
+                        default:
+                            pw.print(mLastMemoryLevel);
+                            pw.println(")");
+                            break;
+                    }
                     pw.print(" Free RAM: "); pw.print(cachedPss + memInfo.getCachedSizeKb()
                             + memInfo.getFreeSizeKb()); pw.print(" kB (");
                             pw.print(cachedPss); pw.print(" cached pss + ");
@@ -12330,7 +12367,7 @@
         app.unlinkDeathRecipient();
         app.makeInactive(mProcessStats);
         app.forcingToForeground = null;
-        app.foregroundServices = false;
+        updateProcessForegroundLocked(app, false, false);
         app.foregroundActivities = false;
         app.hasShownUi = false;
         app.hasAboveClient = false;
@@ -12464,7 +12501,7 @@
                 mPidsSelfLocked.remove(app.pid);
                 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
             }
-            mBatteryStatsService.noteEvent(BatteryStats.HistoryItem.EVENT_PROC_FINISHED,
+            mBatteryStatsService.noteEvent(BatteryStats.HistoryItem.EVENT_PROC_FINISH,
                     app.processName, app.info.uid);
             if (app.isolated) {
                 mBatteryStatsService.removeIsolatedUid(app.uid, app.info.uid);
@@ -15285,8 +15322,66 @@
                 reportingProcessState, now);
     }
 
+    final void updateProcessForegroundLocked(ProcessRecord proc, boolean isForeground,
+            boolean oomAdj) {
+        if (isForeground != proc.foregroundServices) {
+            proc.foregroundServices = isForeground;
+            ArrayList<ProcessRecord> curProcs = mForegroundPackages.get(proc.info.packageName,
+                    proc.info.uid);
+            if (isForeground) {
+                if (curProcs == null) {
+                    curProcs = new ArrayList<ProcessRecord>();
+                    mForegroundPackages.put(proc.info.packageName, proc.info.uid, curProcs);
+                }
+                if (!curProcs.contains(proc)) {
+                    curProcs.add(proc);
+                    mBatteryStatsService.noteEvent(BatteryStats.HistoryItem.EVENT_FOREGROUND_START,
+                            proc.info.packageName, proc.info.uid);
+                }
+            } else {
+                if (curProcs != null) {
+                    if (curProcs.remove(proc)) {
+                        mBatteryStatsService.noteEvent(
+                                BatteryStats.HistoryItem.EVENT_FOREGROUND_FINISH,
+                                proc.info.packageName, proc.info.uid);
+                        if (curProcs.size() <= 0) {
+                            mForegroundPackages.remove(proc.info.packageName, proc.info.uid);
+                        }
+                    }
+                }
+            }
+            if (oomAdj) {
+                updateOomAdjLocked();
+            }
+        }
+    }
+
     private final ActivityRecord resumedAppLocked() {
-        return mStackSupervisor.resumedAppLocked();
+        ActivityRecord act = mStackSupervisor.resumedAppLocked();
+        String pkg;
+        int uid;
+        if (act != null) {
+            pkg = act.packageName;
+            uid = act.info.applicationInfo.uid;
+        } else {
+            pkg = null;
+            uid = -1;
+        }
+        // Has the UID or resumed package name changed?
+        if (uid != mCurResumedUid || (pkg != mCurResumedPackage
+                && (pkg == null || !pkg.equals(mCurResumedPackage)))) {
+            if (mCurResumedPackage != null) {
+                mBatteryStatsService.noteEvent(BatteryStats.HistoryItem.EVENT_TOP_FINISH,
+                        mCurResumedPackage, mCurResumedUid);
+            }
+            mCurResumedPackage = pkg;
+            mCurResumedUid = uid;
+            if (mCurResumedPackage != null) {
+                mBatteryStatsService.noteEvent(BatteryStats.HistoryItem.EVENT_TOP_START,
+                        mCurResumedPackage, mCurResumedUid);
+            }
+        }
+        return act;
     }
 
     final boolean updateOomAdjLocked(ProcessRecord app) {
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 70d85fc..77bb1a9 100755
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -738,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;
@@ -1282,6 +1288,13 @@
     final boolean resumeTopActivityLocked(ActivityRecord prev, Bundle options) {
         if (ActivityManagerService.DEBUG_LOCKSCREEN) mService.logLockScreen("");
 
+        ActivityRecord parent = mActivityContainer.mParentActivity;
+        if (parent != null && parent.state != ActivityState.RESUMED) {
+            // 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;
+        }
+
         cancelInitializingActivities();
 
         // Find the first activity that is not finishing.
@@ -2721,15 +2734,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();
-            }
-            removeTask(task);
-        }
         r.takeFromHistory();
         removeTimeoutsForActivityLocked(r);
         if (DEBUG_STATES) Slog.v(TAG, "Moving to DESTROYED: " + r + " (removed from history)");
@@ -2740,6 +2744,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();
     }
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 6115f06..8f8b2a2 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -277,6 +277,10 @@
     // TODO: Split into two methods isFrontStack for any visible stack and isFrontmostStack for the
     // top of all visible stacks.
     boolean isFrontStack(ActivityStack stack) {
+        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);
@@ -510,6 +514,20 @@
         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);
@@ -1133,7 +1151,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;
@@ -2915,7 +2937,7 @@
             mStack.mStacks = activityDisplay.mStacks;
 
             activityDisplay.attachActivities(mStack);
-            mWindowManager.createStack(mStackId, activityDisplay.mDisplayId);
+            mWindowManager.attachStack(mStackId, activityDisplay.mDisplayId);
         }
 
         @Override
@@ -2945,6 +2967,7 @@
                 mActivityDisplay = null;
                 mStack.mDisplayId = -1;
                 mStack.mStacks = null;
+                mWindowManager.detachStack(mStackId);
             }
         }
 
@@ -2957,7 +2980,7 @@
 
         @Override
         public final int startActivity(Intent intent) {
-            mService.enforceNotIsolatedCaller("ActivityContainer");
+            mService.enforceNotIsolatedCaller("ActivityContainer.startActivity");
             int userId = mService.handleIncomingUser(Binder.getCallingPid(),
                     Binder.getCallingUid(), mCurrentUser, false, true, "ActivityContainer", null);
             // TODO: Switch to user app stacks here.
@@ -2971,20 +2994,40 @@
         }
 
         @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, 0, 0, null, this);
+        }
+
+        @Override
         public IBinder asBinder() {
             return this;
         }
 
         @Override
         public void attachToSurface(Surface surface, int width, int height, int density) {
-            synchronized (mService) {
-                ActivityDisplay activityDisplay =
-                        new ActivityDisplay(surface, width, height, density);
-                mActivityDisplays.put(activityDisplay.mDisplayId, activityDisplay);
-                attachToDisplayLocked(activityDisplay);
+            mService.enforceNotIsolatedCaller("ActivityContainer.attachToSurface");
+
+            final long origId = Binder.clearCallingIdentity();
+            try {
+                synchronized (mService) {
+                    ActivityDisplay activityDisplay =
+                            new ActivityDisplay(surface, width, height, density);
+                    mActivityDisplays.put(activityDisplay.mDisplayId, activityDisplay);
+                    attachToDisplayLocked(activityDisplay);
+                    mStack.resumeTopActivityLocked(null);
+                }
+                if (DEBUG_STACK) Slog.d(TAG, "attachToSurface: " + this + " to display="
+                        + mActivityDisplay);
+            } finally {
+                Binder.restoreCallingIdentity(origId);
             }
-            if (DEBUG_STACK) Slog.d(TAG, "attachToSurface: " + this + " to display="
-                    + mActivityDisplay);
         }
 
         ActivityStackSupervisor getOuter() {
@@ -3030,10 +3073,6 @@
             init(mDisplayManager.getDisplay(displayId));
         }
 
-        ActivityDisplay(Display display) {
-            init(display);
-        }
-
         ActivityDisplay(Surface surface, int width, int height, int density) {
             DisplayManagerGlobal dm = DisplayManagerGlobal.getInstance();
             long ident = Binder.clearCallingIdentity();
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index eda08a9..8a29ac7 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -126,10 +126,11 @@
         }
     }
 
-    public void noteStartWakelock(int uid, int pid, String name, int type) {
+    public void noteStartWakelock(int uid, int pid, String name, int type,
+            boolean unimportantForLogging) {
         enforceCallingPermission();
         synchronized (mStats) {
-            mStats.noteStartWakeLocked(uid, pid, name, type);
+            mStats.noteStartWakeLocked(uid, pid, name, type, unimportantForLogging);
         }
     }
 
@@ -140,10 +141,11 @@
         }
     }
 
-    public void noteStartWakelockFromSource(WorkSource ws, int pid, String name, int type) {
+    public void noteStartWakelockFromSource(WorkSource ws, int pid, String name, int type,
+            boolean unimportantForLogging) {
         enforceCallingPermission();
         synchronized (mStats) {
-            mStats.noteStartWakeFromSourceLocked(ws, pid, name, type);
+            mStats.noteStartWakeFromSourceLocked(ws, pid, name, type, unimportantForLogging);
         }
     }
 
@@ -557,7 +559,7 @@
                     isUnpluggedOnly = true;
                 } else if ("--reset".equals(arg)) {
                     synchronized (mStats) {
-                        mStats.resetAllStatsLocked();
+                        mStats.resetAllStatsCmdLocked();
                         pw.println("Battery stats reset.");
                         noOutput = true;
                     }
diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java
index 17f24a9..00fa216 100644
--- a/services/core/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/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index d5ee838..6be6405 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -124,7 +124,7 @@
     private static final int DISPLAY_BLANK_STATE_BLANKED = 1;
     private static final int DISPLAY_BLANK_STATE_UNBLANKED = 2;
 
-    private Context mContext;
+    private final Context mContext;
     private final DisplayManagerHandler mHandler;
     private final Handler mUiHandler;
     private final DisplayAdapterListener mDisplayAdapterListener;
@@ -208,7 +208,9 @@
     private final DisplayViewport mTempDefaultViewport = new DisplayViewport();
     private final DisplayViewport mTempExternalTouchViewport = new DisplayViewport();
 
-    public DisplayManagerService() {
+    public DisplayManagerService(Context context) {
+        super(context);
+        mContext = context;
         mHandler = new DisplayManagerHandler(DisplayThread.get().getLooper());
         mUiHandler = UiThread.getHandler();
         mDisplayAdapterListener = new DisplayAdapterListener();
@@ -216,11 +218,6 @@
     }
 
     @Override
-    public void onCreate(Context context) {
-        mContext = context;
-    }
-
-    @Override
     public void onStart() {
         mHandler.sendEmptyMessage(MSG_REGISTER_DEFAULT_DISPLAY_ADAPTER);
 
diff --git a/services/core/java/com/android/server/lights/LightsService.java b/services/core/java/com/android/server/lights/LightsService.java
index 62dc090..94cf668 100644
--- a/services/core/java/com/android/server/lights/LightsService.java
+++ b/services/core/java/com/android/server/lights/LightsService.java
@@ -78,6 +78,7 @@
             synchronized (this) {
                 if (mColor == 0 && !mFlashing) {
                     setLightLocked(color, LIGHT_FLASH_HARDWARE, onMS, 1000, BRIGHTNESS_MODE_USER);
+                    mColor = 0;
                     mH.sendMessageDelayed(Message.obtain(mH, 1, this), onMS);
                 }
             }
@@ -156,8 +157,9 @@
         }
     };
 
-    @Override
-    public void onCreate(Context context) {
+    public LightsService(Context context) {
+        super(context);
+
         mNativePointer = init_native();
 
         for (int i = 0; i < LightsManager.LIGHT_ID_COUNT; i++) {
@@ -182,6 +184,7 @@
         }
     };
 
+    @Override
     protected void finalize() throws Throwable {
         finalize_native(mNativePointer);
         super.finalize();
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index e4ea033..01175bb 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -1118,6 +1118,10 @@
         return out;
     }
 
+    public NotificationManagerService(Context context) {
+        super(context);
+    }
+
     @Override
     public void onStart() {
         mAm = ActivityManagerNative.getDefault();
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index e2ff146..6185e50 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -18,6 +18,7 @@
 
 import com.android.server.SystemService;
 
+import android.content.Context;
 import android.content.pm.PackageStats;
 import android.net.LocalSocket;
 import android.net.LocalSocketAddress;
@@ -39,6 +40,10 @@
     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.");
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index bf8c9da..6e90bf6 100755
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -1307,6 +1307,11 @@
 
             // Collect all vendor packages.
             File vendorAppDir = new File("/vendor/app");
+            try {
+                vendorAppDir = vendorAppDir.getCanonicalFile();
+            } catch (IOException e) {
+                // failed to look up canonical path, continue with original one
+            }
             mVendorInstallObserver = new AppDirObserver(
                 vendorAppDir.getPath(), OBSERVER_EVENTS, true, false);
             mVendorInstallObserver.startWatching();
@@ -6106,6 +6111,11 @@
         }
 
         public final void addProvider(PackageParser.Provider p) {
+            if (mProviders.containsKey(p.getComponentName())) {
+                Slog.w(TAG, "Provider " + p.getComponentName() + " already defined; ignoring");
+                return;
+            }
+
             mProviders.put(p.getComponentName(), p);
             if (DEBUG_SHOW_INFO) {
                 Log.v(TAG, "  "
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index c33134a..38a1949 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -92,6 +92,7 @@
     private static final String ATTR_NEXT_SERIAL_NO = "nextSerialNumber";
     private static final String ATTR_PARTIAL = "partial";
     private static final String ATTR_USER_VERSION = "version";
+    private static final String ATTR_RELATED_GROUP_ID = "relatedGroupId";
     private static final String TAG_USERS = "users";
     private static final String TAG_USER = "user";
     private static final String TAG_RESTRICTIONS = "restrictions";
@@ -258,6 +259,29 @@
     }
 
     @Override
+    public List<UserInfo> getRelatedUsers(int userId) {
+        checkManageUsersPermission("query users");
+        synchronized (mPackagesLock) {
+            UserInfo user = getUserInfoLocked(userId);
+            ArrayList<UserInfo> users = new ArrayList<UserInfo>(mUsers.size());
+            for (int i = 0; i < mUsers.size(); i++) {
+                UserInfo ui = mUsers.valueAt(i);
+                if (!areRelatedUsers(user, ui)) {
+                    continue;
+                }
+                users.add(ui);
+            }
+            return users;
+        }
+    }
+
+    private boolean areRelatedUsers(UserInfo user1, UserInfo user2) {
+        return user1.relatedGroupId != UserInfo.NO_RELATED_GROUP_ID &&
+                user1.relatedGroupId == user2.relatedGroupId &&
+                user1.id != user2.id;
+    }
+
+    @Override
     public UserInfo getUserInfo(int userId) {
         checkManageUsersPermission("query user");
         synchronized (mPackagesLock) {
@@ -662,6 +686,10 @@
             if (userInfo.partial) {
                 serializer.attribute(null, ATTR_PARTIAL, "true");
             }
+            if (userInfo.relatedGroupId != UserInfo.NO_RELATED_GROUP_ID) {
+                serializer.attribute(null, ATTR_RELATED_GROUP_ID,
+                        Integer.toString(userInfo.relatedGroupId));
+            }
 
             serializer.startTag(null, TAG_NAME);
             serializer.text(userInfo.name);
@@ -745,6 +773,7 @@
         long salt = 0L;
         String pinHash = null;
         int failedAttempts = 0;
+        int relatedGroupId = UserInfo.NO_RELATED_GROUP_ID;
         long lastAttemptTime = 0L;
         boolean partial = false;
         Bundle restrictions = new Bundle();
@@ -782,6 +811,8 @@
                 pinHash = parser.getAttributeValue(null, ATTR_PIN_HASH);
                 failedAttempts = readIntAttribute(parser, ATTR_FAILED_ATTEMPTS, 0);
                 lastAttemptTime = readLongAttribute(parser, ATTR_LAST_RETRY_MS, 0L);
+                relatedGroupId = readIntAttribute(parser, ATTR_RELATED_GROUP_ID,
+                        UserInfo.NO_RELATED_GROUP_ID);
                 String valueString = parser.getAttributeValue(null, ATTR_PARTIAL);
                 if ("true".equals(valueString)) {
                     partial = true;
@@ -820,6 +851,7 @@
             userInfo.creationTime = creationTime;
             userInfo.lastLoggedInTime = lastLoggedInTime;
             userInfo.partial = partial;
+            userInfo.relatedGroupId = relatedGroupId;
             mUserRestrictions.append(id, restrictions);
             if (salt != 0L) {
                 RestrictionsPinState pinState = mRestrictionsPinStates.get(id);
@@ -934,10 +966,40 @@
         }
     }
 
+    private int getNextRelatedGroupIdLocked() {
+        int maxGroupId = UserInfo.NO_RELATED_GROUP_ID;
+        for (int i = 0; i < mUsers.size(); i++) {
+            UserInfo ui = mUsers.valueAt(i);
+            if (maxGroupId < ui.relatedGroupId) {
+                maxGroupId = ui.relatedGroupId;
+            }
+        }
+        return maxGroupId + 1;
+    }
+
+    @Override
+    public UserInfo createRelatedUser(String name, int flags, int relatedUserId) {
+        checkManageUsersPermission("Only the system can create users");
+        if (relatedUserId != UserHandle.USER_OWNER) {
+            Slog.w(LOG_TAG, "Only user owner can have related users");
+            return null;
+        }
+        synchronized (mPackagesLock) {
+            UserInfo relatedUser = getUserInfoLocked(relatedUserId);
+            if (relatedUser == null) {
+                return null;
+            }
+            return createUserInternal(name, flags, relatedUser);
+        }
+    }
+
     @Override
     public UserInfo createUser(String name, int flags) {
         checkManageUsersPermission("Only the system can create users");
+        return createUserInternal(name, flags, null);
+    }
 
+    private UserInfo createUserInternal(String name, int flags, UserInfo relatedUser) {
         final long ident = Binder.clearCallingIdentity();
         final UserInfo userInfo;
         try {
@@ -954,6 +1016,13 @@
                     Environment.getUserSystemDirectory(userInfo.id).mkdirs();
                     mUsers.put(userId, userInfo);
                     writeUserListLocked();
+                    if (relatedUser != null) {
+                        if (relatedUser.relatedGroupId == UserInfo.NO_RELATED_GROUP_ID) {
+                            relatedUser.relatedGroupId = getNextRelatedGroupIdLocked();
+                        }
+                        userInfo.relatedGroupId = relatedUser.relatedGroupId;
+                        writeUserLocked(relatedUser);
+                    }
                     writeUserLocked(userInfo);
                     mPm.createNewUserLILPw(userId, userPath);
                     userInfo.partial = false;
diff --git a/services/core/java/com/android/server/power/DisplayPowerController.java b/services/core/java/com/android/server/power/DisplayPowerController.java
index f1be504..b63f625 100644
--- a/services/core/java/com/android/server/power/DisplayPowerController.java
+++ b/services/core/java/com/android/server/power/DisplayPowerController.java
@@ -536,6 +536,14 @@
 
         mScreenBrightnessRampAnimator = new RampAnimator<DisplayPowerState>(
                 mPowerState, DisplayPowerState.SCREEN_BRIGHTNESS);
+
+        // Initialize screen on state.
+        if (mPowerState.isScreenOn()) {
+            mNotifier.onScreenOn();
+        } else {
+            mNotifier.onScreenOff();
+        }
+        mNotifier.onScreenBrightness(mPowerState.getScreenBrightness());
     }
 
     private final Animator.AnimatorListener mAnimatorListener = new Animator.AnimatorListener() {
diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java
index 264e2e9..09be3a8 100644
--- a/services/core/java/com/android/server/power/Notifier.java
+++ b/services/core/java/com/android/server/power/Notifier.java
@@ -34,6 +34,7 @@
 import android.os.Looper;
 import android.os.Message;
 import android.os.PowerManager;
+import android.os.Process;
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.UserHandle;
@@ -139,10 +140,14 @@
 
         try {
             final int monitorType = getBatteryStatsWakeLockMonitorType(flags);
+            boolean unimportantForLogging = (flags&PowerManager.UNIMPORTANT_FOR_LOGGING) != 0
+                    && ownerUid == Process.SYSTEM_UID;
             if (workSource != null) {
-                mBatteryStats.noteStartWakelockFromSource(workSource, ownerPid, tag, monitorType);
+                mBatteryStats.noteStartWakelockFromSource(workSource, ownerPid, tag, monitorType,
+                        unimportantForLogging);
             } else {
-                mBatteryStats.noteStartWakelock(ownerUid, ownerPid, tag, monitorType);
+                mBatteryStats.noteStartWakelock(ownerUid, ownerPid, tag, monitorType,
+                        unimportantForLogging);
                 // XXX need to deal with disabled operations.
                 mAppOps.startOperation(AppOpsManager.getToken(mAppOps),
                         AppOpsManager.OP_WAKE_LOCK, ownerUid, packageName);
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index b9ecde1..b2344e6 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -168,7 +168,7 @@
     // effectively and terminate the dream.
     private static final int DREAM_BATTERY_LEVEL_DRAIN_CUTOFF = 5;
 
-    private Context mContext;
+    private final Context mContext;
     private LightsManager mLightsManager;
     private BatteryService mBatteryService;
     private DisplayManagerInternal mDisplayManagerInternal;
@@ -374,7 +374,9 @@
     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");
@@ -391,11 +393,6 @@
     }
 
     @Override
-    public void onCreate(Context context) {
-        mContext = context;
-    }
-
-    @Override
     public void onStart() {
         publishBinderService(Context.POWER_SERVICE, new BinderService());
         publishLocalService(PowerManagerInternal.class, new LocalService());
diff --git a/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java b/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
index 8805084..43a99e0 100644
--- a/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
+++ b/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
@@ -89,11 +89,11 @@
     private long mLastReportedFreeMemTime;
     boolean mLowMemFlag=false;
     private boolean mMemFullFlag=false;
-    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();
@@ -102,10 +102,10 @@
     private long mThreadStartTime = -1;
     boolean mClearSucceeded = false;
     boolean mClearingCache;
-    private Intent mStorageLowIntent;
-    private Intent mStorageOkIntent;
-    private Intent mStorageFullIntent;
-    private Intent mStorageNotFullIntent;
+    private final Intent mStorageLowIntent;
+    private final Intent mStorageOkIntent;
+    private final Intent mStorageFullIntent;
+    private final Intent mStorageNotFullIntent;
     private CachePackageDataObserver mClearCacheObserver;
     private CacheFileDeletedObserver mCacheFileDeletedObserver;
     private static final int _TRUE = 1;
@@ -134,7 +134,7 @@
     * Handler that checks the amount of disk space on the device and sends a
     * notification if the device runs low on disk space
     */
-    private Handler mHandler = new Handler() {
+    private final Handler mHandler = new Handler() {
         @Override
         public void handleMessage(Message msg) {
             //don't handle an invalid message
@@ -310,12 +310,8 @@
                 delay);
     }
 
-    /**
-    * Constructor to run service. initializes the disk space threshold value
-    * and posts an empty message to kickstart the process.
-    */
-    @Override
-    public void onCreate(Context context) {
+    public DeviceStorageMonitorService(Context context) {
+        super(context);
         mLastReportedFreeMemTime = 0;
         mResolver = context.getContentResolver();
         //create StatFs object
@@ -335,6 +331,10 @@
         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
diff --git a/services/core/java/com/android/server/twilight/TwilightService.java b/services/core/java/com/android/server/twilight/TwilightService.java
index 8feb97b..a71961c 100644
--- a/services/core/java/com/android/server/twilight/TwilightService.java
+++ b/services/core/java/com/android/server/twilight/TwilightService.java
@@ -65,6 +65,10 @@
 
     TwilightState mTwilightState;
 
+    public TwilightService(Context context) {
+        super(context);
+    }
+
     @Override
     public void onStart() {
         mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index e98014b..ca4ad8a 100644
--- a/services/core/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/core/java/com/android/server/wm/DimLayer.java b/services/core/java/com/android/server/wm/DimLayer.java
index 978d5b7..574ae2d 100644
--- a/services/core/java/com/android/server/wm/DimLayer.java
+++ b/services/core/java/com/android/server/wm/DimLayer.java
@@ -51,9 +51,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();
@@ -170,7 +170,7 @@
             dw = mBounds.width();
             dh = mBounds.height();
             xPos = mBounds.left;
-            yPos = mBounds.right;
+            yPos = mBounds.top;
         } else {
             // Set surface size to screen size.
             final DisplayInfo info = mDisplayContent.getDisplayInfo();
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 0a070c1..415a06b 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -17,18 +17,15 @@
 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.graphics.Rect;
 import android.graphics.Region;
-import android.util.EventLog;
 import android.util.Slog;
 import android.view.Display;
 import android.view.DisplayInfo;
 import android.view.Surface;
-import com.android.server.EventLogTags;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -50,7 +47,7 @@
 
     /** Z-ordered (bottom-most first) list of all Window objects. Assigned to an element
      * from mDisplayWindows; */
-    private WindowList mWindows = new WindowList();
+    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
@@ -80,21 +77,12 @@
     int pendingLayoutChanges;
     final boolean isDefaultDisplay;
 
-    /**
-     * Window tokens that are in the process of exiting, but still
-     * on screen for animations.
-     */
+    /** 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 all TaskStacks on this display.  Array
      * is stored in display order with the current bottom stack at 0. */
-    private ArrayList<TaskStack> mStacks = new ArrayList<TaskStack>();
+    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. */
@@ -106,17 +94,21 @@
     /** 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();
 
+    /** For gathering Task objects in order. */
+    final ArrayList<Task> mTmpTaskHistory = new ArrayList<Task>();
+
     final WindowManagerService mService;
 
+    static final int DEFER_DETACH = 1;
+    static final int DEFER_REMOVAL = 2;
+    int mDeferredActions;
+
     /**
      * @param display May not be null.
-     * @param service TODO(cmautner):
+     * @param service You know.
      */
     DisplayContent(Display display, WindowManagerService service) {
         mDisplay = display;
@@ -153,41 +145,21 @@
         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() {
-        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;
-                }
-            }
+        mTmpTaskHistory.clear();
+        final int numStacks = mStacks.size();
+        for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
+            mTmpTaskHistory.addAll(mStacks.get(stackNdx).getTasks());
         }
-
-        mTaskHistory.add(taskNdx, task);
-        EventLog.writeEvent(EventLogTags.WM_TASK_MOVED, task.taskId, toTop ? 1 : 0, taskNdx);
-    }
-
-    void removeTask(Task task) {
-        mTaskHistory.remove(task);
+        return mTmpTaskHistory;
     }
 
     TaskStack getHomeStack() {
@@ -227,28 +199,16 @@
         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)} */
-    TaskStack createStack(int stackId) {
-        if (DEBUG_STACK) Slog.d(TAG, "createStack: stackId=" + stackId);
-        TaskStack newStack = new TaskStack(mService, stackId, this);
-        if (stackId == HOME_STACK_ID) {
+    /** Refer to {@link WindowManagerService#attachStack(int, int)} */
+    void attachStack(TaskStack stack) {
+        if (stack.mStackId == HOME_STACK_ID) {
             if (mHomeStack != null) {
-                throw new IllegalArgumentException("createStack: HOME_STACK_ID (0) not first.");
+                throw new IllegalArgumentException("attachStack: HOME_STACK_ID (0) not first.");
             }
-            mHomeStack = newStack;
+            mHomeStack = stack;
         }
-        mStacks.add(newStack);
+        mStacks.add(stack);
         layoutNeeded = true;
-        return newStack;
     }
 
     void moveStack(TaskStack stack, boolean toTop) {
@@ -256,12 +216,8 @@
         mStacks.add(toTop ? mStacks.size() : 0, stack);
     }
 
-    TaskStack removeStack(TaskStack stack) {
+    void detachStack(TaskStack stack) {
         mStacks.remove(stack);
-        if (!mStacks.isEmpty()) {
-            return mStacks.get(mStacks.size() - 1);
-        }
-        return null;
     }
 
     /**
@@ -272,17 +228,6 @@
         mContentRect.set(contentRect);
     }
 
-    boolean getStackBounds(int stackId, Rect bounds) {
-        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
-            final TaskStack stack = mStacks.get(stackNdx);
-            if (stackId == stack.mStackId) {
-                bounds.set(stack.mBounds);
-                return true;
-            }
-        }
-        return false;
-    }
-
     int stackIdFromPoint(int x, int y) {
         for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
             final TaskStack stack = mStacks.get(stackNdx);
@@ -308,7 +253,7 @@
         }
     }
 
-    void switchUserStacks(int oldUserId, int newUserId) {
+    void switchUserStacks(int newUserId) {
         final WindowList windows = getWindowList();
         for (int i = 0; i < windows.size(); i++) {
             final WindowState win = windows.get(i);
@@ -394,22 +339,27 @@
             pw.print(prefix); pw.print("mStacks[" + stackNdx + "]"); pw.println(stack.mStackId);
             stack.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;
+        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("  App #"); pw.print(ndx++);
                             pw.print(' '); pw.print(wtoken); pw.println(":");
                     wtoken.dump(pw, "    ");
                 }
             }
         }
-        if (mExitingTokens.size() > 0) {
+        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--) {
@@ -420,17 +370,6 @@
                 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/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 87cabc9..ca9076f 100644
--- a/services/core/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/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index a1704a6..c301ffe 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -24,6 +24,7 @@
     final AppTokenList mAppTokens = new AppTokenList();
     final int taskId;
     final int mUserId;
+    boolean mDeferRemoval = false;
 
     Task(AppWindowToken wtoken, TaskStack stack, int userId) {
         taskId = wtoken.groupId;
@@ -45,7 +46,6 @@
         if (mAppTokens.size() == 0) {
             EventLog.writeEvent(com.android.server.EventLogTags.WM_TASK_REMOVED, taskId,
                     "removeAppToken: last token");
-            mStack.removeTask(this);
             return true;
         }
         return false;
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index aa6b0c9..7d8cff4 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -41,7 +41,7 @@
     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 */
@@ -52,13 +52,13 @@
     Rect mBounds = new Rect();
 
     /** Used to support {@link android.view.WindowManager.LayoutParams#FLAG_DIM_BEHIND} */
-    final DimLayer mDimLayer;
+    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;
@@ -67,12 +67,12 @@
      * 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();
+
+    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);
@@ -121,18 +121,37 @@
     }
 
     void getBounds(Rect out) {
-        if (mBounds.isEmpty()) {
-            mDisplayContent.getLogicalDisplayRect(out);
+        if (mDisplayContent != null) {
+            if (mBounds.isEmpty()) {
+                mDisplayContent.getLogicalDisplayRect(out);
+            } else {
+                out.set(mBounds);
+            }
+            out.intersect(mDisplayContent.mContentRect);
         } else {
             out.set(mBounds);
         }
-        out.intersect(mDisplayContent.mContentRect);
     }
 
     boolean isFullscreen() {
         return mBounds.isEmpty();
     }
 
+    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;
+    }
+
     void resizeBounds(float oldWidth, float oldHeight, float newWidth, float newHeight) {
         if (oldWidth == newWidth && oldHeight == newHeight) {
             return;
@@ -173,8 +192,8 @@
         mTasks.add(stackNdx, task);
 
         task.mStack = this;
-        mDisplayContent.addTask(task, toTop);
         mDisplayContent.moveStack(this, true);
+        EventLog.writeEvent(EventLogTags.WM_TASK_MOVED, task.taskId, toTop ? 1 : 0, stackNdx);
     }
 
     void moveTaskToTop(Task task) {
@@ -198,22 +217,34 @@
     void removeTask(Task task) {
         if (DEBUG_TASK_MOVEMENT) Slog.d(TAG, "removeTask: task=" + task);
         mTasks.remove(task);
-        mDisplayContent.removeTask(task);
-        if (mTasks.isEmpty()) {
-            mDisplayContent.moveStack(this, false);
+        if (mDisplayContent != null) {
+            if (mTasks.isEmpty()) {
+                mDisplayContent.moveStack(this, false);
+            }
+            mDisplayContent.layoutNeeded = true;
         }
-        mDisplayContent.layoutNeeded = true;
     }
 
-    int remove() {
-        mAnimationBackgroundSurface.destroySurface();
-        mDimLayer.destroySurface();
-        EventLog.writeEvent(EventLogTags.WM_STACK_REMOVED, mStackId);
-        TaskStack next = mDisplayContent.removeStack(this);
-        if (next != null) {
-            return next.mStackId;
+    void attachDisplayContent(DisplayContent displayContent) {
+        if (mDisplayContent != null) {
+            throw new IllegalStateException("attachDisplayContent: Already attached");
         }
-        return -1;
+
+        mDisplayContent = displayContent;
+        mDimLayer = new DimLayer(mService, this, displayContent);
+        mAnimationBackgroundSurface = new DimLayer(mService, this, displayContent);
+    }
+
+    void detachDisplay() {
+        EventLog.writeEvent(EventLogTags.WM_STACK_REMOVED, mStackId);
+        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() {
@@ -335,6 +366,34 @@
         mAnimationBackgroundSurface.mDimSurface.destroy();
     }
 
+    void checkForDeferredActions() {
+        if (mDisplayContent != null &&
+                (mDisplayContent.mDeferredActions & DisplayContent.DEFER_DETACH) != 0 &&
+                !isAnimating()) {
+            mDisplayContent.mDeferredActions &= ~DisplayContent.DEFER_DETACH;
+            mService.detachStack(mStackId);
+            if ((mDisplayContent.mDeferredActions & DisplayContent.DEFER_REMOVAL) != 0) {
+                mDisplayContent.mDeferredActions &= ~DisplayContent.DEFER_REMOVAL;
+                mService.onDisplayRemoved(mDisplayContent.getDisplayId());
+            }
+        }
+        for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
+            final Task task = mTasks.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);
+            }
+        }
+    }
+
     public void dump(String prefix, PrintWriter pw) {
         pw.print(prefix); pw.print("mStackId="); pw.println(mStackId);
         for (int taskNdx = 0; taskNdx < mTasks.size(); ++taskNdx) {
@@ -349,6 +408,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/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index 91f15f3..a9947c0 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -64,7 +64,7 @@
     Object mLastWindowFreezeSource;
 
     SparseArray<DisplayContentsAnimator> mDisplayContentsAnimators =
-            new SparseArray<WindowAnimator.DisplayContentsAnimator>(2);
+            new SparseArray<DisplayContentsAnimator>(2);
 
     boolean mInitialized = false;
 
@@ -151,14 +151,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 +185,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 +451,6 @@
         }
     }
 
-    private void performAnimationsLocked(final int displayId) {
-        updateWindowsLocked(displayId);
-        updateWallpaperLocked(displayId);
-    }
-
 
     /** Locked on mService.mWindowMap. */
     private void animateLocked() {
@@ -494,7 +491,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 +640,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 +658,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 +679,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/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 6c7fb26..8f07e27 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -21,6 +21,7 @@
 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;
 
@@ -155,8 +156,7 @@
 
 /** {@hide} */
 public class WindowManagerService extends IWindowManager.Stub
-        implements Watchdog.Monitor, WindowManagerPolicy.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;
@@ -269,10 +269,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;
@@ -364,6 +364,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];
@@ -603,6 +608,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;
@@ -742,7 +750,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);
@@ -874,7 +881,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);
             }
         }
@@ -905,7 +912,7 @@
     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();
 
         final WindowList windows = win.getWindowList();
         final int N = windows.size();
@@ -1082,7 +1089,7 @@
 
     private void addAttachedWindowToListLocked(final WindowState win, boolean addToToken) {
         final WindowToken token = win.mToken;
-        final DisplayContent displayContent = win.mDisplayContent;
+        final DisplayContent displayContent = win.getDisplayContent();
         final WindowState attached = win.mAttachedWindow;
 
         WindowList tokenWindowList = getTokenWindowsOnDisplay(token, displayContent);
@@ -2016,7 +2023,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;
@@ -2076,7 +2086,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;
@@ -2428,7 +2441,10 @@
                 //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();
@@ -2485,8 +2501,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;
@@ -2541,12 +2555,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();
+                }
             }
         }
 
@@ -2621,7 +2642,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();
                 }
             }
@@ -2707,7 +2731,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 = window.getDisplayContent().getDisplayInfo();
         final RectF dispRect = new RectF(0, 0,
                 displayInfo.logicalWidth, displayInfo.logicalHeight);
         matrix.mapRect(dispRect);
@@ -2716,7 +2745,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();
     }
 
@@ -2997,7 +3026,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();
@@ -3091,7 +3123,10 @@
                         getDefaultDisplayContentLocked().pendingLayoutChanges |=
                                 WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
                     }
-                    win.mDisplayContent.layoutNeeded = true;
+                    final DisplayContent displayContent = win.getDisplayContent();
+                    if (displayContent != null) {
+                        displayContent.layoutNeeded = true;
+                    }
                     requestTraversalLocked();
                 }
             }
@@ -3349,7 +3384,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;
@@ -3364,7 +3399,9 @@
                                         WindowManagerPolicy.TRANSIT_EXIT);
                             }
                             changed = true;
-                            displayContent.layoutNeeded = true;
+                            if (displayContent != null) {
+                                displayContent.layoutNeeded = true;
+                            }
                         }
                     }
 
@@ -3377,7 +3414,9 @@
                     }
 
                     if (delayed) {
-                        displayContent.mExitingTokens.add(wtoken);
+                        if (displayContent != null) {
+                            displayContent.mExitingTokens.add(wtoken);
+                        }
                     } else if (wtoken.windowType == TYPE_WALLPAPER) {
                         mWallpaperTokens.remove(wtoken);
                     }
@@ -3392,6 +3431,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);
@@ -3473,8 +3514,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);
@@ -3767,7 +3808,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;
         }
@@ -4224,7 +4268,10 @@
                             }
                         }
                         changed = true;
-                        win.mDisplayContent.layoutNeeded = true;
+                        final DisplayContent displayContent = win.getDisplayContent();
+                        if (displayContent != null) {
+                            displayContent.layoutNeeded = true;
+                        }
                     }
                 } else if (win.isVisibleNow()) {
                     if (!runningAppAnimation) {
@@ -4238,7 +4285,10 @@
                         }
                     }
                     changed = true;
-                    win.mDisplayContent.layoutNeeded = true;
+                    final DisplayContent displayContent = win.getDisplayContent();
+                    if (displayContent != null) {
+                        displayContent.layoutNeeded = true;
+                    }
                 }
             }
 
@@ -4386,7 +4436,10 @@
                     }
                     w.mLastFreezeDuration = 0;
                     unfrozeWindows = true;
-                    w.mDisplayContent.layoutNeeded = true;
+                    final DisplayContent displayContent = w.getDisplayContent();
+                    if (displayContent != null) {
+                        displayContent.layoutNeeded = true;
+                    }
                 }
             }
             if (force || unfrozeWindows) {
@@ -4480,6 +4533,13 @@
         }
     }
 
+    void removeAppFromTaskLocked(AppWindowToken wtoken) {
+        final Task task = mTaskIdToTask.get(wtoken.groupId);
+        if (task != null) {
+            task.removeAppToken(wtoken);
+        }
+    }
+
     @Override
     public void removeAppToken(IBinder token) {
         if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
@@ -4512,26 +4572,25 @@
                         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();
+                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;
@@ -4566,13 +4625,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();
@@ -4588,29 +4649,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));
             }
         }
     }
@@ -4722,23 +4786,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.
@@ -4822,15 +4891,25 @@
      * @param stackId The unique identifier of the new stack.
      * @param displayId The unique identifier of the DisplayContent.
      */
-    public void createStack(int stackId, int displayId) {
+    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 = displayContent.createStack(stackId);
-                    mStackIdToStack.put(stackId, stack);
-                    performLayoutAndPlaceSurfacesLocked();
+                    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();
+                    }
                 }
             }
         } finally {
@@ -4838,6 +4917,38 @@
         }
     }
 
+    public void detachStack(int stackId) {
+        synchronized (mWindowMap) {
+            TaskStack stack = mStackIdToStack.get(stackId);
+            if (stack != null) {
+                final DisplayContent displayContent = stack.getDisplayContent();
+                if (displayContent != null) {
+                    if (stack.isAnimating()) {
+                        displayContent.mDeferredActions |= DisplayContent.DEFER_DETACH;
+                        return;
+                    }
+                    displayContent.detachStack(stack);
+                    stack.detachDisplay();
+                }
+            }
+        }
+    }
+
+    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) {
         synchronized (mWindowMap) {
             Task task = mTaskIdToTask.get(taskId);
@@ -4845,14 +4956,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);
+            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;
@@ -5161,7 +5272,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();
@@ -7314,15 +7425,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);
+                                    }
                                 }
                             }
                         }
@@ -7888,7 +8002,6 @@
     }
 
     final void rebuildAppWindowListLocked() {
-        // TODO: Multidisplay, when ActivityStacks and tasks exist on more than one display.
         rebuildAppWindowListLocked(getDefaultDisplayContentLocked());
     }
 
@@ -7933,27 +8046,34 @@
         // 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);
+                    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];
@@ -8621,15 +8741,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();
@@ -8763,8 +8882,8 @@
             if (canBeSeen) {
                 // This function assumes that the contents of the default display are
                 // processed first before secondary displays.
-                final DisplayContent displayContent = w.mDisplayContent;
-                if (displayContent.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
@@ -8773,8 +8892,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;
                 }
@@ -8782,7 +8902,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()
@@ -8800,22 +8920,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();
+                        }
                     }
                 }
             }
@@ -8846,10 +8967,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;
             }
         }
 
@@ -8982,7 +9107,7 @@
                     }
 
                     if (!stack.testDimmingTag()) {
-                        handleFlagDimBehind(w, innerDw, innerDh);
+                        handleFlagDimBehind(w);
                     }
 
                     if (isDefaultDisplay && obscuredChanged && (mWallpaperTarget == w)
@@ -9198,57 +9323,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);
         }
 
@@ -9296,9 +9371,13 @@
                     }
                 }
             }
+        }
 
-            // 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)) {
@@ -9309,10 +9388,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);
                 }
             }
@@ -9393,8 +9469,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);
                 }
             }
 
@@ -9404,6 +9481,11 @@
             }
         }
 
+        // Remove all deferred Stacks, tasks, and activities.
+        for (int stackNdx = mPendingStacksRemove.size() - 1; stackNdx >= 0; --stackNdx) {
+            mPendingStacksRemove.removeAt(stackNdx).checkForDeferredActions();
+        }
+
         setFocusedStackFrame();
 
         // Check to see if we are now in a state where the screen should
@@ -10765,7 +10847,6 @@
         return displayContent != null ? displayContent.getWindowList() : null;
     }
 
-    @Override
     public void onDisplayAdded(int displayId) {
         mH.sendMessage(mH.obtainMessage(H.DO_DISPLAY_ADDED, displayId, 0));
     }
@@ -10780,7 +10861,6 @@
         }
     }
 
-    @Override
     public void onDisplayRemoved(int displayId) {
         mH.sendMessage(mH.obtainMessage(H.DO_DISPLAY_REMOVED, displayId, 0));
     }
@@ -10788,21 +10868,19 @@
     private void handleDisplayRemovedLocked(int displayId) {
         final DisplayContent displayContent = getDisplayContentLocked(displayId);
         if (displayContent != null) {
+            if ((displayContent.mDeferredActions & DisplayContent.DEFER_DETACH) != 0) {
+                displayContent.mDeferredActions |= DisplayContent.DEFER_REMOVAL;
+                return;
+            }
             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);
-            }
         }
         mAnimator.removeDisplayLocked(displayId);
     }
 
-    @Override
     public void onDisplayChanged(int displayId) {
         mH.sendMessage(mH.obtainMessage(H.DO_DISPLAY_CHANGED, displayId, 0));
     }
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 77a36b8..a8e45c4 100644
--- a/services/core/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;
@@ -593,9 +598,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 +716,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() {
@@ -722,7 +738,8 @@
                 }
                 Slog.e(TAG, "getStack: mStack null for task=" + task);
             } else {
-                Slog.e(TAG, "getStack: couldn't find taskId=" + wtoken.groupId);
+                Slog.e(TAG, "getStack: " + this + " couldn't find taskId=" + wtoken.groupId
+                    + " Callers=" + Debug.getCallers(4));
             }
         }
         return mDisplayContent.getHomeStack();
@@ -1196,7 +1213,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) {
@@ -1213,7 +1235,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) {
@@ -1255,7 +1281,8 @@
     }
 
     WindowList getWindowList() {
-        return mDisplayContent.getWindowList();
+        final DisplayContent displayContent = getDisplayContent();
+        return displayContent == null ? null : displayContent.getWindowList();
     }
 
     /**
@@ -1284,6 +1311,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) {
@@ -1308,7 +1383,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/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index c405170..ffb17f1 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -150,8 +150,6 @@
     int mAttrFlags;
     int mAttrType;
 
-    final int mLayerStack;
-
     public WindowStateAnimator(final WindowState win) {
         final WindowManagerService service = win.mService;
 
@@ -159,7 +157,7 @@
         mAnimator = service.mAnimator;
         mPolicy = service.mPolicy;
         mContext = service.mContext;
-        final DisplayInfo displayInfo = win.mDisplayContent.getDisplayInfo();
+        final DisplayInfo displayInfo = win.getDisplayContent().getDisplayInfo();
         mAnimDw = displayInfo.appWidth;
         mAnimDh = displayInfo.appHeight;
 
@@ -171,7 +169,6 @@
         mAttrFlags = win.mAttrs.flags;
         mAttrType = win.mAttrs.type;
         mIsWallpaper = win.mIsWallpaper;
-        mLayerStack = win.mDisplayContent.getDisplay().getLayerStack();
     }
 
     public void setAnimation(Animation anim) {
@@ -243,7 +240,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 +256,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 +335,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 +363,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));
@@ -414,6 +416,7 @@
             mService.mPendingRemove.add(mWin);
             mWin.mRemoveOnExit = false;
         }
+        mService.mPendingStacksRemove.add(mWin.getStack());
         mAnimator.hideWallpapersLocked(mWin);
     }
 
@@ -732,7 +735,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 +927,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 +1007,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 +1085,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 +1190,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);
@@ -1444,7 +1452,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/core/java/service.mk b/services/core/java/service.mk
deleted file mode 100644
index 4cb411b..0000000
--- a/services/core/java/service.mk
+++ /dev/null
@@ -1,6 +0,0 @@
-SUB_DIR := core/java
-
-LOCAL_SRC_FILES += \
-      $(call all-java-files-under,$(SUB_DIR)) \
-      $(SUB_DIR)/com/android/server/EventLogTags.logtags \
-      $(SUB_DIR)/com/android/server/am/EventLogTags.logtags
diff --git a/services/core/jni/Android.mk b/services/core/jni/Android.mk
index 1a3ce63..85f69a4 100644
--- a/services/core/jni/Android.mk
+++ b/services/core/jni/Android.mk
@@ -2,6 +2,8 @@
 # files
 LOCAL_REL_DIR := core/jni
 
+LOCAL_CFLAGS += -Wno-unused-parameter
+
 LOCAL_SRC_FILES += \
     $(LOCAL_REL_DIR)/com_android_server_AlarmManagerService.cpp \
     $(LOCAL_REL_DIR)/com_android_server_AssetAtlasService.cpp \
@@ -45,6 +47,7 @@
     libutils \
     libui \
     libinput \
+    libinputflinger \
     libinputservice \
     libsensorservice \
     libskia \
diff --git a/services/core/jni/com_android_server_ConsumerIrService.cpp b/services/core/jni/com_android_server_ConsumerIrService.cpp
index 004c0aa..3a50ff7 100644
--- a/services/core/jni/com_android_server_ConsumerIrService.cpp
+++ b/services/core/jni/com_android_server_ConsumerIrService.cpp
@@ -29,7 +29,7 @@
 
 namespace android {
 
-static jint halOpen(JNIEnv *env, jobject obj) {
+static jlong halOpen(JNIEnv *env, jobject obj) {
     hw_module_t const* module;
     consumerir_device_t *dev;
     int err;
@@ -47,10 +47,10 @@
         return 0;
     }
 
-    return reinterpret_cast<jint>(dev);
+    return reinterpret_cast<jlong>(dev);
 }
 
-static jint halTransmit(JNIEnv *env, jobject obj, jint halObject,
+static jint halTransmit(JNIEnv *env, jobject obj, jlong halObject,
    jint carrierFrequency, jintArray pattern) {
     int ret;
 
@@ -67,8 +67,8 @@
 }
 
 static jintArray halGetCarrierFrequencies(JNIEnv *env, jobject obj,
-    jint halObject) {
-    consumerir_device_t *dev = (consumerir_device_t *) halObject;
+    jlong halObject) {
+    consumerir_device_t *dev = reinterpret_cast<consumerir_device_t*>(halObject);
     consumerir_freq_range_t *ranges;
     int len;
 
@@ -101,9 +101,9 @@
 }
 
 static JNINativeMethod method_table[] = {
-    { "halOpen", "()I", (void *)halOpen },
-    { "halTransmit", "(II[I)I", (void *)halTransmit },
-    { "halGetCarrierFrequencies", "(I)[I", (void *)halGetCarrierFrequencies},
+    { "halOpen", "()J", (void *)halOpen },
+    { "halTransmit", "(JI[I)I", (void *)halTransmit },
+    { "halGetCarrierFrequencies", "(J)[I", (void *)halGetCarrierFrequencies},
 };
 
 int register_android_server_ConsumerIrService(JNIEnv *env) {
diff --git a/services/core/jni/com_android_server_input_InputApplicationHandle.h b/services/core/jni/com_android_server_input_InputApplicationHandle.h
index 89d48c6..62c8570 100644
--- a/services/core/jni/com_android_server_input_InputApplicationHandle.h
+++ b/services/core/jni/com_android_server_input_InputApplicationHandle.h
@@ -17,7 +17,7 @@
 #ifndef _ANDROID_SERVER_INPUT_APPLICATION_HANDLE_H
 #define _ANDROID_SERVER_INPUT_APPLICATION_HANDLE_H
 
-#include <input/InputApplication.h>
+#include <inputflinger/InputApplication.h>
 
 #include "JNIHelp.h"
 #include "jni.h"
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 43fbe9d..321776c 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -35,10 +35,11 @@
 #include <utils/Looper.h>
 #include <utils/threads.h>
 
-#include <input/InputManager.h>
 #include <input/PointerController.h>
 #include <input/SpriteController.h>
 
+#include <inputflinger/InputManager.h>
+
 #include <android_os_MessageQueue.h>
 #include <android_view_InputDevice.h>
 #include <android_view_KeyEvent.h>
diff --git a/services/core/jni/com_android_server_input_InputWindowHandle.cpp b/services/core/jni/com_android_server_input_InputWindowHandle.cpp
index b80183c..03bf7eb 100644
--- a/services/core/jni/com_android_server_input_InputWindowHandle.cpp
+++ b/services/core/jni/com_android_server_input_InputWindowHandle.cpp
@@ -23,6 +23,7 @@
 
 #include <android_view_InputChannel.h>
 #include <android/graphics/Region.h>
+#include <ui/Region.h>
 
 #include "com_android_server_input_InputWindowHandle.h"
 #include "com_android_server_input_InputApplicationHandle.h"
@@ -86,6 +87,8 @@
 
     if (!mInfo) {
         mInfo = new InputWindowInfo();
+    } else {
+        mInfo->touchableRegion.clear();
     }
 
     jobject inputChannelObj = env->GetObjectField(obj,
@@ -131,10 +134,11 @@
             gInputWindowHandleClassInfo.touchableRegion);
     if (regionObj) {
         SkRegion* region = android_graphics_Region_getSkRegion(env, regionObj);
-        mInfo->touchableRegion.set(*region);
+        for (SkRegion::Iterator it(*region); !it.done(); it.next()) {
+            const SkIRect& rect = it.rect();
+            mInfo->addTouchableRegion(Rect(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom));
+        }
         env->DeleteLocalRef(regionObj);
-    } else {
-        mInfo->touchableRegion.setEmpty();
     }
 
     mInfo->visible = env->GetBooleanField(obj,
diff --git a/services/core/jni/com_android_server_input_InputWindowHandle.h b/services/core/jni/com_android_server_input_InputWindowHandle.h
index 2cfa17d3..8d9e7d7 100644
--- a/services/core/jni/com_android_server_input_InputWindowHandle.h
+++ b/services/core/jni/com_android_server_input_InputWindowHandle.h
@@ -17,7 +17,7 @@
 #ifndef _ANDROID_SERVER_INPUT_WINDOW_HANDLE_H
 #define _ANDROID_SERVER_INPUT_WINDOW_HANDLE_H
 
-#include <input/InputWindow.h>
+#include <inputflinger/InputWindow.h>
 
 #include "JNIHelp.h"
 #include "jni.h"
diff --git a/services/core/jni/com_android_server_power_PowerManagerService.h b/services/core/jni/com_android_server_power_PowerManagerService.h
index 0808b80..b48e546 100644
--- a/services/core/jni/com_android_server_power_PowerManagerService.h
+++ b/services/core/jni/com_android_server_power_PowerManagerService.h
@@ -20,7 +20,7 @@
 #include "JNIHelp.h"
 #include "jni.h"
 
-#include <androidfw/PowerManager.h>
+#include <powermanager/PowerManager.h>
 
 namespace android {
 
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/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java
new file mode 100644
index 0000000..1b048a1
--- /dev/null
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java
@@ -0,0 +1,274 @@
+/*
+ * 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.devicepolicy;
+
+import android.app.AppGlobals;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.Environment;
+import android.os.RemoteException;
+import android.util.AtomicFile;
+import android.util.Slog;
+import android.util.Xml;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.FastXmlSerializer;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.HashMap;
+
+/**
+ * Stores and restores state for the Device and Profile owners. By definition there can be
+ * only one device owner, but there may be a profile owner for each user.
+ */
+public class DeviceOwner {
+    private static final String TAG = "DevicePolicyManagerService";
+
+    private static final String DEVICE_OWNER_XML = "device_owner.xml";
+    private static final String TAG_DEVICE_OWNER = "device-owner";
+    private static final String TAG_PROFILE_OWNER = "profile-owner";
+    private static final String ATTR_NAME = "name";
+    private static final String ATTR_PACKAGE = "package";
+    private static final String ATTR_USERID = "userId";
+
+    private AtomicFile fileForWriting;
+
+    // Input/Output streams for testing.
+    private InputStream mInputStreamForTest;
+    private OutputStream mOutputStreamForTest;
+
+    // Internal state for the device owner package.
+    private String mDeviceOwnerPackageName;
+    private String mDeviceOwnerName;
+
+    // Internal state for the profile owner packages.
+    private final HashMap<Integer, String[]> mProfileOwners = new HashMap<Integer, String[]>();
+
+    // Private default constructor.
+    private DeviceOwner() {
+    }
+
+    @VisibleForTesting
+    DeviceOwner(InputStream in, OutputStream out) {
+        mInputStreamForTest = in;
+        mOutputStreamForTest = out;
+    }
+
+    /**
+     * Loads the device owner state from disk.
+     */
+    static DeviceOwner load() {
+        DeviceOwner owner = new DeviceOwner();
+        if (new File(Environment.getSystemSecureDirectory(), DEVICE_OWNER_XML).exists()) {
+            owner.readOwnerFile();
+            return owner;
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Creates an instance of the device owner object with the device owner set.
+     */
+    static DeviceOwner createWithDeviceOwner(String packageName, String ownerName) {
+        DeviceOwner owner = new DeviceOwner();
+        owner.mDeviceOwnerPackageName = packageName;
+        owner.mDeviceOwnerName = ownerName;
+        return owner;
+    }
+
+    /**
+     * Creates an instance of the device owner object with the profile owner set.
+     */
+    static DeviceOwner createWithProfileOwner(String packageName, String ownerName, int userId) {
+        DeviceOwner owner = new DeviceOwner();
+        owner.mProfileOwners.put(userId, new String[] { packageName, ownerName });
+        return owner;
+    }
+
+    String getDeviceOwnerPackageName() {
+        return mDeviceOwnerPackageName;
+    }
+
+    String getDeviceOwnerName() {
+        return mDeviceOwnerName;
+    }
+
+    void setDeviceOwner(String packageName, String ownerName) {
+        mDeviceOwnerPackageName = packageName;
+        mDeviceOwnerName = ownerName;
+    }
+
+    void setProfileOwner(String packageName, String ownerName, int userId) {
+        mProfileOwners.put(userId, new String[] { packageName, ownerName });
+    }
+
+    void removeProfileOwner(int userId) {
+        mProfileOwners.remove(userId);
+    }
+
+    String getProfileOwnerPackageName(int userId) {
+        String[] profileOwner = mProfileOwners.get(userId);
+        return profileOwner != null ? profileOwner[0] : null;
+    }
+
+    String getProfileOwnerName(int userId) {
+        String[] profileOwner = mProfileOwners.get(userId);
+        return profileOwner != null ? profileOwner[1] : null;
+    }
+
+    boolean hasDeviceOwner() {
+        return mDeviceOwnerPackageName != null;
+    }
+
+    static boolean isInstalled(String packageName, PackageManager pm) {
+        try {
+            PackageInfo pi;
+            if ((pi = pm.getPackageInfo(packageName, 0)) != null) {
+                if ((pi.applicationInfo.flags) != 0) {
+                    return true;
+                }
+            }
+        } catch (NameNotFoundException nnfe) {
+            Slog.w(TAG, "Device Owner package " + packageName + " not installed.");
+        }
+        return false;
+    }
+
+    static boolean isInstalledForUser(String packageName, int userHandle) {
+        try {
+            PackageInfo pi = (AppGlobals.getPackageManager())
+                    .getPackageInfo(packageName, 0, userHandle);
+            if (pi != null && pi.applicationInfo.flags != 0) {
+                return true;
+            }
+        } catch (RemoteException re) {
+            throw new RuntimeException("Package manager has died", re);
+        }
+
+        return false;
+    }
+
+    void readOwnerFile() {
+        try {
+            InputStream input = openRead();
+            XmlPullParser parser = Xml.newPullParser();
+            parser.setInput(input, null);
+            int type;
+            while ((type=parser.next()) != XmlPullParser.END_DOCUMENT) {
+                if (type!=XmlPullParser.START_TAG) {
+                    continue;
+                }
+
+                String tag = parser.getName();
+                if (tag.equals(TAG_DEVICE_OWNER)) {
+                    mDeviceOwnerPackageName = parser.getAttributeValue(null, ATTR_PACKAGE);
+                    mDeviceOwnerName = parser.getAttributeValue(null, ATTR_NAME);
+                } else if (tag.equals(TAG_PROFILE_OWNER)) {
+                    String profileOwnerPackageName = parser.getAttributeValue(null, ATTR_PACKAGE);
+                    String profileOwnerName = parser.getAttributeValue(null, ATTR_NAME);
+                    int userId = Integer.parseInt(parser.getAttributeValue(null, ATTR_USERID));
+                    mProfileOwners.put(userId,
+                            new String[] { profileOwnerPackageName, profileOwnerName });
+                } else {
+                    throw new XmlPullParserException(
+                            "Unexpected tag in device owner file: " + tag);
+                }
+            }
+            input.close();
+        } catch (XmlPullParserException xppe) {
+            Slog.e(TAG, "Error parsing device-owner file\n" + xppe);
+        } catch (IOException ioe) {
+            Slog.e(TAG, "IO Exception when reading device-owner file\n" + ioe);
+        }
+    }
+
+    void writeOwnerFile() {
+        synchronized (this) {
+            writeOwnerFileLocked();
+        }
+    }
+
+    private void writeOwnerFileLocked() {
+        try {
+            OutputStream outputStream = startWrite();
+            XmlSerializer out = new FastXmlSerializer();
+            out.setOutput(outputStream, "utf-8");
+            out.startDocument(null, true);
+
+            // Write device owner tag
+            if (mDeviceOwnerPackageName != null) {
+                out.startTag(null, TAG_DEVICE_OWNER);
+                out.attribute(null, ATTR_PACKAGE, mDeviceOwnerPackageName);
+                if (mDeviceOwnerName != null) {
+                    out.attribute(null, ATTR_NAME, mDeviceOwnerName);
+                }
+                out.endTag(null, TAG_DEVICE_OWNER);
+            }
+
+            // Write profile owner tags
+            if (mProfileOwners.size() > 0) {
+                for (HashMap.Entry<Integer, String[]> owner : mProfileOwners.entrySet()) {
+                    out.startTag(null, TAG_PROFILE_OWNER);
+                    out.attribute(null, ATTR_PACKAGE, owner.getValue()[0]);
+                    out.attribute(null, ATTR_NAME, owner.getValue()[1]);
+                    out.attribute(null, ATTR_USERID, Integer.toString(owner.getKey()));
+                    out.endTag(null, TAG_PROFILE_OWNER);
+                }
+            }
+            out.endDocument();
+            out.flush();
+            finishWrite(outputStream);
+        } catch (IOException ioe) {
+            Slog.e(TAG, "IO Exception when writing device-owner file\n" + ioe);
+        }
+    }
+
+    private InputStream openRead() throws IOException {
+        if (mInputStreamForTest != null) {
+            return mInputStreamForTest;
+        }
+
+        return new AtomicFile(new File(Environment.getSystemSecureDirectory(),
+                DEVICE_OWNER_XML)).openRead();
+    }
+
+    private OutputStream startWrite() throws IOException {
+        if (mOutputStreamForTest != null) {
+            return mOutputStreamForTest;
+        }
+
+        fileForWriting = new AtomicFile(new File(Environment.getSystemSecureDirectory(),
+                DEVICE_OWNER_XML));
+        return fileForWriting.startWrite();
+    }
+
+    private void finishWrite(OutputStream stream) {
+        if (fileForWriting != null) {
+            fileForWriting.finishWrite((FileOutputStream) stream);
+        }
+    }
+}
\ No newline at end of file
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 186fbe1..bb96544 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -25,10 +25,7 @@
 import com.android.internal.util.XmlUtils;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.org.conscrypt.TrustedCertificateStore;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
+import com.android.server.SystemService;
 
 import android.app.Activity;
 import android.app.ActivityManagerNative;
@@ -49,9 +46,7 @@
 import android.content.IntentFilter;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageManager;
-import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ResolveInfo;
 import android.content.pm.UserInfo;
 import android.net.ProxyProperties;
@@ -75,7 +70,6 @@
 import android.security.IKeyChainService;
 import android.security.KeyChain;
 import android.security.KeyChain.KeyChainConnection;
-import android.util.AtomicFile;
 import android.util.Log;
 import android.util.PrintWriterPrinter;
 import android.util.Printer;
@@ -84,6 +78,10 @@
 import android.util.Xml;
 import android.view.IWindowManager;
 
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
 import java.io.ByteArrayInputStream;
 import java.io.File;
 import java.io.FileDescriptor;
@@ -132,6 +130,7 @@
     IWindowManager mIWindowManager;
     NotificationManager mNotificationManager;
 
+    // Stores and loads state on device and profile owners.
     private DeviceOwner mDeviceOwner;
 
     /**
@@ -140,6 +139,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;
@@ -601,6 +620,11 @@
                 Slog.w(LOG_TAG, "Tried to remove device policy file for user 0! Ignoring.");
                 return;
             }
+            if (mDeviceOwner != null) {
+                mDeviceOwner.removeProfileOwner(userHandle);
+                mDeviceOwner.writeOwnerFile();
+            }
+
             DevicePolicyData policy = mUserData.get(userHandle);
             if (policy != null) {
                 mUserData.remove(userHandle);
@@ -614,9 +638,7 @@
 
     void loadDeviceOwner() {
         synchronized (this) {
-            if (DeviceOwner.isRegistered()) {
-                mDeviceOwner = new DeviceOwner();
-            }
+            mDeviceOwner = DeviceOwner.load();
         }
     }
 
@@ -1294,7 +1316,8 @@
             if (admin.getUid() != Binder.getCallingUid()) {
                 // If trying to remove device owner, refuse when the caller is not the owner.
                 if (mDeviceOwner != null
-                        && adminReceiver.getPackageName().equals(mDeviceOwner.getPackageName())) {
+                        && adminReceiver.getPackageName().equals(
+                        mDeviceOwner.getDeviceOwnerPackageName())) {
                     return;
                 }
                 mContext.enforceCallingOrSelfPermission(
@@ -2739,14 +2762,26 @@
                     + " for device owner");
         }
         synchronized (this) {
-            if (mDeviceOwner == null && !isDeviceProvisioned()) {
-                mDeviceOwner = new DeviceOwner(packageName, ownerName);
+            if (isDeviceProvisioned()) {
+                throw new IllegalStateException(
+                        "Trying to set device owner but device is already provisioned.");
+            }
+
+            if (mDeviceOwner != null && mDeviceOwner.hasDeviceOwner()) {
+                throw new IllegalStateException(
+                        "Trying to set device owner but device owner is already set.");
+            }
+
+            if (mDeviceOwner == null) {
+                // Device owner is not set and does not exist, set it.
+                mDeviceOwner = DeviceOwner.createWithDeviceOwner(packageName, ownerName);
                 mDeviceOwner.writeOwnerFile();
                 return true;
             } else {
-                throw new IllegalStateException("Trying to set device owner to " + packageName
-                        + ", owner=" + mDeviceOwner.getPackageName()
-                        + ", device_provisioned=" + isDeviceProvisioned());
+                // Device owner is not set but a profile owner exists, update Device owner state.
+                mDeviceOwner.setDeviceOwner(packageName, ownerName);
+                mDeviceOwner.writeOwnerFile();
+                return true;
             }
         }
     }
@@ -2758,7 +2793,7 @@
         }
         synchronized (this) {
             return mDeviceOwner != null
-                    && mDeviceOwner.getPackageName().equals(packageName);
+                    && mDeviceOwner.getDeviceOwnerPackageName().equals(packageName);
         }
     }
 
@@ -2769,7 +2804,7 @@
         }
         synchronized (this) {
             if (mDeviceOwner != null) {
-                return mDeviceOwner.getPackageName();
+                return mDeviceOwner.getDeviceOwnerPackageName();
             }
         }
         return null;
@@ -2783,7 +2818,67 @@
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null);
         synchronized (this) {
             if (mDeviceOwner != null) {
-                return mDeviceOwner.getName();
+                return mDeviceOwner.getDeviceOwnerName();
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public boolean setProfileOwner(String packageName, String ownerName, int userHandle) {
+        if (!mHasFeature) {
+            return false;
+        }
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null);
+        if (packageName == null
+                || !DeviceOwner.isInstalledForUser(packageName, userHandle)) {
+            throw new IllegalArgumentException("Package name " + packageName
+                    + " not installed for userId:" + userHandle);
+        }
+        synchronized (this) {
+            if (isUserSetupComplete(userHandle)) {
+                throw new IllegalStateException(
+                        "Trying to set profile owner but user is already set-up.");
+            }
+            if (mDeviceOwner == null) {
+                // Device owner state does not exist, create it.
+                mDeviceOwner = DeviceOwner.createWithProfileOwner(packageName, ownerName,
+                        userHandle);
+                mDeviceOwner.writeOwnerFile();
+                return true;
+            } else {
+                // Device owner already exists, update it.
+                mDeviceOwner.setProfileOwner(packageName, ownerName, userHandle);
+                mDeviceOwner.writeOwnerFile();
+                return true;
+            }
+        }
+    }
+
+    @Override
+    public String getProfileOwner(int userHandle) {
+        if (!mHasFeature) {
+            return null;
+        }
+
+        synchronized (this) {
+            if (mDeviceOwner != null) {
+                return mDeviceOwner.getProfileOwnerPackageName(userHandle);
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public String getProfileOwnerName(int userHandle) {
+        if (!mHasFeature) {
+            return null;
+        }
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null);
+
+        synchronized (this) {
+            if (mDeviceOwner != null) {
+                return mDeviceOwner.getProfileOwnerName(userHandle);
             }
         }
         return null;
@@ -2794,6 +2889,11 @@
                 Settings.Global.DEVICE_PROVISIONED, 0) > 0;
     }
 
+    private boolean isUserSetupComplete(int userId) {
+        return Settings.Secure.getIntForUser(mContext.getContentResolver(),
+                Settings.Secure.USER_SETUP_COMPLETE, 0, userId) > 0;
+    }
+
     private void enforceCrossUserPermission(int userHandle) {
         if (userHandle < 0) {
             throw new IllegalArgumentException("Invalid userId " + userHandle);
@@ -2858,103 +2958,4 @@
             }
         }
     }
-
-    static class DeviceOwner {
-        private static final String DEVICE_OWNER_XML = "device_owner.xml";
-        private static final String TAG_DEVICE_OWNER = "device-owner";
-        private static final String ATTR_NAME = "name";
-        private static final String ATTR_PACKAGE = "package";
-        private String mPackageName;
-        private String mOwnerName;
-
-        DeviceOwner() {
-            readOwnerFile();
-        }
-
-        DeviceOwner(String packageName, String ownerName) {
-            this.mPackageName = packageName;
-            this.mOwnerName = ownerName;
-        }
-
-        static boolean isRegistered() {
-            return new File(Environment.getSystemSecureDirectory(),
-                    DEVICE_OWNER_XML).exists();
-        }
-
-        String getPackageName() {
-            return mPackageName;
-        }
-
-        String getName() {
-            return mOwnerName;
-        }
-
-        static boolean isInstalled(String packageName, PackageManager pm) {
-            try {
-                PackageInfo pi;
-                if ((pi = pm.getPackageInfo(packageName, 0)) != null) {
-                    if ((pi.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
-                        return true;
-                    }
-                }
-            } catch (NameNotFoundException nnfe) {
-                Slog.w(LOG_TAG, "Device Owner package " + packageName + " not installed.");
-            }
-            return false;
-        }
-
-        void readOwnerFile() {
-            AtomicFile file = new AtomicFile(new File(Environment.getSystemSecureDirectory(),
-                    DEVICE_OWNER_XML));
-            try {
-                FileInputStream input = file.openRead();
-                XmlPullParser parser = Xml.newPullParser();
-                parser.setInput(input, null);
-                int type;
-                while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
-                        && type != XmlPullParser.START_TAG) {
-                }
-                String tag = parser.getName();
-                if (!TAG_DEVICE_OWNER.equals(tag)) {
-                    throw new XmlPullParserException(
-                            "Device Owner file does not start with device-owner tag: found " + tag);
-                }
-                mPackageName = parser.getAttributeValue(null, ATTR_PACKAGE);
-                mOwnerName = parser.getAttributeValue(null, ATTR_NAME);
-                input.close();
-            } catch (XmlPullParserException xppe) {
-                Slog.e(LOG_TAG, "Error parsing device-owner file\n" + xppe);
-            } catch (IOException ioe) {
-                Slog.e(LOG_TAG, "IO Exception when reading device-owner file\n" + ioe);
-            }
-        }
-
-        void writeOwnerFile() {
-            synchronized (this) {
-                writeOwnerFileLocked();
-            }
-        }
-
-        private void writeOwnerFileLocked() {
-            AtomicFile file = new AtomicFile(new File(Environment.getSystemSecureDirectory(),
-                    DEVICE_OWNER_XML));
-            try {
-                FileOutputStream output = file.startWrite();
-                XmlSerializer out = new FastXmlSerializer();
-                out.setOutput(output, "utf-8");
-                out.startDocument(null, true);
-                out.startTag(null, TAG_DEVICE_OWNER);
-                out.attribute(null, ATTR_PACKAGE, mPackageName);
-                if (mOwnerName != null) {
-                    out.attribute(null, ATTR_NAME, mOwnerName);
-                }
-                out.endTag(null, TAG_DEVICE_OWNER);
-                out.endDocument();
-                out.flush();
-                file.finishWrite(output);
-            } catch (IOException ioe) {
-                Slog.e(LOG_TAG, "IO Exception when writing device-owner file\n" + ioe);
-            }
-        }
-    }
 }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerSystemService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerSystemService.java
deleted file mode 100644
index 160aa39..0000000
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerSystemService.java
+++ /dev/null
@@ -1,46 +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.devicepolicy;
-
-import android.content.Context;
-
-import com.android.server.SystemService;
-
-/**
- * SystemService wrapper for the DevicePolicyManager implementation. Publishes
- * Context.DEVICE_POLICY_SERVICE.
- */
-public final class DevicePolicyManagerSystemService extends SystemService {
-    private DevicePolicyManagerService mDevicePolicyManagerImpl;
-
-    @Override
-    public void onCreate(Context context) {
-        mDevicePolicyManagerImpl = new DevicePolicyManagerService(context);
-    }
-
-    @Override
-    public void onStart() {
-        publishBinderService(Context.DEVICE_POLICY_SERVICE, mDevicePolicyManagerImpl);
-    }
-
-    @Override
-    public void onBootPhase(int phase) {
-        if (phase == PHASE_LOCK_SETTINGS_READY) {
-            mDevicePolicyManagerImpl.systemReady();
-        }
-    }
-}
\ No newline at end of file
diff --git a/services/devicepolicy/java/service.mk b/services/devicepolicy/java/service.mk
deleted file mode 100644
index e64cc96..0000000
--- a/services/devicepolicy/java/service.mk
+++ /dev/null
@@ -1,11 +0,0 @@
-# Include only if the service is required
-ifneq ($(findstring devicepolicy,$(REQUIRED_SERVICES)),)
-
-SUB_DIR := devicepolicy/java
-
-LOCAL_SRC_FILES += \
-      $(call all-java-files-under,$(SUB_DIR))
-
-#DEFINED_SERVICES += com.android.server.devicepolicy.DevicePolicyManagerService
-
-endif
diff --git a/services/core/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
similarity index 97%
rename from services/core/java/com/android/server/SystemServer.java
rename to services/java/com/android/server/SystemServer.java
index 1f6235f..85e5e23 100644
--- a/services/core/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -51,7 +51,6 @@
 import com.android.internal.R;
 import com.android.internal.os.BinderInternal;
 import com.android.internal.os.SamplingProfilerIntegration;
-import com.android.server.accessibility.AccessibilityManagerService;
 import com.android.server.accounts.AccountManagerService;
 import com.android.server.am.ActivityManagerService;
 import com.android.server.am.BatteryStatsService;
@@ -105,9 +104,9 @@
      * them from the build system somehow.
      */
     private static final String BACKUP_MANAGER_SERVICE_CLASS =
-            "com.android.server.backup.BackupManagerSystemService";
+            "com.android.server.backup.BackupManagerService$Lifecycle";
     private static final String DEVICE_POLICY_MANAGER_SERVICE_CLASS =
-            "com.android.server.devicepolicy.DevicePolicyManagerSystemService";
+            "com.android.server.devicepolicy.DevicePolicyManagerService$Lifecycle";
     private static final String APPWIDGET_SERVICE_CLASS =
             "com.android.server.appwidget.AppWidgetService";
     private static final String PRINT_MANAGER_SERVICE_CLASS =
@@ -210,6 +209,7 @@
 
         // Create the system service manager.
         mSystemServiceManager = new SystemServiceManager(mSystemContext);
+        LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
 
         // Start services.
         try {
@@ -478,8 +478,8 @@
 
                 try {
                     Slog.i(TAG, "Accessibility Manager");
-                    ServiceManager.addService(Context.ACCESSIBILITY_SERVICE,
-                            new AccessibilityManagerService(context));
+                    ServiceManager.addService(Context.ACCESSIBILITY_SERVICE, (IBinder)
+                            getClass().getClassLoader().loadClass("com.android.server.accessibility.AccessibilityManagerService").getConstructor(Context.class).newInstance(context));
                 } catch (Throwable e) {
                     reportWtf("starting Accessibility Manager", e);
                 }
@@ -532,8 +532,10 @@
                 }
 
                 try {
-                    Slog.i(TAG, "Device Policy");
-                    mSystemServiceManager.startServiceIfExists(DEVICE_POLICY_MANAGER_SERVICE_CLASS);
+                    if (pm.hasSystemFeature("android.software.device_admin")) {
+                        mSystemServiceManager.startServiceIfExists(
+                                DEVICE_POLICY_MANAGER_SERVICE_CLASS);
+                    }
                 } catch (Throwable e) {
                     reportWtf("starting DevicePolicyService", e);
                 }
@@ -780,15 +782,17 @@
 
             if (!disableNonCoreServices) {
                 try {
-                    Slog.i(TAG, "Backup Service");
-                    mSystemServiceManager.startServiceIfExists(BACKUP_MANAGER_SERVICE_CLASS);
+                    if (pm.hasSystemFeature("android.software.backup")) {
+                        mSystemServiceManager.startServiceIfExists(BACKUP_MANAGER_SERVICE_CLASS);
+                    }
                 } catch (Throwable e) {
                     Slog.e(TAG, "Failure starting Backup Service", e);
                 }
 
                 try {
-                    Slog.i(TAG, "AppWidget Service");
-                    mSystemServiceManager.startServiceIfExists(APPWIDGET_SERVICE_CLASS);
+                    if (pm.hasSystemFeature("android.software.app_widgets")) {
+                        mSystemServiceManager.startServiceIfExists(APPWIDGET_SERVICE_CLASS);
+                    }
                 } catch (Throwable e) {
                     reportWtf("starting AppWidget Service", e);
                 }
@@ -848,7 +852,7 @@
                 }
             }
 
-            if (!disableNonCoreServices && 
+            if (!disableNonCoreServices &&
                 context.getResources().getBoolean(R.bool.config_dreamsSupported)) {
                 try {
                     Slog.i(TAG, "Dreams Service");
@@ -878,8 +882,9 @@
             }
 
             try {
-                Slog.i(TAG, "Print Service");
-                mSystemServiceManager.startServiceIfExists(PRINT_MANAGER_SERVICE_CLASS);
+                if (pm.hasSystemFeature("android.software.print")) {
+                    mSystemServiceManager.startServiceIfExists(PRINT_MANAGER_SERVICE_CLASS);
+                }
             } catch (Throwable e) {
                 reportWtf("starting Print Service", e);
             }
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
index 7f146a7..f7bec6e 100644
--- a/services/print/java/com/android/server/print/PrintManagerService.java
+++ b/services/print/java/com/android/server/print/PrintManagerService.java
@@ -52,7 +52,6 @@
 import com.android.internal.content.PackageMonitor;
 import com.android.internal.os.BackgroundThread;
 import com.android.server.SystemService;
-import com.android.server.devicepolicy.DevicePolicyManagerService;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -67,13 +66,13 @@
  */
 
 public final class PrintManagerService extends SystemService {
+    private final PrintManagerImpl mPrintManagerImpl;
 
-    private PrintManagerImpl mPrintManagerImpl;
-
-    @Override
-    public void onCreate(Context context) {
+    public PrintManagerService(Context context) {
+        super(context);
         mPrintManagerImpl = new PrintManagerImpl(context);
     }
+
     @Override
     public void onStart() {
         publishBinderService(Context.PRINT_SERVICE, mPrintManagerImpl);
diff --git a/services/print/java/service.mk b/services/print/java/service.mk
deleted file mode 100644
index cba3612..0000000
--- a/services/print/java/service.mk
+++ /dev/null
@@ -1,11 +0,0 @@
-# Include only if the service is required
-ifneq ($(findstring print,$(REQUIRED_SERVICES)),)
-
-SUB_DIR := print/java
-
-LOCAL_SRC_FILES += \
-      $(call all-java-files-under,$(SUB_DIR))
-
-#DEFINED_SERVICES += com.android.server.print.PrintManagerService
-
-endif
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DeviceOwnerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DeviceOwnerTest.java
new file mode 100644
index 0000000..f913b97
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DeviceOwnerTest.java
@@ -0,0 +1,88 @@
+/*
+ * 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.devicepolicy;
+
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+
+/**
+ * Tests for the DeviceOwner object that saves & loads device and policy owner information.
+ * run this test with:
+ *   make -j FrameworksServicesTests
+ *   runtest --path frameworks/base/services/tests/servicestests/ \
+ *       src/com/android/server/devicepolicy/DeviceOwnerTest.java
+ */
+public class DeviceOwnerTest extends AndroidTestCase {
+
+    private ByteArrayInputStream mInputStreamForTest;
+    private ByteArrayOutputStream mOutputStreamForTest = new ByteArrayOutputStream();
+
+    @SmallTest
+    public void testDeviceOwnerOnly() throws Exception {
+        DeviceOwner out = new DeviceOwner(null, mOutputStreamForTest);
+        out.setDeviceOwner("some.device.owner.package", "owner");
+        out.writeOwnerFile();
+
+        mInputStreamForTest = new ByteArrayInputStream(mOutputStreamForTest.toByteArray());
+        DeviceOwner in = new DeviceOwner(mInputStreamForTest, null);
+        in.readOwnerFile();
+
+        assertEquals("some.device.owner.package", in.getDeviceOwnerPackageName());
+        assertEquals("owner", in.getDeviceOwnerName());
+        assertNull(in.getProfileOwnerPackageName(1));
+    }
+
+    @SmallTest
+    public void testProfileOwnerOnly() throws Exception {
+        DeviceOwner out = new DeviceOwner(null, mOutputStreamForTest);
+        out.setProfileOwner("some.profile.owner.package", "some-company", 1);
+        out.writeOwnerFile();
+
+        mInputStreamForTest = new ByteArrayInputStream(mOutputStreamForTest.toByteArray());
+        DeviceOwner in = new DeviceOwner(mInputStreamForTest, null);
+        in.readOwnerFile();
+
+        assertNull(in.getDeviceOwnerPackageName());
+        assertNull(in.getDeviceOwnerName());
+        assertEquals("some.profile.owner.package", in.getProfileOwnerPackageName(1));
+        assertEquals("some-company", in.getProfileOwnerName(1));
+    }
+
+    @SmallTest
+    public void testDeviceAndProfileOwners() throws Exception {
+        DeviceOwner out = new DeviceOwner(null, mOutputStreamForTest);
+        out.setDeviceOwner("some.device.owner.package", "owner");
+        out.setProfileOwner("some.profile.owner.package", "some-company", 1);
+        out.setProfileOwner("some.other.profile.owner", "some-other-company", 2);
+        out.writeOwnerFile();
+
+        mInputStreamForTest = new ByteArrayInputStream(mOutputStreamForTest.toByteArray());
+
+        DeviceOwner in = new DeviceOwner(mInputStreamForTest, null);
+        in.readOwnerFile();
+
+        assertEquals("some.device.owner.package", in.getDeviceOwnerPackageName());
+        assertEquals("owner", in.getDeviceOwnerName());
+        assertEquals("some.profile.owner.package", in.getProfileOwnerPackageName(1));
+        assertEquals("some-company", in.getProfileOwnerName(1));
+        assertEquals("some.other.profile.owner", in.getProfileOwnerPackageName(2));
+        assertEquals("some-other-company", in.getProfileOwnerName(2));
+    }
+}
\ No newline at end of file
diff --git a/telephony/java/android/telephony/CellInfo.java b/telephony/java/android/telephony/CellInfo.java
index bfa0942..b5e4eef 100644
--- a/telephony/java/android/telephony/CellInfo.java
+++ b/telephony/java/android/telephony/CellInfo.java
@@ -76,7 +76,7 @@
         return mRegistered;
     }
     /** @hide */
-    public void setRegisterd(boolean registered) {
+    public void setRegistered(boolean registered) {
         mRegistered = registered;
     }
 
diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java
index 022bf12..d34c55c 100644
--- a/telephony/java/android/telephony/PhoneStateListener.java
+++ b/telephony/java/android/telephony/PhoneStateListener.java
@@ -275,7 +275,7 @@
      * @param otaspMode is integer <code>OTASP_UNKNOWN=1<code>
      *   means the value is currently unknown and the system should wait until
      *   <code>OTASP_NEEDED=2<code> or <code>OTASP_NOT_NEEDED=3<code> is received before
-     *   making the decisision to perform OTASP or not.
+     *   making the decision to perform OTASP or not.
      *
      * @hide
      */
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index a785bac..3d416fb 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -23,7 +23,6 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemProperties;
-import android.telephony.Rlog;
 
 import com.android.internal.telephony.IPhoneSubInfo;
 import com.android.internal.telephony.ITelephony;
@@ -433,7 +432,7 @@
         case RILConstants.NETWORK_MODE_GSM_UMTS:
         case RILConstants.NETWORK_MODE_LTE_GSM_WCDMA:
         case RILConstants.NETWORK_MODE_LTE_WCDMA:
-        case RILConstants.NETWORK_MODE_LTE_CMDA_EVDO_GSM_WCDMA:
+        case RILConstants.NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA:
             return PhoneConstants.PHONE_TYPE_GSM;
 
         // Use CDMA Phone for the global mode including CDMA
@@ -1258,7 +1257,7 @@
      * At registration, and when a specified telephony state
      * changes, the telephony manager invokes the appropriate
      * callback method on the listener object and passes the
-     * current (udpated) values.
+     * current (updated) values.
      * <p>
      * To unregister a listener, pass the listener object and set the
      * events argument to
@@ -1480,7 +1479,7 @@
      *
      * Input parameters equivalent to TS 27.007 AT+CGLA command.
      *
-     * @param channel is the channel id to be closed as retruned by a successful
+     * @param channel is the channel id to be closed as returned by a successful
      *            iccOpenLogicalChannel.
      * @param cla Class of the APDU command.
      * @param instruction Instruction of the APDU command.
@@ -1502,4 +1501,102 @@
         }
         return "";
     }
+
+    /**
+     * Read one of the NV items defined in {@link com.android.internal.telephony.RadioNVItems}.
+     * Used for device configuration by some CDMA operators.
+     *
+     * @param itemID the ID of the item to read.
+     * @return the NV item as a String, or null on any failure.
+     * @hide
+     */
+    public String nvReadItem(int itemID) {
+        try {
+            return getITelephony().nvReadItem(itemID);
+        } catch (RemoteException ex) {
+            Rlog.e(TAG, "nvReadItem RemoteException", ex);
+        } catch (NullPointerException ex) {
+            Rlog.e(TAG, "nvReadItem NPE", ex);
+        }
+        return "";
+    }
+
+
+    /**
+     * Write one of the NV items defined in {@link com.android.internal.telephony.RadioNVItems}.
+     * Used for device configuration by some CDMA operators.
+     *
+     * @param itemID the ID of the item to read.
+     * @param itemValue the value to write, as a String.
+     * @return true on success; false on any failure.
+     * @hide
+     */
+    public boolean nvWriteItem(int itemID, String itemValue) {
+        try {
+            return getITelephony().nvWriteItem(itemID, itemValue);
+        } catch (RemoteException ex) {
+            Rlog.e(TAG, "nvWriteItem RemoteException", ex);
+        } catch (NullPointerException ex) {
+            Rlog.e(TAG, "nvWriteItem NPE", ex);
+        }
+        return false;
+    }
+
+    /**
+     * Update the CDMA Preferred Roaming List (PRL) in the radio NV storage.
+     * Used for device configuration by some CDMA operators.
+     *
+     * @param preferredRoamingList byte array containing the new PRL.
+     * @return true on success; false on any failure.
+     * @hide
+     */
+    public boolean nvWriteCdmaPrl(byte[] preferredRoamingList) {
+        try {
+            return getITelephony().nvWriteCdmaPrl(preferredRoamingList);
+        } catch (RemoteException ex) {
+            Rlog.e(TAG, "nvWriteCdmaPrl RemoteException", ex);
+        } catch (NullPointerException ex) {
+            Rlog.e(TAG, "nvWriteCdmaPrl NPE", ex);
+        }
+        return false;
+    }
+
+    /**
+     * Perform the specified type of NV config reset.
+     * Used for device configuration by some CDMA operators.
+     *
+     * @param resetType the type of reset to perform (1 == factory reset; 2 == NV-only reset).
+     * @return true on success; false on any failure.
+     * @hide
+     */
+    public boolean nvResetConfig(int resetType) {
+        try {
+            return getITelephony().nvResetConfig(resetType);
+        } catch (RemoteException ex) {
+            Rlog.e(TAG, "nvResetConfig RemoteException", ex);
+        } catch (NullPointerException ex) {
+            Rlog.e(TAG, "nvResetConfig NPE", ex);
+        }
+        return false;
+    }
+
+    /**
+     * Change the radio to the specified mode.
+     * Used for device configuration by some operators.
+     *
+     * @param radioMode is 0 for offline mode, 1 for online mode, 2 for low-power mode,
+     *                  or 3 to reset the radio.
+     * @return true on success; false on any failure.
+     * @hide
+     */
+    public boolean setRadioMode(int radioMode) {
+        try {
+            return getITelephony().setRadioMode(radioMode);
+        } catch (RemoteException ex) {
+            Rlog.e(TAG, "setRadioMode RemoteException", ex);
+        } catch (NullPointerException ex) {
+            Rlog.e(TAG, "setRadioMode NPE", ex);
+        }
+        return false;
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index d9e9d56..370e27a 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -365,4 +365,51 @@
      */
     String iccTransmitApduLogicalChannel(int channel, int cla, int instruction,
             int p1, int p2, int p3, String data);
+
+    /**
+     * Read one of the NV items defined in {@link RadioNVItems} / {@code ril_nv_items.h}.
+     * Used for device configuration by some CDMA operators.
+     *
+     * @param itemID the ID of the item to read.
+     * @return the NV item as a String, or null on any failure.
+     */
+    String nvReadItem(int itemID);
+
+    /**
+     * Write one of the NV items defined in {@link RadioNVItems} / {@code ril_nv_items.h}.
+     * Used for device configuration by some CDMA operators.
+     *
+     * @param itemID the ID of the item to read.
+     * @param itemValue the value to write, as a String.
+     * @return true on success; false on any failure.
+     */
+    boolean nvWriteItem(int itemID, String itemValue);
+
+    /**
+     * Update the CDMA Preferred Roaming List (PRL) in the radio NV storage.
+     * Used for device configuration by some CDMA operators.
+     *
+     * @param preferredRoamingList byte array containing the new PRL.
+     * @return true on success; false on any failure.
+     */
+    boolean nvWriteCdmaPrl(in byte[] preferredRoamingList);
+
+    /**
+     * Perform the specified type of NV config reset.
+     * Used for device configuration by some CDMA operators.
+     *
+     * @param resetType the type of reset to perform (1 == factory reset; 2 == NV-only reset).
+     * @return true on success; false on any failure.
+     */
+    boolean nvResetConfig(int resetType);
+
+    /**
+     * Change the radio to the specified mode.
+     * Used for device configuration by some operators.
+     *
+     * @param radioMode is 0 for offline mode, 1 for online mode, 2 for low-power mode,
+     *                  or 3 to reset the radio.
+     * @return true on success; false on any failure.
+     */
+    boolean setRadioMode(int radioMode);
 }
diff --git a/telephony/java/com/android/internal/telephony/PhoneConstants.java b/telephony/java/com/android/internal/telephony/PhoneConstants.java
index 4163255..fc6c997 100644
--- a/telephony/java/com/android/internal/telephony/PhoneConstants.java
+++ b/telephony/java/com/android/internal/telephony/PhoneConstants.java
@@ -63,11 +63,11 @@
     public static final int LTE_ON_CDMA_FALSE = RILConstants.LTE_ON_CDMA_FALSE;
     public static final int LTE_ON_CDMA_TRUE = RILConstants.LTE_ON_CDMA_TRUE;
 
-    // Number presentation type for caller id display (From internal/Conneciton.java)
-    public static int PRESENTATION_ALLOWED = 1;    // normal
-    public static int PRESENTATION_RESTRICTED = 2; // block by user
-    public static int PRESENTATION_UNKNOWN = 3;    // no specified or unknown by network
-    public static int PRESENTATION_PAYPHONE = 4;   // show pay phone info
+    // Number presentation type for caller id display (From internal/Connection.java)
+    public static final int PRESENTATION_ALLOWED = 1;    // normal
+    public static final int PRESENTATION_RESTRICTED = 2; // block by user
+    public static final int PRESENTATION_UNKNOWN = 3;    // no specified or unknown by network
+    public static final int PRESENTATION_PAYPHONE = 4;   // show pay phone info
 
 
     public static final String PHONE_NAME_KEY = "phoneName";
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index 8e445d9..6015df0 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -72,7 +72,7 @@
                                             AVAILABLE Application Settings menu*/
     int NETWORK_MODE_LTE_CDMA_EVDO  = 8; /* LTE, CDMA and EvDo */
     int NETWORK_MODE_LTE_GSM_WCDMA  = 9; /* LTE, GSM/WCDMA */
-    int NETWORK_MODE_LTE_CMDA_EVDO_GSM_WCDMA = 10; /* LTE, CDMA, EvDo, GSM/WCDMA */
+    int NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA = 10; /* LTE, CDMA, EvDo, GSM/WCDMA */
     int NETWORK_MODE_LTE_ONLY       = 11; /* LTE Only mode. */
     int NETWORK_MODE_LTE_WCDMA      = 12; /* LTE/WCDMA */
     int PREFERRED_NETWORK_MODE      = NETWORK_MODE_WCDMA_PREF;
@@ -114,6 +114,10 @@
     int DEACTIVATE_REASON_RADIO_OFF = 1;
     int DEACTIVATE_REASON_PDP_RESET = 2;
 
+    /* NV config radio reset types. */
+    int NV_CONFIG_RESET_FACTORY = 1;
+    int NV_CONFIG_RESET_NV_ONLY = 2;
+
 /*
 cat include/telephony/ril.h | \
    egrep '^#define' | \
@@ -271,6 +275,12 @@
     int RIL_REQUEST_SIM_OPEN_CHANNEL = 115;
     int RIL_REQUEST_SIM_CLOSE_CHANNEL = 116;
     int RIL_REQUEST_SIM_TRANSMIT_APDU_CHANNEL = 117;
+    int RIL_REQUEST_NV_READ_ITEM = 118;
+    int RIL_REQUEST_NV_WRITE_ITEM = 119;
+    int RIL_REQUEST_NV_WRITE_CDMA_PRL = 120;
+    int RIL_REQUEST_NV_RESET_CONFIG = 121;
+    int RIL_REQUEST_SET_RADIO_MODE = 122;
+
     int RIL_UNSOL_RESPONSE_BASE = 1000;
     int RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED = 1000;
     int RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED = 1001;
diff --git a/telephony/java/com/android/internal/telephony/TelephonyIntents.java b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
index a7baf1c..9ad2d42 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyIntents.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
@@ -125,16 +125,14 @@
      * Broadcast Action: The data connection state has changed for any one of the
      * phone's mobile data connections (eg, default, MMS or GPS specific connection).
      * The intent will have the following extra values:</p>
-     * <ul>
-     *   <li><em>phoneName</em> - A string version of the phone name.</li>
-     *   <li><em>state</em> - One of <code>"CONNECTED"</code>
-     *      <code>"CONNECTING"</code> or <code>"DISCONNNECTED"</code></li>
-     *   <li><em>apn</em> - A string that is the APN associated with this
-     *      connection.</li>
-     *   <li><em>apnType</em> - A string array of APN types associated with
-     *      this connection.  The APN type <code>"*"</code> is a special
-     *      type that means this APN services all types.</li>
-     * </ul>
+     * <dl>
+     *   <dt>phoneName</dt><dd>A string version of the phone name.</dd>
+     *   <dt>state</dt><dd>One of {@code CONNECTED}, {@code CONNECTING},
+     *      or {@code DISCONNECTED}.</dd>
+     *   <dt>apn</dt><dd>A string that is the APN associated with this connection.</dd>
+     *   <dt>apnType</dt><dd>A string array of APN types associated with this connection.
+     *      The APN type {@code *} is a special type that means this APN services all types.</dd>
+     * </dl>
      *
      * <p class="note">
      * Requires the READ_PHONE_STATE permission.
@@ -149,16 +147,14 @@
      * Broadcast Action: Occurs when a data connection connects to a provisioning apn
      * and is broadcast by the low level data connection code.
      * The intent will have the following extra values:</p>
-     * <ul>
-     *   <li><em>apn</em> - A string that is the APN associated with this
-     *      connection.</li>
-     *   <li><em>apnType</em> - A string array of APN types associated with
-     *      this connection.  The APN type <code>"*"</code> is a special
-     *      type that means this APN services all types.</li>
-     *   <li><em>linkProperties</em> - The <code>LinkProperties</code> for this APN</li>
-     *   <li><em>linkCapabilities</em> - The <code>linkCapabilities</code> for this APN</li>
-     *   <li><em>iface</em> - A string that is the name of the interface</li>
-     * </ul>
+     * <dl>
+     *   <dt>apn</dt><dd>A string that is the APN associated with this connection.</dd>
+     *   <dt>apnType</dt><dd>A string array of APN types associated with this connection.
+     *      The APN type {@code *} is a special type that means this APN services all types.</dd>
+     *   <dt>linkProperties</dt><dd>{@code LinkProperties} for this APN.</dd>
+     *   <dt>linkCapabilities</dt><dd>The {@code LinkCapabilities} for this APN.</dd>
+     *   <dt>iface</dt><dd>A string that is the name of the interface.</dd>
+     * </dl>
      *
      * <p class="note">
      * Requires the READ_PHONE_STATE permission.
@@ -172,12 +168,11 @@
     /**
      * Broadcast Action: An attempt to establish a data connection has failed.
      * The intent will have the following extra values:</p>
-     * <ul>
-     *   <li><em>phoneName</em> &mdash A string version of the phone name.</li>
-     *   <li><em>state</em> &mdash; One of <code>"CONNECTED"</code>
-     *      <code>"CONNECTING"</code> or <code>"DISCONNNECTED"</code></li>
-     * <li><em>reason</em> &mdash; A string indicating the reason for the failure, if available</li>
-     * </ul>
+     * <dl>
+     *   <dt>phoneName</dt><dd>A string version of the phone name.</dd>
+     *   <dt>state</dt><dd>One of {@code CONNECTED}, {@code CONNECTING}, or {code DISCONNECTED}.</dd>
+     *   <dt>reason</dt><dd>A string indicating the reason for the failure, if available.</dd>
+     * </dl>
      *
      * <p class="note">
      * Requires the READ_PHONE_STATE permission.
@@ -192,16 +187,23 @@
     /**
      * Broadcast Action: The sim card state has changed.
      * The intent will have the following extra values:</p>
-     * <ul>
-     *   <li><em>phoneName</em> - A string version of the phone name.</li>
-     *   <li><em>ss</em> - The sim state.  One of
-     *   <code>"ABSENT"</code> <code>"LOCKED"</code>
-     *   <code>"READY"</code> <code>"ISMI"</code> <code>"LOADED"</code> </li>
-     *   <li><em>reason</em> - The reason while ss is LOCKED, otherwise is null
-     *   <code>"PIN"</code> locked on PIN1
-     *   <code>"PUK"</code> locked on PUK1
-     *   <code>"NETWORK"</code> locked on Network Personalization </li>
-     * </ul>
+     * <dl>
+     *   <dt>phoneName</dt><dd>A string version of the phone name.</dd>
+     *   <dt>ss</dt><dd>The sim state. One of:
+     *     <dl>
+     *       <dt>{@code ABSENT}</dt><dd>SIM card not found</dd>
+     *       <dt>{@code LOCKED}</dt><dd>SIM card locked (see {@code reason})</dd>
+     *       <dt>{@code READY}</dt><dd>SIM card ready</dd>
+     *       <dt>{@code IMSI}</dt><dd>FIXME: what is this state?</dd>
+     *       <dt>{@code LOADED}</dt><dd>SIM card data loaded</dd>
+     *     </dl></dd>
+     *   <dt>reason</dt><dd>The reason why ss is {@code LOCKED}; null otherwise.</dd>
+     *   <dl>
+     *       <dt>{@code PIN}</dt><dd>locked on PIN1</dd>
+     *       <dt>{@code PUK}</dt><dd>locked on PUK1</dd>
+     *       <dt>{@code NETWORK}</dt><dd>locked on network personalization</dd>
+     *   </dl>
+     * </dl>
      *
      * <p class="note">
      * Requires the READ_PHONE_STATE permission.
@@ -272,31 +274,30 @@
     /**
      * A <em>prefix</em> for the MCC/MNC filtering used with {@link #ACTION_CARRIER_SETUP}.
      * The MCC/MNC will be concatenated (zero-padded to 3 digits each) to create a final
-     * string of the form:
-     * <br />
-     * <code>android.intent.category.MCCMNC_310260</code>
+     * string of the form: {@code android.intent.category.MCCMNC_310260}
      */
     public static final String CATEGORY_MCCMNC_PREFIX = "android.intent.category.MCCMNC_";
 
     /**
      * Broadcast Action: A "secret code" has been entered in the dialer. Secret codes are
-     * of the form *#*#<code>#*#*. The intent will have the data URI:</p>
+     * of the form {@code *#*#<code>#*#*}. The intent will have the data URI:
      *
-     * <p><code>android_secret_code://&lt;code&gt;</code></p>
+     * {@code android_secret_code://<code>}
      */
-    public static final String SECRET_CODE_ACTION =
-            "android.provider.Telephony.SECRET_CODE";
+    public static final String SECRET_CODE_ACTION = "android.provider.Telephony.SECRET_CODE";
 
     /**
      * Broadcast Action: The Service Provider string(s) have been updated.  Activities or
      * services that use these strings should update their display.
      * The intent will have the following extra values:</p>
-     * <ul>
-     *   <li><em>showPlmn</em> - Boolean that indicates whether the PLMN should be shown.</li>
-     *   <li><em>plmn</em> - The operator name of the registered network, as a string.</li>
-     *   <li><em>showSpn</em> - Boolean that indicates whether the SPN should be shown.</li>
-     *   <li><em>spn</em> - The service provider name, as a string.</li>
-     * </ul>
+     *
+     * <dl>
+     *   <dt>showPlmn</dt><dd>Boolean that indicates whether the PLMN should be shown.</dd>
+     *   <dt>plmn</dt><dd>The operator name of the registered network, as a string.</dd>
+     *   <dt>showSpn</dt><dd>Boolean that indicates whether the SPN should be shown.</dd>
+     *   <dt>spn</dt><dd>The service provider name, as a string.</dd>
+     * </dl>
+     *
      * Note that <em>showPlmn</em> may indicate that <em>plmn</em> should be displayed, even
      * though the value for <em>plmn</em> is null.  This can happen, for example, if the phone
      * has not registered to a network yet.  In this case the receiver may substitute an
@@ -305,8 +306,7 @@
      * It is recommended to display <em>plmn</em> before / above <em>spn</em> if
      * both are displayed.
      *
-     * <p>Note this is a protected intent that can only be sent
-     * by the system.
+     * <p>Note: this is a protected intent that can only be sent by the system.
      */
     public static final String SPN_STRINGS_UPDATED_ACTION =
             "android.provider.Telephony.SPN_STRINGS_UPDATED";
diff --git a/tests/CanvasCompare/src/com/android/test/hwuicompare/CompareActivity.java b/tests/CanvasCompare/src/com/android/test/hwuicompare/CompareActivity.java
index 0b85189..8d8d9de 100644
--- a/tests/CanvasCompare/src/com/android/test/hwuicompare/CompareActivity.java
+++ b/tests/CanvasCompare/src/com/android/test/hwuicompare/CompareActivity.java
@@ -97,7 +97,7 @@
                 Log.d(LOG_TAG, "failure to access hardware layer");
                 return;
             }
-            Method copyInto = hardwareLayer.getClass().getSuperclass()
+            Method copyInto = hardwareLayer.getClass()
                     .getDeclaredMethod("copyInto", Bitmap.class);
             if (!copyInto.isAccessible())
                 copyInto.setAccessible(true);
diff --git a/tests/CanvasCompare/src/com/android/test/hwuicompare/ErrorCalculator.java b/tests/CanvasCompare/src/com/android/test/hwuicompare/ErrorCalculator.java
index a08b558..c90b626 100644
--- a/tests/CanvasCompare/src/com/android/test/hwuicompare/ErrorCalculator.java
+++ b/tests/CanvasCompare/src/com/android/test/hwuicompare/ErrorCalculator.java
@@ -35,23 +35,24 @@
     private static final boolean LOG_TIMING = false;
     private static final boolean LOG_CALC = false;
 
-    private final RenderScript mRS;
+    private RenderScript mRS;
     private Allocation mIdealPixelsAllocation;
     private Allocation mGivenPixelsAllocation;
     private Allocation mOutputPixelsAllocation;
 
-    private final Allocation mInputRowsAllocation;
-    private final Allocation mOutputRegionsAllocation;
+    private Allocation mInputRowsAllocation;
+    private Allocation mOutputRegionsAllocation;
 
-    private final ScriptC_errorCalculator mScript;
+    private ScriptC_errorCalculator mScript;
 
-    private final int[] mOutputRowRegions;
+    private int[] mOutputRowRegions;
 
     public ErrorCalculator(Context c, Resources resources) {
         int width = resources.getDimensionPixelSize(R.dimen.layer_width);
         int height = resources.getDimensionPixelSize(R.dimen.layer_height);
         mOutputRowRegions = new int[height / REGION_SIZE];
 
+/*
         mRS = RenderScript.create(c);
         int[] rowIndices = new int[height / REGION_SIZE];
         for (int i = 0; i < rowIndices.length; i++)
@@ -67,12 +68,15 @@
         mInputRowsAllocation.copyFrom(rowIndices);
         mOutputRegionsAllocation = Allocation.createSized(mRS, Element.I32(mRS),
                 mOutputRowRegions.length, Allocation.USAGE_SCRIPT);
+*/
     }
 
 
     private static long startMillis, middleMillis;
 
     public float calcErrorRS(Bitmap ideal, Bitmap given) {
+        if (true)
+            return calcError(ideal, given);
         if (LOG_TIMING) {
             startMillis = System.currentTimeMillis();
         }
diff --git a/tests/HwAccelerationTest/res/layout/projection.xml b/tests/HwAccelerationTest/res/layout/projection.xml
index 564201a..b6e4c5e 100644
--- a/tests/HwAccelerationTest/res/layout/projection.xml
+++ b/tests/HwAccelerationTest/res/layout/projection.xml
@@ -1,11 +1,12 @@
 <?xml version="1.0" encoding="utf-8"?>
-<view class="com.android.test.hwui.ProjectionActivity$ProjecteeLayout"
+<LinearLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:tools="http://schemas.android.com/tools"
     android:id="@+id/container"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:orientation="vertical"
+    android:background="#66ff0000"
     tools:context="com.example.projection.ProjectionActivity"
     tools:ignore="MergeRootFrame">
     <TextView
@@ -33,4 +34,4 @@
         android:layout_height="100dp"
         android:textSize="50sp"
         android:text="TextView"/>
-</view>
\ No newline at end of file
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ProjectionActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/ProjectionActivity.java
index f27652d..208c387 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/ProjectionActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/ProjectionActivity.java
@@ -72,33 +72,6 @@
         }
     }
 
-    public static class ProjecteeLayout extends LinearLayout {
-        private final Paint mPaint = new Paint();
-        private final RectF mRectF = new RectF();
-
-        public ProjecteeLayout(Context context) {
-            this(context, null);
-        }
-
-        public ProjecteeLayout(Context context, AttributeSet attrs) {
-            this(context, attrs, 0);
-        }
-
-        public ProjecteeLayout(Context context, AttributeSet attrs, int defStyle) {
-            super(context, attrs, defStyle);
-        }
-
-        @Override
-        protected void dispatchDraw(Canvas canvas) {
-            canvas.save(0x20); // secret save flag
-            mRectF.set(0, 0, getWidth(), getHeight());
-            mPaint.setColor(0x5f000000);
-            canvas.drawOval(mRectF, mPaint);
-            canvas.restore();
-            super.dispatchDraw(canvas);
-        }
-    }
-
     static View container;
 
     @Override
diff --git a/tests/SystemUIDemoModeController/Android.mk b/tests/SystemUIDemoModeController/Android.mk
new file mode 100644
index 0000000..64ea63c
--- /dev/null
+++ b/tests/SystemUIDemoModeController/Android.mk
@@ -0,0 +1,10 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := DemoModeController
+
+include $(BUILD_PACKAGE)
diff --git a/tests/SystemUIDemoModeController/AndroidManifest.xml b/tests/SystemUIDemoModeController/AndroidManifest.xml
new file mode 100644
index 0000000..2e97932
--- /dev/null
+++ b/tests/SystemUIDemoModeController/AndroidManifest.xml
@@ -0,0 +1,39 @@
+<?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.example.android.demomodecontroller"
+    android:versionCode="1"
+    android:versionName="0.1" >
+
+    <uses-sdk
+        android:minSdkVersion="19"
+        android:targetSdkVersion="19" />
+
+    <application
+        android:allowBackup="false"
+        android:label="@string/app_name" >
+        <activity
+            android:name=".DemoModeController" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+
+</manifest>
diff --git a/tests/SystemUIDemoModeController/res/values/strings.xml b/tests/SystemUIDemoModeController/res/values/strings.xml
new file mode 100644
index 0000000..257a353
--- /dev/null
+++ b/tests/SystemUIDemoModeController/res/values/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+
+    <string name="app_name">Demo Mode Controller</string>
+    <string name="help_text">"Drag: control icon states\nLong-press + drag: control background color\nDouble-tap: toggle bar mode</string>
+
+</resources>
diff --git a/tests/SystemUIDemoModeController/src/com/example/android/demomodecontroller/DemoModeController.java b/tests/SystemUIDemoModeController/src/com/example/android/demomodecontroller/DemoModeController.java
new file mode 100644
index 0000000..b177d7e
--- /dev/null
+++ b/tests/SystemUIDemoModeController/src/com/example/android/demomodecontroller/DemoModeController.java
@@ -0,0 +1,340 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.demomodecontroller;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Color;
+import android.graphics.PointF;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.SystemClock;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.View.OnTouchListener;
+import android.view.ViewConfiguration;
+import android.view.WindowManager;
+import android.widget.Toast;
+
+public class DemoModeController extends Activity implements OnTouchListener {
+    private static final String TAG = DemoModeController.class.getSimpleName();
+    private static final boolean DEBUG = false;
+
+    private final Context mContext = this;
+    private final Handler mHandler = new Handler();
+    private final PointF mLastDown = new PointF();
+
+    private View mContent;
+    private Handler mBackground;
+    private int mTouchSlop;
+    private long mLastDownTime;
+    private boolean mControllingColor;
+    private Toast mToast;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        getWindow().addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+                | WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS  // so WM gives us enough room
+                | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
+        getActionBar().hide();
+        mContent = new View(mContext);
+        mContent.setBackgroundColor(0xff33b5e5);
+        mContent.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+                | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+                | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
+        mContent.setOnTouchListener(this);
+        setContentView(mContent);
+        mTouchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop();
+
+        final HandlerThread background = new HandlerThread("background");
+        background.start();
+        mBackground = new Handler(background.getLooper());
+        updateMode();
+    }
+
+    @Override
+    protected void onPause() {
+        super.onPause();
+        exitDemoMode();
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+        exitDemoMode();
+        mToast = Toast.makeText(mContext, R.string.help_text, Toast.LENGTH_LONG);
+        mToast.show();
+    }
+
+    @Override
+    public boolean onTouch(View v, MotionEvent event) {
+        if (mToast != null) {
+            mToast.cancel();
+            mToast = null;
+        }
+        final int action = event.getAction();
+        if (action == MotionEvent.ACTION_DOWN) {
+            if (DEBUG) Log.d(TAG, "down");
+            mHandler.postDelayed(mLongPressCheck, 500);
+            final long now = SystemClock.uptimeMillis();
+            if (now - mLastDownTime < 200) {
+                toggleMode();
+            }
+            mLastDownTime = now;
+            mLastDown.x = event.getX();
+            mLastDown.y = event.getY();
+            return true;
+        }
+        if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
+            if (DEBUG) Log.d(TAG, "upOrCancel");
+            mControllingColor = false;
+            mHandler.removeCallbacks(mLongPressCheck);
+        }
+        if (action != MotionEvent.ACTION_MOVE) return false;
+
+        float x = event.getX();
+        float y = event.getY();
+        if (Math.abs(mLastDown.x - x) > mTouchSlop || Math.abs(mLastDown.y - y) > mTouchSlop) {
+            mHandler.removeCallbacks(mLongPressCheck);
+        }
+        x = Math.max(x, 0);
+        y = Math.max(y, 0);
+        final int h = mContent.getMeasuredHeight();
+        final int w = mContent.getMeasuredWidth();
+        x = Math.min(x, w);
+        y = Math.min(y, h);
+
+        y = h - y;
+        x = w - x;
+
+        if (mControllingColor) {
+            final float hue = y / (h / 360);
+            final float sat = 1 - (x / (float)w);
+            final float val = x / (float)w;
+            final int color = Color.HSVToColor(new float[]{hue, sat, val});
+            if (DEBUG) Log.d(TAG, String.format("hsv=(%s,%s,%s) argb=#%08x", hue, sat, val, color));
+            mContent.setBackgroundColor(color);
+            return true;
+        }
+
+        final int hh = (int)x / (w / 12);
+        if (hh != mHH) {
+            mHH = hh;
+            mBackground.removeCallbacks(mUpdateClock);
+            mBackground.post(mUpdateClock);
+        }
+
+        final int mm = (int)y / (h / 60);
+        if (mm != mMM) {
+            mMM = mm;
+            mBackground.removeCallbacks(mUpdateClock);
+            mBackground.post(mUpdateClock);
+        }
+
+        final int batteryLevel = (int)y / (h / 101);
+        if (batteryLevel != mBatteryLevel) {
+            mBatteryLevel = batteryLevel;
+            mBackground.removeCallbacks(mUpdateBattery);
+            mBackground.post(mUpdateBattery);
+        }
+
+        final boolean batteryPlugged = x >= w / 2;
+        if (batteryPlugged != mBatteryPlugged) {
+            mBatteryPlugged = batteryPlugged;
+            mBackground.removeCallbacks(mUpdateBattery);
+            mBackground.post(mUpdateBattery);
+        }
+
+        final int mobileLevel = (int)y / (h / 10);
+        if (mobileLevel != mMobileLevel) {
+            mMobileLevel = mobileLevel;
+            mBackground.removeCallbacks(mUpdateMobile);
+            mBackground.post(mUpdateMobile);
+        }
+
+        final int wifiLevel = (int)y / (h / 10);
+        if (wifiLevel != mWifiLevel) {
+            mWifiLevel = wifiLevel;
+            mBackground.removeCallbacks(mUpdateWifi);
+            mBackground.post(mUpdateWifi);
+        }
+
+        final int statusSlots = (int)x / (w / 13);
+        if (statusSlots != mStatusSlots) {
+            mStatusSlots = statusSlots;
+            mBackground.removeCallbacks(mUpdateStatus);
+            mBackground.post(mUpdateStatus);
+        }
+
+        final int networkIcons = (int)x / (w / 4);
+        if (networkIcons != mNetworkIcons) {
+            mNetworkIcons = networkIcons;
+            mBackground.removeCallbacks(mUpdateNetwork);
+            mBackground.post(mUpdateNetwork);
+        }
+
+        final int mobileDataType = (int)y / (h / 9);
+        if (mobileDataType != mMobileDataType) {
+            mMobileDataType = mobileDataType;
+            mBackground.removeCallbacks(mUpdateMobile);
+            mBackground.post(mUpdateMobile);
+        }
+        return true;
+    }
+
+    private void toggleMode() {
+        if (DEBUG) Log.d(TAG, "toggleMode");
+        mBarMode = (mBarMode + 1) % 3;
+        updateMode();
+    }
+
+    private void updateMode() {
+        mBackground.removeCallbacks(mUpdateBarMode);
+        mBackground.post(mUpdateBarMode);
+    }
+
+    private final Runnable mLongPressCheck = new Runnable() {
+        @Override
+        public void run() {
+            if (DEBUG) Log.d(TAG, "mControllingColor = true");
+            mControllingColor = true;
+
+        }
+    };
+
+    private void exitDemoMode() {
+        if (DEBUG) Log.d(TAG, "exitDemoMode");
+        final Intent intent = new Intent("com.android.systemui.demo");
+        intent.putExtra("command", "exit");
+        mContext.sendBroadcast(intent);
+    }
+
+    private int mStatusSlots; // 0 - 12
+    private final Runnable mUpdateStatus = new Runnable() {
+        @Override
+        public void run() {
+            final Intent intent = new Intent("com.android.systemui.demo");
+            intent.putExtra("command", "status");
+            intent.putExtra("volume", mStatusSlots < 1 ? "hide"
+                    : mStatusSlots < 2 ? "silent" : "vibrate");
+            intent.putExtra("bluetooth", mStatusSlots < 3 ? "hide"
+                    : mStatusSlots < 4 ? "disconnected" : "connected");
+            intent.putExtra("location", mStatusSlots < 5 ? "hide" : "show");
+            intent.putExtra("alarm", mStatusSlots < 6 ? "hide" : "show");
+            intent.putExtra("sync", mStatusSlots < 7 ? "hide" : "show");
+            intent.putExtra("tty", mStatusSlots < 8 ? "hide" : "show");
+            intent.putExtra("eri", mStatusSlots < 9 ? "hide" : "show");
+            intent.putExtra("secure", mStatusSlots < 10 ? "hide" : "show");
+            intent.putExtra("mute", mStatusSlots < 11 ? "hide" : "show");
+            intent.putExtra("speakerphone", mStatusSlots < 12 ? "hide" : "show");
+            mContext.sendBroadcast(intent);
+        }
+    };
+
+    private int mNetworkIcons;  // 0:airplane  1:mobile  2:airplane+wifi  3:mobile+wifi
+    private final Runnable mUpdateNetwork = new Runnable() {
+        @Override
+        public void run() {
+            final Intent intent = new Intent("com.android.systemui.demo");
+            intent.putExtra("command", "network");
+            intent.putExtra("airplane", mNetworkIcons % 2 == 0 ? "show" : "hide");
+            intent.putExtra("wifi", mNetworkIcons >= 2 ? "show" : "hide");
+            intent.putExtra("mobile", mNetworkIcons % 2 == 1 ? "show" : "hide");
+            mContext.sendBroadcast(intent);
+        }
+    };
+
+    private int mWifiLevel; // 0 - 4, 5 - 9, fully
+    private final Runnable mUpdateWifi = new Runnable() {
+        @Override
+        public void run() {
+            final Intent intent = new Intent("com.android.systemui.demo");
+            intent.putExtra("command", "network");
+            intent.putExtra("wifi", mNetworkIcons >= 2 ? "show" : "hide");
+            intent.putExtra("level", Integer.toString(mWifiLevel % 5));
+            intent.putExtra("fully", Boolean.toString(mWifiLevel > 4));
+            mContext.sendBroadcast(intent);
+        }
+    };
+
+    private int mMobileLevel; // 0 - 4, 5 - 9, fully
+    private int mMobileDataType; // 0 - 8
+    private static final String getDataType(int dataType) {
+        if (dataType == 1) return "1x";
+        if (dataType == 2) return "3g";
+        if (dataType == 3) return "4g";
+        if (dataType == 4) return "e";
+        if (dataType == 5) return "g";
+        if (dataType == 6) return "h";
+        if (dataType == 7) return "lte";
+        if (dataType == 8) return "roam";
+        return "";
+    }
+    private final Runnable mUpdateMobile = new Runnable() {
+        @Override
+        public void run() {
+            final Intent intent = new Intent("com.android.systemui.demo");
+            intent.putExtra("command", "network");
+            intent.putExtra("mobile", mNetworkIcons % 2 == 1 ? "show" : "hide");
+            intent.putExtra("level", Integer.toString(mMobileLevel % 5));
+            intent.putExtra("fully", Boolean.toString(mMobileLevel > 4));
+            intent.putExtra("datatype", getDataType(mMobileDataType));
+            mContext.sendBroadcast(intent);
+        }
+    };
+
+    private boolean mBatteryPlugged;
+    private int mBatteryLevel; // 0 - 100
+    private final Runnable mUpdateBattery = new Runnable() {
+        @Override
+        public void run() {
+            final Intent intent = new Intent("com.android.systemui.demo");
+            intent.putExtra("command", "battery");
+            intent.putExtra("level", Integer.toString(mBatteryLevel));
+            intent.putExtra("plugged", Boolean.toString(mBatteryPlugged));
+            mContext.sendBroadcast(intent);
+        }
+    };
+
+    private int mHH; // 0 - 11
+    private int mMM; // 0 - 59
+    private final Runnable mUpdateClock = new Runnable() {
+        @Override
+        public void run() {
+            final Intent intent = new Intent("com.android.systemui.demo");
+            intent.putExtra("command", "clock");
+            intent.putExtra("hhmm", String.format("%02d%02d", mHH + 1, mMM));
+            mContext.sendBroadcast(intent);
+        }
+    };
+
+    private int mBarMode; // 0 - 2  (opaque, semi-transparent, translucent)
+    private final Runnable mUpdateBarMode = new Runnable() {
+        @Override
+        public void run() {
+            final Intent intent = new Intent("com.android.systemui.demo");
+            intent.putExtra("command", "bars");
+            intent.putExtra("mode", mBarMode == 1 ? "semi-transparent"
+                    : mBarMode == 2 ? "translucent" : "opaque");
+            mContext.sendBroadcast(intent);
+        }
+    };
+}
diff --git a/tools/aapt/AaptAssets.cpp b/tools/aapt/AaptAssets.cpp
index 6a3c506..f9a2d19 100644
--- a/tools/aapt/AaptAssets.cpp
+++ b/tools/aapt/AaptAssets.cpp
@@ -149,205 +149,506 @@
 // =========================================================================
 // =========================================================================
 
-status_t
-AaptGroupEntry::parseNamePart(const String8& part, int* axis, uint32_t* value)
+/* static */ void AaptLocaleValue::splitAndLowerCase(const char* const chars,
+        Vector<String8>* parts, const char separator) {
+    const char *p = chars;
+    const char *q;
+    while (NULL != (q = strchr(p, separator))) {
+         String8 val(p, q - p);
+         val.toLower();
+         parts->add(val);
+         p = q+1;
+    }
+
+    if (p < chars + strlen(chars)) {
+        String8 val(p);
+        val.toLower();
+        parts->add(val);
+    }
+}
+
+/* static */
+inline bool isAlpha(const String8& string) {
+     const size_t length = string.length();
+     for (size_t i = 0; i < length; ++i) {
+          if (!isalpha(string[i])) {
+              return false;
+          }
+     }
+
+     return true;
+}
+
+/* static */
+inline bool isNumber(const String8& string) {
+     const size_t length = string.length();
+     for (size_t i = 0; i < length; ++i) {
+          if (!isdigit(string[i])) {
+              return false;
+          }
+     }
+
+     return true;
+}
+
+void AaptLocaleValue::setLanguage(const char* languageChars) {
+     size_t i = 0;
+     while ((*languageChars) != '\0') {
+          language[i++] = tolower(*languageChars);
+          languageChars++;
+     }
+}
+
+void AaptLocaleValue::setRegion(const char* regionChars) {
+    size_t i = 0;
+    while ((*regionChars) != '\0') {
+         region[i++] = toupper(*regionChars);
+         regionChars++;
+    }
+}
+
+void AaptLocaleValue::setScript(const char* scriptChars) {
+    size_t i = 0;
+    while ((*scriptChars) != '\0') {
+         if (i == 0) {
+             script[i++] = toupper(*scriptChars);
+         } else {
+             script[i++] = tolower(*scriptChars);
+         }
+         scriptChars++;
+    }
+}
+
+void AaptLocaleValue::setVariant(const char* variantChars) {
+     size_t i = 0;
+     while ((*variantChars) != '\0') {
+          variant[i++] = *variantChars;
+          variantChars++;
+     }
+}
+
+bool AaptLocaleValue::initFromFilterString(const String8& str) {
+     // A locale (as specified in the filter) is an underscore separated name such
+     // as "en_US", "en_Latn_US", or "en_US_POSIX".
+     Vector<String8> parts;
+     splitAndLowerCase(str.string(), &parts, '_');
+
+     const int numTags = parts.size();
+     bool valid = false;
+     if (numTags >= 1) {
+         const String8& lang = parts[0];
+         if (isAlpha(lang) && (lang.length() == 2 || lang.length() == 3)) {
+             setLanguage(lang.string());
+             valid = true;
+         }
+     }
+
+     if (!valid || numTags == 1) {
+         return valid;
+     }
+
+     // At this point, valid == true && numTags > 1.
+     const String8& part2 = parts[1];
+     if ((part2.length() == 2 && isAlpha(part2)) ||
+         (part2.length() == 3 && isNumber(part2))) {
+         setRegion(part2.string());
+     } else if (part2.length() == 4 && isAlpha(part2)) {
+         setScript(part2.string());
+     } else if (part2.length() >= 5 && part2.length() <= 8) {
+         setVariant(part2.string());
+     } else {
+         valid = false;
+     }
+
+     if (!valid || numTags == 2) {
+         return valid;
+     }
+
+     // At this point, valid == true && numTags > 1.
+     const String8& part3 = parts[2];
+     if (((part3.length() == 2 && isAlpha(part3)) ||
+         (part3.length() == 3 && isNumber(part3))) && script[0]) {
+         setRegion(part3.string());
+     } else if (part3.length() >= 5 && part3.length() <= 8) {
+         setVariant(part3.string());
+     } else {
+         valid = false;
+     }
+
+     if (!valid || numTags == 3) {
+         return valid;
+     }
+
+     const String8& part4 = parts[3];
+     if (part4.length() >= 5 && part4.length() <= 8) {
+         setVariant(part4.string());
+     } else {
+         valid = false;
+     }
+
+     if (!valid || numTags > 4) {
+         return false;
+     }
+
+     return true;
+}
+
+int AaptLocaleValue::initFromDirName(const Vector<String8>& parts, const int startIndex) {
+    const int size = parts.size();
+    int currentIndex = startIndex;
+
+    String8 part = parts[currentIndex];
+    if (part[0] == 'b' && part[1] == '+') {
+        // This is a "modified" BCP-47 language tag. Same semantics as BCP-47 tags,
+        // except that the separator is "+" and not "-".
+        Vector<String8> subtags;
+        AaptLocaleValue::splitAndLowerCase(part.string(), &subtags, '+');
+        subtags.removeItemsAt(0);
+        if (subtags.size() == 1) {
+            setLanguage(subtags[0]);
+        } else if (subtags.size() == 2) {
+            setLanguage(subtags[0]);
+
+            // The second tag can either be a region, a variant or a script.
+            switch (subtags[1].size()) {
+                case 2:
+                case 3:
+                    setRegion(subtags[1]);
+                    break;
+                case 4:
+                    setScript(subtags[1]);
+                    break;
+                case 5:
+                case 6:
+                case 7:
+                case 8:
+                    setVariant(subtags[1]);
+                    break;
+                default:
+                    fprintf(stderr, "ERROR: Invalid BCP-47 tag in directory name %s\n",
+                            part.string());
+                    return -1;
+            }
+        } else if (subtags.size() == 3) {
+            // The language is always the first subtag.
+            setLanguage(subtags[0]);
+
+            // The second subtag can either be a script or a region code.
+            // If its size is 4, it's a script code, else it's a region code.
+            bool hasRegion = false;
+            if (subtags[1].size() == 4) {
+                setScript(subtags[1]);
+            } else if (subtags[1].size() == 2 || subtags[1].size() == 3) {
+                setRegion(subtags[1]);
+                hasRegion = true;
+            } else {
+                fprintf(stderr, "ERROR: Invalid BCP-47 tag in directory name %s\n", part.string());
+                return -1;
+            }
+
+            // The third tag can either be a region code (if the second tag was
+            // a script), else a variant code.
+            if (subtags[2].size() > 4) {
+                setVariant(subtags[2]);
+            } else {
+                setRegion(subtags[2]);
+            }
+        } else if (subtags.size() == 4) {
+            setLanguage(subtags[0]);
+            setScript(subtags[1]);
+            setRegion(subtags[2]);
+            setVariant(subtags[3]);
+        } else {
+            fprintf(stderr, "ERROR: Invalid BCP-47 tag in directory name: %s\n", part.string());
+            return -1;
+        }
+
+        return ++currentIndex;
+    } else {
+        if ((part.length() == 2 || part.length() == 3) && isAlpha(part)) {
+            setLanguage(part);
+            if (++currentIndex == size) {
+                return size;
+            }
+        } else {
+            return currentIndex;
+        }
+
+        part = parts[currentIndex];
+        if (part.string()[0] == 'r' && part.length() == 3) {
+            setRegion(part.string() + 1);
+            if (++currentIndex == size) {
+                return size;
+            }
+        }
+    }
+
+    return currentIndex;
+}
+
+
+String8 AaptLocaleValue::toDirName() const {
+    String8 dirName("");
+    if (language[0]) {
+        dirName += language;
+    } else {
+        return dirName;
+    }
+
+    if (script[0]) {
+        dirName += "-s";
+        dirName += script;
+    }
+
+    if (region[0]) {
+        dirName += "-r";
+        dirName += region;
+    }
+
+    if (variant[0]) {
+        dirName += "-v";
+        dirName += variant;
+    }
+
+    return dirName;
+}
+
+void AaptLocaleValue::initFromResTable(const ResTable_config& config) {
+    config.unpackLanguage(language);
+    config.unpackRegion(region);
+    if (config.localeScript[0]) {
+        memcpy(script, config.localeScript, sizeof(config.localeScript));
+    }
+
+    if (config.localeVariant[0]) {
+        memcpy(variant, config.localeVariant, sizeof(config.localeVariant));
+    }
+}
+
+void AaptLocaleValue::writeTo(ResTable_config* out) const {
+    out->packLanguage(language);
+    out->packRegion(region);
+
+    if (script[0]) {
+        memcpy(out->localeScript, script, sizeof(out->localeScript));
+    }
+
+    if (variant[0]) {
+        memcpy(out->localeVariant, variant, sizeof(out->localeVariant));
+    }
+}
+
+
+/* static */ bool
+AaptGroupEntry::parseFilterNamePart(const String8& part, int* axis, AxisValue* value)
 {
     ResTable_config config;
+    memset(&config, 0, sizeof(ResTable_config));
 
     // IMSI - MCC
     if (getMccName(part.string(), &config)) {
         *axis = AXIS_MCC;
-        *value = config.mcc;
-        return 0;
+        value->intValue = config.mcc;
+        return true;
     }
 
     // IMSI - MNC
     if (getMncName(part.string(), &config)) {
         *axis = AXIS_MNC;
-        *value = config.mnc;
-        return 0;
+        value->intValue = config.mnc;
+        return true;
     }
 
     // locale - language
-    if (part.length() == 2 && isalpha(part[0]) && isalpha(part[1])) {
-        *axis = AXIS_LANGUAGE;
-        *value = part[1] << 8 | part[0];
-        return 0;
-    }
-
-    // locale - language_REGION
-    if (part.length() == 5 && isalpha(part[0]) && isalpha(part[1])
-            && part[2] == '_' && isalpha(part[3]) && isalpha(part[4])) {
-        *axis = AXIS_LANGUAGE;
-        *value = (part[4] << 24) | (part[3] << 16) | (part[1] << 8) | (part[0]);
-        return 0;
+    if (value->localeValue.initFromFilterString(part)) {
+        *axis = AXIS_LOCALE;
+        return true;
     }
 
     // layout direction
     if (getLayoutDirectionName(part.string(), &config)) {
         *axis = AXIS_LAYOUTDIR;
-        *value = (config.screenLayout&ResTable_config::MASK_LAYOUTDIR);
-        return 0;
+        value->intValue = (config.screenLayout&ResTable_config::MASK_LAYOUTDIR);
+        return true;
     }
 
     // smallest screen dp width
     if (getSmallestScreenWidthDpName(part.string(), &config)) {
         *axis = AXIS_SMALLESTSCREENWIDTHDP;
-        *value = config.smallestScreenWidthDp;
-        return 0;
+        value->intValue = config.smallestScreenWidthDp;
+        return true;
     }
 
     // screen dp width
     if (getScreenWidthDpName(part.string(), &config)) {
         *axis = AXIS_SCREENWIDTHDP;
-        *value = config.screenWidthDp;
-        return 0;
+        value->intValue = config.screenWidthDp;
+        return true;
     }
 
     // screen dp height
     if (getScreenHeightDpName(part.string(), &config)) {
         *axis = AXIS_SCREENHEIGHTDP;
-        *value = config.screenHeightDp;
-        return 0;
+        value->intValue = config.screenHeightDp;
+        return true;
     }
 
     // screen layout size
     if (getScreenLayoutSizeName(part.string(), &config)) {
         *axis = AXIS_SCREENLAYOUTSIZE;
-        *value = (config.screenLayout&ResTable_config::MASK_SCREENSIZE);
-        return 0;
+        value->intValue = (config.screenLayout&ResTable_config::MASK_SCREENSIZE);
+        return true;
     }
 
     // screen layout long
     if (getScreenLayoutLongName(part.string(), &config)) {
         *axis = AXIS_SCREENLAYOUTLONG;
-        *value = (config.screenLayout&ResTable_config::MASK_SCREENLONG);
-        return 0;
+        value->intValue = (config.screenLayout&ResTable_config::MASK_SCREENLONG);
+        return true;
     }
 
     // orientation
     if (getOrientationName(part.string(), &config)) {
         *axis = AXIS_ORIENTATION;
-        *value = config.orientation;
-        return 0;
+        value->intValue = config.orientation;
+        return true;
     }
 
     // ui mode type
     if (getUiModeTypeName(part.string(), &config)) {
         *axis = AXIS_UIMODETYPE;
-        *value = (config.uiMode&ResTable_config::MASK_UI_MODE_TYPE);
-        return 0;
+        value->intValue = (config.uiMode&ResTable_config::MASK_UI_MODE_TYPE);
+        return true;
     }
 
     // ui mode night
     if (getUiModeNightName(part.string(), &config)) {
         *axis = AXIS_UIMODENIGHT;
-        *value = (config.uiMode&ResTable_config::MASK_UI_MODE_NIGHT);
-        return 0;
+        value->intValue = (config.uiMode&ResTable_config::MASK_UI_MODE_NIGHT);
+        return true;
     }
 
     // density
     if (getDensityName(part.string(), &config)) {
         *axis = AXIS_DENSITY;
-        *value = config.density;
-        return 0;
+        value->intValue = config.density;
+        return true;
     }
 
     // touchscreen
     if (getTouchscreenName(part.string(), &config)) {
         *axis = AXIS_TOUCHSCREEN;
-        *value = config.touchscreen;
-        return 0;
+        value->intValue = config.touchscreen;
+        return true;
     }
 
     // keyboard hidden
     if (getKeysHiddenName(part.string(), &config)) {
         *axis = AXIS_KEYSHIDDEN;
-        *value = config.inputFlags;
-        return 0;
+        value->intValue = config.inputFlags;
+        return true;
     }
 
     // keyboard
     if (getKeyboardName(part.string(), &config)) {
         *axis = AXIS_KEYBOARD;
-        *value = config.keyboard;
-        return 0;
+        value->intValue = config.keyboard;
+        return true;
     }
 
     // navigation hidden
     if (getNavHiddenName(part.string(), &config)) {
         *axis = AXIS_NAVHIDDEN;
-        *value = config.inputFlags;
+        value->intValue = config.inputFlags;
         return 0;
     }
 
     // navigation
     if (getNavigationName(part.string(), &config)) {
         *axis = AXIS_NAVIGATION;
-        *value = config.navigation;
-        return 0;
+        value->intValue = config.navigation;
+        return true;
     }
 
     // screen size
     if (getScreenSizeName(part.string(), &config)) {
         *axis = AXIS_SCREENSIZE;
-        *value = config.screenSize;
-        return 0;
+        value->intValue = config.screenSize;
+        return true;
     }
 
     // version
     if (getVersionName(part.string(), &config)) {
         *axis = AXIS_VERSION;
-        *value = config.version;
-        return 0;
+        value->intValue = config.version;
+        return true;
     }
 
-    return 1;
+    return false;
 }
 
-uint32_t
+AxisValue
 AaptGroupEntry::getConfigValueForAxis(const ResTable_config& config, int axis)
 {
+    AxisValue value;
     switch (axis) {
         case AXIS_MCC:
-            return config.mcc;
+            value.intValue = config.mcc;
+            break;
         case AXIS_MNC:
-            return config.mnc;
-        case AXIS_LANGUAGE:
-            return (((uint32_t)config.country[1]) << 24) | (((uint32_t)config.country[0]) << 16)
-                | (((uint32_t)config.language[1]) << 8) | (config.language[0]);
+            value.intValue = config.mnc;
+            break;
+        case AXIS_LOCALE:
+            value.localeValue.initFromResTable(config);
+            break;
         case AXIS_LAYOUTDIR:
-            return config.screenLayout&ResTable_config::MASK_LAYOUTDIR;
+            value.intValue = config.screenLayout&ResTable_config::MASK_LAYOUTDIR;
+            break;
         case AXIS_SCREENLAYOUTSIZE:
-            return config.screenLayout&ResTable_config::MASK_SCREENSIZE;
+            value.intValue = config.screenLayout&ResTable_config::MASK_SCREENSIZE;
+            break;
         case AXIS_ORIENTATION:
-            return config.orientation;
+            value.intValue = config.orientation;
+            break;
         case AXIS_UIMODETYPE:
-            return (config.uiMode&ResTable_config::MASK_UI_MODE_TYPE);
+            value.intValue = (config.uiMode&ResTable_config::MASK_UI_MODE_TYPE);
+            break;
         case AXIS_UIMODENIGHT:
-            return (config.uiMode&ResTable_config::MASK_UI_MODE_NIGHT);
+            value.intValue = (config.uiMode&ResTable_config::MASK_UI_MODE_NIGHT);
+            break;
         case AXIS_DENSITY:
-            return config.density;
+            value.intValue = config.density;
+            break;
         case AXIS_TOUCHSCREEN:
-            return config.touchscreen;
+            value.intValue = config.touchscreen;
+            break;
         case AXIS_KEYSHIDDEN:
-            return config.inputFlags;
+            value.intValue = config.inputFlags;
+            break;
         case AXIS_KEYBOARD:
-            return config.keyboard;
+            value.intValue = config.keyboard;
+            break;
         case AXIS_NAVIGATION:
-            return config.navigation;
+            value.intValue = config.navigation;
+            break;
         case AXIS_SCREENSIZE:
-            return config.screenSize;
+            value.intValue = config.screenSize;
+            break;
         case AXIS_SMALLESTSCREENWIDTHDP:
-            return config.smallestScreenWidthDp;
+            value.intValue = config.smallestScreenWidthDp;
+            break;
         case AXIS_SCREENWIDTHDP:
-            return config.screenWidthDp;
+            value.intValue = config.screenWidthDp;
+            break;
         case AXIS_SCREENHEIGHTDP:
-            return config.screenHeightDp;
+            value.intValue = config.screenHeightDp;
+            break;
         case AXIS_VERSION:
-            return config.version;
+            value.intValue = config.version;
+            break;
     }
-    return 0;
+
+    return value;
 }
 
 bool
@@ -371,24 +672,14 @@
     mParamsChanged = true;
 
     Vector<String8> parts;
+    AaptLocaleValue::splitAndLowerCase(dir, &parts, '-');
 
-    String8 mcc, mnc, loc, layoutsize, layoutlong, orient, den;
+    String8 mcc, mnc, layoutsize, layoutlong, orient, den;
     String8 touch, key, keysHidden, nav, navHidden, size, layoutDir, vers;
     String8 uiModeType, uiModeNight, smallestwidthdp, widthdp, heightdp;
 
-    const char *p = dir;
-    const char *q;
-    while (NULL != (q = strchr(p, '-'))) {
-        String8 val(p, q-p);
-        val.toLower();
-        parts.add(val);
-        //printf("part: %s\n", parts[parts.size()-1].string());
-        p = q+1;
-    }
-    String8 val(p);
-    val.toLower();
-    parts.add(val);
-    //printf("part: %s\n", parts[parts.size()-1].string());
+    AaptLocaleValue locale;
+    int numLocaleComponents = 0;
 
     const int N = parts.size();
     int index = 0;
@@ -429,38 +720,18 @@
         }
         part = parts[index];
     } else {
-        //printf("not mcc: %s\n", part.string());
+        //printf("not mnc: %s\n", part.string());
     }
 
-    // locale - language
-    if (part.length() == 2 && isalpha(part[0]) && isalpha(part[1])) {
-        loc = part;
-
-        index++;
-        if (index == N) {
-            goto success;
-        }
-        part = parts[index];
-    } else {
-        //printf("not language: %s\n", part.string());
+    index = locale.initFromDirName(parts, index);
+    if (index == -1) {
+        return false;
+    }
+    if (index >= N){
+        goto success;
     }
 
-    // locale - region
-    if (loc.length() > 0
-            && part.length() == 3 && part[0] == 'r' && part[0] && part[1]) {
-        loc += "-";
-        part.toUpper();
-        loc += part.string() + 1;
-
-        index++;
-        if (index == N) {
-            goto success;
-        }
-        part = parts[index];
-    } else {
-        //printf("not region: %s\n", part.string());
-    }
-
+    part = parts[index];
     if (getLayoutDirectionName(part.string())) {
         layoutDir = part;
 
@@ -679,7 +950,7 @@
 success:
     this->mcc = mcc;
     this->mnc = mnc;
-    this->locale = loc;
+    this->locale = locale;
     this->screenLayoutSize = layoutsize;
     this->screenLayoutLong = layoutlong;
     this->smallestScreenWidthDp = smallestwidthdp;
@@ -711,7 +982,7 @@
     s += ",";
     s += this->mnc;
     s += ",";
-    s += this->locale;
+    s += locale.toDirName();
     s += ",";
     s += layoutDirection;
     s += ",";
@@ -765,12 +1036,15 @@
         }
         s += mnc;
     }
-    if (this->locale != "") {
-        if (s.length() > 0) {
-            s += "-";
-        }
-        s += locale;
+
+    const String8 localeComponent = locale.toDirName();
+    if (localeComponent != "") {
+         if (s.length() > 0) {
+             s += "-";
+         }
+         s += localeComponent;
     }
+
     if (this->layoutDirection != "") {
         if (s.length() > 0) {
             s += "-";
@@ -942,55 +1216,6 @@
     return true;
 }
 
-/*
- * Does this directory name fit the pattern of a locale dir ("en-rUS" or
- * "default")?
- *
- * TODO: Should insist that the first two letters are lower case, and the
- * second two are upper.
- */
-bool AaptGroupEntry::getLocaleName(const char* fileName,
-                                   ResTable_config* out)
-{
-    if (strcmp(fileName, kWildcardName) == 0
-            || strcmp(fileName, kDefaultLocale) == 0) {
-        if (out) {
-            out->language[0] = 0;
-            out->language[1] = 0;
-            out->country[0] = 0;
-            out->country[1] = 0;
-        }
-        return true;
-    }
-
-    if (strlen(fileName) == 2 && isalpha(fileName[0]) && isalpha(fileName[1])) {
-        if (out) {
-            out->language[0] = fileName[0];
-            out->language[1] = fileName[1];
-            out->country[0] = 0;
-            out->country[1] = 0;
-        }
-        return true;
-    }
-
-    if (strlen(fileName) == 5 &&
-        isalpha(fileName[0]) &&
-        isalpha(fileName[1]) &&
-        fileName[2] == '-' &&
-        isalpha(fileName[3]) &&
-        isalpha(fileName[4])) {
-        if (out) {
-            out->language[0] = fileName[0];
-            out->language[1] = fileName[1];
-            out->country[0] = fileName[3];
-            out->country[1] = fileName[4];
-        }
-        return true;
-    }
-
-    return false;
-}
-
 bool AaptGroupEntry::getLayoutDirectionName(const char* name, ResTable_config* out)
 {
     if (strcmp(name, kWildcardName) == 0) {
@@ -1496,18 +1721,18 @@
     return v;
 }
 
-const ResTable_config& AaptGroupEntry::toParams() const
+const ResTable_config AaptGroupEntry::toParams() const
 {
     if (!mParamsChanged) {
         return mParams;
     }
 
     mParamsChanged = false;
-    ResTable_config& params(mParams);
-    memset(&params, 0, sizeof(params));
+    ResTable_config& params = mParams;
+    memset(&params, 0, sizeof(ResTable_config));
     getMccName(mcc.string(), &params);
     getMncName(mnc.string(), &params);
-    getLocaleName(locale.string(), &params);
+    locale.writeTo(&params);
     getLayoutDirectionName(layoutDirection.string(), &params);
     getSmallestScreenWidthDpName(smallestScreenWidthDp.string(), &params);
     getScreenWidthDpName(screenWidthDp.string(), &params);
@@ -1992,7 +2217,9 @@
 
 AaptAssets::AaptAssets()
     : AaptDir(String8(), String8()),
-      mChanged(false), mHaveIncludedAssets(false), mRes(NULL)
+      mHavePrivateSymbols(false),
+      mChanged(false), mHaveIncludedAssets(false),
+      mRes(NULL)
 {
 }
 
@@ -2505,9 +2732,9 @@
             // If our preferred density is hdpi but we only have mdpi and xhdpi resources, we
             // pick xhdpi.
             uint32_t preferredDensity = 0;
-            const SortedVector<uint32_t>* preferredConfigs = prefFilter.configsForAxis(AXIS_DENSITY);
+            const SortedVector<AxisValue>* preferredConfigs = prefFilter.configsForAxis(AXIS_DENSITY);
             if (preferredConfigs != NULL && preferredConfigs->size() > 0) {
-                preferredDensity = (*preferredConfigs)[0];
+                preferredDensity = (*preferredConfigs)[0].intValue;
             }
 
             // Now deal with preferred configurations.
diff --git a/tools/aapt/AaptAssets.h b/tools/aapt/AaptAssets.h
index 9cc9007..336d08b 100644
--- a/tools/aapt/AaptAssets.h
+++ b/tools/aapt/AaptAssets.h
@@ -13,7 +13,6 @@
 #include <utils/RefBase.h>
 #include <utils/SortedVector.h>
 #include <utils/String8.h>
-#include <utils/String8.h>
 #include <utils/Vector.h>
 #include "ZipFile.h"
 
@@ -34,8 +33,7 @@
     AXIS_NONE = 0,
     AXIS_MCC = 1,
     AXIS_MNC,
-    AXIS_LANGUAGE,
-    AXIS_REGION,
+    AXIS_LOCALE,
     AXIS_SCREENLAYOUTSIZE,
     AXIS_SCREENLAYOUTLONG,
     AXIS_ORIENTATION,
@@ -58,6 +56,73 @@
     AXIS_END = AXIS_VERSION,
 };
 
+struct AaptLocaleValue {
+     char language[4];
+     char region[4];
+     char script[4];
+     char variant[8];
+
+     AaptLocaleValue() {
+         memset(this, 0, sizeof(AaptLocaleValue));
+     }
+
+     // Initialize this AaptLocaleValue from a config string.
+     bool initFromFilterString(const String8& config);
+
+     int initFromDirName(const Vector<String8>& parts, const int startIndex);
+
+     // Initialize this AaptLocaleValue from a ResTable_config.
+     void initFromResTable(const ResTable_config& config);
+
+     void writeTo(ResTable_config* out) const;
+
+     String8 toDirName() const;
+
+     int compare(const AaptLocaleValue& other) const {
+         return memcmp(this, &other, sizeof(AaptLocaleValue));
+     }
+
+     static void splitAndLowerCase(const char* const chars, Vector<String8>* parts,
+             const char separator);
+
+     inline bool operator<(const AaptLocaleValue& o) const { return compare(o) < 0; }
+     inline bool operator<=(const AaptLocaleValue& o) const { return compare(o) <= 0; }
+     inline bool operator==(const AaptLocaleValue& o) const { return compare(o) == 0; }
+     inline bool operator!=(const AaptLocaleValue& o) const { return compare(o) != 0; }
+     inline bool operator>=(const AaptLocaleValue& o) const { return compare(o) >= 0; }
+     inline bool operator>(const AaptLocaleValue& o) const { return compare(o) > 0; }
+private:
+     void setLanguage(const char* language);
+     void setRegion(const char* language);
+     void setScript(const char* script);
+     void setVariant(const char* variant);
+};
+
+struct AxisValue {
+    // Used for all axes except AXIS_LOCALE, which is represented
+    // as a AaptLocaleValue value.
+    int intValue;
+    AaptLocaleValue localeValue;
+
+    AxisValue() : intValue(0) {
+    }
+
+    inline int compare(const AxisValue &other) const  {
+        if (intValue != other.intValue) {
+            return intValue - other.intValue;
+        }
+
+        return localeValue.compare(other.localeValue);
+    }
+
+    inline bool operator<(const AxisValue& o) const { return compare(o) < 0; }
+    inline bool operator<=(const AxisValue& o) const { return compare(o) <= 0; }
+    inline bool operator==(const AxisValue& o) const { return compare(o) == 0; }
+    inline bool operator!=(const AxisValue& o) const { return compare(o) != 0; }
+    inline bool operator>=(const AxisValue& o) const { return compare(o) >= 0; }
+    inline bool operator>(const AxisValue& o) const { return compare(o) > 0; }
+};
+
 /**
  * This structure contains a specific variation of a single file out
  * of all the variations it can have that we can have.
@@ -65,22 +130,38 @@
 struct AaptGroupEntry
 {
 public:
-    AaptGroupEntry() : mParamsChanged(true) { }
-    AaptGroupEntry(const String8& _locale, const String8& _vendor)
-        : locale(_locale), vendor(_vendor), mParamsChanged(true) { }
+    AaptGroupEntry() : mParamsChanged(true) {
+        memset(&mParams, 0, sizeof(ResTable_config));
+    }
 
     bool initFromDirName(const char* dir, String8* resType);
 
-    static status_t parseNamePart(const String8& part, int* axis, uint32_t* value);
+    static bool parseFilterNamePart(const String8& part, int* axis, AxisValue* value);
 
-    static uint32_t getConfigValueForAxis(const ResTable_config& config, int axis);
+    static AxisValue getConfigValueForAxis(const ResTable_config& config, int axis);
 
     static bool configSameExcept(const ResTable_config& config,
             const ResTable_config& otherConfig, int axis);
 
+    int compare(const AaptGroupEntry& o) const;
+
+    const ResTable_config toParams() const;
+
+    inline bool operator<(const AaptGroupEntry& o) const { return compare(o) < 0; }
+    inline bool operator<=(const AaptGroupEntry& o) const { return compare(o) <= 0; }
+    inline bool operator==(const AaptGroupEntry& o) const { return compare(o) == 0; }
+    inline bool operator!=(const AaptGroupEntry& o) const { return compare(o) != 0; }
+    inline bool operator>=(const AaptGroupEntry& o) const { return compare(o) >= 0; }
+    inline bool operator>(const AaptGroupEntry& o) const { return compare(o) > 0; }
+
+    String8 toString() const;
+    String8 toDirName(const String8& resType) const;
+
+    const String8& getVersionString() const { return version; }
+
+private:
     static bool getMccName(const char* name, ResTable_config* out = NULL);
     static bool getMncName(const char* name, ResTable_config* out = NULL);
-    static bool getLocaleName(const char* name, ResTable_config* out = NULL);
     static bool getScreenLayoutSizeName(const char* name, ResTable_config* out = NULL);
     static bool getScreenLayoutLongName(const char* name, ResTable_config* out = NULL);
     static bool getOrientationName(const char* name, ResTable_config* out = NULL);
@@ -99,26 +180,9 @@
     static bool getLayoutDirectionName(const char* name, ResTable_config* out = NULL);
     static bool getVersionName(const char* name, ResTable_config* out = NULL);
 
-    int compare(const AaptGroupEntry& o) const;
-
-    const ResTable_config& toParams() const;
-
-    inline bool operator<(const AaptGroupEntry& o) const { return compare(o) < 0; }
-    inline bool operator<=(const AaptGroupEntry& o) const { return compare(o) <= 0; }
-    inline bool operator==(const AaptGroupEntry& o) const { return compare(o) == 0; }
-    inline bool operator!=(const AaptGroupEntry& o) const { return compare(o) != 0; }
-    inline bool operator>=(const AaptGroupEntry& o) const { return compare(o) >= 0; }
-    inline bool operator>(const AaptGroupEntry& o) const { return compare(o) > 0; }
-
-    String8 toString() const;
-    String8 toDirName(const String8& resType) const;
-
-    const String8& getVersionString() const { return version; }
-
-private:
     String8 mcc;
     String8 mnc;
-    String8 locale;
+    AaptLocaleValue locale;
     String8 vendor;
     String8 smallestScreenWidthDp;
     String8 screenWidthDp;
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index 48e3125..8e856b7 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -600,6 +600,7 @@
     // the API version because key resources like icons will have an implicit
     // version if they are using newer config types like density.
     ResTable_config config;
+    memset(&config, 0, sizeof(ResTable_config));
     config.language[0] = 'e';
     config.language[1] = 'n';
     config.country[0] = 'U';
diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp
index a390e42..c923bc2 100644
--- a/tools/aapt/Resource.cpp
+++ b/tools/aapt/Resource.cpp
@@ -80,6 +80,7 @@
     ResourceDirIterator(const sp<ResourceTypeSet>& set, const String8& resType)
         : mResType(resType), mSet(set), mSetPos(0), mGroupPos(0)
     {
+        memset(&mParams, 0, sizeof(ResTable_config));
     }
 
     inline const sp<AaptGroup>& getGroup() const { return mGroup; }
diff --git a/tools/aapt/ResourceFilter.cpp b/tools/aapt/ResourceFilter.cpp
index 8cfd2a5..e8a2be4 100644
--- a/tools/aapt/ResourceFilter.cpp
+++ b/tools/aapt/ResourceFilter.cpp
@@ -28,8 +28,8 @@
             mContainsPseudo = true;
         }
         int axis;
-        uint32_t value;
-        if (AaptGroupEntry::parseNamePart(part, &axis, &value)) {
+        AxisValue value;
+        if (!AaptGroupEntry::parseFilterNamePart(part, &axis, &value)) {
             fprintf(stderr, "Invalid configuration: %s\n", arg);
             fprintf(stderr, "                       ");
             for (int i=0; i<p-arg; i++) {
@@ -44,15 +44,20 @@
 
         ssize_t index = mData.indexOfKey(axis);
         if (index < 0) {
-            mData.add(axis, SortedVector<uint32_t>());
+            mData.add(axis, SortedVector<AxisValue>());
         }
-        SortedVector<uint32_t>& sv = mData.editValueFor(axis);
+        SortedVector<AxisValue>& sv = mData.editValueFor(axis);
         sv.add(value);
-        // if it's a locale with a region, also match an unmodified locale of the
-        // same language
-        if (axis == AXIS_LANGUAGE) {
-            if (value & 0xffff0000) {
-                sv.add(value & 0x0000ffff);
+
+        // If it's a locale with a region, script or variant, we should also match an
+        // unmodified locale of the same language
+        if (axis == AXIS_LOCALE) {
+            if (value.localeValue.region[0] || value.localeValue.script[0] ||
+                value.localeValue.variant[0]) {
+                AxisValue copy;
+                memcpy(copy.localeValue.language, value.localeValue.language,
+                       sizeof(value.localeValue.language));
+                sv.add(copy);
             }
         }
         p = q;
@@ -70,9 +75,9 @@
 }
 
 bool
-ResourceFilter::match(int axis, uint32_t value) const
+ResourceFilter::match(int axis, const AxisValue& value) const
 {
-    if (value == 0) {
+    if (value.intValue == 0 && (value.localeValue.language[0] == 0)) {
         // they didn't specify anything so take everything
         return true;
     }
@@ -81,7 +86,7 @@
         // we didn't request anything on this axis so take everything
         return true;
     }
-    const SortedVector<uint32_t>& sv = mData.valueAt(index);
+    const SortedVector<AxisValue>& sv = mData.valueAt(index);
     return sv.indexOf(value) >= 0;
 }
 
@@ -102,7 +107,7 @@
     return true;
 }
 
-const SortedVector<uint32_t>* ResourceFilter::configsForAxis(int axis) const
+const SortedVector<AxisValue>* ResourceFilter::configsForAxis(int axis) const
 {
     ssize_t index = mData.indexOfKey(axis);
     if (index < 0) {
diff --git a/tools/aapt/ResourceFilter.h b/tools/aapt/ResourceFilter.h
index 647b7bb..0d127ba 100644
--- a/tools/aapt/ResourceFilter.h
+++ b/tools/aapt/ResourceFilter.h
@@ -19,14 +19,15 @@
     ResourceFilter() : mData(), mContainsPseudo(false) {}
     status_t parse(const char* arg);
     bool isEmpty() const;
-    bool match(int axis, uint32_t value) const;
     bool match(int axis, const ResTable_config& config) const;
     bool match(const ResTable_config& config) const;
-    const SortedVector<uint32_t>* configsForAxis(int axis) const;
+    const SortedVector<AxisValue>* configsForAxis(int axis) const;
     inline bool containsPseudo() const { return mContainsPseudo; }
 
 private:
-    KeyedVector<int,SortedVector<uint32_t> > mData;
+    bool match(int axis, const AxisValue& value) const;
+
+    KeyedVector<int,SortedVector<AxisValue> > mData;
     bool mContainsPseudo;
 };
 
diff --git a/tools/aapt/ResourceIdCache.h b/tools/aapt/ResourceIdCache.h
index 65f7781..e6bcda2 100644
--- a/tools/aapt/ResourceIdCache.h
+++ b/tools/aapt/ResourceIdCache.h
@@ -7,7 +7,6 @@
 #define RESOURCE_ID_CACHE_H
 
 namespace android {
-class android::String16;
 
 class ResourceIdCache {
 public:
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index 02a74b1..aff0088 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -1292,8 +1292,8 @@
                 curIsStyled = true;
             } else if (strcmp16(block.getElementName(&len), string16.string()) == 0) {
                 // Note the existence and locale of every string we process
-                char rawLocale[16];
-                curParams.getLocale(rawLocale);
+                char rawLocale[RESTABLE_MAX_LOCALE_LEN];
+                curParams.getBcp47Locale(rawLocale);
                 String8 locale(rawLocale);
                 String16 name;
                 String16 translatable;
diff --git a/tools/layoutlib/Android.mk b/tools/layoutlib/Android.mk
index ed497a5..1fa9615 100644
--- a/tools/layoutlib/Android.mk
+++ b/tools/layoutlib/Android.mk
@@ -33,6 +33,8 @@
 
 built_ext_dep := $(call java-lib-deps,ext)
 built_ext_classes := $(call java-lib-files,ext)
+built_ext_data := $(call intermediates-dir-for, \
+			JAVA_LIBRARIES,ext,,COMMON)/javalib.jar
 
 built_layoutlib_create_jar := $(call intermediates-dir-for, \
 			JAVA_LIBRARIES,layoutlib_create,HOST)/javalib.jar
@@ -60,7 +62,8 @@
 	             $@ \
 	             $(built_core_classes) \
 	             $(built_framework_classes) \
-	             $(built_ext_classes)
+	             $(built_ext_classes) \
+	             $(built_ext_data)
 	$(hide) ls -l $(built_framework_classes)
 
 
diff --git a/tools/layoutlib/bridge/src/android/graphics/BidiRenderer.java b/tools/layoutlib/bridge/src/android/graphics/BidiRenderer.java
index 62d0a0d..802cf1c 100644
--- a/tools/layoutlib/bridge/src/android/graphics/BidiRenderer.java
+++ b/tools/layoutlib/bridge/src/android/graphics/BidiRenderer.java
@@ -20,6 +20,7 @@
 import java.awt.Graphics2D;
 import java.awt.font.FontRenderContext;
 import java.awt.font.GlyphVector;
+import java.awt.geom.Rectangle2D;
 import java.util.LinkedList;
 import java.util.List;
 
@@ -50,9 +51,12 @@
         }
     }
 
-    /* package */ Graphics2D graphics;
-    /* package */ Paint_Delegate paint;
-    /* package */ char[] text;
+    private Graphics2D mGraphics;
+    private Paint_Delegate mPaint;
+    private char[] mText;
+    // Bounds of the text drawn so far.
+    private RectF mBounds;
+    private float mBaseline;
 
     /**
      * @param graphics May be null.
@@ -61,9 +65,9 @@
      */
     /* package */ BidiRenderer(Graphics2D graphics, Paint_Delegate paint, char[] text) {
         assert (paint != null);
-        this.graphics = graphics;
-        this.paint = paint;
-        this.text = text;
+        mGraphics = graphics;
+        mPaint = paint;
+        mText = text;
     }
 
     /**
@@ -77,61 +81,62 @@
      * @param advances If not null, then advances for each character to be rendered are returned
      *            here.
      * @param advancesIndex index into advances from where the advances need to be filled.
-     * @param draw If true and {@link graphics} is not null, draw the rendered text on the graphics
+     * @param draw If true and {@code graphics} is not null, draw the rendered text on the graphics
      *            at the given co-ordinates
      * @param x The x-coordinate of the left edge of where the text should be drawn on the given
      *            graphics.
-     * @param y The y-coordinate at which to draw the text on the given graphics.
-     * @return The x-coordinate of the right edge of the drawn text. In other words,
-     *            x + the width of the text.
+     * @param y The y-coordinate at which to draw the text on the given mGraphics.
+     * @return A rectangle specifying the bounds of the text drawn.
      */
-    /* package */ float renderText(int start, int limit, boolean isRtl, float advances[],
+    /* package */ RectF renderText(int start, int limit, boolean isRtl, float[] advances,
             int advancesIndex, boolean draw, float x, float y) {
         // We break the text into scripts and then select font based on it and then render each of
         // the script runs.
-        for (ScriptRun run : getScriptRuns(text, start, limit, isRtl, paint.getFonts())) {
+        mBounds = new RectF(x, y, x, y);
+        mBaseline = y;
+        for (ScriptRun run : getScriptRuns(mText, start, limit, isRtl, mPaint.getFonts())) {
             int flag = Font.LAYOUT_NO_LIMIT_CONTEXT | Font.LAYOUT_NO_START_CONTEXT;
             flag |= isRtl ? Font.LAYOUT_RIGHT_TO_LEFT : Font.LAYOUT_LEFT_TO_RIGHT;
-            x = renderScript(run.start, run.limit, run.font, flag, advances, advancesIndex, draw,
-                    x, y);
+            renderScript(run.start, run.limit, run.font, flag, advances, advancesIndex, draw);
             advancesIndex += run.limit - run.start;
         }
-        return x;
+        return mBounds;
     }
 
     /**
-     * Render a script run. Use the preferred font to render as much as possible. This also
-     * implements a fallback mechanism to render characters that cannot be drawn using the
-     * preferred font.
-     *
-     * @return x + width of the text drawn.
+     * Render a script run to the right of the bounds passed. Use the preferred font to render as
+     * much as possible. This also implements a fallback mechanism to render characters that cannot
+     * be drawn using the preferred font.
      */
-    private float renderScript(int start, int limit, FontInfo preferredFont, int flag,
-            float advances[], int advancesIndex, boolean draw, float x, float y) {
-        List<FontInfo> fonts = paint.getFonts();
+    private void renderScript(int start, int limit, FontInfo preferredFont, int flag,
+            float[] advances, int advancesIndex, boolean draw) {
+        List<FontInfo> fonts = mPaint.getFonts();
         if (fonts == null || preferredFont == null) {
-            return x;
+            return;
         }
 
         while (start < limit) {
             boolean foundFont = false;
-            int canDisplayUpTo = preferredFont.mFont.canDisplayUpTo(text, start, limit);
+            int canDisplayUpTo = preferredFont.mFont.canDisplayUpTo(mText, start, limit);
             if (canDisplayUpTo == -1) {
-                return render(start, limit, preferredFont, flag, advances, advancesIndex, draw,
-                        x, y);
-            } else if (canDisplayUpTo > start) { // can draw something
-                x = render(start, canDisplayUpTo, preferredFont, flag, advances, advancesIndex,
-                        draw, x, y);
+                // We can draw all characters in the text.
+                render(start, limit, preferredFont, flag, advances, advancesIndex, draw);
+                return;
+            }
+            if (canDisplayUpTo > start) {
+                // We can draw something.
+                render(start, canDisplayUpTo, preferredFont, flag, advances, advancesIndex, draw);
                 advancesIndex += canDisplayUpTo - start;
                 start = canDisplayUpTo;
             }
 
-            int charCount = Character.isHighSurrogate(text[start]) ? 2 : 1;
+            // The current character cannot be drawn with the preferred font. Cycle through all the
+            // fonts to check which one can draw it.
+            int charCount = Character.isHighSurrogate(mText[start]) ? 2 : 1;
             for (FontInfo font : fonts) {
-                canDisplayUpTo = font.mFont.canDisplayUpTo(text, start, start + charCount);
+                canDisplayUpTo = font.mFont.canDisplayUpTo(mText, start, start + charCount);
                 if (canDisplayUpTo == -1) {
-                    x = render(start, start+charCount, font, flag, advances, advancesIndex, draw,
-                            x, y);
+                    render(start, start+charCount, font, flag, advances, advancesIndex, draw);
                     start += charCount;
                     advancesIndex += charCount;
                     foundFont = true;
@@ -143,46 +148,63 @@
                 // probably appear as a box or a blank space. We could, probably, use some
                 // heuristics and break the character into the base character and diacritics and
                 // then draw it, but it's probably not worth the effort.
-                x = render(start, start + charCount, preferredFont, flag, advances, advancesIndex,
-                        draw, x, y);
+                render(start, start + charCount, preferredFont, flag, advances, advancesIndex,
+                        draw);
                 start += charCount;
                 advancesIndex += charCount;
             }
         }
-        return x;
     }
 
     /**
-     * Render the text with the given font.
+     * Renders the text to the right of the bounds with the given font.
+     * @param font The font to render the text with.
      */
-    private float render(int start, int limit, FontInfo font, int flag, float advances[],
-            int advancesIndex, boolean draw, float x, float y) {
+    private void render(int start, int limit, FontInfo font, int flag, float[] advances,
+            int advancesIndex, boolean draw) {
 
-        float totalAdvance = 0;
         // Since the metrics don't have anti-aliasing set, we create a new FontRenderContext with
         // the anti-aliasing set.
         FontRenderContext f = font.mMetrics.getFontRenderContext();
-        FontRenderContext frc = new FontRenderContext(f.getTransform(), paint.isAntiAliased(),
+        FontRenderContext frc = new FontRenderContext(f.getTransform(), mPaint.isAntiAliased(),
                 f.usesFractionalMetrics());
-        GlyphVector gv = font.mFont.layoutGlyphVector(frc, text, start, limit, flag);
+        GlyphVector gv = font.mFont.layoutGlyphVector(frc, mText, start, limit, flag);
         int ng = gv.getNumGlyphs();
         int[] ci = gv.getGlyphCharIndices(0, ng, null);
-        for (int i = 0; i < ng; i++) {
-            float adv = gv.getGlyphMetrics(i).getAdvanceX();
-            if (advances != null) {
+        if (advances != null) {
+            for (int i = 0; i < ng; i++) {
                 int adv_idx = advancesIndex + ci[i];
-                advances[adv_idx] += adv;
+                advances[adv_idx] += gv.getGlyphMetrics(i).getAdvanceX();
             }
-            totalAdvance += adv;
         }
-        if (draw && graphics != null) {
-            graphics.drawGlyphVector(gv, x, y);
+        if (draw && mGraphics != null) {
+            mGraphics.drawGlyphVector(gv, mBounds.right, mBaseline);
         }
-        return x + totalAdvance;
+
+        // Update the bounds.
+        Rectangle2D awtBounds = gv.getLogicalBounds();
+        RectF bounds = awtRectToAndroidRect(awtBounds, mBounds.right, mBaseline);
+        // If the width of the bounds is zero, no text had been drawn earlier. Hence, use the
+        // coordinates from the bounds as an offset.
+        if (Math.abs(mBounds.right - mBounds.left) == 0) {
+            mBounds = bounds;
+        } else {
+            mBounds.union(bounds);
+        }
     }
 
     // --- Static helper methods ---
 
+    private static RectF awtRectToAndroidRect(Rectangle2D awtRec, float offsetX, float offsetY) {
+        float left = (float) awtRec.getX();
+        float top = (float) awtRec.getY();
+        float right = (float) (left + awtRec.getWidth());
+        float bottom = (float) (top + awtRec.getHeight());
+        RectF androidRect = new RectF(left, top, right, bottom);
+        androidRect.offset(offsetX, offsetY);
+        return androidRect;
+    }
+
     /* package */  static List<ScriptRun> getScriptRuns(char[] text, int start, int limit,
             boolean isRtl, List<FontInfo> fonts) {
         LinkedList<ScriptRun> scriptRuns = new LinkedList<ScriptRun>();
diff --git a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
index 602717b..1cc8ea5 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
@@ -991,7 +991,8 @@
                 int limit = index + count;
                 boolean isRtl = flags == Canvas.DIRECTION_RTL;
                 if (paintDelegate.getTextAlign() != Paint.Align.LEFT.nativeInt) {
-                    float m = paintDelegate.measureText(text, index, count, isRtl);
+                    RectF bounds = paintDelegate.measureText(text, index, count, isRtl);
+                    float m = bounds.right - bounds.left;
                     if (paintDelegate.getTextAlign() == Paint.Align.CENTER.nativeInt) {
                         x -= m / 2;
                     } else if (paintDelegate.getTextAlign() == Paint.Align.RIGHT.nativeInt) {
diff --git a/tools/layoutlib/bridge/src/android/graphics/NinePatch_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/NinePatch_Delegate.java
index 38745ce..74b2893 100644
--- a/tools/layoutlib/bridge/src/android/graphics/NinePatch_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/NinePatch_Delegate.java
@@ -176,7 +176,7 @@
     /*package*/ static void nativeDraw(long canvas_instance, RectF loc, long bitmap_instance,
             long chunk, long paint_instance_or_null, int destDensity, int srcDensity) {
         draw(canvas_instance,
-                (int) loc.left, (int) loc.top, (int) loc.width(), (int) loc.height(),
+                (int) loc.left, (int) loc.top, (int) loc.right, (int) loc.bottom,
                 bitmap_instance, chunk, paint_instance_or_null,
                 destDensity, srcDensity);
     }
@@ -185,7 +185,7 @@
     /*package*/ static void nativeDraw(long canvas_instance, Rect loc, long bitmap_instance,
             long chunk, long paint_instance_or_null, int destDensity, int srcDensity) {
         draw(canvas_instance,
-                loc.left, loc.top, loc.width(), loc.height(),
+                loc.left, loc.top, loc.right, loc.bottom,
                 bitmap_instance, chunk, paint_instance_or_null,
                 destDensity, srcDensity);
     }
diff --git a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
index ca8e8aa..7007b71 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
@@ -575,7 +575,8 @@
             return 0;
         }
 
-        return delegate.measureText(text, index, count, isRtl(bidiFlags));
+        RectF bounds = delegate.measureText(text, index, count, isRtl(bidiFlags));
+        return bounds.right - bounds.left;
     }
 
     @LayoutlibDelegate
@@ -614,7 +615,8 @@
             }
 
             // measure from start to end
-            float res = delegate.measureText(text, start, end - start + 1, isRtl(bidiFlags));
+            RectF bounds = delegate.measureText(text, start, end - start + 1, isRtl(bidiFlags));
+            float res = bounds.right - bounds.left;
 
             if (measuredWidth != null) {
                 measuredWidth[measureIndex] = res;
@@ -991,8 +993,9 @@
         boolean isRtl = isRtl(flags);
 
         int limit = index + count;
-        return new BidiRenderer(null, delegate, text).renderText(
+        RectF bounds = new BidiRenderer(null, delegate, text).renderText(
                 index, limit, isRtl, advances, advancesIndex, false, 0, 0);
+        return bounds.right - bounds.left;
     }
 
     @LayoutlibDelegate
@@ -1058,9 +1061,7 @@
         if (delegate == null || delegate.mFonts == null || delegate.mFonts.size() == 0) {
             return;
         }
-        int w = (int) delegate.measureText(text, index, count, isRtl(bidiFlags));
-        int h= delegate.getFonts().get(0).mMetrics.getHeight();
-        bounds.set(0, 0, w, h);
+        delegate.measureText(text, index, count, isRtl(bidiFlags)).roundOut(bounds);
     }
 
     @LayoutlibDelegate
@@ -1154,7 +1155,7 @@
         }
     }
 
-    /*package*/ float measureText(char[] text, int index, int count, boolean isRtl) {
+    /*package*/ RectF measureText(char[] text, int index, int count, boolean isRtl) {
         return new BidiRenderer(null, this, text).renderText(
                 index, index + count, isRtl, null, 0, false, 0, 0);
     }
diff --git a/tools/layoutlib/bridge/src/android/text/format/Time_Delegate.java b/tools/layoutlib/bridge/src/android/text/format/Time_Delegate.java
index 15cd687..320dd0d 100644
--- a/tools/layoutlib/bridge/src/android/text/format/Time_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/text/format/Time_Delegate.java
@@ -17,6 +17,7 @@
 package android.text.format;
 
 import java.util.Calendar;
+import java.util.TimeZone;
 import java.util.UnknownFormatConversionException;
 import java.util.regex.Pattern;
 
@@ -35,6 +36,28 @@
     // Regex to match odd number of '%'.
     private static final Pattern p = Pattern.compile("(?<!%)(%%)*%(?!%)");
 
+    // Format used by toString()
+    private static final String FORMAT = "%1$tY%1$tm%1$tdT%1$tH%1$tM%1$tS<%1$tZ>";
+
+    @LayoutlibDelegate
+    /*package*/ static long normalize(Time thisTime, boolean ignoreDst) {
+        long millis = toMillis(thisTime, ignoreDst);
+        set(thisTime, millis);
+        return millis;
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static void switchTimezone(Time thisTime, String timezone) {
+        Calendar c = timeToCalendar(thisTime);
+        c.setTimeZone(TimeZone.getTimeZone(timezone));
+        calendarToTime(c, thisTime);
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static int nativeCompare(Time a, Time b) {
+      return timeToCalendar(a).compareTo(timeToCalendar(b));
+    }
+
     @LayoutlibDelegate
     /*package*/ static String format1(Time thisTime, String format) {
 
@@ -46,16 +69,92 @@
             // of $.
             return String.format(
                     p.matcher(format).replaceAll("$0\\1\\$t"),
-                    timeToCalendar(thisTime, Calendar.getInstance()));
+                    timeToCalendar(thisTime));
         } catch (UnknownFormatConversionException e) {
             Bridge.getLog().fidelityWarning(LayoutLog.TAG_STRFTIME, "Unrecognized format", e, format);
             return format;
         }
     }
 
-    private static Calendar timeToCalendar(Time time, Calendar calendar) {
+    /**
+     * Return the current time in YYYYMMDDTHHMMSS<tz> format
+     */
+    @LayoutlibDelegate
+    /*package*/ static String toString(Time thisTime) {
+        Calendar c = timeToCalendar(thisTime);
+        return String.format(FORMAT, c);
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static boolean nativeParse(Time thisTime, String s) {
+        Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED,
+                "android.text.format.Time.parse() not supported.", null);
+        return false;
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static boolean nativeParse3339(Time thisTime, String s) {
+        Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED,
+                "android.text.format.Time.parse3339() not supported.", null);
+        return false;
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static void setToNow(Time thisTime) {
+        calendarToTime(getCalendarInstance(thisTime), thisTime);
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static long toMillis(Time thisTime, boolean ignoreDst) {
+        // TODO: Respect ignoreDst.
+        return timeToCalendar(thisTime).getTimeInMillis();
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static void set(Time thisTime, long millis) {
+        Calendar c = getCalendarInstance(thisTime);
+        c.setTimeInMillis(millis);
+        calendarToTime(c,thisTime);
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static String format2445(Time thisTime) {
+        Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED,
+                "android.text.format.Time.format2445() not supported.", null);
+        return "";
+    }
+
+    // ---- private helper methods ----
+
+    private static Calendar timeToCalendar(Time time) {
+        Calendar calendar = getCalendarInstance(time);
         calendar.set(time.year, time.month, time.monthDay, time.hour, time.minute, time.second);
         return calendar;
     }
 
+    private static void calendarToTime(Calendar c, Time time) {
+        time.timezone = c.getTimeZone().getID();
+        time.set(c.get(Calendar.SECOND), c.get(Calendar.MINUTE), c.get(Calendar.HOUR_OF_DAY),
+                c.get(Calendar.DATE), c.get(Calendar.MONTH), c.get(Calendar.YEAR));
+        time.weekDay = c.get(Calendar.DAY_OF_WEEK);
+        time.yearDay = c.get(Calendar.DAY_OF_YEAR);
+        time.isDst = c.getTimeZone().inDaylightTime(c.getTime()) ? 1 : 0;
+        // gmtoff is in seconds and TimeZone.getOffset() returns milliseconds.
+        time.gmtoff = c.getTimeZone().getOffset(c.getTimeInMillis()) / DateUtils.SECOND_IN_MILLIS;
+    }
+
+    /**
+     * Return a calendar instance with the correct timezone.
+     *
+     * @param time Time to obtain the timezone from.
+     */
+    private static Calendar getCalendarInstance(Time time) {
+        // TODO: Check platform code to make sure the behavior is same for null/invalid timezone.
+        if (time == null || time.timezone == null) {
+            // Default to local timezone.
+            return Calendar.getInstance();
+        }
+        // If timezone is invalid, use GMT.
+        return Calendar.getInstance(TimeZone.getTimeZone(time.timezone));
+    }
 }
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 57771e3..377d996 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
@@ -334,7 +334,7 @@
                 backgroundView = backgroundLayout;
                 backgroundLayout.setOrientation(LinearLayout.VERTICAL);
                 LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
-                        LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
+                        LayoutParams.MATCH_PARENT, 0);
                 layoutParams.weight = 1;
                 backgroundLayout.setLayoutParams(layoutParams);
                 topLayout.addView(backgroundLayout);
@@ -369,7 +369,7 @@
                 // content frame
                 mContentRoot = new FrameLayout(context);
                 layoutParams = new LinearLayout.LayoutParams(
-                        LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
+                        LayoutParams.MATCH_PARENT, 0);
                 layoutParams.weight = 1;
                 mContentRoot.setLayoutParams(layoutParams);
                 backgroundLayout.addView(mContentRoot);
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 1572a40..9a31705 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
@@ -29,6 +29,7 @@
 import org.objectweb.asm.signature.SignatureVisitor;
 
 import java.io.IOException;
+import java.io.InputStream;
 import java.util.ArrayList;
 import java.util.Enumeration;
 import java.util.List;
@@ -60,6 +61,9 @@
     private final String[] mIncludeGlobs;
     /** The set of classes to exclude.*/
     private final Set<String> mExcludedClasses;
+    /** Glob patterns of files to keep as is. */
+    private final String[] mIncludeFileGlobs;
+    /** Copy these files into the output as is. */
 
     /**
      * Creates a new analyzer.
@@ -70,15 +74,19 @@
      * @param deriveFrom Keep all classes that derive from these one (these included).
      * @param includeGlobs Glob patterns of classes to keep, e.g. "com.foo.*"
      *        ("*" does not matches dots whilst "**" does, "." and "$" are interpreted as-is)
+     * @param includeFileGlobs Glob patterns of files which are kept as is. This is only for files
+     *        not ending in .class.
      */
     public AsmAnalyzer(Log log, List<String> osJarPath, AsmGenerator gen,
-            String[] deriveFrom, String[] includeGlobs, Set<String> excludeClasses) {
+            String[] deriveFrom, String[] includeGlobs, Set<String> excludeClasses,
+            String[] includeFileGlobs) {
         mLog = log;
         mGen = gen;
         mOsSourceJar = osJarPath != null ? osJarPath : new ArrayList<String>();
         mDeriveFrom = deriveFrom != null ? deriveFrom : new String[0];
         mIncludeGlobs = includeGlobs != null ? includeGlobs : new String[0];
         mExcludedClasses = excludeClasses;
+        mIncludeFileGlobs = includeFileGlobs != null ? includeFileGlobs : new String[0];
     }
 
     /**
@@ -86,7 +94,11 @@
      * Fills the generator with classes & dependencies found.
      */
     public void analyze() throws IOException, LogAbortException {
-        Map<String, ClassReader> zipClasses = parseZip(mOsSourceJar);
+
+        TreeMap<String, ClassReader> zipClasses = new TreeMap<String, ClassReader>();
+        Map<String, InputStream> filesFound = new TreeMap<String, InputStream>();
+
+        parseZip(mOsSourceJar, zipClasses, filesFound);
         mLog.info("Found %d classes in input JAR%s.", zipClasses.size(),
                 mOsSourceJar.size() > 1 ? "s" : "");
 
@@ -96,15 +108,29 @@
         if (mGen != null) {
             mGen.setKeep(found);
             mGen.setDeps(deps);
+            mGen.setCopyFiles(filesFound);
         }
     }
 
     /**
-     * Parses a JAR file and returns a list of all classes founds using a map
-     * class name => ASM ClassReader. Class names are in the form "android.view.View".
+     * Parses a JAR file and adds all the classes found to <code>classes</code>
+     * and all other files to <code>filesFound</code>.
+     *
+     * @param classes The map of class name => ASM ClassReader. Class names are
+     *                in the form "android.view.View".
+     * @param fileFound The map of file name => InputStream. The file name is
+     *                  in the form "android/data/dataFile".
      */
-    Map<String,ClassReader> parseZip(List<String> jarPathList) throws IOException {
-        TreeMap<String, ClassReader> classes = new TreeMap<String, ClassReader>();
+    void parseZip(List<String> jarPathList, Map<String, ClassReader> classes,
+            Map<String, InputStream> filesFound) throws IOException {
+        if (classes == null || filesFound == null) {
+            return;
+        }
+
+        Pattern[] includeFilePatterns = new Pattern[mIncludeFileGlobs.length];
+        for (int i = 0; i < mIncludeFileGlobs.length; ++i) {
+            includeFilePatterns[i] = getPatternFromGlob(mIncludeFileGlobs[i]);
+        }
 
         for (String jarPath : jarPathList) {
             ZipFile zip = new ZipFile(jarPath);
@@ -116,11 +142,17 @@
                     ClassReader cr = new ClassReader(zip.getInputStream(entry));
                     String className = classReaderToClassName(cr);
                     classes.put(className, cr);
+                } else {
+                    for (int i = 0; i < includeFilePatterns.length; ++i) {
+                        if (includeFilePatterns[i].matcher(entry.getName()).matches()) {
+                            filesFound.put(entry.getName(), zip.getInputStream(entry));
+                            break;
+                        }
+                    }
                 }
             }
         }
 
-        return classes;
     }
 
     /**
@@ -202,7 +234,19 @@
      */
     void findGlobs(String globPattern, Map<String, ClassReader> zipClasses,
             Map<String, ClassReader> inOutFound) throws LogAbortException {
-        // transforms the glob pattern in a regexp:
+
+        Pattern regexp = getPatternFromGlob(globPattern);
+
+        for (Entry<String, ClassReader> entry : zipClasses.entrySet()) {
+            String class_name = entry.getKey();
+            if (regexp.matcher(class_name).matches()) {
+                findClass(class_name, zipClasses, inOutFound);
+            }
+        }
+    }
+
+    Pattern getPatternFromGlob(String globPattern) {
+     // transforms the glob pattern in a regexp:
         // - escape "." with "\."
         // - replace "*" by "[^.]*"
         // - escape "$" with "\$"
@@ -216,14 +260,7 @@
         globPattern = globPattern.replaceAll("@", ".*");
         globPattern += "$";
 
-        Pattern regexp = Pattern.compile(globPattern);
-
-        for (Entry<String, ClassReader> entry : zipClasses.entrySet()) {
-            String class_name = entry.getKey();
-            if (regexp.matcher(class_name).matches()) {
-                findClass(class_name, zipClasses, inOutFound);
-            }
-        }
+        return Pattern.compile(globPattern);
     }
 
     /**
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java
index b102561..207d8ae 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java
@@ -20,6 +20,7 @@
 import org.objectweb.asm.ClassVisitor;
 import org.objectweb.asm.ClassWriter;
 
+import java.io.ByteArrayOutputStream;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.IOException;
@@ -52,6 +53,8 @@
     private Map<String, ClassReader> mKeep;
     /** All dependencies that must be completely stubbed. */
     private Map<String, ClassReader> mDeps;
+    /** All files that are to be copied as-is. */
+    private Map<String, InputStream> mCopyFiles;
     /** Counter of number of classes renamed during transform. */
     private int mRenameCount;
     /** FQCN Names of the classes to rename: map old-FQCN => new-FQCN */
@@ -195,6 +198,11 @@
         mDeps = deps;
     }
 
+    /** Sets the map of files to output as-is. */
+    public void setCopyFiles(Map<String, InputStream> copyFiles) {
+        mCopyFiles = copyFiles;
+    }
+
     /** Gets the map of classes to output as-is, except if they have native methods */
     public Map<String, ClassReader> getKeep() {
         return mKeep;
@@ -205,6 +213,11 @@
         return mDeps;
     }
 
+    /** Gets the map of files to output as-is. */
+    public Map<String, InputStream> getCopyFiles() {
+        return mCopyFiles;
+    }
+
     /** Generates the final JAR */
     public void generate() throws FileNotFoundException, IOException {
         TreeMap<String, byte[]> all = new TreeMap<String, byte[]>();
@@ -232,6 +245,15 @@
             all.put(name, b);
         }
 
+        for (Entry<String, InputStream> entry : mCopyFiles.entrySet()) {
+            try {
+                byte[] b = inputStreamToByteArray(entry.getValue());
+                all.put(entry.getKey(), b);
+            } catch (IOException e) {
+                // Ignore.
+            }
+
+        }
         mLog.info("# deps classes: %d", mDeps.size());
         mLog.info("# keep classes: %d", mKeep.size());
         mLog.info("# renamed     : %d", mRenameCount);
@@ -381,4 +403,13 @@
         return cv.hasNativeMethods();
     }
 
+    private byte[] inputStreamToByteArray(InputStream is) throws IOException {
+        ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+        byte[] data = new byte[8192];  // 8KB
+        int n;
+        while ((n = is.read(data, 0, data.length)) != -1) {
+            buffer.write(data, 0, n);
+        }
+        return buffer.toByteArray();
+    }
 }
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 f6779e3..79aa642 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
@@ -131,7 +131,6 @@
         "android.os.HandlerThread#run",
         "android.os.Build#getString",
         "android.text.format.DateFormat#is24HourFormat",
-        "android.text.format.Time#format1",
         "android.view.Choreographer#getRefreshRate",
         "android.view.Display#updateDisplayInfoLocked",
         "android.view.LayoutInflater#rInflate",
@@ -188,6 +187,7 @@
         "android.graphics.Xfermode",
         "android.os.SystemClock",
         "android.text.AndroidBidi",
+        "android.text.format.Time",
         "android.util.FloatMath",
         "android.view.Display",
         "libcore.icu.DateIntervalFormat",
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 ee501d2..a79fba1 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
@@ -115,7 +115,10 @@
                         "android.database.ContentObserver", // for Digital clock
                         "com.android.i18n.phonenumbers.*",  // for TextView with autolink attribute
                     },
-                    excludeClasses);
+                    excludeClasses,
+                    new String[] {
+                        "com/android/i18n/phonenumbers/data/*",
+                    });
             aa.analyze();
             agen.generate();
 
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 005fc9d..7ec0d38 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
@@ -29,6 +29,7 @@
 import org.objectweb.asm.ClassReader;
 
 import java.io.IOException;
+import java.io.InputStream;
 import java.net.URL;
 import java.util.ArrayList;
 import java.util.HashSet;
@@ -55,8 +56,10 @@
 
         Set<String> excludeClasses = new HashSet<String>(1);
         excludeClasses.add("java.lang.JavaClass");
-        mAa = new AsmAnalyzer(mLog, mOsJarPath, null /* gen */,
-                null /* deriveFrom */, null /* includeGlobs */, excludeClasses);
+
+        String[] includeFiles = new String[]{"mock_android/data/data*"};
+        mAa = new AsmAnalyzer(mLog, mOsJarPath, null /* gen */, null /* deriveFrom */,
+                null /* includeGlobs */, excludeClasses, includeFiles);
     }
 
     @After
@@ -65,7 +68,11 @@
 
     @Test
     public void testParseZip() throws IOException {
-        Map<String, ClassReader> map = mAa.parseZip(mOsJarPath);
+
+        Map<String, ClassReader> map = new TreeMap<String, ClassReader>();
+        Map<String, InputStream> filesFound = new TreeMap<String, InputStream>();
+
+        mAa.parseZip(mOsJarPath, map, filesFound);
 
         assertArrayEquals(new String[] {
                 "java.lang.JavaClass",
@@ -86,11 +93,17 @@
                 "mock_android.widget.TableLayout$LayoutParams"
             },
             map.keySet().toArray());
+        assertArrayEquals(new String[] {"mock_android/data/dataFile"},
+            filesFound.keySet().toArray());
     }
 
     @Test
     public void testFindClass() throws IOException, LogAbortException {
-        Map<String, ClassReader> zipClasses = mAa.parseZip(mOsJarPath);
+
+        Map<String, ClassReader> zipClasses = new TreeMap<String, ClassReader>();
+        Map<String, InputStream> filesFound = new TreeMap<String, InputStream>();
+
+        mAa.parseZip(mOsJarPath, zipClasses, filesFound);
         TreeMap<String, ClassReader> found = new TreeMap<String, ClassReader>();
 
         ClassReader cr = mAa.findClass("mock_android.view.ViewGroup$LayoutParams",
@@ -105,7 +118,11 @@
 
     @Test
     public void testFindGlobs() throws IOException, LogAbortException {
-        Map<String, ClassReader> zipClasses = mAa.parseZip(mOsJarPath);
+
+        Map<String, ClassReader> zipClasses = new TreeMap<String, ClassReader>();
+        Map<String, InputStream> filesFound = new TreeMap<String, InputStream>();
+
+        mAa.parseZip(mOsJarPath, zipClasses, filesFound);
         TreeMap<String, ClassReader> found = new TreeMap<String, ClassReader>();
 
         // this matches classes, a package match returns nothing
@@ -164,7 +181,11 @@
 
     @Test
     public void testFindClassesDerivingFrom() throws LogAbortException, IOException {
-        Map<String, ClassReader> zipClasses = mAa.parseZip(mOsJarPath);
+
+        Map<String, ClassReader> zipClasses = new TreeMap<String, ClassReader>();
+        Map<String, InputStream> filesFound = new TreeMap<String, InputStream>();
+
+        mAa.parseZip(mOsJarPath, zipClasses, filesFound);
         TreeMap<String, ClassReader> found = new TreeMap<String, ClassReader>();
 
         mAa.findClassesDerivingFrom("mock_android.view.View", zipClasses, found);
@@ -186,7 +207,11 @@
 
     @Test
     public void testDependencyVisitor() throws IOException, LogAbortException {
-        Map<String, ClassReader> zipClasses = mAa.parseZip(mOsJarPath);
+
+        Map<String, ClassReader> zipClasses = new TreeMap<String, ClassReader>();
+        Map<String, InputStream> filesFound = new TreeMap<String, InputStream>();
+
+        mAa.parseZip(mOsJarPath, zipClasses, filesFound);
         TreeMap<String, ClassReader> keep = new TreeMap<String, ClassReader>();
         TreeMap<String, ClassReader> new_keep = new TreeMap<String, ClassReader>();
         TreeMap<String, ClassReader> in_deps = new TreeMap<String, ClassReader>();
diff --git a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java
index 8a27173..0dbc238 100644
--- a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java
+++ b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java
@@ -33,6 +33,7 @@
 
 import java.io.File;
 import java.io.IOException;
+import java.io.InputStream;
 import java.net.URL;
 import java.util.ArrayList;
 import java.util.Enumeration;
@@ -131,7 +132,8 @@
                 new String[] {        // include classes
                     "**"
                 },
-                new HashSet<String>(0) /* excluded classes */);
+                new HashSet<String>(0) /* excluded classes */,
+                new String[]{} /* include files */);
         aa.analyze();
         agen.generate();
 
@@ -195,10 +197,15 @@
                 new String[] {        // include classes
                     "**"
                 },
-                new HashSet<String>(1));
+                new HashSet<String>(1),
+                new String[] {        /* include files */
+                    "mock_android/data/data*"
+                });
         aa.analyze();
         agen.generate();
-        Map<String, ClassReader> output = parseZip(mOsDestJar);
+        Map<String, ClassReader> output = new TreeMap<String, ClassReader>();
+        Map<String, InputStream> filesFound = new TreeMap<String, InputStream>();
+        parseZip(mOsDestJar, output, filesFound);
         boolean injectedClassFound = false;
         for (ClassReader cr: output.values()) {
             TestClassVisitor cv = new TestClassVisitor();
@@ -206,10 +213,13 @@
             injectedClassFound |= cv.mInjectedClassFound;
         }
         assertTrue(injectedClassFound);
+        assertArrayEquals(new String[] {"mock_android/data/dataFile"},
+                filesFound.keySet().toArray());
     }
 
-    private Map<String,ClassReader> parseZip(String jarPath) throws IOException {
-        TreeMap<String, ClassReader> classes = new TreeMap<String, ClassReader>();
+    private void parseZip(String jarPath,
+            Map<String, ClassReader> classes,
+            Map<String, InputStream> filesFound) throws IOException {
 
             ZipFile zip = new ZipFile(jarPath);
             Enumeration<? extends ZipEntry> entries = zip.entries();
@@ -220,10 +230,11 @@
                     ClassReader cr = new ClassReader(zip.getInputStream(entry));
                     String className = classReaderToClassName(cr);
                     classes.put(className, cr);
+                } else {
+                    filesFound.put(entry.getName(), zip.getInputStream(entry));
                 }
             }
 
-        return classes;
     }
 
     private String classReaderToClassName(ClassReader classReader) {
diff --git a/tools/layoutlib/create/tests/data/mock_android.jar b/tools/layoutlib/create/tests/data/mock_android.jar
index 60d8efb..8dd0481 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/data/anotherDataFile b/tools/layoutlib/create/tests/mock_data/mock_android/data/anotherDataFile
new file mode 100644
index 0000000..ab29fbe
--- /dev/null
+++ b/tools/layoutlib/create/tests/mock_data/mock_android/data/anotherDataFile
@@ -0,0 +1 @@
+A simple data file that should *not* be copied to the output jar.
\ No newline at end of file
diff --git a/tools/layoutlib/create/tests/mock_data/mock_android/data/dataFile b/tools/layoutlib/create/tests/mock_data/mock_android/data/dataFile
new file mode 100644
index 0000000..9b01893
--- /dev/null
+++ b/tools/layoutlib/create/tests/mock_data/mock_android/data/dataFile
@@ -0,0 +1 @@
+A simple data file that should be copied to the output jar unchanged.
\ No newline at end of file