Add new API to take over a window's Surface.

Change-Id: Iad6245faadc95f19ea63c8e229a1c02e9188f69e
diff --git a/api/current.xml b/api/current.xml
index e17e31d..b141ad1 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -186070,6 +186070,19 @@
 <parameter name="get" type="boolean">
 </parameter>
 </method>
+<method name="takeSurface"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="callback" type="android.view.SurfaceHolder.Callback">
+</parameter>
+</method>
 <method name="togglePanel"
  return="void"
  abstract="true"
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index 3d1d7d6..2ade44e 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -522,20 +522,14 @@
                     }
                     
                     try {
-                        SurfaceHolder.Callback callbacks[] = null;
-                        synchronized (mSurfaceHolder.mCallbacks) {
-                            final int N = mSurfaceHolder.mCallbacks.size();
-                            if (N > 0) {
-                                callbacks = new SurfaceHolder.Callback[N];
-                                mSurfaceHolder.mCallbacks.toArray(callbacks);
-                            }
-                        }
+                        mSurfaceHolder.ungetCallbacks();
 
                         if (surfaceCreating) {
                             mIsCreating = true;
                             if (DEBUG) Log.v(TAG, "onSurfaceCreated("
                                     + mSurfaceHolder + "): " + this);
                             onSurfaceCreated(mSurfaceHolder);
+                            SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
                             if (callbacks != null) {
                                 for (SurfaceHolder.Callback c : callbacks) {
                                     c.surfaceCreated(mSurfaceHolder);
@@ -557,6 +551,7 @@
                                     + "): " + this);
                             onSurfaceChanged(mSurfaceHolder, mFormat,
                                     mCurWidth, mCurHeight);
+                            SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
                             if (callbacks != null) {
                                 for (SurfaceHolder.Callback c : callbacks) {
                                     c.surfaceChanged(mSurfaceHolder, mFormat,
@@ -698,14 +693,12 @@
         void reportSurfaceDestroyed() {
             if (mSurfaceCreated) {
                 mSurfaceCreated = false;
-                SurfaceHolder.Callback callbacks[];
-                synchronized (mSurfaceHolder.mCallbacks) {
-                    callbacks = new SurfaceHolder.Callback[
-                            mSurfaceHolder.mCallbacks.size()];
-                    mSurfaceHolder.mCallbacks.toArray(callbacks);
-                }
-                for (SurfaceHolder.Callback c : callbacks) {
-                    c.surfaceDestroyed(mSurfaceHolder);
+                mSurfaceHolder.ungetCallbacks();
+                SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
+                if (callbacks != null) {
+                    for (SurfaceHolder.Callback c : callbacks) {
+                        c.surfaceDestroyed(mSurfaceHolder);
+                    }
                 }
                 if (DEBUG) Log.v(TAG, "onSurfaceDestroyed("
                         + mSurfaceHolder + "): " + this);
diff --git a/core/java/android/view/SurfaceHolder.java b/core/java/android/view/SurfaceHolder.java
index 64a10d1..34e4638 100644
--- a/core/java/android/view/SurfaceHolder.java
+++ b/core/java/android/view/SurfaceHolder.java
@@ -182,7 +182,6 @@
     /**
      * Enable or disable option to keep the screen turned on while this
      * surface is displayed.  The default is false, allowing it to turn off.
-     * Enabling the option effectivelty.
      * This is safe to call from any thread.
      * 
      * @param screenOn Supply to true to force the screen to stay on, false
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index a9dd844..aa124e6 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -16,8 +16,10 @@
 
 package android.view;
 
+import com.android.internal.view.BaseSurfaceHolder;
 import com.android.internal.view.IInputMethodCallback;
 import com.android.internal.view.IInputMethodSession;
+import com.android.internal.view.RootViewSurfaceTaker;
 
 import android.graphics.Canvas;
 import android.graphics.PixelFormat;
@@ -135,6 +137,11 @@
     int mViewVisibility;
     boolean mAppVisible = true;
 
+    SurfaceHolder.Callback mSurfaceHolderCallback;
+    BaseSurfaceHolder mSurfaceHolder;
+    boolean mIsCreating;
+    boolean mDrawingAllowed;
+    
     final Region mTransparentRegion;
     final Region mPreviousTransparentRegion;
 
@@ -440,6 +447,13 @@
                 mView = view;
                 mWindowAttributes.copyFrom(attrs);
                 attrs = mWindowAttributes;
+                if (view instanceof RootViewSurfaceTaker) {
+                    mSurfaceHolderCallback =
+                            ((RootViewSurfaceTaker)view).willYouTakeTheSurface();
+                    if (mSurfaceHolderCallback != null) {
+                        mSurfaceHolder = new TakenSurfaceHolder();
+                    }
+                }
                 Resources resources = mView.getContext().getResources();
                 CompatibilityInfo compatibilityInfo = resources.getCompatibilityInfo();
                 mTranslator = compatibilityInfo.getTranslator();
@@ -695,6 +709,7 @@
         boolean windowResizesToFitContent = false;
         boolean fullRedrawNeeded = mFullRedrawNeeded;
         boolean newSurface = false;
+        boolean surfaceChanged = false;
         WindowManager.LayoutParams lp = mWindowAttributes;
 
         int desiredWindowWidth;
@@ -713,6 +728,7 @@
         WindowManager.LayoutParams params = null;
         if (mWindowAttributesChanged) {
             mWindowAttributesChanged = false;
+            surfaceChanged = true;
             params = lp;
         }
         Rect frame = mWinFrame;
@@ -899,11 +915,18 @@
                 }
             }
 
+            if (mSurfaceHolder != null) {
+                mSurfaceHolder.mSurfaceLock.lock();
+                mDrawingAllowed = true;
+                lp.format = mSurfaceHolder.getRequestedFormat();
+                lp.type = mSurfaceHolder.getRequestedType();
+            }
+            
             boolean initialized = false;
             boolean contentInsetsChanged = false;
             boolean visibleInsetsChanged;
+            boolean hadSurface = mSurface.isValid();
             try {
-                boolean hadSurface = mSurface.isValid();
                 int fl = 0;
                 if (params != null) {
                     fl = params.flags;
@@ -978,6 +1001,7 @@
                 }
             } catch (RemoteException e) {
             }
+            
             if (DEBUG_ORIENTATION) Log.v(
                     "ViewRoot", "Relayout returned: frame=" + frame + ", surface=" + mSurface);
 
@@ -990,6 +1014,57 @@
             mWidth = frame.width();
             mHeight = frame.height();
 
+            if (mSurfaceHolder != null) {
+                // The app owns the surface; tell it about what is going on.
+                if (mSurface.isValid()) {
+                    // XXX .copyFrom() doesn't work!
+                    //mSurfaceHolder.mSurface.copyFrom(mSurface);
+                    mSurfaceHolder.mSurface = mSurface;
+                }
+                mSurfaceHolder.mSurfaceLock.unlock();
+                if (mSurface.isValid()) {
+                    if (!hadSurface) {
+                        mSurfaceHolder.ungetCallbacks();
+
+                        mIsCreating = true;
+                        mSurfaceHolderCallback.surfaceCreated(mSurfaceHolder);
+                        SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
+                        if (callbacks != null) {
+                            for (SurfaceHolder.Callback c : callbacks) {
+                                c.surfaceCreated(mSurfaceHolder);
+                            }
+                        }
+                        surfaceChanged = true;
+                    }
+                    if (surfaceChanged) {
+                        mSurfaceHolderCallback.surfaceChanged(mSurfaceHolder,
+                                lp.format, mWidth, mHeight);
+                        SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
+                        if (callbacks != null) {
+                            for (SurfaceHolder.Callback c : callbacks) {
+                                c.surfaceChanged(mSurfaceHolder, lp.format,
+                                        mWidth, mHeight);
+                            }
+                        }
+                    }
+                    mIsCreating = false;
+                } else if (hadSurface) {
+                    mSurfaceHolder.ungetCallbacks();
+                    SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
+                    mSurfaceHolderCallback.surfaceDestroyed(mSurfaceHolder);
+                    if (callbacks != null) {
+                        for (SurfaceHolder.Callback c : callbacks) {
+                            c.surfaceDestroyed(mSurfaceHolder);
+                        }
+                    }
+                    mSurfaceHolder.mSurfaceLock.lock();
+                    // Make surface invalid.
+                    //mSurfaceHolder.mSurface.copyFrom(mSurface);
+                    mSurfaceHolder.mSurface = new Surface();
+                    mSurfaceHolder.mSurfaceLock.unlock();
+                }
+            }
+            
             if (initialized) {
                 mGlCanvas.setViewport((int) (mWidth * appScale + 0.5f),
                         (int) (mHeight * appScale + 0.5f));
@@ -1281,6 +1356,12 @@
         boolean scalingRequired = mAttachInfo.mScalingRequired;
 
         Rect dirty = mDirty;
+        if (mSurfaceHolder != null) {
+            // The app owns the surface, we won't draw.
+            dirty.setEmpty();
+            return;
+        }
+        
         if (mUseGL) {
             if (!dirty.isEmpty()) {
                 Canvas canvas = mGlCanvas;
@@ -2828,6 +2909,46 @@
         return scrollToRectOrFocus(rectangle, immediate);
     }
 
+    class TakenSurfaceHolder extends BaseSurfaceHolder {
+        @Override
+        public boolean onAllowLockCanvas() {
+            return mDrawingAllowed;
+        }
+
+        @Override
+        public void onRelayoutContainer() {
+            // Not currently interesting -- from changing between fixed and layout size.
+        }
+
+        public void setFormat(int format) {
+            ((RootViewSurfaceTaker)mView).setSurfaceFormat(format);
+        }
+
+        public void setType(int type) {
+            ((RootViewSurfaceTaker)mView).setSurfaceType(type);
+        }
+        
+        @Override
+        public void onUpdateSurface() {
+            // We take care of format and type changes on our own.
+            throw new IllegalStateException("Shouldn't be here");
+        }
+
+        public boolean isCreating() {
+            return mIsCreating;
+        }
+
+        @Override
+        public void setFixedSize(int width, int height) {
+            throw new UnsupportedOperationException(
+                    "Currently only support sizing from layout");
+        }
+        
+        public void setKeepScreenOn(boolean screenOn) {
+            ((RootViewSurfaceTaker)mView).setSurfaceKeepScreenOn(screenOn);
+        }
+    }
+    
     static class InputMethodCallback extends IInputMethodCallback.Stub {
         private WeakReference<ViewRoot> mViewRoot;
 
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 7dd5085..234deba 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -473,6 +473,14 @@
     }
 
     /**
+     * Take ownership of this window's surface.  The window's view hierarchy
+     * will no longer draw into the surface, though it will otherwise continue
+     * to operate (such as for receiving input events).  The given SurfaceHolder
+     * callback will be used to tell you about state changes to the surface.
+     */
+    public abstract void takeSurface(SurfaceHolder.Callback callback);
+    
+    /**
      * Return whether this window is being displayed with a floating style
      * (based on the {@link android.R.attr#windowIsFloating} attribute in
      * the style/theme).
diff --git a/core/java/com/android/internal/view/BaseSurfaceHolder.java b/core/java/com/android/internal/view/BaseSurfaceHolder.java
index e0d3a5f..3a04993 100644
--- a/core/java/com/android/internal/view/BaseSurfaceHolder.java
+++ b/core/java/com/android/internal/view/BaseSurfaceHolder.java
@@ -33,9 +33,11 @@
 
     public final ArrayList<SurfaceHolder.Callback> mCallbacks
             = new ArrayList<SurfaceHolder.Callback>();
-
+    SurfaceHolder.Callback[] mGottenCallbacks;
+    boolean mHaveGottenCallbacks;
+    
     public final ReentrantLock mSurfaceLock = new ReentrantLock();
-    public final Surface mSurface = new Surface();
+    public Surface mSurface = new Surface();
 
     int mRequestedWidth = -1;
     int mRequestedHeight = -1;
@@ -83,6 +85,31 @@
         }
     }
     
+    public SurfaceHolder.Callback[] getCallbacks() {
+        if (mHaveGottenCallbacks) {
+            return mGottenCallbacks;
+        }
+        
+        synchronized (mCallbacks) {
+            final int N = mCallbacks.size();
+            if (N > 0) {
+                if (mGottenCallbacks == null || mGottenCallbacks.length != N) {
+                    mGottenCallbacks = new SurfaceHolder.Callback[N];
+                }
+                mCallbacks.toArray(mGottenCallbacks);
+            } else {
+                mGottenCallbacks = null;
+            }
+            mHaveGottenCallbacks = true;
+        }
+        
+        return mGottenCallbacks;
+    }
+    
+    public void ungetCallbacks() {
+        mHaveGottenCallbacks = false;
+    }
+    
     public void setFixedSize(int width, int height) {
         if (mRequestedWidth != width || mRequestedHeight != height) {
             mRequestedWidth = width;
diff --git a/core/java/com/android/internal/view/RootViewSurfaceTaker.java b/core/java/com/android/internal/view/RootViewSurfaceTaker.java
new file mode 100644
index 0000000..fcb1645
--- /dev/null
+++ b/core/java/com/android/internal/view/RootViewSurfaceTaker.java
@@ -0,0 +1,11 @@
+package com.android.internal.view;
+
+import android.view.SurfaceHolder;
+
+/** hahahah */
+public interface RootViewSurfaceTaker {
+    SurfaceHolder.Callback willYouTakeTheSurface();
+    void setSurfaceType(int type);
+    void setSurfaceFormat(int format);
+    void setSurfaceKeepScreenOn(boolean keepOn);
+}
diff --git a/native/include/android/native_activity.h b/native/include/android/native_activity.h
index 8b09461..c0f35f8 100644
--- a/native/include/android/native_activity.h
+++ b/native/include/android/native_activity.h
@@ -55,11 +55,6 @@
 
 extern android_activity_create_t android_onCreateActivity;
 
-#if 0
-extern android_onCreateActivity(android_activity_t activity,
-        void* savedState, size_t savedStateSize);
-#endif
-
 #ifdef __cplusplus
 };
 #endif
diff --git a/policy/com/android/internal/policy/impl/PhoneWindow.java b/policy/com/android/internal/policy/impl/PhoneWindow.java
index 5592b6d..0cb0efc 100644
--- a/policy/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/com/android/internal/policy/impl/PhoneWindow.java
@@ -22,6 +22,8 @@
 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
 import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
 
+import com.android.internal.view.BaseSurfaceHolder;
+import com.android.internal.view.RootViewSurfaceTaker;
 import com.android.internal.view.menu.ContextMenuBuilder;
 import com.android.internal.view.menu.MenuBuilder;
 import com.android.internal.view.menu.MenuDialogHelper;
@@ -42,6 +44,7 @@
 import android.media.AudioManager;
 import android.net.Uri;
 import android.os.Bundle;
+import android.os.Message;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.SystemClock;
@@ -59,6 +62,8 @@
 import android.view.Menu;
 import android.view.MenuItem;
 import android.view.MotionEvent;
+import android.view.Surface;
+import android.view.SurfaceHolder;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewManager;
@@ -100,6 +105,9 @@
     // mDecor itself, or a child of mDecor where the contents go.
     private ViewGroup mContentParent;
 
+    SurfaceHolder.Callback mTakeSurfaceCallback;
+    BaseSurfaceHolder mSurfaceHolder;
+    
     private boolean mIsFloating;
 
     private LayoutInflater mLayoutInflater;
@@ -239,6 +247,11 @@
     }
 
     @Override
+    public void takeSurface(SurfaceHolder.Callback callback) {
+        mTakeSurfaceCallback = callback;
+    }
+    
+    @Override
     public boolean isFloating() {
         return mIsFloating;
     }
@@ -1554,7 +1567,7 @@
         }
     }
 
-    private final class DecorView extends FrameLayout {
+    private final class DecorView extends FrameLayout implements RootViewSurfaceTaker {
         /* package */int mDefaultOpacity = PixelFormat.OPAQUE;
 
         /** The feature ID of the panel, or -1 if this is the application's DecorView */
@@ -2019,6 +2032,23 @@
                 closeAllPanels();
             }
         }
+
+        public android.view.SurfaceHolder.Callback willYouTakeTheSurface() {
+            return mFeatureId < 0 ? mTakeSurfaceCallback : null;
+        }
+        
+        public void setSurfaceType(int type) {
+            PhoneWindow.this.setType(type);
+        }
+        
+        public void setSurfaceFormat(int format) {
+            PhoneWindow.this.setFormat(format);
+        }
+        
+        public void setSurfaceKeepScreenOn(boolean keepOn) {
+            if (keepOn) PhoneWindow.this.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+            else PhoneWindow.this.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+        }
     }
 
     protected DecorView generateDecor() {