Make real API for native code to get its window.

Added implementation to use ANativeWindow and provide
it to a NativeActivity.

Change-Id: I890d71b6e15d4af71e6cf81b327961d7061ec1c2
diff --git a/core/java/android/app/NativeActivity.java b/core/java/android/app/NativeActivity.java
index d43368b..161161c 100644
--- a/core/java/android/app/NativeActivity.java
+++ b/core/java/android/app/NativeActivity.java
@@ -5,12 +5,14 @@
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
+import android.graphics.PixelFormat;
 import android.os.Bundle;
 import android.os.Looper;
 import android.os.MessageQueue;
 import android.view.InputChannel;
 import android.view.InputQueue;
 import android.view.KeyEvent;
+import android.view.Surface;
 import android.view.SurfaceHolder;
 import android.view.View;
 
@@ -41,10 +43,10 @@
     private native void onStopNative(int handle);
     private native void onLowMemoryNative(int handle);
     private native void onWindowFocusChangedNative(int handle, boolean focused);
-    private native void onSurfaceCreatedNative(int handle, SurfaceHolder holder);
-    private native void onSurfaceChangedNative(int handle, SurfaceHolder holder,
+    private native void onSurfaceCreatedNative(int handle, Surface surface);
+    private native void onSurfaceChangedNative(int handle, Surface surface,
             int format, int width, int height);
-    private native void onSurfaceDestroyedNative(int handle, SurfaceHolder holder);
+    private native void onSurfaceDestroyedNative(int handle);
     private native void onInputChannelCreatedNative(int handle, InputChannel channel);
     private native void onInputChannelDestroyedNative(int handle, InputChannel channel);
     
@@ -55,6 +57,7 @@
         
         getWindow().takeSurface(this);
         getWindow().takeInputQueue(this);
+        getWindow().setFormat(PixelFormat.RGB_565);
         
         try {
             ai = getPackageManager().getActivityInfo(
@@ -98,7 +101,7 @@
     protected void onDestroy() {
         mDestroyed = true;
         if (mCurSurfaceHolder != null) {
-            onSurfaceDestroyedNative(mNativeHandle, mCurSurfaceHolder);
+            onSurfaceDestroyedNative(mNativeHandle);
             mCurSurfaceHolder = null;
         }
         if (mCurInputQueue != null) {
@@ -158,21 +161,21 @@
     public void surfaceCreated(SurfaceHolder holder) {
         if (!mDestroyed) {
             mCurSurfaceHolder = holder;
-            onSurfaceCreatedNative(mNativeHandle, holder);
+            onSurfaceCreatedNative(mNativeHandle, holder.getSurface());
         }
     }
     
     public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
         if (!mDestroyed) {
             mCurSurfaceHolder = holder;
-            onSurfaceChangedNative(mNativeHandle, holder, format, width, height);
+            onSurfaceChangedNative(mNativeHandle, holder.getSurface(), format, width, height);
         }
     }
     
     public void surfaceDestroyed(SurfaceHolder holder) {
         mCurSurfaceHolder = null;
         if (!mDestroyed) {
-            onSurfaceDestroyedNative(mNativeHandle, holder);
+            onSurfaceDestroyedNative(mNativeHandle);
         }
     }
     
@@ -196,4 +199,12 @@
             decor.dispatchKeyEvent(event);
         }
     }
+    
+    void setWindowFlags(int flags, int mask) {
+        getWindow().setFlags(flags, mask);
+    }
+    
+    void setWindowFormat(int format) {
+        getWindow().setFormat(format);
+    }
 }
diff --git a/core/jni/android_app_NativeActivity.cpp b/core/jni/android_app_NativeActivity.cpp
index dd59d63..49b9609 100644
--- a/core/jni/android_app_NativeActivity.cpp
+++ b/core/jni/android_app_NativeActivity.cpp
@@ -22,6 +22,8 @@
 
 #include <android_runtime/AndroidRuntime.h>
 #include <android/native_activity.h>
+#include <surfaceflinger/Surface.h>
+#include <ui/egl/android_natives.h>
 #include <ui/InputTransport.h>
 #include <utils/PollLoop.h>
 
@@ -29,6 +31,7 @@
 #include "android_os_MessageQueue.h"
 #include "android_view_InputChannel.h"
 #include "android_view_KeyEvent.h"
+#include "android_view_Surface.h"
 
 namespace android
 {
@@ -37,8 +40,16 @@
     jclass clazz;
 
     jmethodID dispatchUnhandledKeyEvent;
+    jmethodID setWindowFlags;
+    jmethodID setWindowFormat;
 } gNativeActivityClassInfo;
 
+// ------------------------------------------------------------------------
+
+/*
+ * Specialized input queue that allows unhandled key events to be dispatched
+ * back to the native activity's Java framework code.
+ */
 struct MyInputQueue : AInputQueue {
     explicit MyInputQueue(const android::sp<android::InputChannel>& channel, int workWrite)
         : AInputQueue(channel), mWorkWrite(workWrite) {
@@ -74,13 +85,18 @@
     Vector<KeyEvent*> mPendingKeys;
 };
 
+// ------------------------------------------------------------------------
+
+/*
+ * Native state for interacting with the NativeActivity class.
+ */
 struct NativeCode {
     NativeCode(void* _dlhandle, ANativeActivity_createFunc* _createFunc) {
         memset(&activity, sizeof(activity), 0);
         memset(&callbacks, sizeof(callbacks), 0);
         dlhandle = _dlhandle;
         createActivityFunc = _createFunc;
-        surface = NULL;
+        nativeWindow = NULL;
         inputChannel = NULL;
         nativeInputQueue = NULL;
         mainWorkRead = mainWorkWrite = -1;
@@ -104,18 +120,18 @@
         if (mainWorkRead >= 0) close(mainWorkRead);
         if (mainWorkWrite >= 0) close(mainWorkWrite);
         if (dlhandle != NULL) {
-            dlclose(dlhandle);
+            // for now don't unload...  we probably should clean this
+            // up and only keep one open dlhandle per proc, since there
+            // is really no benefit to unloading the code.
+            //dlclose(dlhandle);
         }
     }
     
     void setSurface(jobject _surface) {
-        if (surface != NULL) {
-            activity.env->DeleteGlobalRef(surface);
-        }
         if (_surface != NULL) {
-            surface = activity.env->NewGlobalRef(_surface);
+            nativeWindow = android_Surface_getNativeWindow(activity.env, _surface);
         } else {
-            surface = NULL;
+            nativeWindow = NULL;
         }
     }
     
@@ -150,7 +166,7 @@
     void* dlhandle;
     ANativeActivity_createFunc* createActivityFunc;
     
-    jobject surface;
+    sp<ANativeWindow> nativeWindow;
     jobject inputChannel;
     struct MyInputQueue* nativeInputQueue;
     
@@ -160,6 +176,11 @@
     sp<PollLoop> pollLoop;
 };
 
+// ------------------------------------------------------------------------
+
+/*
+ * Callback for handling native events on the application's main thread.
+ */
 static bool mainWorkCallback(int fd, int events, void* data) {
     NativeCode* code = (NativeCode*)data;
     if ((events & POLLIN) != 0) {
@@ -180,6 +201,8 @@
     return true;
 }
 
+// ------------------------------------------------------------------------
+
 static jint
 loadNativeCode_native(JNIEnv* env, jobject clazz, jstring path, jobject messageQueue)
 {
@@ -323,9 +346,9 @@
     if (handle != 0) {
         NativeCode* code = (NativeCode*)handle;
         code->setSurface(surface);
-        if (code->callbacks.onSurfaceCreated != NULL) {
-            code->callbacks.onSurfaceCreated(&code->activity,
-                    (ASurfaceHolder*)code->surface);
+        if (code->nativeWindow != NULL && code->callbacks.onNativeWindowCreated != NULL) {
+            code->callbacks.onNativeWindowCreated(&code->activity,
+                    code->nativeWindow.get());
         }
     }
 }
@@ -336,9 +359,13 @@
 {
     if (handle != 0) {
         NativeCode* code = (NativeCode*)handle;
-        if (code->surface != NULL && code->callbacks.onSurfaceChanged != NULL) {
-            code->callbacks.onSurfaceChanged(&code->activity,
-                    (ASurfaceHolder*)code->surface, format, width, height);
+        sp<ANativeWindow> oldNativeWindow = code->nativeWindow;
+        code->setSurface(surface);
+        if (oldNativeWindow != code->nativeWindow) {
+            if (code->nativeWindow != NULL && code->callbacks.onNativeWindowChanged != NULL) {
+                code->callbacks.onNativeWindowChanged(&code->activity,
+                        code->nativeWindow.get());
+            }
         }
     }
 }
@@ -348,9 +375,9 @@
 {
     if (handle != 0) {
         NativeCode* code = (NativeCode*)handle;
-        if (code->surface != NULL && code->callbacks.onSurfaceDestroyed != NULL) {
-            code->callbacks.onSurfaceDestroyed(&code->activity,
-                    (ASurfaceHolder*)code->surface);
+        if (code->nativeWindow != NULL && code->callbacks.onNativeWindowDestroyed != NULL) {
+            code->callbacks.onNativeWindowDestroyed(&code->activity,
+                    code->nativeWindow.get());
         }
         code->setSurface(NULL);
     }
@@ -398,9 +425,9 @@
     { "onStopNative", "(I)V", (void*)onStop_native },
     { "onLowMemoryNative", "(I)V", (void*)onLowMemory_native },
     { "onWindowFocusChangedNative", "(IZ)V", (void*)onWindowFocusChanged_native },
-    { "onSurfaceCreatedNative", "(ILandroid/view/SurfaceHolder;)V", (void*)onSurfaceCreated_native },
-    { "onSurfaceChangedNative", "(ILandroid/view/SurfaceHolder;III)V", (void*)onSurfaceChanged_native },
-    { "onSurfaceDestroyedNative", "(ILandroid/view/SurfaceHolder;)V", (void*)onSurfaceDestroyed_native },
+    { "onSurfaceCreatedNative", "(ILandroid/view/Surface;)V", (void*)onSurfaceCreated_native },
+    { "onSurfaceChangedNative", "(ILandroid/view/Surface;III)V", (void*)onSurfaceChanged_native },
+    { "onSurfaceDestroyedNative", "(I)V", (void*)onSurfaceDestroyed_native },
     { "onInputChannelCreatedNative", "(ILandroid/view/InputChannel;)V", (void*)onInputChannelCreated_native },
     { "onInputChannelDestroyedNative", "(ILandroid/view/InputChannel;)V", (void*)onInputChannelDestroyed_native },
 };
@@ -421,11 +448,18 @@
     //LOGD("register_android_app_NativeActivity");
 
     FIND_CLASS(gNativeActivityClassInfo.clazz, kNativeActivityPathName);
-        
+    
     GET_METHOD_ID(gNativeActivityClassInfo.dispatchUnhandledKeyEvent,
             gNativeActivityClassInfo.clazz,
             "dispatchUnhandledKeyEvent", "(Landroid/view/KeyEvent;)V");
-            
+
+    GET_METHOD_ID(gNativeActivityClassInfo.setWindowFlags,
+            gNativeActivityClassInfo.clazz,
+            "setWindowFlags", "(II)V");
+    GET_METHOD_ID(gNativeActivityClassInfo.setWindowFormat,
+            gNativeActivityClassInfo.clazz,
+            "setWindowFormat", "(I)V");
+
     return AndroidRuntime::registerNativeMethods(
         env, kNativeActivityPathName,
         g_methods, NELEM(g_methods));
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index cef5c10..a82abc93 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -33,6 +33,7 @@
 
 #include "jni.h"
 #include <android_runtime/AndroidRuntime.h>
+#include "android_view_Surface.h"
 #include <utils/misc.h>
 
 
@@ -179,7 +180,7 @@
     return result;
 }
 
-EGLNativeWindowType android_Surface_getEGLNativeWindow(
+sp<ANativeWindow> android_Surface_getNativeWindow(
         JNIEnv* env, jobject clazz) {
     return getSurface(env, clazz).get();
 }
diff --git a/core/jni/android_view_Surface.h b/core/jni/android_view_Surface.h
new file mode 100644
index 0000000..c37932e
--- /dev/null
+++ b/core/jni/android_view_Surface.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _ANDROID_VIEW_SURFACE_H
+#define _ANDROID_VIEW_SURFACE_H
+
+#include <android/native_window.h>
+
+#include "jni.h"
+
+namespace android {
+
+extern sp<ANativeWindow> android_Surface_getNativeWindow(
+        JNIEnv* env, jobject clazz);
+
+} // namespace android
+
+#endif // _ANDROID_VIEW_SURFACE_H
diff --git a/core/jni/com_google_android_gles_jni_EGLImpl.cpp b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
index d5cde48..866c038 100644
--- a/core/jni/com_google_android_gles_jni_EGLImpl.cpp
+++ b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
@@ -25,10 +25,9 @@
 #include <SkBitmap.h>
 #include <SkPixelRef.h>
 
-namespace android {
+#include "android_view_Surface.h"
 
-extern EGLNativeWindowType android_Surface_getEGLNativeWindow(
-        JNIEnv* env, jobject clazz);
+namespace android {
 
 static jclass gDisplay_class;
 static jclass gContext_class;
@@ -325,7 +324,7 @@
     }
     EGLDisplay dpy = getDisplay(_env, display);
     EGLContext cnf = getConfig(_env, config);
-    EGLNativeWindowType window = 0;
+    sp<ANativeWindow> window;
     if (native_window == NULL) {
 not_valid_surface:
         doThrow(_env, "java/lang/IllegalArgumentException",
@@ -333,12 +332,12 @@
         return 0;
     }
 
-    window = android_Surface_getEGLNativeWindow(_env, native_window);
+    window = android_Surface_getNativeWindow(_env, native_window);
     if (window == NULL)
         goto not_valid_surface;
 
     jint* base = beginNativeAttribList(_env, attrib_list);
-    EGLSurface sur = eglCreateWindowSurface(dpy, cnf, window, base);
+    EGLSurface sur = eglCreateWindowSurface(dpy, cnf, window.get(), base);
     endNativeAttributeList(_env, attrib_list, base);
     return (jint)sur;
 }
diff --git a/native/android/Android.mk b/native/android/Android.mk
index 8c621b6..fe8ed00 100644
--- a/native/android/Android.mk
+++ b/native/android/Android.mk
@@ -7,7 +7,8 @@
 #
 LOCAL_SRC_FILES:= \
     activity.cpp \
-    input.cpp
+    input.cpp \
+    native_window.cpp
 
 LOCAL_SHARED_LIBRARIES := \
     libandroid_runtime \
diff --git a/native/android/native_window.cpp b/native/android/native_window.cpp
new file mode 100644
index 0000000..7a6eb6d
--- /dev/null
+++ b/native/android/native_window.cpp
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "Surface"
+#include <utils/Log.h>
+
+#include <android/native_window.h>
+#include <surfaceflinger/Surface.h>
+
+using android::Surface;
+
+static int32_t getWindowProp(ANativeWindow* window, int what) {
+    int value;
+    int res = window->query(window, what, &value);
+    return res < 0 ? res : value;
+}
+
+int32_t ANativeWindow_getWidth(ANativeWindow* window) {
+    return getWindowProp(window, NATIVE_WINDOW_WIDTH);
+}
+
+int32_t ANativeWindow_getHeight(ANativeWindow* window) {
+    return getWindowProp(window, NATIVE_WINDOW_HEIGHT);
+}
+
+int32_t ANativeWindow_getFormat(ANativeWindow* window) {
+    return getWindowProp(window, NATIVE_WINDOW_FORMAT);
+}
diff --git a/native/include/android/native_activity.h b/native/include/android/native_activity.h
index c5c8f9d..d23e40f 100644
--- a/native/include/android/native_activity.h
+++ b/native/include/android/native_activity.h
@@ -24,15 +24,12 @@
 #include <jni.h>
 
 #include <android/input.h>
+#include <android/native_window.h>
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-// Temporary until native surface API is defined.
-struct ASurfaceHolder;
-typedef struct ASurfaceHolder ASurfaceHolder;
-
 struct ANativeActivityCallbacks;
 
 /**
@@ -129,30 +126,28 @@
     void (*onWindowFocusChanged)(ANativeActivity* activity, int hasFocus);
     
     /**
-     * The drawing surface for this native activity has been created.  You
-     * can use the given surface object to start drawing.  NOTE: surface
-     * drawing API is not yet defined.
+     * The drawing window for this native activity has been created.  You
+     * can use the given native window object to start drawing.
      */
-    void (*onSurfaceCreated)(ANativeActivity* activity, ASurfaceHolder* surface);
+    void (*onNativeWindowCreated)(ANativeActivity* activity, ANativeWindow* window);
 
     /**
-     * The drawing surface for this native activity has changed.  The surface
-     * given here is guaranteed to be the same as the one last given to
-     * onSurfaceCreated.  This is simply to inform you about interesting
-     * changed to that surface.
+     * The drawing window for this native activity has changed.  During this time,
+     * old ANativeWindow object is still valid but no longer active and drawing
+     * should switch to the new ANativeWindow given here.  After returning from
+     * this function, you must not touch the old window.
      */
-    void (*onSurfaceChanged)(ANativeActivity* activity, ASurfaceHolder* surface,
-            int format, int width, int height);
+    void (*onNativeWindowChanged)(ANativeActivity* activity, ANativeWindow* window);
 
     /**
-     * The drawing surface for this native activity is going to be destroyed.
-     * You MUST ensure that you do not touch the surface object after returning
-     * from this function: in the common case of drawing to the surface from
+     * The drawing window for this native activity is going to be destroyed.
+     * You MUST ensure that you do not touch the window object after returning
+     * from this function: in the common case of drawing to the window from
      * another thread, that means the implementation of this callback must
      * properly synchronize with the other thread to stop its drawing before
      * returning from here.
      */
-    void (*onSurfaceDestroyed)(ANativeActivity* activity, ASurfaceHolder* surface);
+    void (*onNativeWindowDestroyed)(ANativeActivity* activity, ANativeWindow* window);
     
     /**
      * The input queue for this native activity's window has been created.
diff --git a/native/include/android/native_window.h b/native/include/android/native_window.h
index e6d5fea..b3f47b2 100644
--- a/native/include/android/native_window.h
+++ b/native/include/android/native_window.h
@@ -25,6 +25,23 @@
 struct ANativeWindow;
 typedef struct ANativeWindow ANativeWindow;
 
+/*
+ * Return the current width in pixels of the window surface.  Returns a
+ * negative value on error.
+ */
+int32_t ANativeWindow_getWidth(ANativeWindow* window);
+
+/*
+ * Return the current height in pixels of the window surface.  Returns a
+ * negative value on error.
+ */
+int32_t ANativeWindow_getHeight(ANativeWindow* window);
+
+/*
+ * Return the current pixel format of the window surface.  Returns a
+ * negative value on error.
+ */
+int32_t ANativeWindow_getFormat(ANativeWindow* window);
 
 #ifdef __cplusplus
 };