Merge "Fixed a bug where the outline was not correctly updated"
diff --git a/api/current.txt b/api/current.txt
index d4be98c..1c8698a 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -491,6 +491,7 @@
     field public static final int editTextStyle = 16842862; // 0x101006e
     field public static final deprecated int editable = 16843115; // 0x101016b
     field public static final int editorExtras = 16843300; // 0x1010224
+    field public static final int elevation = 16843852; // 0x101044c
     field public static final int ellipsize = 16842923; // 0x10100ab
     field public static final int ems = 16843096; // 0x1010158
     field public static final int enabled = 16842766; // 0x101000e
@@ -28162,12 +28163,19 @@
     field public static final java.lang.String SERVICE_INTERFACE = "android.tv.TvInputService";
   }
 
-  public abstract class TvInputService.TvInputSessionImpl {
+  public abstract class TvInputService.TvInputSessionImpl implements android.view.KeyEvent.Callback {
     ctor public TvInputService.TvInputSessionImpl();
     method public android.view.View onCreateOverlayView();
+    method public boolean onGenericMotionEvent(android.view.MotionEvent);
+    method public boolean onKeyDown(int, android.view.KeyEvent);
+    method public boolean onKeyLongPress(int, android.view.KeyEvent);
+    method public boolean onKeyMultiple(int, int, android.view.KeyEvent);
+    method public boolean onKeyUp(int, android.view.KeyEvent);
     method public abstract void onRelease();
     method public abstract boolean onSetSurface(android.view.Surface);
     method public abstract void onSetVolume(float);
+    method public boolean onTouchEvent(android.view.MotionEvent);
+    method public boolean onTrackballEvent(android.view.MotionEvent);
     method public abstract boolean onTune(android.net.Uri);
     method public void setOverlayViewEnabled(boolean);
   }
@@ -28177,9 +28185,16 @@
     ctor public TvView(android.content.Context, android.util.AttributeSet);
     ctor public TvView(android.content.Context, android.util.AttributeSet, int);
     method public void bindTvInput(android.content.ComponentName, android.tv.TvInputManager.SessionCreateCallback);
+    method public boolean dispatchUnhandledInputEvent(android.view.InputEvent);
+    method public boolean onUnhandledInputEvent(android.view.InputEvent);
+    method public void setOnUnhandledInputEventListener(android.tv.TvView.OnUnhandledInputEventListener);
     method public void unbindTvInput();
   }
 
+  public static abstract interface TvView.OnUnhandledInputEventListener {
+    method public abstract boolean onUnhandledInputEvent(android.view.InputEvent);
+  }
+
 }
 
 package android.util {
@@ -30121,6 +30136,7 @@
     method public int getDrawingCacheQuality();
     method public void getDrawingRect(android.graphics.Rect);
     method public long getDrawingTime();
+    method public float getElevation();
     method public boolean getFilterTouchesWhenObscured();
     method public boolean getFitsSystemWindows();
     method public java.util.ArrayList<android.view.View> getFocusables(int);
@@ -30219,6 +30235,7 @@
     method public void getWindowVisibleDisplayFrame(android.graphics.Rect);
     method public float getX();
     method public float getY();
+    method public float getZ();
     method public boolean hasFocus();
     method public boolean hasFocusable();
     method public boolean hasNestedScrollingParent();
@@ -30385,6 +30402,7 @@
     method public void setDrawingCacheEnabled(boolean);
     method public void setDrawingCacheQuality(int);
     method public void setDuplicateParentStateEnabled(boolean);
+    method public void setElevation(float);
     method public void setEnabled(boolean);
     method public void setFadingEdgeLength(int);
     method public void setFilterTouchesWhenObscured(boolean);
@@ -30470,6 +30488,7 @@
     method public void setWillNotDraw(boolean);
     method public void setX(float);
     method public void setY(float);
+    method public void setZ(float);
     method public boolean showContextMenu();
     method public android.view.ActionMode startActionMode(android.view.ActionMode.Callback);
     method public void startAnimation(android.view.animation.Animation);
@@ -31049,6 +31068,8 @@
     method public android.view.ViewPropertyAnimator xBy(float);
     method public android.view.ViewPropertyAnimator y(float);
     method public android.view.ViewPropertyAnimator yBy(float);
+    method public android.view.ViewPropertyAnimator z(float);
+    method public android.view.ViewPropertyAnimator zBy(float);
   }
 
   public final class ViewStub extends android.view.View {
diff --git a/core/java/android/hardware/camera2/impl/CameraDevice.java b/core/java/android/hardware/camera2/impl/CameraDevice.java
index ee2adac..40a7905 100644
--- a/core/java/android/hardware/camera2/impl/CameraDevice.java
+++ b/core/java/android/hardware/camera2/impl/CameraDevice.java
@@ -157,7 +157,14 @@
         mCameraId = cameraId;
         mDeviceListener = listener;
         mDeviceHandler = handler;
-        TAG = String.format("CameraDevice-%s-JV", mCameraId);
+
+        final int MAX_TAG_LEN = 23;
+        String tag = String.format("CameraDevice-JV-%s", mCameraId);
+        if (tag.length() > MAX_TAG_LEN) {
+            tag = tag.substring(0, MAX_TAG_LEN);
+        }
+        TAG = tag;
+
         DEBUG = Log.isLoggable(TAG, Log.DEBUG);
     }
 
diff --git a/core/java/android/text/BoringLayout.java b/core/java/android/text/BoringLayout.java
index 77cd71e..6f00707 100644
--- a/core/java/android/text/BoringLayout.java
+++ b/core/java/android/text/BoringLayout.java
@@ -188,10 +188,6 @@
             spacing = metrics.descent - metrics.ascent;
         }
 
-        if (spacingmult != 1 || spacingadd != 0) {
-            spacing = (int)(spacing * spacingmult + spacingadd + 0.5f);
-        }
-
         mBottom = spacing;
 
         if (includepad) {
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index f7ac75a..0db00f0 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -632,7 +632,11 @@
             bottom = fm.bottom;
         }
 
-        if (j == 0) {
+        boolean firstLine = (j == 0);
+        boolean currentLineIsTheLastVisibleOne = (j + 1 == mMaximumVisibleLineCount);
+        boolean lastLine = currentLineIsTheLastVisibleOne || (end == bufEnd);
+
+        if (firstLine) {
             if (trackPad) {
                 mTopPadding = top - above;
             }
@@ -641,7 +645,10 @@
                 above = top;
             }
         }
-        if (end == bufEnd) {
+
+        int extra;
+
+        if (lastLine) {
             if (trackPad) {
                 mBottomPadding = bottom - below;
             }
@@ -651,9 +658,8 @@
             }
         }
 
-        int extra;
 
-        if (needMultiply && end != bufEnd) {
+        if (needMultiply && !lastLine) {
             double ex = (below - above) * (spacingmult - 1) + spacingadd;
             if (ex >= 0) {
                 extra = (int)(ex + EXTRA_ROUNDING);
@@ -690,8 +696,6 @@
         if (ellipsize != null) {
             // If there is only one line, then do any type of ellipsis except when it is MARQUEE
             // if there are multiple lines, just allow END ellipsis on the last line
-            boolean firstLine = (j == 0);
-            boolean currentLineIsTheLastVisibleOne = (j + 1 == mMaximumVisibleLineCount);
             boolean forceEllipsis = moreChars && (mLineCount + 1 == mMaximumVisibleLineCount);
 
             boolean doEllipsis =
diff --git a/core/java/android/tv/ITvInputClient.aidl b/core/java/android/tv/ITvInputClient.aidl
index 43be6f0..538f8a1 100644
--- a/core/java/android/tv/ITvInputClient.aidl
+++ b/core/java/android/tv/ITvInputClient.aidl
@@ -18,6 +18,7 @@
 
 import android.content.ComponentName;
 import android.tv.ITvInputSession;
+import android.view.InputChannel;
 
 /**
  * Interface a client of the ITvInputManager implements, to identify itself and receive information
@@ -25,6 +26,6 @@
  * @hide
  */
 oneway interface ITvInputClient {
-    void onSessionCreated(in ComponentName name, IBinder token, int seq);
+    void onSessionCreated(in ComponentName name, IBinder token, in InputChannel channel, int seq);
     void onAvailabilityChanged(in ComponentName name, boolean isAvailable);
 }
diff --git a/core/java/android/tv/ITvInputService.aidl b/core/java/android/tv/ITvInputService.aidl
index 672784f..4f1bc2b 100644
--- a/core/java/android/tv/ITvInputService.aidl
+++ b/core/java/android/tv/ITvInputService.aidl
@@ -18,6 +18,7 @@
 
 import android.tv.ITvInputServiceCallback;
 import android.tv.ITvInputSessionCallback;
+import android.view.InputChannel;
 
 /**
  * Top-level interface to a TV input component (implemented in a Service).
@@ -26,5 +27,5 @@
 oneway interface ITvInputService {
     void registerCallback(ITvInputServiceCallback callback);
     void unregisterCallback(in ITvInputServiceCallback callback);
-    void createSession(ITvInputSessionCallback callback);
+    void createSession(in InputChannel channel, ITvInputSessionCallback callback);
 }
diff --git a/core/java/android/tv/ITvInputSessionWrapper.java b/core/java/android/tv/ITvInputSessionWrapper.java
index a6e0877..3ccccf3 100644
--- a/core/java/android/tv/ITvInputSessionWrapper.java
+++ b/core/java/android/tv/ITvInputSessionWrapper.java
@@ -20,9 +20,16 @@
 import android.graphics.Rect;
 import android.net.Uri;
 import android.os.IBinder;
+import android.os.Looper;
 import android.os.Message;
+import android.tv.TvInputManager.Session;
 import android.tv.TvInputService.TvInputSessionImpl;
 import android.util.Log;
+import android.view.InputChannel;
+import android.view.InputEvent;
+import android.view.InputEventReceiver;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
 import android.view.Surface;
 
 import com.android.internal.os.HandlerCaller;
@@ -45,50 +52,66 @@
     private static final int DO_RELAYOUT_OVERLAY_VIEW = 6;
     private static final int DO_REMOVE_OVERLAY_VIEW = 7;
 
-    private TvInputSessionImpl mTvInputSession;
     private final HandlerCaller mCaller;
 
-    public ITvInputSessionWrapper(Context context, TvInputSessionImpl session) {
+    private TvInputSessionImpl mTvInputSessionImpl;
+    private InputChannel mChannel;
+    private TvInputEventReceiver mReceiver;
+
+    public ITvInputSessionWrapper(Context context, TvInputSessionImpl sessionImpl,
+            InputChannel channel) {
         mCaller = new HandlerCaller(context, null, this, true /* asyncHandler */);
-        mTvInputSession = session;
+        mTvInputSessionImpl = sessionImpl;
+        mChannel = channel;
+        if (channel != null) {
+            mReceiver = new TvInputEventReceiver(channel, context.getMainLooper());
+        }
     }
 
     @Override
     public void executeMessage(Message msg) {
-        if (mTvInputSession == null) {
+        if (mTvInputSessionImpl == null) {
             return;
         }
 
         switch (msg.what) {
             case DO_RELEASE: {
-                mTvInputSession.release();
-                mTvInputSession = null;
+                mTvInputSessionImpl.release();
+                mTvInputSessionImpl = null;
+                if (mReceiver != null) {
+                    mReceiver.dispose();
+                    mReceiver = null;
+                }
+                if (mChannel != null) {
+                    mChannel.dispose();
+                    mChannel = null;
+                }
                 return;
             }
             case DO_SET_SURFACE: {
-                mTvInputSession.setSurface((Surface) msg.obj);
+                mTvInputSessionImpl.setSurface((Surface) msg.obj);
                 return;
             }
             case DO_SET_VOLUME: {
-                mTvInputSession.setVolume((Float) msg.obj);
+                mTvInputSessionImpl.setVolume((Float) msg.obj);
                 return;
             }
             case DO_TUNE: {
-                mTvInputSession.tune((Uri) msg.obj);
+                mTvInputSessionImpl.tune((Uri) msg.obj);
                 return;
             }
             case DO_CREATE_OVERLAY_VIEW: {
                 SomeArgs args = (SomeArgs) msg.obj;
-                mTvInputSession.createOverlayView((IBinder) args.arg1, (Rect) args.arg2);
+                mTvInputSessionImpl.createOverlayView((IBinder) args.arg1, (Rect) args.arg2);
                 args.recycle();
                 return;
             }
             case DO_RELAYOUT_OVERLAY_VIEW: {
-                mTvInputSession.relayoutOverlayView((Rect) msg.obj);
+                mTvInputSessionImpl.relayoutOverlayView((Rect) msg.obj);
                 return;
             }
             case DO_REMOVE_OVERLAY_VIEW: {
-                mTvInputSession.removeOverlayView(true);
+                mTvInputSessionImpl.removeOverlayView(true);
                 return;
             }
             default: {
@@ -133,4 +156,24 @@
     public void removeOverlayView() {
         mCaller.executeOrSendMessage(mCaller.obtainMessage(DO_REMOVE_OVERLAY_VIEW));
     }
+
+    private final class TvInputEventReceiver extends InputEventReceiver {
+        public TvInputEventReceiver(InputChannel inputChannel, Looper looper) {
+            super(inputChannel, looper);
+        }
+
+        @Override
+        public void onInputEvent(InputEvent event) {
+            if (mTvInputSessionImpl == null) {
+                // The session has been finished.
+                finishInputEvent(event, false);
+                return;
+            }
+
+            int handled = mTvInputSessionImpl.dispatchInputEvent(event, this);
+            if (handled != Session.DISPATCH_IN_PROGRESS) {
+                finishInputEvent(event, handled == Session.DISPATCH_HANDLED);
+            }
+        }
+    }
 }
diff --git a/core/java/android/tv/TvInputManager.java b/core/java/android/tv/TvInputManager.java
index 05f0b9c..7b9b1fb 100644
--- a/core/java/android/tv/TvInputManager.java
+++ b/core/java/android/tv/TvInputManager.java
@@ -21,9 +21,16 @@
 import android.net.Uri;
 import android.os.Handler;
 import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
 import android.os.RemoteException;
 import android.util.Log;
+import android.util.Pools.Pool;
+import android.util.Pools.SimplePool;
 import android.util.SparseArray;
+import android.view.InputChannel;
+import android.view.InputEvent;
+import android.view.InputEventSender;
 import android.view.Surface;
 import android.view.View;
 
@@ -138,7 +145,8 @@
         mUserId = userId;
         mClient = new ITvInputClient.Stub() {
             @Override
-            public void onSessionCreated(ComponentName name, IBinder token, int seq) {
+            public void onSessionCreated(ComponentName name, IBinder token, InputChannel channel,
+                    int seq) {
                 synchronized (mSessionCreateCallbackRecordMap) {
                     SessionCreateCallbackRecord record = mSessionCreateCallbackRecordMap.get(seq);
                     mSessionCreateCallbackRecordMap.delete(seq);
@@ -148,7 +156,7 @@
                     }
                     Session session = null;
                     if (token != null) {
-                        session = new Session(name, token, mService, mUserId);
+                        session = new Session(token, channel, mService, mUserId);
                     }
                     record.postSessionCreated(session);
                 }
@@ -321,13 +329,30 @@
 
     /** The Session provides the per-session functionality of TV inputs. */
     public static final class Session {
+        static final int DISPATCH_IN_PROGRESS = -1;
+        static final int DISPATCH_NOT_HANDLED = 0;
+        static final int DISPATCH_HANDLED = 1;
+
+        private static final long INPUT_SESSION_NOT_RESPONDING_TIMEOUT = 2500;
+
         private final ITvInputManager mService;
         private final int mUserId;
+
+        // For scheduling input event handling on the main thread. This also serves as a lock to
+        // protect pending input events and the input channel.
+        private final InputEventHandler mHandler = new InputEventHandler(Looper.getMainLooper());
+
+        private final Pool<PendingEvent> mPendingEventPool = new SimplePool<PendingEvent>(20);
+        private final SparseArray<PendingEvent> mPendingEvents = new SparseArray<PendingEvent>(20);
+
         private IBinder mToken;
+        private TvInputEventSender mSender;
+        private InputChannel mChannel;
 
         /** @hide */
-        private Session(ComponentName name, IBinder token, ITvInputManager service, int userId) {
+        private Session(IBinder token, InputChannel channel, ITvInputManager service, int userId) {
             mToken = token;
+            mChannel = channel;
             mService = service;
             mUserId = userId;
         }
@@ -347,6 +372,18 @@
             } catch (RemoteException e) {
                 throw new RuntimeException(e);
             }
+
+            synchronized (mHandler) {
+                if (mChannel != null) {
+                    if (mSender != null) {
+                        flushPendingEventsLocked();
+                        mSender.dispose();
+                        mSender = null;
+                    }
+                    mChannel.dispose();
+                    mChannel = null;
+                }
+            }
         }
 
         /**
@@ -478,5 +515,228 @@
                 throw new RuntimeException(e);
             }
         }
+
+        /**
+         * Dispatches an input event to this session.
+         *
+         * @param event {@link InputEvent} to dispatch.
+         * @param token A token used to identify the input event later in the callback.
+         * @param callback A callback used to receive the dispatch result.
+         * @param handler {@link Handler} that the dispatch result will be delivered to.
+         * @return Returns {@link #DISPATCH_HANDLED} if the event was handled. Returns
+         *         {@link #DISPATCH_NOT_HANDLED} if the event was not handled. Returns
+         *         {@link #DISPATCH_IN_PROGRESS} if the event is in progress and the callback will
+         *         be invoked later.
+         * @throws IllegalArgumentException if any of the necessary arguments is {@code null}.
+         * @hide
+         */
+        public int dispatchInputEvent(InputEvent event, Object token,
+                FinishedInputEventCallback callback, Handler handler) {
+            if (event == null) {
+                throw new IllegalArgumentException("event cannot be null");
+            }
+            if (callback != null && handler == null) {
+                throw new IllegalArgumentException("handler cannot be null");
+            }
+            synchronized (mHandler) {
+                if (mChannel == null) {
+                    return DISPATCH_NOT_HANDLED;
+                }
+                PendingEvent p = obtainPendingEventLocked(event, token, callback, handler);
+                if (Looper.myLooper() == Looper.getMainLooper()) {
+                    // Already running on the main thread so we can send the event immediately.
+                    return sendInputEventOnMainLooperLocked(p);
+                }
+
+                // Post the event to the main thread.
+                Message msg = mHandler.obtainMessage(InputEventHandler.MSG_SEND_INPUT_EVENT, p);
+                msg.setAsynchronous(true);
+                mHandler.sendMessage(msg);
+                return DISPATCH_IN_PROGRESS;
+            }
+        }
+
+        /**
+         * Callback that is invoked when an input event that was dispatched to this session has been
+         * finished.
+         *
+         * @hide
+         */
+        public interface FinishedInputEventCallback {
+            /**
+             * Called when the dispatched input event is finished.
+             *
+             * @param token a token passed to {@link #dispatchInputEvent}.
+             * @param handled {@code true} if the dispatched input event was handled properly.
+             *            {@code false} otherwise.
+             */
+            public void onFinishedInputEvent(Object token, boolean handled);
+        }
+
+        // Must be called on the main looper
+        private void sendInputEventAndReportResultOnMainLooper(PendingEvent p) {
+            synchronized (mHandler) {
+                int result = sendInputEventOnMainLooperLocked(p);
+                if (result == DISPATCH_IN_PROGRESS) {
+                    return;
+                }
+            }
+
+            invokeFinishedInputEventCallback(p, false);
+        }
+
+        private int sendInputEventOnMainLooperLocked(PendingEvent p) {
+            if (mChannel != null) {
+                if (mSender == null) {
+                    mSender = new TvInputEventSender(mChannel, mHandler.getLooper());
+                }
+
+                final InputEvent event = p.mEvent;
+                final int seq = event.getSequenceNumber();
+                if (mSender.sendInputEvent(seq, event)) {
+                    mPendingEvents.put(seq, p);
+                    Message msg = mHandler.obtainMessage(InputEventHandler.MSG_TIMEOUT_INPUT_EVENT, p);
+                    msg.setAsynchronous(true);
+                    mHandler.sendMessageDelayed(msg, INPUT_SESSION_NOT_RESPONDING_TIMEOUT);
+                    return DISPATCH_IN_PROGRESS;
+                }
+
+                Log.w(TAG, "Unable to send input event to session: " + mToken + " dropping:"
+                        + event);
+            }
+            return DISPATCH_NOT_HANDLED;
+        }
+
+        void finishedInputEvent(int seq, boolean handled, boolean timeout) {
+            final PendingEvent p;
+            synchronized (mHandler) {
+                int index = mPendingEvents.indexOfKey(seq);
+                if (index < 0) {
+                    return; // spurious, event already finished or timed out
+                }
+
+                p = mPendingEvents.valueAt(index);
+                mPendingEvents.removeAt(index);
+
+                if (timeout) {
+                    Log.w(TAG, "Timeout waiting for seesion to handle input event after "
+                            + INPUT_SESSION_NOT_RESPONDING_TIMEOUT + " ms: " + mToken);
+                } else {
+                    mHandler.removeMessages(InputEventHandler.MSG_TIMEOUT_INPUT_EVENT, p);
+                }
+            }
+
+            invokeFinishedInputEventCallback(p, handled);
+        }
+
+        // Assumes the event has already been removed from the queue.
+        void invokeFinishedInputEventCallback(PendingEvent p, boolean handled) {
+            p.mHandled = handled;
+            if (p.mHandler.getLooper().isCurrentThread()) {
+                // Already running on the callback handler thread so we can send the callback
+                // immediately.
+                p.run();
+            } else {
+                // Post the event to the callback handler thread.
+                // In this case, the callback will be responsible for recycling the event.
+                Message msg = Message.obtain(p.mHandler, p);
+                msg.setAsynchronous(true);
+                msg.sendToTarget();
+            }
+        }
+
+        private void flushPendingEventsLocked() {
+            mHandler.removeMessages(InputEventHandler.MSG_FLUSH_INPUT_EVENT);
+
+            final int count = mPendingEvents.size();
+            for (int i = 0; i < count; i++) {
+                int seq = mPendingEvents.keyAt(i);
+                Message msg = mHandler.obtainMessage(InputEventHandler.MSG_FLUSH_INPUT_EVENT, seq, 0);
+                msg.setAsynchronous(true);
+                msg.sendToTarget();
+            }
+        }
+
+        private PendingEvent obtainPendingEventLocked(InputEvent event, Object token,
+                FinishedInputEventCallback callback, Handler handler) {
+            PendingEvent p = mPendingEventPool.acquire();
+            if (p == null) {
+                p = new PendingEvent();
+            }
+            p.mEvent = event;
+            p.mToken = token;
+            p.mCallback = callback;
+            p.mHandler = handler;
+            return p;
+        }
+
+        private void recyclePendingEventLocked(PendingEvent p) {
+            p.recycle();
+            mPendingEventPool.release(p);
+        }
+
+        private final class InputEventHandler extends Handler {
+            public static final int MSG_SEND_INPUT_EVENT = 1;
+            public static final int MSG_TIMEOUT_INPUT_EVENT = 2;
+            public static final int MSG_FLUSH_INPUT_EVENT = 3;
+
+            InputEventHandler(Looper looper) {
+                super(looper, null, true);
+            }
+
+            @Override
+            public void handleMessage(Message msg) {
+                switch (msg.what) {
+                    case MSG_SEND_INPUT_EVENT: {
+                        sendInputEventAndReportResultOnMainLooper((PendingEvent) msg.obj);
+                        return;
+                    }
+                    case MSG_TIMEOUT_INPUT_EVENT: {
+                        finishedInputEvent(msg.arg1, false, true);
+                        return;
+                    }
+                    case MSG_FLUSH_INPUT_EVENT: {
+                        finishedInputEvent(msg.arg1, false, false);
+                        return;
+                    }
+                }
+            }
+        }
+
+        private final class TvInputEventSender extends InputEventSender {
+            public TvInputEventSender(InputChannel inputChannel, Looper looper) {
+                super(inputChannel, looper);
+            }
+
+            @Override
+            public void onInputEventFinished(int seq, boolean handled) {
+                finishedInputEvent(seq, handled, false);
+            }
+        }
+
+        private final class PendingEvent implements Runnable {
+            public InputEvent mEvent;
+            public Object mToken;
+            public FinishedInputEventCallback mCallback;
+            public Handler mHandler;
+            public boolean mHandled;
+
+            public void recycle() {
+                mEvent = null;
+                mToken = null;
+                mCallback = null;
+                mHandler = null;
+                mHandled = false;
+            }
+
+            @Override
+            public void run() {
+                mCallback.onFinishedInputEvent(mToken, mHandled);
+
+                synchronized (mHandler) {
+                    recyclePendingEventLocked(this);
+                }
+            }
+        }
     }
 }
diff --git a/core/java/android/tv/TvInputService.java b/core/java/android/tv/TvInputService.java
index 80eb407..636e3b4 100644
--- a/core/java/android/tv/TvInputService.java
+++ b/core/java/android/tv/TvInputService.java
@@ -28,13 +28,21 @@
 import android.os.Message;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
+import android.tv.TvInputManager.Session;
 import android.util.Log;
 import android.view.Gravity;
+import android.view.InputChannel;
+import android.view.InputDevice;
+import android.view.InputEvent;
+import android.view.InputEventReceiver;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
 import android.view.Surface;
 import android.view.View;
 import android.view.WindowManager;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.os.SomeArgs;
 
 /**
  * A base class for implementing television input service.
@@ -89,10 +97,17 @@
             }
 
             @Override
-            public void createSession(ITvInputSessionCallback cb) {
-                if (cb != null) {
-                    mHandler.obtainMessage(ServiceHandler.DO_CREATE_SESSION, cb).sendToTarget();
+            public void createSession(InputChannel channel, ITvInputSessionCallback cb) {
+                if (channel == null) {
+                    Log.w(TAG, "Creating session without input channel");
                 }
+                if (cb == null) {
+                    return;
+                }
+                SomeArgs args = SomeArgs.obtain();
+                args.arg1 = channel;
+                args.arg2 = cb;
+                mHandler.obtainMessage(ServiceHandler.DO_CREATE_SESSION, args).sendToTarget();
             }
         };
     }
@@ -131,7 +146,8 @@
     /**
      * Base class for derived classes to implement to provide {@link TvInputManager.Session}.
      */
-    public abstract class TvInputSessionImpl {
+    public abstract class TvInputSessionImpl implements KeyEvent.Callback {
+        private final KeyEvent.DispatcherState mDispatcherState = new KeyEvent.DispatcherState();
         private final WindowManager mWindowManager;
         private WindowManager.LayoutParams mWindowParams;
         private View mOverlayView;
@@ -143,6 +159,13 @@
             mWindowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
         }
 
+        /**
+         * Enables or disables the overlay view. By default, the overlay view is disabled. Must be
+         * called explicitly after the session is created to enable the overlay view.
+         *
+         * @param enable {@code true} if you want to enable the overlay view. {@code false}
+         *            otherwise.
+         */
         public void setOverlayViewEnabled(final boolean enable) {
             mHandler.post(new Runnable() {
                 @Override
@@ -203,6 +226,121 @@
         }
 
         /**
+         * Default implementation of {@link android.view.KeyEvent.Callback#onKeyDown(int, KeyEvent)
+         * KeyEvent.Callback.onKeyDown()}: always returns false (doesn't handle the event).
+         * <p>
+         * Override this to intercept key down events before they are processed by the application.
+         * If you return true, the application will not process the event itself. If you return
+         * false, the normal application processing will occur as if the TV input had not seen the
+         * event at all.
+         *
+         * @param keyCode The value in event.getKeyCode().
+         * @param event Description of the key event.
+         * @return If you handled the event, return {@code true}. If you want to allow the event to
+         *         be handled by the next receiver, return {@code false}.
+         */
+        @Override
+        public boolean onKeyDown(int keyCode, KeyEvent event) {
+            return false;
+        }
+
+        /**
+         * Default implementation of
+         * {@link android.view.KeyEvent.Callback#onKeyLongPress(int, KeyEvent)
+         * KeyEvent.Callback.onKeyLongPress()}: always returns false (doesn't handle the event).
+         * <p>
+         * Override this to intercept key long press events before they are processed by the
+         * application. If you return true, the application will not process the event itself. If
+         * you return false, the normal application processing will occur as if the TV input had not
+         * seen the event at all.
+         *
+         * @param keyCode The value in event.getKeyCode().
+         * @param event Description of the key event.
+         * @return If you handled the event, return {@code true}. If you want to allow the event to
+         *         be handled by the next receiver, return {@code false}.
+         */
+        @Override
+        public boolean onKeyLongPress(int keyCode, KeyEvent event) {
+            return false;
+        }
+
+        /**
+         * Default implementation of
+         * {@link android.view.KeyEvent.Callback#onKeyMultiple(int, int, KeyEvent)
+         * KeyEvent.Callback.onKeyMultiple()}: always returns false (doesn't handle the event).
+         * <p>
+         * Override this to intercept special key multiple events before they are processed by the
+         * application. If you return true, the application will not itself process the event. If
+         * you return false, the normal application processing will occur as if the TV input had not
+         * seen the event at all.
+         *
+         * @param keyCode The value in event.getKeyCode().
+         * @param count The number of times the action was made.
+         * @param event Description of the key event.
+         * @return If you handled the event, return {@code true}. If you want to allow the event to
+         *         be handled by the next receiver, return {@code false}.
+         */
+        @Override
+        public boolean onKeyMultiple(int keyCode, int count, KeyEvent event) {
+            return false;
+        }
+
+        /**
+         * Default implementation of {@link android.view.KeyEvent.Callback#onKeyUp(int, KeyEvent)
+         * KeyEvent.Callback.onKeyUp()}: always returns false (doesn't handle the event).
+         * <p>
+         * Override this to intercept key up events before they are processed by the application. If
+         * you return true, the application will not itself process the event. If you return false,
+         * the normal application processing will occur as if the TV input had not seen the event at
+         * all.
+         *
+         * @param keyCode The value in event.getKeyCode().
+         * @param event Description of the key event.
+         * @return If you handled the event, return {@code true}. If you want to allow the event to
+         *         be handled by the next receiver, return {@code false}.
+         */
+        @Override
+        public boolean onKeyUp(int keyCode, KeyEvent event) {
+            return false;
+        }
+
+        /**
+         * Implement this method to handle touch screen motion events on the current input session.
+         *
+         * @param event The motion event being received.
+         * @return If you handled the event, return {@code true}. If you want to allow the event to
+         *         be handled by the next receiver, return {@code false}.
+         * @see View#onTouchEvent
+         */
+        public boolean onTouchEvent(MotionEvent event) {
+            return false;
+        }
+
+        /**
+         * Implement this method to handle trackball events on the current input session.
+         *
+         * @param event The motion event being received.
+         * @return If you handled the event, return {@code true}. If you want to allow the event to
+         *         be handled by the next receiver, return {@code false}.
+         * @see View#onTrackballEvent
+         */
+        public boolean onTrackballEvent(MotionEvent event) {
+            return false;
+        }
+
+        /**
+         * Implement this method to handle generic motion events on the current input session.
+         *
+         * @param event The motion event being received.
+         * @return If you handled the event, return {@code true}. If you want to allow the event to
+         *         be handled by the next receiver, return {@code false}.
+         * @see View#onGenericMotionEvent
+         */
+        public boolean onGenericMotionEvent(MotionEvent event) {
+            return false;
+        }
+
+        /**
          * This method is called when the application would like to stop using the current input
          * session.
          */
@@ -212,7 +350,7 @@
         }
 
         /**
-         * Calls {@link onSetSurface}.
+         * Calls {@link #onSetSurface}.
          */
         void setSurface(Surface surface) {
             onSetSurface(surface);
@@ -220,14 +358,14 @@
         }
 
         /**
-         * Calls {@link onSetVolume}.
+         * Calls {@link #onSetVolume}.
          */
         void setVolume(float volume) {
             onSetVolume(volume);
         }
 
         /**
-         * Calls {@link onTune}.
+         * Calls {@link #onTune}.
          */
         void tune(Uri channelUri) {
             onTune(channelUri);
@@ -235,8 +373,8 @@
         }
 
         /**
-         * Creates an overlay view. This calls {@link onCreateOverlayView} to get
-         * a view to attach to the overlay window.
+         * Creates an overlay view. This calls {@link #onCreateOverlayView} to get a view to attach
+         * to the overlay window.
          *
          * @param windowToken A window token of an application.
          * @param frame A position of the overlay view.
@@ -314,6 +452,42 @@
                 mWindowParams = null;
             }
         }
+
+        /**
+         * Takes care of dispatching incoming input events and tells whether the event was handled.
+         */
+        int dispatchInputEvent(InputEvent event, InputEventReceiver receiver) {
+            if (DEBUG) Log.d(TAG, "dispatchInputEvent(" + event + ")");
+            if (event instanceof KeyEvent) {
+                if (((KeyEvent) event).dispatch(this, mDispatcherState, this)) {
+                    return Session.DISPATCH_HANDLED;
+                }
+            } else if (event instanceof MotionEvent) {
+                MotionEvent motionEvent = (MotionEvent) event;
+                final int source = motionEvent.getSource();
+                if (motionEvent.isTouchEvent()) {
+                    if (onTouchEvent(motionEvent)) {
+                        return Session.DISPATCH_HANDLED;
+                    }
+                } else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
+                    if (onTrackballEvent(motionEvent)) {
+                        return Session.DISPATCH_HANDLED;
+                    }
+                } else {
+                    if (onGenericMotionEvent(motionEvent)) {
+                        return Session.DISPATCH_HANDLED;
+                    }
+                }
+            }
+            if (mOverlayView == null) {
+                return Session.DISPATCH_NOT_HANDLED;
+            }
+            if (!mOverlayView.hasWindowFocus()) {
+                mOverlayView.getViewRootImpl().windowFocusChanged(true, true);
+            }
+            mOverlayView.getViewRootImpl().dispatchInputEvent(event, receiver);
+            return Session.DISPATCH_IN_PROGRESS;
+        }
     }
 
     private final class ServiceHandler extends Handler {
@@ -324,20 +498,23 @@
         public final void handleMessage(Message msg) {
             switch (msg.what) {
                 case DO_CREATE_SESSION: {
-                    ITvInputSessionCallback cb = (ITvInputSessionCallback) msg.obj;
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    InputChannel channel = (InputChannel) args.arg1;
+                    ITvInputSessionCallback cb = (ITvInputSessionCallback) args.arg2;
                     try {
                         TvInputSessionImpl sessionImpl = onCreateSession();
                         if (sessionImpl == null) {
                             // Failed to create a session.
                             cb.onSessionCreated(null);
-                            return;
+                        } else {
+                            ITvInputSession stub = new ITvInputSessionWrapper(TvInputService.this,
+                                    sessionImpl, channel);
+                            cb.onSessionCreated(stub);
                         }
-                        ITvInputSession stub = new ITvInputSessionWrapper(TvInputService.this,
-                                sessionImpl);
-                        cb.onSessionCreated(stub);
                     } catch (RemoteException e) {
                         Log.e(TAG, "error in onSessionCreated");
                     }
+                    args.recycle();
                     return;
                 }
                 case DO_BROADCAST_AVAILABILITY_CHANGE: {
diff --git a/core/java/android/tv/TvView.java b/core/java/android/tv/TvView.java
index 325950d..289823b 100644
--- a/core/java/android/tv/TvView.java
+++ b/core/java/android/tv/TvView.java
@@ -20,20 +20,24 @@
 import android.content.Context;
 import android.graphics.Rect;
 import android.os.Handler;
-import android.tv.TvInputManager;
 import android.tv.TvInputManager.Session;
+import android.tv.TvInputManager.Session.FinishedInputEventCallback;
 import android.tv.TvInputManager.SessionCreateCallback;
 import android.util.AttributeSet;
 import android.util.Log;
+import android.view.InputEvent;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
 import android.view.Surface;
 import android.view.SurfaceHolder;
 import android.view.SurfaceView;
-import android.view.ViewTreeObserver;
 
 /**
  * View playing TV
  */
 public class TvView extends SurfaceView {
+    // STOPSHIP: Turn debugging off.
+    private static final boolean DEBUG = true;
     private static final String TAG = "TvView";
 
     private final Handler mHandler = new Handler();
@@ -41,11 +45,11 @@
     private Surface mSurface;
     private boolean mOverlayViewCreated;
     private Rect mOverlayViewFrame;
-    private boolean mGlobalListenersAdded;
-    private TvInputManager mTvInputManager;
+    private final TvInputManager mTvInputManager;
     private SessionCreateCallback mSessionCreateCallback;
+    private OnUnhandledInputEventListener mOnUnhandledInputEventListener;
 
-    private SurfaceHolder.Callback mSurfaceHolderCallback = new SurfaceHolder.Callback() {
+    private final SurfaceHolder.Callback mSurfaceHolderCallback = new SurfaceHolder.Callback() {
         @Override
         public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
             Log.d(TAG, "surfaceChanged(holder=" + holder + ", format=" + format + ", width=" + width
@@ -70,6 +74,25 @@
         }
     };
 
+    private final FinishedInputEventCallback mFinishedInputEventCallback =
+            new FinishedInputEventCallback() {
+        @Override
+        public void onFinishedInputEvent(Object token, boolean handled) {
+            if (DEBUG) {
+                Log.d(TAG, "onFinishedInputEvent(token=" + token + ", handled=" + handled + ")");
+            }
+            if (handled) {
+                return;
+            }
+            // TODO: Re-order unhandled events.
+            InputEvent event = (InputEvent) token;
+            if (dispatchUnhandledInputEvent(event)) {
+                return;
+            }
+            getViewRootImpl().dispatchUnhandledInputEvent(event);
+        }
+    };
+
     public TvView(Context context) {
         this(context, null, 0);
     }
@@ -124,6 +147,98 @@
         }
     }
 
+    /**
+     * Dispatches an unhandled input event to the next receiver.
+     * <p>
+     * Except system keys, TvView always consumes input events in the normal flow. This is called
+     * asynchronously from where the event is dispatched. It gives the host application a chance to
+     * dispatch the unhandled input events.
+     *
+     * @param event The input event.
+     * @return {@code true} if the event was handled by the view, {@code false} otherwise.
+     */
+    public boolean dispatchUnhandledInputEvent(InputEvent event) {
+        if (mOnUnhandledInputEventListener != null) {
+            if (mOnUnhandledInputEventListener.onUnhandledInputEvent(event)) {
+                return true;
+            }
+        }
+        return onUnhandledInputEvent(event);
+    }
+
+    /**
+     * Called when an unhandled input event was also not handled by the user provided callback. This
+     * is the last chance to handle the unhandled input event in the TvView.
+     *
+     * @param event The input event.
+     * @return If you handled the event, return {@code true}. If you want to allow the event to be
+     *         handled by the next receiver, return {@code false}.
+     */
+    public boolean onUnhandledInputEvent(InputEvent event) {
+        return false;
+    }
+
+    /**
+     * Registers a callback to be invoked when an input event was not handled by the bound TV input.
+     *
+     * @param listener The callback to invoke when the unhandled input event was received.
+     */
+    public void setOnUnhandledInputEventListener(OnUnhandledInputEventListener listener) {
+        mOnUnhandledInputEventListener = listener;
+    }
+
+    @Override
+    public boolean dispatchKeyEvent(KeyEvent event) {
+        if (super.dispatchKeyEvent(event)) {
+            return true;
+        }
+        if (DEBUG) Log.d(TAG, "dispatchKeyEvent(" + event + ")");
+        if (mSession == null) {
+            return false;
+        }
+        int ret = mSession.dispatchInputEvent(event, event, mFinishedInputEventCallback, mHandler);
+        return ret != Session.DISPATCH_NOT_HANDLED;
+    }
+
+    @Override
+    public boolean dispatchTouchEvent(MotionEvent event) {
+        if (super.dispatchTouchEvent(event)) {
+            return true;
+        }
+        if (DEBUG) Log.d(TAG, "dispatchTouchEvent(" + event + ")");
+        if (mSession == null) {
+            return false;
+        }
+        int ret = mSession.dispatchInputEvent(event, event, mFinishedInputEventCallback, mHandler);
+        return ret != Session.DISPATCH_NOT_HANDLED;
+    }
+
+    @Override
+    public boolean dispatchTrackballEvent(MotionEvent event) {
+        if (super.dispatchTrackballEvent(event)) {
+            return true;
+        }
+        if (DEBUG) Log.d(TAG, "dispatchTrackballEvent(" + event + ")");
+        if (mSession == null) {
+            return false;
+        }
+        int ret = mSession.dispatchInputEvent(event, event, mFinishedInputEventCallback, mHandler);
+        return ret != Session.DISPATCH_NOT_HANDLED;
+    }
+
+    @Override
+    public boolean dispatchGenericMotionEvent(MotionEvent event) {
+        if (super.dispatchGenericMotionEvent(event)) {
+            return true;
+        }
+        if (DEBUG) Log.d(TAG, "dispatchGenericMotionEvent(" + event + ")");
+        if (mSession == null) {
+            return false;
+        }
+        int ret = mSession.dispatchInputEvent(event, event, mFinishedInputEventCallback, mHandler);
+        return ret != Session.DISPATCH_NOT_HANDLED;
+    }
+
     @Override
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
@@ -196,6 +311,23 @@
                 location[0] + getWidth(), location[1] + getHeight());
     }
 
+    /**
+     * Interface definition for a callback to be invoked when the unhandled input event is received.
+     */
+    public interface OnUnhandledInputEventListener {
+        /**
+         * Called when an input event was not handled by the bound TV input.
+         * <p>
+         * This is called asynchronously from where the event is dispatched. It gives the host
+         * application a chance to handle the unhandled input events.
+         *
+         * @param event The input event.
+         * @return If you handled the event, return {@code true}. If you want to allow the event to
+         *         be handled by the next receiver, return {@code false}.
+         */
+        boolean onUnhandledInputEvent(InputEvent event);
+    }
+
     private class MySessionCreateCallback implements SessionCreateCallback {
         final SessionCreateCallback mExternalCallback;
 
diff --git a/core/java/android/view/RenderNode.java b/core/java/android/view/RenderNode.java
index 30e4281..3dc09c4 100644
--- a/core/java/android/view/RenderNode.java
+++ b/core/java/android/view/RenderNode.java
@@ -443,6 +443,14 @@
         return nHasOverlappingRendering(mNativeRenderNode);
     }
 
+    public void setElevation(float lift) {
+        nSetElevation(mNativeRenderNode, lift);
+    }
+
+    public float getElevation() {
+        return nGetElevation(mNativeRenderNode);
+    }
+
     /**
      * Sets the translation value for the display list on the X axis.
      *
@@ -854,6 +862,7 @@
     private static native void nSetAlpha(long renderNode, float alpha);
     private static native void nSetHasOverlappingRendering(long renderNode,
             boolean hasOverlappingRendering);
+    private static native void nSetElevation(long renderNode, float lift);
     private static native void nSetTranslationX(long renderNode, float translationX);
     private static native void nSetTranslationY(long renderNode, float translationY);
     private static native void nSetTranslationZ(long renderNode, float translationZ);
@@ -874,6 +883,7 @@
     private static native float nGetCameraDistance(long renderNode);
     private static native float nGetScaleX(long renderNode);
     private static native float nGetScaleY(long renderNode);
+    private static native float nGetElevation(long renderNode);
     private static native float nGetTranslationX(long renderNode);
     private static native float nGetTranslationY(long renderNode);
     private static native float nGetTranslationZ(long renderNode);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 743ab77..76becda 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -3649,6 +3649,7 @@
         float tx = 0;
         float ty = 0;
         float tz = 0;
+        float elevation = 0;
         float rotation = 0;
         float rotationX = 0;
         float rotationY = 0;
@@ -3732,6 +3733,10 @@
                     tz = a.getDimensionPixelOffset(attr, 0);
                     transformSet = true;
                     break;
+                case com.android.internal.R.styleable.View_elevation:
+                    elevation = a.getDimensionPixelOffset(attr, 0);
+                    transformSet = true;
+                    break;
                 case com.android.internal.R.styleable.View_rotation:
                     rotation = a.getFloat(attr, 0);
                     transformSet = true;
@@ -4080,6 +4085,7 @@
             setTranslationX(tx);
             setTranslationY(ty);
             setTranslationZ(tz);
+            setElevation(elevation);
             setRotation(rotation);
             setRotationX(rotationX);
             setRotationY(rotationY);
@@ -10435,6 +10441,48 @@
         setTranslationY(y - mTop);
     }
 
+    /**
+     * The visual z position of this view, in pixels. This is equivalent to the
+     * {@link #setTranslationZ(float) translationZ} property plus the current
+     * {@link #getElevation() elevation} property.
+     *
+     * @return The visual z position of this view, in pixels.
+     */
+    @ViewDebug.ExportedProperty(category = "drawing")
+    public float getZ() {
+        return getElevation() + getTranslationZ();
+    }
+
+    /**
+     * Sets the visual z position of this view, in pixels. This is equivalent to setting the
+     * {@link #setTranslationZ(float) translationZ} property to be the difference between
+     * the x value passed in and the current {@link #getElevation() elevation} property.
+     *
+     * @param z The visual z position of this view, in pixels.
+     */
+    public void setZ(float z) {
+        setTranslationZ(z - getElevation());
+    }
+
+    @ViewDebug.ExportedProperty(category = "drawing")
+    public float getElevation() {
+        return mRenderNode.getElevation();
+    }
+
+    /**
+     * Sets the base depth location of this view.
+     *
+     * @attr ref android.R.styleable#View_elevation
+     */
+    public void setElevation(float elevation) {
+        if (elevation != getElevation()) {
+            invalidateViewProperty(true, false);
+            mRenderNode.setElevation(elevation);
+            invalidateViewProperty(false, true);
+
+            invalidateParentIfNeededAndWasQuickRejected();
+        }
+    }
 
     /**
      * The horizontal location of this view relative to its {@link #getLeft() left} position.
@@ -10502,9 +10550,9 @@
     }
 
     /**
-     * The depth location of this view relative to its parent.
+     * The depth location of this view relative to its {@link #getElevation() elevation}.
      *
-     * @return The depth of this view relative to its parent.
+     * @return The depth of this view relative to its elevation.
      */
     @ViewDebug.ExportedProperty(category = "drawing")
     public float getTranslationZ() {
@@ -10512,7 +10560,7 @@
     }
 
     /**
-     * Sets the depth location of this view relative to its parent.
+     * Sets the depth location of this view relative to its {@link #getElevation() elevation}.
      *
      * @attr ref android.R.styleable#View_translationZ
      */
@@ -11185,7 +11233,7 @@
             }
 
             // Damage the entire IsolatedZVolume recieving this view's shadow.
-            if (isHardwareAccelerated() && getTranslationZ() != 0) {
+            if (isHardwareAccelerated() && getZ() != 0) {
                 damageShadowReceiver();
             }
         }
@@ -11261,7 +11309,7 @@
         } else {
             damageInParent();
         }
-        if (isHardwareAccelerated() && invalidateParent && getTranslationZ() != 0) {
+        if (isHardwareAccelerated() && invalidateParent && getZ() != 0) {
             damageShadowReceiver();
         }
     }
diff --git a/core/java/android/view/ViewPropertyAnimator.java b/core/java/android/view/ViewPropertyAnimator.java
index 6b21451..b1aa7b2 100644
--- a/core/java/android/view/ViewPropertyAnimator.java
+++ b/core/java/android/view/ViewPropertyAnimator.java
@@ -144,10 +144,11 @@
     private static final int ROTATION_Y     = 0x0080;
     private static final int X              = 0x0100;
     private static final int Y              = 0x0200;
-    private static final int ALPHA          = 0x0400;
+    private static final int Z              = 0x0400;
+    private static final int ALPHA          = 0x0800;
 
     private static final int TRANSFORM_MASK = TRANSLATION_X | TRANSLATION_Y | TRANSLATION_Z |
-            SCALE_X | SCALE_Y | ROTATION | ROTATION_X | ROTATION_Y | X | Y;
+            SCALE_X | SCALE_Y | ROTATION | ROTATION_X | ROTATION_Y | X | Y | Z;
 
     /**
      * The mechanism by which the user can request several properties that are then animated
@@ -470,6 +471,32 @@
     }
 
     /**
+     * This method will cause the View's <code>z</code> property to be animated to the
+     * specified value. Animations already running on the property will be canceled.
+     *
+     * @param value The value to be animated to.
+     * @see View#setZ(float)
+     * @return This object, allowing calls to methods in this class to be chained.
+     */
+    public ViewPropertyAnimator z(float value) {
+        animateProperty(Z, value);
+        return this;
+    }
+
+    /**
+     * This method will cause the View's <code>z</code> property to be animated by the
+     * specified value. Animations already running on the property will be canceled.
+     *
+     * @param value The amount to be animated by, as an offset from the current value.
+     * @see View#setZ(float)
+     * @return This object, allowing calls to methods in this class to be chained.
+     */
+    public ViewPropertyAnimator zBy(float value) {
+        animatePropertyBy(Z, value);
+        return this;
+    }
+
+    /**
      * This method will cause the View's <code>rotation</code> property to be animated to the
      * specified value. Animations already running on the property will be canceled.
      *
@@ -957,6 +984,9 @@
             case Y:
                 renderNode.setTranslationY(value - mView.mTop);
                 break;
+            case Z:
+                renderNode.setTranslationZ(value - renderNode.getElevation());
+                break;
             case ALPHA:
                 info.mAlpha = value;
                 renderNode.setAlpha(value);
@@ -993,6 +1023,8 @@
                 return mView.mLeft + node.getTranslationX();
             case Y:
                 return mView.mTop + node.getTranslationY();
+            case Z:
+                return node.getElevation() + node.getTranslationZ();
             case ALPHA:
                 return mView.mTransformationInfo.mAlpha;
         }
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 5a48a9a..14e422c 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -3212,8 +3212,11 @@
                 doDie();
                 break;
             case MSG_DISPATCH_INPUT_EVENT: {
-                InputEvent event = (InputEvent)msg.obj;
-                enqueueInputEvent(event, null, 0, true);
+                SomeArgs args = (SomeArgs)msg.obj;
+                InputEvent event = (InputEvent)args.arg1;
+                InputEventReceiver receiver = (InputEventReceiver)args.arg2;
+                enqueueInputEvent(event, receiver, 0, true);
+                args.recycle();
             } break;
             case MSG_DISPATCH_KEY_FROM_IME: {
                 if (LOCAL_LOGV) Log.v(
@@ -5795,7 +5798,14 @@
     }
 
     public void dispatchInputEvent(InputEvent event) {
-        Message msg = mHandler.obtainMessage(MSG_DISPATCH_INPUT_EVENT, event);
+        dispatchInputEvent(event, null);
+    }
+
+    public void dispatchInputEvent(InputEvent event, InputEventReceiver receiver) {
+        SomeArgs args = SomeArgs.obtain();
+        args.arg1 = event;
+        args.arg2 = receiver;
+        Message msg = mHandler.obtainMessage(MSG_DISPATCH_INPUT_EVENT, args);
         msg.setAsynchronous(true);
         mHandler.sendMessage(msg);
     }
diff --git a/core/java/com/android/internal/app/AlertController.java b/core/java/com/android/internal/app/AlertController.java
index 7640749..4726da7 100644
--- a/core/java/com/android/internal/app/AlertController.java
+++ b/core/java/com/android/internal/app/AlertController.java
@@ -102,7 +102,7 @@
 
     private ScrollView mScrollView;
     
-    private int mIconId = -1;
+    private int mIconId = 0;
     
     private Drawable mIcon;
     
@@ -337,25 +337,39 @@
     }
 
     /**
-     * Set resId to 0 if you don't want an icon.
-     * @param resId the resourceId of the drawable to use as the icon or 0
-     * if you don't want an icon.
+     * Specifies the icon to display next to the alert title.
+     *
+     * @param resId the resource identifier of the drawable to use as the icon,
+     *            or 0 for no icon
      */
     public void setIcon(int resId) {
+        mIcon = null;
         mIconId = resId;
+
         if (mIconView != null) {
-            if (resId > 0) {
+            if (resId != 0) {
                 mIconView.setImageResource(mIconId);
-            } else if (resId == 0) {
+            } else {
                 mIconView.setVisibility(View.GONE);
             }
         }
     }
-    
+
+    /**
+     * Specifies the icon to display next to the alert title.
+     *
+     * @param icon the drawable to use as the icon or null for no icon
+     */
     public void setIcon(Drawable icon) {
         mIcon = icon;
-        if ((mIconView != null) && (mIcon != null)) {
-            mIconView.setImageDrawable(icon);
+        mIconId = 0;
+
+        if (mIconView != null) {
+            if (icon != null) {
+                mIconView.setImageDrawable(icon);
+            } else {
+                mIconView.setVisibility(View.GONE);
+            }
         }
     }
 
@@ -485,28 +499,24 @@
             View titleTemplate = mWindow.findViewById(R.id.title_template);
             titleTemplate.setVisibility(View.GONE);
         } else {
-            final boolean hasTextTitle = !TextUtils.isEmpty(mTitle);
-            
             mIconView = (ImageView) mWindow.findViewById(R.id.icon);
-            if (hasTextTitle) {
-                /* Display the title if a title is supplied, else hide it */
-                mTitleView = (TextView) mWindow.findViewById(R.id.alertTitle);
 
+            final boolean hasTextTitle = !TextUtils.isEmpty(mTitle);
+            if (hasTextTitle) {
+                // Display the title if a title is supplied, else hide it.
+                mTitleView = (TextView) mWindow.findViewById(R.id.alertTitle);
                 mTitleView.setText(mTitle);
-                
-                /* Do this last so that if the user has supplied any
-                 * icons we use them instead of the default ones. If the
-                 * user has specified 0 then make it disappear.
-                 */
-                if (mIconId > 0) {
+
+                // Do this last so that if the user has supplied any icons we
+                // use them instead of the default ones. If the user has
+                // specified 0 then make it disappear.
+                if (mIconId != 0) {
                     mIconView.setImageResource(mIconId);
                 } else if (mIcon != null) {
                     mIconView.setImageDrawable(mIcon);
-                } else if (mIconId == 0) {
-                    
-                    /* Apply the padding from the icon to ensure the
-                     * title is aligned correctly.
-                     */
+                } else {
+                    // Apply the padding from the icon to ensure the title is
+                    // aligned correctly.
                     mTitleView.setPadding(mIconView.getPaddingLeft(),
                             mIconView.getPaddingTop(),
                             mIconView.getPaddingRight(),
@@ -514,9 +524,8 @@
                     mIconView.setVisibility(View.GONE);
                 }
             } else {
-                
                 // Hide the title template
-                View titleTemplate = mWindow.findViewById(R.id.title_template);
+                final View titleTemplate = mWindow.findViewById(R.id.title_template);
                 titleTemplate.setVisibility(View.GONE);
                 mIconView.setVisibility(View.GONE);
                 topPanel.setVisibility(View.GONE);
diff --git a/core/java/com/android/internal/backup/LocalTransport.java b/core/java/com/android/internal/backup/LocalTransport.java
index 1bfad05..446ef55 100644
--- a/core/java/com/android/internal/backup/LocalTransport.java
+++ b/core/java/com/android/internal/backup/LocalTransport.java
@@ -26,6 +26,9 @@
 import android.os.Environment;
 import android.os.ParcelFileDescriptor;
 import android.os.SELinux;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.StructStat;
 import android.util.Log;
 
 import com.android.org.bouncycastle.util.encoders.Base64;
@@ -37,10 +40,7 @@
 import java.util.ArrayList;
 import java.util.Collections;
 
-import libcore.io.ErrnoException;
-import libcore.io.Libcore;
-import libcore.io.StructStat;
-import static libcore.io.OsConstants.*;
+import static android.system.OsConstants.*;
 
 /**
  * Backup transport for stashing stuff into a known location on disk, and
@@ -109,7 +109,7 @@
     public int performBackup(PackageInfo packageInfo, ParcelFileDescriptor data) {
         if (DEBUG) {
             try {
-            StructStat ss = Libcore.os.fstat(data.getFileDescriptor());
+            StructStat ss = Os.fstat(data.getFileDescriptor());
             Log.v(TAG, "performBackup() pkg=" + packageInfo.packageName
                     + " size=" + ss.st_size);
             } catch (ErrnoException e) {
@@ -152,7 +152,7 @@
                     changeSet.readEntityData(buf, 0, dataSize);
                     if (DEBUG) {
                         try {
-                            long cur = Libcore.os.lseek(data.getFileDescriptor(), 0, SEEK_CUR);
+                            long cur = Os.lseek(data.getFileDescriptor(), 0, SEEK_CUR);
                             Log.v(TAG, "  read entity data; new pos=" + cur);
                         }
                         catch (ErrnoException e) {
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index c5fa0a1..54c532a 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -18,8 +18,8 @@
 
 
 import dalvik.system.ZygoteHooks;
-import libcore.io.ErrnoException;
-import libcore.io.Libcore;
+import android.system.ErrnoException;
+import android.system.Os;
 
 /** @hide */
 public final class Zygote {
@@ -141,7 +141,7 @@
     public static void execShell(String command) {
         String[] args = { "/system/bin/sh", "-c", command };
         try {
-            Libcore.os.execv(args[0], args);
+            Os.execv(args[0], args);
         } catch (ErrnoException e) {
             throw new RuntimeException(e);
         }
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index 58a8e62..0c48368 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -21,6 +21,8 @@
 import android.os.Process;
 import android.os.SELinux;
 import android.os.SystemProperties;
+import android.system.ErrnoException;
+import android.system.Os;
 import android.util.Log;
 import dalvik.system.PathClassLoader;
 import java.io.BufferedReader;
@@ -34,9 +36,7 @@
 import java.io.PrintStream;
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
-import libcore.io.ErrnoException;
 import libcore.io.IoUtils;
-import libcore.io.Libcore;
 
 /**
  * A connection that can make spawn requests.
@@ -186,7 +186,7 @@
             }
 
             if (parsedArgs.runtimeInit && parsedArgs.invokeWith != null) {
-                FileDescriptor[] pipeFds = Libcore.os.pipe();
+                FileDescriptor[] pipeFds = Os.pipe();
                 childPipeFd = pipeFds[1];
                 serverPipeFd = pipeFds[0];
                 ZygoteInit.setCloseOnExec(serverPipeFd, true);
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index ef2908d..3ea749e 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -16,8 +16,8 @@
 
 package com.android.internal.os;
 
-import static libcore.io.OsConstants.S_IRWXG;
-import static libcore.io.OsConstants.S_IRWXO;
+import static android.system.OsConstants.S_IRWXG;
+import static android.system.OsConstants.S_IRWXO;
 
 import android.content.res.Resources;
 import android.content.res.TypedArray;
@@ -28,14 +28,15 @@
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.Trace;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.OsConstants;
 import android.util.EventLog;
 import android.util.Log;
 
 import dalvik.system.VMRuntime;
 
 import libcore.io.IoUtils;
-import libcore.io.Libcore;
-import libcore.io.OsConstants;
 
 import java.io.BufferedReader;
 import java.io.FileDescriptor;
@@ -195,12 +196,12 @@
                 FileDescriptor fd = sServerSocket.getFileDescriptor();
                 sServerSocket.close();
                 if (fd != null) {
-                    Libcore.os.close(fd);
+                    Os.close(fd);
                 }
             }
         } catch (IOException ex) {
             Log.e(TAG, "Zygote:  error closing sockets", ex);
-        } catch (libcore.io.ErrnoException ex) {
+        } catch (ErrnoException ex) {
             Log.e(TAG, "Zygote:  error closing descriptor", ex);
         }
 
@@ -481,7 +482,7 @@
         closeServerSocket();
 
         // set umask to 0077 so new files and directories will default to owner-only permissions.
-        Libcore.os.umask(S_IRWXG | S_IRWXO);
+        Os.umask(S_IRWXG | S_IRWXO);
 
         if (parsedArgs.niceName != null) {
             Process.setArgV0(parsedArgs.niceName);
diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp
index 8dacfeb..3ad2ae5 100644
--- a/core/jni/android_view_RenderNode.cpp
+++ b/core/jni/android_view_RenderNode.cpp
@@ -164,6 +164,12 @@
     renderNode->mutateStagingProperties().setHasOverlappingRendering(hasOverlappingRendering);
 }
 
+static void android_view_RenderNode_setElevation(JNIEnv* env,
+        jobject clazz, jlong renderNodePtr, float elevation) {
+    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
+    renderNode->mutateStagingProperties().setElevation(elevation);
+}
+
 static void android_view_RenderNode_setTranslationX(JNIEnv* env,
         jobject clazz, jlong renderNodePtr, float tx) {
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
@@ -331,6 +337,12 @@
     return renderNode->stagingProperties().getScaleY();
 }
 
+static jfloat android_view_RenderNode_getElevation(JNIEnv* env,
+        jobject clazz, jlong renderNodePtr) {
+    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
+    return renderNode->stagingProperties().getElevation();
+}
+
 static jfloat android_view_RenderNode_getTranslationX(JNIEnv* env,
         jobject clazz, jlong renderNodePtr) {
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
@@ -457,6 +469,7 @@
     { "nSetAlpha",             "(JF)V",  (void*) android_view_RenderNode_setAlpha },
     { "nSetHasOverlappingRendering", "(JZ)V",
             (void*) android_view_RenderNode_setHasOverlappingRendering },
+    { "nSetElevation",         "(JF)V",  (void*) android_view_RenderNode_setElevation },
     { "nSetTranslationX",      "(JF)V",  (void*) android_view_RenderNode_setTranslationX },
     { "nSetTranslationY",      "(JF)V",  (void*) android_view_RenderNode_setTranslationY },
     { "nSetTranslationZ",      "(JF)V",  (void*) android_view_RenderNode_setTranslationZ },
@@ -485,6 +498,7 @@
     { "nGetCameraDistance",       "(J)F",  (void*) android_view_RenderNode_getCameraDistance },
     { "nGetScaleX",               "(J)F",  (void*) android_view_RenderNode_getScaleX },
     { "nGetScaleY",               "(J)F",  (void*) android_view_RenderNode_getScaleY },
+    { "nGetElevation",            "(J)F",  (void*) android_view_RenderNode_getElevation },
     { "nGetTranslationX",         "(J)F",  (void*) android_view_RenderNode_getTranslationX },
     { "nGetTranslationY",         "(J)F",  (void*) android_view_RenderNode_getTranslationY },
     { "nGetTranslationZ",         "(J)F",  (void*) android_view_RenderNode_getTranslationZ },
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 69440be..abac60e 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2191,6 +2191,9 @@
              (completely opaque). -->
         <attr name="alpha" format="float" />
 
+        <!-- base z depth of the view -->
+        <attr name="elevation" format="dimension" />
+
         <!-- translation in x of the view. This value is added post-layout to the left
              property of the view, which is set by its layout. -->
         <attr name="translationX" format="dimension" />
@@ -2199,7 +2202,7 @@
              property of the view, which is set by its layout. -->
         <attr name="translationY" format="dimension" />
 
-        <!-- translation in z of the view. This value is added post-layout to its position. -->
+        <!-- translation in z of the view. This value is added to its elevation. -->
         <attr name="translationZ" format="dimension" />
 
         <!-- x location of the pivot point around which the view will rotate and scale.
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index f68f759..85ef004 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2163,6 +2163,7 @@
   <public type="attr" name="windowAllowEnterTransitionOverlap" />
   <public type="attr" name="sessionService" />
   <public type="attr" name="switchStyle" />
+  <public type="attr" name="elevation" />
 
   <public-padding type="dimen" name="l_resource_pad" end="0x01050010" />
 
diff --git a/core/tests/coretests/src/com/android/internal/util/FileRotatorTest.java b/core/tests/coretests/src/com/android/internal/util/FileRotatorTest.java
index 0e3c13a0..3f9e62e 100644
--- a/core/tests/coretests/src/com/android/internal/util/FileRotatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/util/FileRotatorTest.java
@@ -46,7 +46,6 @@
 import junit.framework.Assert;
 
 import libcore.io.IoUtils;
-import libcore.io.Libcore;
 
 /**
  * Tests for {@link FileRotator}.
diff --git a/docs/html/guide/topics/manifest/manifest-element.jd b/docs/html/guide/topics/manifest/manifest-element.jd
index 20dc4ea..7717696 100644
--- a/docs/html/guide/topics/manifest/manifest-element.jd
+++ b/docs/html/guide/topics/manifest/manifest-element.jd
@@ -30,7 +30,7 @@
 <br/><code><a href="{@docRoot}guide/topics/manifest/permission-element.html">&lt;permission&gt;</a></code>
 <br/><code><a href="{@docRoot}guide/topics/manifest/permission-group-element.html">&lt;permission-group&gt;</a></code>
 <br/><code><a href="{@docRoot}guide/topics/manifest/permission-tree-element.html">&lt;permission-tree&gt;</a></code>
-<br/><code><a href="{@docRoot}guide/topics/manifest/supports-gl-texture.html">&lt;supports-gl-texture&gt;</a></code
+<br/><code><a href="{@docRoot}guide/topics/manifest/supports-gl-texture-element.html">&lt;supports-gl-texture&gt;</a></code>
 <br/><code><a href="{@docRoot}guide/topics/manifest/supports-screens-element.html">&lt;supports-screens&gt;</a></code>
 <br/><code><a href="{@docRoot}guide/topics/manifest/uses-configuration-element.html">&lt;uses-configuration&gt;</a></code>  <!-- ##api level 3## -->
 <br/><code><a href="{@docRoot}guide/topics/manifest/uses-feature-element.html">&lt;uses-feature&gt;</a></code>
@@ -193,4 +193,4 @@
 <dd>
 <code><a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code></dd>
 
-</dl>
\ No newline at end of file
+</dl>
diff --git a/drm/java/android/drm/DrmOutputStream.java b/drm/java/android/drm/DrmOutputStream.java
index 22e7ac2..ba1c56f 100644
--- a/drm/java/android/drm/DrmOutputStream.java
+++ b/drm/java/android/drm/DrmOutputStream.java
@@ -18,14 +18,14 @@
 
 import static android.drm.DrmConvertedStatus.STATUS_OK;
 import static android.drm.DrmManagerClient.INVALID_SESSION;
-import static libcore.io.OsConstants.SEEK_SET;
+import static android.system.OsConstants.SEEK_SET;
 
 import android.os.ParcelFileDescriptor;
+import android.system.ErrnoException;
+import android.system.Os;
 import android.util.Log;
 
-import libcore.io.ErrnoException;
 import libcore.io.IoBridge;
-import libcore.io.Libcore;
 import libcore.io.Streams;
 
 import java.io.FileDescriptor;
@@ -69,7 +69,7 @@
         final DrmConvertedStatus status = mClient.closeConvertSession(mSessionId);
         if (status.statusCode == STATUS_OK) {
             try {
-                Libcore.os.lseek(mFd, status.offset, SEEK_SET);
+                Os.lseek(mFd, status.offset, SEEK_SET);
             } catch (ErrnoException e) {
                 e.rethrowAsIOException();
             }
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 2008f02..838e5ac 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -219,11 +219,11 @@
         matrix.multiply(anim);
     }
 
-    bool applyTranslationZ = true3dTransform && !MathUtils::isZero(properties().getTranslationZ());
+    bool applyTranslationZ = true3dTransform && !MathUtils::isZero(properties().getZ());
     if (properties().hasTransformMatrix() || applyTranslationZ) {
         if (properties().isTransformTranslateOnly()) {
             matrix.translate(properties().getTranslationX(), properties().getTranslationY(),
-                    true3dTransform ? properties().getTranslationZ() : 0.0f);
+                    true3dTransform ? properties().getZ() : 0.0f);
         } else {
             if (!true3dTransform) {
                 matrix.multiply(*properties().getTransformMatrix());
@@ -232,7 +232,7 @@
                 true3dMat.loadTranslate(
                         properties().getPivotX() + properties().getTranslationX(),
                         properties().getPivotY() + properties().getTranslationY(),
-                        properties().getTranslationZ());
+                        properties().getZ());
                 true3dMat.rotate(properties().getRotationX(), 1, 0, 0);
                 true3dMat.rotate(properties().getRotationY(), 0, 1, 0);
                 true3dMat.rotate(properties().getRotation(), 0, 0, 1);
@@ -344,7 +344,9 @@
 
 void RenderNode::deferNodeTree(DeferStateStruct& deferStruct) {
     DeferOperationHandler handler(deferStruct, 0);
-    if (properties().getTranslationZ() > 0.0f) issueDrawShadowOperation(Matrix4::identity(), handler);
+    if (MathUtils::isPositive(properties().getZ())) {
+        issueDrawShadowOperation(Matrix4::identity(), handler);
+    }
     issueOperations<DeferOperationHandler>(deferStruct.mRenderer, handler);
 }
 
@@ -380,7 +382,9 @@
 
 void RenderNode::replayNodeTree(ReplayStateStruct& replayStruct) {
     ReplayOperationHandler handler(replayStruct, 0);
-    if (properties().getTranslationZ() > 0.0f) issueDrawShadowOperation(Matrix4::identity(), handler);
+    if (MathUtils::isPositive(properties().getZ())) {
+        issueDrawShadowOperation(Matrix4::identity(), handler);
+    }
     issueOperations<ReplayOperationHandler>(replayStruct.mRenderer, handler);
 }
 
@@ -395,7 +399,7 @@
     for (unsigned int i = 0; i < mDisplayListData->children().size(); i++) {
         DrawDisplayListOp* childOp = mDisplayListData->children()[i];
         RenderNode* child = childOp->mDisplayList;
-        float childZ = child->properties().getTranslationZ();
+        float childZ = child->properties().getZ();
 
         if (!MathUtils::isZero(childZ)) {
             zTranslatedNodes.add(ZDrawDisplayListOpPair(childZ, childOp));
diff --git a/libs/hwui/RenderProperties.cpp b/libs/hwui/RenderProperties.cpp
index a922db8..9ec7297 100644
--- a/libs/hwui/RenderProperties.cpp
+++ b/libs/hwui/RenderProperties.cpp
@@ -37,6 +37,7 @@
         , mProjectionReceiver(false)
         , mAlpha(1)
         , mHasOverlappingRendering(true)
+        , mElevation(0)
         , mTranslationX(0), mTranslationY(0), mTranslationZ(0)
         , mRotation(0), mRotationX(0), mRotationY(0)
         , mScaleX(1), mScaleY(1)
@@ -100,7 +101,7 @@
     if (hasTransformMatrix()) {
         if (isTransformTranslateOnly()) {
             ALOGD("%*sTranslate %.2f, %.2f, %.2f",
-                    level * 2, "", mPrimitiveFields.mTranslationX, mPrimitiveFields.mTranslationY, mPrimitiveFields.mTranslationZ);
+                    level * 2, "", getTranslationX(), getTranslationY(), getZ());
         } else {
             ALOGD("%*sConcatMatrix %p: " SK_MATRIX_STRING,
                     level * 2, "", mComputedFields.mTransformMatrix, SK_MATRIX_ARGS(mComputedFields.mTransformMatrix));
diff --git a/libs/hwui/RenderProperties.h b/libs/hwui/RenderProperties.h
index 4270da2..8fc2dd0 100644
--- a/libs/hwui/RenderProperties.h
+++ b/libs/hwui/RenderProperties.h
@@ -105,6 +105,17 @@
         return mPrimitiveFields.mHasOverlappingRendering;
     }
 
+    void setElevation(float elevation) {
+        if (elevation != mPrimitiveFields.mElevation) {
+            mPrimitiveFields.mElevation = elevation;
+            // mMatrixOrPivotDirty not set, since matrix doesn't respect Z
+        }
+    }
+
+    float getElevation() const {
+        return mPrimitiveFields.mElevation;
+    }
+
     void setTranslationX(float translationX) {
         if (translationX != mPrimitiveFields.mTranslationX) {
             mPrimitiveFields.mTranslationX = translationX;
@@ -130,7 +141,7 @@
     void setTranslationZ(float translationZ) {
         if (translationZ != mPrimitiveFields.mTranslationZ) {
             mPrimitiveFields.mTranslationZ = translationZ;
-            mPrimitiveFields.mMatrixOrPivotDirty = true;
+            // mMatrixOrPivotDirty not set, since matrix doesn't respect Z
         }
     }
 
@@ -138,6 +149,10 @@
         return mPrimitiveFields.mTranslationZ;
     }
 
+    float getZ() const {
+        return getElevation() + getTranslationZ();
+    }
+
     void setRotation(float rotation) {
         if (rotation != mPrimitiveFields.mRotation) {
             mPrimitiveFields.mRotation = rotation;
@@ -302,7 +317,8 @@
     }
 
     void setLeftTopRightBottom(int left, int top, int right, int bottom) {
-        if (left != mPrimitiveFields.mLeft || top != mPrimitiveFields.mTop || right != mPrimitiveFields.mRight || bottom != mPrimitiveFields.mBottom) {
+        if (left != mPrimitiveFields.mLeft || top != mPrimitiveFields.mTop
+                || right != mPrimitiveFields.mRight || bottom != mPrimitiveFields.mBottom) {
             mPrimitiveFields.mLeft = left;
             mPrimitiveFields.mTop = top;
             mPrimitiveFields.mRight = right;
@@ -429,6 +445,7 @@
         bool mProjectionReceiver;
         float mAlpha;
         bool mHasOverlappingRendering;
+        float mElevation;
         float mTranslationX, mTranslationY, mTranslationZ;
         float mRotation, mRotationX, mRotationY;
         float mScaleX, mScaleY;
diff --git a/libs/hwui/utils/MathUtils.h b/libs/hwui/utils/MathUtils.h
index 57ba8fa..7deabe9 100644
--- a/libs/hwui/utils/MathUtils.h
+++ b/libs/hwui/utils/MathUtils.h
@@ -29,6 +29,10 @@
     inline static bool isZero(float value) {
         return (value >= -gNonZeroEpsilon) && (value <= gNonZeroEpsilon);
     }
+
+    inline static bool isPositive(float value) {
+        return value >= gNonZeroEpsilon;
+    }
 }; // class MathUtils
 
 } /* namespace uirenderer */
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 0b688b6..0082b1e 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -74,6 +74,8 @@
 import android.os.Environment.UserEnvironment;
 import android.os.storage.IMountService;
 import android.provider.Settings;
+import android.system.ErrnoException;
+import android.system.Os;
 import android.util.EventLog;
 import android.util.Log;
 import android.util.Slog;
@@ -142,9 +144,6 @@
 import javax.crypto.spec.PBEKeySpec;
 import javax.crypto.spec.SecretKeySpec;
 
-import libcore.io.ErrnoException;
-import libcore.io.Libcore;
-
 public class BackupManagerService extends IBackupManager.Stub {
 
     private static final String TAG = "BackupManagerService";
@@ -2471,7 +2470,7 @@
                 // operations any more during this pass).
                 Slog.w(TAG, "Unable to save widget state for " + pkgName);
                 try {
-                    Libcore.os.ftruncate(fd, filepos);
+                    Os.ftruncate(fd, filepos);
                 } catch (ErrnoException ee) {
                     Slog.w(TAG, "Unable to roll back!");
                 }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index b6a41bf..0c91907 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -1859,24 +1859,28 @@
         @Override
         public boolean onPackageChanged(String packageName, int uid, String[] components) {
             final PackageManager pm = mContext.getPackageManager();
-            final ArrayList<TaskRecord> recentTasks = new ArrayList<TaskRecord>();
-            final ArrayList<TaskRecord> tasksToRemove = new ArrayList<TaskRecord>();
+            final ArrayList<Pair<Intent, Integer>> recentTaskIntents =
+                    new ArrayList<Pair<Intent, Integer>>();
+            final ArrayList<Integer> tasksToRemove = new ArrayList<Integer>();
             // Copy the list of recent tasks so that we don't hold onto the lock on
             // ActivityManagerService for long periods while checking if components exist.
             synchronized (ActivityManagerService.this) {
-                recentTasks.addAll(mRecentTasks);
+                for (int i = mRecentTasks.size() - 1; i >= 0; i--) {
+                    TaskRecord tr = mRecentTasks.get(i);
+                    recentTaskIntents.add(new Pair<Intent, Integer>(tr.intent, tr.taskId));
+                }
             }
             // Check the recent tasks and filter out all tasks with components that no longer exist.
             Intent tmpI = new Intent();
-            for (int i = recentTasks.size() - 1; i >= 0; i--) {
-                TaskRecord tr = recentTasks.get(i);
-                ComponentName cn = tr.intent.getComponent();
+            for (int i = recentTaskIntents.size() - 1; i >= 0; i--) {
+                Pair<Intent, Integer> p = recentTaskIntents.get(i);
+                ComponentName cn = p.first.getComponent();
                 if (cn != null && cn.getPackageName().equals(packageName)) {
                     try {
                         // Add the task to the list to remove if the component no longer exists
                         tmpI.setComponent(cn);
                         if (pm.queryIntentActivities(tmpI, PackageManager.MATCH_DEFAULT_ONLY).isEmpty()) {
-                            tasksToRemove.add(tr);
+                            tasksToRemove.add(p.second);
                         }
                     } catch (Exception e) {}
                 }
@@ -1884,9 +1888,9 @@
             // Prune all the tasks with removed components from the list of recent tasks
             synchronized (ActivityManagerService.this) {
                 for (int i = tasksToRemove.size() - 1; i >= 0; i--) {
-                    TaskRecord tr = tasksToRemove.get(i);
-                    // Remove the task but don't kill the process
-                    removeTaskByIdLocked(tr.taskId, 0);
+                    // Remove the task but don't kill the process (since other components in that
+                    // package may still be running and in the background)
+                    removeTaskByIdLocked(tasksToRemove.get(i), 0);
                 }
             }
             return true;
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index bea926f..6769c9c 100755
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -2329,7 +2329,10 @@
                     mStackSupervisor.moveHomeToTop();
                 }
             }
-            mService.setFocusedActivityLocked(mStackSupervisor.topRunningActivityLocked());
+            ActivityRecord top = mStackSupervisor.topRunningActivityLocked();
+            if (top != null) {
+                mService.setFocusedActivityLocked(top);
+            }
         }
     }
 
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index 5ceb992..649f9dc 100644
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -49,9 +49,9 @@
 import android.tv.ITvInputSessionCallback;
 import android.tv.TvInputInfo;
 import android.tv.TvInputService;
-import android.util.Log;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.view.InputChannel;
 import android.view.Surface;
 
 import com.android.internal.content.PackageMonitor;
@@ -292,6 +292,9 @@
             Slog.d(TAG, "createSessionInternalLocked(name=" + sessionState.name.getClassName()
                     + ")");
         }
+
+        final InputChannel[] channels = InputChannel.openInputChannelPair(sessionToken.toString());
+
         // Set up a callback to send the session token.
         ITvInputSessionCallback callback = new ITvInputSessionCallback.Stub() {
             @Override
@@ -304,30 +307,32 @@
                     if (session == null) {
                         removeSessionStateLocked(sessionToken, userId);
                         sendSessionTokenToClientLocked(sessionState.client, sessionState.name, null,
-                                sessionState.seq, userId);
+                                null, sessionState.seq, userId);
                     } else {
                         sendSessionTokenToClientLocked(sessionState.client, sessionState.name,
-                                sessionToken, sessionState.seq, userId);
+                                sessionToken, channels[0], sessionState.seq, userId);
                     }
+                    channels[0].dispose();
                 }
             }
         };
 
         // Create a session. When failed, send a null token immediately.
         try {
-            service.createSession(callback);
+            service.createSession(channels[1], callback);
         } catch (RemoteException e) {
             Slog.e(TAG, "error in createSession", e);
             removeSessionStateLocked(sessionToken, userId);
-            sendSessionTokenToClientLocked(sessionState.client, sessionState.name, null,
+            sendSessionTokenToClientLocked(sessionState.client, sessionState.name, null, null,
                     sessionState.seq, userId);
         }
+        channels[1].dispose();
     }
 
     private void sendSessionTokenToClientLocked(ITvInputClient client, ComponentName name,
-            IBinder sessionToken, int seq, int userId) {
+            IBinder sessionToken, InputChannel channel, int seq, int userId) {
         try {
-            client.onSessionCreated(name, sessionToken, seq);
+            client.onSessionCreated(name, sessionToken, channel, seq);
         } catch (RemoteException exception) {
             Slog.e(TAG, "error in onSessionCreated", exception);
         }
@@ -834,7 +839,7 @@
                     return;
                 }
                 default: {
-                    Log.w(TAG, "Unhandled message code: " + msg.what);
+                    Slog.w(TAG, "Unhandled message code: " + msg.what);
                     return;
                 }
             }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java
index 629dea2..3c46e40 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java
@@ -208,7 +208,7 @@
                     int userId = Integer.parseInt(parser.getAttributeValue(null, ATTR_USERID));
                     mProfileOwners.put(userId,
                             new OwnerInfo(
-                                    profileOwnerPackageName, profileOwnerName, profileEnabled));
+                                    profileOwnerName, profileOwnerPackageName, profileEnabled));
                 } else {
                     throw new XmlPullParserException(
                             "Unexpected tag in device owner file: " + tag);
@@ -304,4 +304,4 @@
             this.packageName = packageName;
         }
     }
-}
\ No newline at end of file
+}
diff --git a/tests/HwAccelerationTest/res/layout/projection_clipping.xml b/tests/HwAccelerationTest/res/layout/projection_clipping.xml
index 7caf90a..7177fc8f 100644
--- a/tests/HwAccelerationTest/res/layout/projection_clipping.xml
+++ b/tests/HwAccelerationTest/res/layout/projection_clipping.xml
@@ -6,7 +6,7 @@
     <FrameLayout
         android:translationX="50dp"
         android:translationY="50dp"
-        android:translationZ="30dp"
+        android:elevation="30dp"
         android:layout_width="200dp"
         android:layout_height="200dp"
         android:background="@drawable/round_rect_background">