Merge "More stuff I need for the proc stats UI." into klp-dev
diff --git a/api/current.txt b/api/current.txt
index b9d51fdf..e4f31b0 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -27828,6 +27828,7 @@
     method public final boolean hasChildren();
     method public boolean hasFeature(int);
     method protected final boolean hasSoftInputMode();
+    method public void injectInputEvent(android.view.InputEvent);
     method public abstract void invalidatePanelMenu(int);
     method public final boolean isActive();
     method public abstract boolean isFloating();
@@ -27865,6 +27866,7 @@
     method public void setGravity(int);
     method public void setIcon(int);
     method public void setLayout(int, int);
+    method public void setLocalFocus(boolean, boolean);
     method public void setLogo(int);
     method public void setSoftInputMode(int);
     method public abstract void setTitle(java.lang.CharSequence);
@@ -28003,6 +28005,7 @@
     field public static final int FLAG_LAYOUT_IN_OVERSCAN = 33554432; // 0x2000000
     field public static final int FLAG_LAYOUT_IN_SCREEN = 256; // 0x100
     field public static final int FLAG_LAYOUT_NO_LIMITS = 512; // 0x200
+    field public static final int FLAG_LOCAL_FOCUS_MODE = 268435456; // 0x10000000
     field public static final int FLAG_NOT_FOCUSABLE = 8; // 0x8
     field public static final int FLAG_NOT_TOUCHABLE = 16; // 0x10
     field public static final int FLAG_NOT_TOUCH_MODAL = 32; // 0x20
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 3dff1b0..7a82892 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -14013,10 +14013,6 @@
         }
 
         if (more && hardwareAccelerated) {
-            // invalidation is the trigger to recreate display lists, so if we're using
-            // display lists to render, force an invalidate to allow the animation to
-            // continue drawing another frame
-            parent.invalidate(true);
             if (a.hasAlpha() && (mPrivateFlags & PFLAG_ALPHA_SET) == PFLAG_ALPHA_SET) {
                 // alpha animations should cause the child to recreate its display list
                 invalidate(true);
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 1f7ff9b..3977a33 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -608,6 +608,11 @@
         }
     }
 
+    /** Whether the window is in local focus mode or not */
+    private boolean isInLocalFocusMode() {
+        return (mWindowAttributes.flags & WindowManager.LayoutParams.FLAG_LOCAL_FOCUS_MODE) != 0;
+    }
+
     void destroyHardwareResources() {
         if (mAttachInfo.mHardwareRenderer != null) {
             if (mAttachInfo.mHardwareRenderer.isEnabled()) {
@@ -1818,7 +1823,7 @@
         mNewSurfaceNeeded = false;
         mViewVisibility = viewVisibility;
 
-        if (mAttachInfo.mHasWindowFocus) {
+        if (mAttachInfo.mHasWindowFocus && !isInLocalFocusMode()) {
             final boolean imTarget = WindowManager.LayoutParams
                     .mayUseInputMethod(mWindowAttributes.flags);
             if (imTarget != mLastWasImTarget) {
@@ -2906,7 +2911,7 @@
     private final static int MSG_RESIZED = 4;
     private final static int MSG_RESIZED_REPORT = 5;
     private final static int MSG_WINDOW_FOCUS_CHANGED = 6;
-    private final static int MSG_DISPATCH_KEY = 7;
+    private final static int MSG_DISPATCH_INPUT_EVENT = 7;
     private final static int MSG_DISPATCH_APP_VISIBILITY = 8;
     private final static int MSG_DISPATCH_GET_NEW_SURFACE = 9;
     private final static int MSG_DISPATCH_KEY_FROM_IME = 11;
@@ -2941,8 +2946,8 @@
                     return "MSG_RESIZED_REPORT";
                 case MSG_WINDOW_FOCUS_CHANGED:
                     return "MSG_WINDOW_FOCUS_CHANGED";
-                case MSG_DISPATCH_KEY:
-                    return "MSG_DISPATCH_KEY";
+                case MSG_DISPATCH_INPUT_EVENT:
+                    return "MSG_DISPATCH_INPUT_EVENT";
                 case MSG_DISPATCH_APP_VISIBILITY:
                     return "MSG_DISPATCH_APP_VISIBILITY";
                 case MSG_DISPATCH_GET_NEW_SURFACE:
@@ -3092,7 +3097,8 @@
 
                     InputMethodManager imm = InputMethodManager.peekInstance();
                     if (mView != null) {
-                        if (hasWindowFocus && imm != null && mLastWasImTarget) {
+                        if (hasWindowFocus && imm != null && mLastWasImTarget &&
+                                !isInLocalFocusMode()) {
                             imm.startGettingWindowFocus(mView);
                         }
                         mAttachInfo.mKeyDispatchState.reset();
@@ -3103,7 +3109,7 @@
                     // Note: must be done after the focus change callbacks,
                     // so all of the view state is set up correctly.
                     if (hasWindowFocus) {
-                        if (imm != null && mLastWasImTarget) {
+                        if (imm != null && mLastWasImTarget && !isInLocalFocusMode()) {
                             imm.onWindowFocus(mView, mView.findFocus(),
                                     mWindowAttributes.softInputMode,
                                     !mHasHadWindowFocus, mWindowAttributes.flags);
@@ -3131,8 +3137,8 @@
             case MSG_DIE:
                 doDie();
                 break;
-            case MSG_DISPATCH_KEY: {
-                KeyEvent event = (KeyEvent)msg.obj;
+            case MSG_DISPATCH_INPUT_EVENT: {
+                InputEvent event = (InputEvent)msg.obj;
                 enqueueInputEvent(event, null, 0, true);
             } break;
             case MSG_DISPATCH_KEY_FROM_IME: {
@@ -3222,7 +3228,9 @@
 
         // tell the window manager
         try {
-            mWindowSession.setInTouchMode(inTouchMode);
+            if (!isInLocalFocusMode()) {
+                mWindowSession.setInTouchMode(inTouchMode);
+            }
         } catch (RemoteException e) {
             throw new RuntimeException(e);
         }
@@ -3624,7 +3632,7 @@
 
         @Override
         protected int onProcess(QueuedInputEvent q) {
-            if (mLastWasImTarget) {
+            if (mLastWasImTarget && !isInLocalFocusMode()) {
                 InputMethodManager imm = InputMethodManager.peekInstance();
                 if (imm != null) {
                     final InputEvent event = q.mEvent;
@@ -5666,8 +5674,8 @@
         mInvalidateOnAnimationRunnable.removeView(view);
     }
 
-    public void dispatchKey(KeyEvent event) {
-        Message msg = mHandler.obtainMessage(MSG_DISPATCH_KEY, event);
+    public void dispatchInputEvent(InputEvent event) {
+        Message msg = mHandler.obtainMessage(MSG_DISPATCH_INPUT_EVENT, event);
         msg.setAsynchronous(true);
         mHandler.sendMessage(msg);
     }
@@ -5697,7 +5705,7 @@
                         flags, event.getSource(), null);
                 fallbackAction.recycle();
 
-                dispatchKey(fallbackEvent);
+                dispatchInputEvent(fallbackEvent);
             }
         }
     }
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 39d48a7..7a24243 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -1290,4 +1290,18 @@
      * @hide
      */
     public void setDefaultLogo(int resId) { }
+
+    /**
+     * Set focus locally. The window should have the
+     * {@link WindowManager.LayoutParams#FLAG_LOCAL_FOCUS_MODE} flag set already.
+     * @param hasFocus Whether this window has focus or not.
+     * @param inTouchMode Whether this window is in touch mode or not.
+     */
+    public void setLocalFocus(boolean hasFocus, boolean inTouchMode) { }
+
+    /**
+     * Inject an event to window locally.
+     * @param event A key or touch event to inject to this window.
+     */
+    public void injectInputEvent(InputEvent event) { }
 }
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 83a58be..c9c74e7 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -866,6 +866,15 @@
          */
         public static final int FLAG_NEEDS_MENU_KEY = 0x08000000;
 
+        /**
+         * Flag for a window in local focus mode.
+         * Window in local focus mode can control focus independent of window manager using
+         * {@link Window#setLocalFocus(boolean, boolean)}.
+         * Usually window in this mode will not get touch/key events from window manager, but will
+         * get events only via local injection using {@link Window#injectInputEvent(InputEvent)}.
+         */
+        public static final int FLAG_LOCAL_FOCUS_MODE = 0x10000000;
+
         /** Window flag: special flag to limit the size of the window to be
          * original size ([320x480] x density). Used to create window for applications
          * running under compatibility mode.
@@ -905,6 +914,7 @@
          * @see #FLAG_DISMISS_KEYGUARD
          * @see #FLAG_SPLIT_TOUCH
          * @see #FLAG_HARDWARE_ACCELERATED
+         * @see #FLAG_LOCAL_FOCUS_MODE
          */
         @ViewDebug.ExportedProperty(flagMapping = {
             @ViewDebug.FlagToString(mask = FLAG_ALLOW_LOCK_WHILE_SCREEN_ON, equals = FLAG_ALLOW_LOCK_WHILE_SCREEN_ON,
@@ -956,7 +966,9 @@
             @ViewDebug.FlagToString(mask = FLAG_SPLIT_TOUCH, equals = FLAG_SPLIT_TOUCH,
                     name = "FLAG_SPLIT_TOUCH"),
             @ViewDebug.FlagToString(mask = FLAG_HARDWARE_ACCELERATED, equals = FLAG_HARDWARE_ACCELERATED,
-                    name = "FLAG_HARDWARE_ACCELERATED")
+                    name = "FLAG_HARDWARE_ACCELERATED"),
+            @ViewDebug.FlagToString(mask = FLAG_LOCAL_FOCUS_MODE, equals = FLAG_LOCAL_FOCUS_MODE,
+                    name = "FLAG_LOCAL_FOCUS_MODE")
         })
         public int flags;
 
diff --git a/core/java/android/widget/ZoomButtonsController.java b/core/java/android/widget/ZoomButtonsController.java
index a89c9c1..50c803b 100644
--- a/core/java/android/widget/ZoomButtonsController.java
+++ b/core/java/android/widget/ZoomButtonsController.java
@@ -503,7 +503,7 @@
 
             ViewRootImpl viewRoot = mOwnerView.getViewRootImpl();
             if (viewRoot != null) {
-                viewRoot.dispatchKey(event);
+                viewRoot.dispatchInputEvent(event);
             }
 
             // We gave the key to the owner, don't let the container handle this key
diff --git a/core/java/com/android/internal/widget/PasswordEntryKeyboardHelper.java b/core/java/com/android/internal/widget/PasswordEntryKeyboardHelper.java
index f8332c4..a3df291 100644
--- a/core/java/com/android/internal/widget/PasswordEntryKeyboardHelper.java
+++ b/core/java/com/android/internal/widget/PasswordEntryKeyboardHelper.java
@@ -184,7 +184,7 @@
                 KeyEvent event = events[i];
                 event = KeyEvent.changeFlags(event, event.getFlags()
                         | KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE);
-                viewRootImpl.dispatchKey(event);
+                viewRootImpl.dispatchInputEvent(event);
             }
         }
     }
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index 26f910e..a3bd785 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -67,6 +67,7 @@
 import android.view.Gravity;
 import android.view.IRotationWatcher;
 import android.view.IWindowManager;
+import android.view.InputEvent;
 import android.view.InputQueue;
 import android.view.KeyCharacterMap;
 import android.view.KeyEvent;
@@ -79,6 +80,7 @@
 import android.view.ViewGroup;
 import android.view.ViewManager;
 import android.view.ViewParent;
+import android.view.ViewRootImpl;
 import android.view.ViewStub;
 import android.view.Window;
 import android.view.WindowManager;
@@ -1459,6 +1461,27 @@
         }
     }
 
+    @Override
+    public void setLocalFocus(boolean hasFocus, boolean inTouchMode) {
+        getViewRootImpl().windowFocusChanged(hasFocus, inTouchMode);
+
+    }
+
+    @Override
+    public void injectInputEvent(InputEvent event) {
+        getViewRootImpl().dispatchInputEvent(event);
+    }
+
+    private ViewRootImpl getViewRootImpl() {
+        if (mDecor != null) {
+            ViewRootImpl viewRootImpl = mDecor.getViewRootImpl();
+            if (viewRootImpl != null) {
+                return viewRootImpl;
+            }
+        }
+        throw new IllegalStateException("view not added");
+    }
+
     /**
      * Request that key events come to this activity. Use this if your activity
      * has no views with focus, but the activity still wants a chance to process
diff --git a/services/java/com/android/server/wm/WindowStateAnimator.java b/services/java/com/android/server/wm/WindowStateAnimator.java
index 6fa9cd0..73325cb 100644
--- a/services/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/java/com/android/server/wm/WindowStateAnimator.java
@@ -1272,6 +1272,11 @@
                             if (mIsWallpaper) {
                                 mService.dispatchWallpaperVisibility(w, true);
                             }
+                            // This draw means the difference between unique content and mirroring.
+                            // Run another pass through performLayout to set mHasContent in the
+                            // LogicalDisplay.
+                            mAnimator.setPendingLayoutChanges(w.getDisplayId(),
+                                    WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM);
                         } else {
                             w.mOrientationChanging = false;
                         }