app: merge android.go with loop_android.go.

There's no need for more than one Android .go file.

Change-Id: I75f5ced5680088b0ddbe5c700981b9a595d9e321
Reviewed-on: https://go-review.googlesource.com/13343
Reviewed-by: David Crawshaw <crawshaw@golang.org>
diff --git a/app/android.c b/app/android.c
index 849d82a..6733e2b 100644
--- a/app/android.c
+++ b/app/android.c
@@ -8,9 +8,6 @@
 #include <dlfcn.h>
 #include <errno.h>
 #include <fcntl.h>
-#include <jni.h>
-#include <pthread.h>
-#include <stdlib.h>
 #include <stdint.h>
 #include <string.h>
 #include "_cgo_export.h"
@@ -111,3 +108,71 @@
 
 	onCreate(activity);
 }
+
+// TODO(crawshaw): Test configuration on more devices.
+const EGLint RGB_888[] = {
+	EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+	EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+	EGL_BLUE_SIZE, 8,
+	EGL_GREEN_SIZE, 8,
+	EGL_RED_SIZE, 8,
+	EGL_DEPTH_SIZE, 16,
+	EGL_CONFIG_CAVEAT, EGL_NONE,
+	EGL_NONE
+};
+
+EGLDisplay display = NULL;
+EGLSurface surface = NULL;
+
+char* initEGLDisplay() {
+	display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+	if (!eglInitialize(display, 0, 0)) {
+		return "EGL initialize failed";
+	}
+	return NULL;
+}
+
+char* createEGLSurface(ANativeWindow* window) {
+	char* err;
+	EGLint numConfigs, format;
+	EGLConfig config;
+	EGLContext context;
+
+	if (display == 0) {
+		if ((err = initEGLDisplay()) != NULL) {
+			return err;
+		}
+	}
+
+	if (!eglChooseConfig(display, RGB_888, &config, 1, &numConfigs)) {
+		return "EGL choose RGB_888 config failed";
+	}
+	if (numConfigs <= 0) {
+		return "EGL no config found";
+	}
+
+	eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &format);
+	if (ANativeWindow_setBuffersGeometry(window, 0, 0, format) != 0) {
+		return "EGL set buffers geometry failed";
+	}
+
+	surface = eglCreateWindowSurface(display, config, window, NULL);
+	if (surface == EGL_NO_SURFACE) {
+		return "EGL create surface failed";
+	}
+
+	const EGLint contextAttribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
+	context = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttribs);
+
+	if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE) {
+		return "eglMakeCurrent failed";
+	}
+	return NULL;
+}
+
+char* destroyEGLSurface() {
+	if (!eglDestroySurface(display, surface)) {
+		return "EGL destroy surface failed";
+	}
+	return NULL;
+}
diff --git a/app/android.go b/app/android.go
index 3edec1f..416ce64 100644
--- a/app/android.go
+++ b/app/android.go
@@ -22,14 +22,12 @@
 package app
 
 /*
-// The C libraries listed here but not explicitly used in this file are used by
-// other *_android.go files. There should be only one #cgo declaration.
 #cgo LDFLAGS: -landroid -llog -lEGL -lGLESv2
 
 #include <android/configuration.h>
 #include <android/native_activity.h>
-#include <time.h>
-
+#include <android/native_window.h>
+#include <EGL/egl.h>
 #include <jni.h>
 #include <pthread.h>
 #include <stdlib.h>
@@ -37,15 +35,30 @@
 jclass current_ctx_clazz;
 
 jclass app_find_class(JNIEnv* env, const char* name);
+
+EGLDisplay display;
+EGLSurface surface;
+
+char* initEGLDisplay();
+char* createEGLSurface(ANativeWindow* window);
+char* destroyEGLSurface();
 */
 import "C"
 import (
+	"fmt"
 	"log"
 	"os"
+	"runtime"
 	"time"
 	"unsafe"
 
 	"golang.org/x/mobile/app/internal/callfn"
+	"golang.org/x/mobile/event/config"
+	"golang.org/x/mobile/event/lifecycle"
+	"golang.org/x/mobile/event/paint"
+	"golang.org/x/mobile/event/touch"
+	"golang.org/x/mobile/geom"
+	"golang.org/x/mobile/gl"
 	"golang.org/x/mobile/internal/mobileinit"
 )
 
@@ -225,3 +238,176 @@
 func init() {
 	registerGLViewportFilter()
 }
+
+func main(f func(App)) {
+	// Preserve this OS thread for the GL context created below.
+	runtime.LockOSThread()
+
+	donec := make(chan struct{})
+	go func() {
+		f(app{})
+		close(donec)
+	}()
+
+	var q *C.AInputQueue
+
+	// Android can send a windowRedrawNeeded event any time, including
+	// in the middle of a paint cycle. The redraw event may have changed
+	// the size of the screen, so any partial painting is now invalidated.
+	// We must also not return to Android (via sending on windowRedrawDone)
+	// until a complete paint with the new configuration is complete.
+	//
+	// When a windowRedrawNeeded request comes in, we increment redrawGen
+	// (Gen is short for generation number), and do not make a paint cycle
+	// visible on <-endPaint unless Generation agrees. If possible,
+	// windowRedrawDone is signalled, allowing onNativeWindowRedrawNeeded
+	// to return.
+	var redrawGen uint32
+
+	for {
+		if q != nil {
+			processEvents(q)
+		}
+		select {
+		case <-windowCreated:
+		case q = <-inputQueue:
+		case <-donec:
+			return
+		case cfg := <-windowConfigChange:
+			// TODO save orientation
+			pixelsPerPt = cfg.pixelsPerPt
+		case w := <-windowRedrawNeeded:
+			newWindow := C.surface == nil
+			if newWindow {
+				if errStr := C.createEGLSurface(w); errStr != nil {
+					log.Printf("app: %s (%s)", C.GoString(errStr), eglGetError())
+					return
+				}
+			}
+			sendLifecycle(lifecycle.StageFocused)
+			widthPx := int(C.ANativeWindow_getWidth(w))
+			heightPx := int(C.ANativeWindow_getHeight(w))
+			eventsIn <- config.Event{
+				WidthPx:     widthPx,
+				HeightPx:    heightPx,
+				WidthPt:     geom.Pt(float32(widthPx) / pixelsPerPt),
+				HeightPt:    geom.Pt(float32(heightPx) / pixelsPerPt),
+				PixelsPerPt: pixelsPerPt,
+			}
+			redrawGen++
+			if newWindow {
+				// New window, begin paint loop.
+				eventsIn <- paint.Event{redrawGen}
+			}
+		case <-windowDestroyed:
+			if C.surface != nil {
+				if errStr := C.destroyEGLSurface(); errStr != nil {
+					log.Printf("app: %s (%s)", C.GoString(errStr), eglGetError())
+					return
+				}
+			}
+			C.surface = nil
+			sendLifecycle(lifecycle.StageAlive)
+		case <-gl.WorkAvailable:
+			gl.DoWork()
+		case p := <-endPaint:
+			if p.Generation != redrawGen {
+				continue
+			}
+			if C.surface != nil {
+				// eglSwapBuffers blocks until vsync.
+				if C.eglSwapBuffers(C.display, C.surface) == C.EGL_FALSE {
+					log.Printf("app: failed to swap buffers (%s)", eglGetError())
+				}
+			}
+			select {
+			case windowRedrawDone <- struct{}{}:
+			default:
+			}
+			if C.surface != nil {
+				redrawGen++
+				eventsIn <- paint.Event{redrawGen}
+			}
+		}
+	}
+}
+
+func processEvents(queue *C.AInputQueue) {
+	var event *C.AInputEvent
+	for C.AInputQueue_getEvent(queue, &event) >= 0 {
+		if C.AInputQueue_preDispatchEvent(queue, event) != 0 {
+			continue
+		}
+		processEvent(event)
+		C.AInputQueue_finishEvent(queue, event, 0)
+	}
+}
+
+func processEvent(e *C.AInputEvent) {
+	switch C.AInputEvent_getType(e) {
+	case C.AINPUT_EVENT_TYPE_KEY:
+		log.Printf("TODO input event: key")
+	case C.AINPUT_EVENT_TYPE_MOTION:
+		// At most one of the events in this batch is an up or down event; get its index and change.
+		upDownIndex := C.size_t(C.AMotionEvent_getAction(e)&C.AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> C.AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT
+		upDownType := touch.TypeMove
+		switch C.AMotionEvent_getAction(e) & C.AMOTION_EVENT_ACTION_MASK {
+		case C.AMOTION_EVENT_ACTION_DOWN, C.AMOTION_EVENT_ACTION_POINTER_DOWN:
+			upDownType = touch.TypeBegin
+		case C.AMOTION_EVENT_ACTION_UP, C.AMOTION_EVENT_ACTION_POINTER_UP:
+			upDownType = touch.TypeEnd
+		}
+
+		for i, n := C.size_t(0), C.AMotionEvent_getPointerCount(e); i < n; i++ {
+			t := touch.TypeMove
+			if i == upDownIndex {
+				t = upDownType
+			}
+			eventsIn <- touch.Event{
+				X:        float32(C.AMotionEvent_getX(e, i)),
+				Y:        float32(C.AMotionEvent_getY(e, i)),
+				Sequence: touch.Sequence(C.AMotionEvent_getPointerId(e, i)),
+				Type:     t,
+			}
+		}
+	default:
+		log.Printf("unknown input event, type=%d", C.AInputEvent_getType(e))
+	}
+}
+
+func eglGetError() string {
+	switch errNum := C.eglGetError(); errNum {
+	case C.EGL_SUCCESS:
+		return "EGL_SUCCESS"
+	case C.EGL_NOT_INITIALIZED:
+		return "EGL_NOT_INITIALIZED"
+	case C.EGL_BAD_ACCESS:
+		return "EGL_BAD_ACCESS"
+	case C.EGL_BAD_ALLOC:
+		return "EGL_BAD_ALLOC"
+	case C.EGL_BAD_ATTRIBUTE:
+		return "EGL_BAD_ATTRIBUTE"
+	case C.EGL_BAD_CONTEXT:
+		return "EGL_BAD_CONTEXT"
+	case C.EGL_BAD_CONFIG:
+		return "EGL_BAD_CONFIG"
+	case C.EGL_BAD_CURRENT_SURFACE:
+		return "EGL_BAD_CURRENT_SURFACE"
+	case C.EGL_BAD_DISPLAY:
+		return "EGL_BAD_DISPLAY"
+	case C.EGL_BAD_SURFACE:
+		return "EGL_BAD_SURFACE"
+	case C.EGL_BAD_MATCH:
+		return "EGL_BAD_MATCH"
+	case C.EGL_BAD_PARAMETER:
+		return "EGL_BAD_PARAMETER"
+	case C.EGL_BAD_NATIVE_PIXMAP:
+		return "EGL_BAD_NATIVE_PIXMAP"
+	case C.EGL_BAD_NATIVE_WINDOW:
+		return "EGL_BAD_NATIVE_WINDOW"
+	case C.EGL_CONTEXT_LOST:
+		return "EGL_CONTEXT_LOST"
+	default:
+		return fmt.Sprintf("Unknown EGL err: %d", errNum)
+	}
+}
diff --git a/app/loop_android.go b/app/loop_android.go
deleted file mode 100644
index 5d6c3ca..0000000
--- a/app/loop_android.go
+++ /dev/null
@@ -1,267 +0,0 @@
-// Copyright 2014 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package app
-
-/*
-#include <android/native_activity.h>
-#include <android/native_window.h>
-#include <android/input.h>
-#include <EGL/egl.h>
-#include <GLES/gl.h>
-
-// TODO(crawshaw): Test configuration on more devices.
-const EGLint RGB_888[] = {
-	EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
-	EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
-	EGL_BLUE_SIZE, 8,
-	EGL_GREEN_SIZE, 8,
-	EGL_RED_SIZE, 8,
-	EGL_DEPTH_SIZE, 16,
-	EGL_CONFIG_CAVEAT, EGL_NONE,
-	EGL_NONE
-};
-
-EGLDisplay display = NULL;
-EGLSurface surface = NULL;
-
-char* initEGLDisplay() {
-	display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
-	if (!eglInitialize(display, 0, 0)) {
-		return "EGL initialize failed";
-	}
-	return NULL;
-}
-
-char* createEGLSurface(ANativeWindow* window) {
-	char* err;
-	EGLint numConfigs, format;
-	EGLConfig config;
-	EGLContext context;
-
-	if (display == 0) {
-		if ((err = initEGLDisplay()) != NULL) {
-			return err;
-		}
-	}
-
-	if (!eglChooseConfig(display, RGB_888, &config, 1, &numConfigs)) {
-		return "EGL choose RGB_888 config failed";
-	}
-	if (numConfigs <= 0) {
-		return "EGL no config found";
-	}
-
-	eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &format);
-	if (ANativeWindow_setBuffersGeometry(window, 0, 0, format) != 0) {
-		return "EGL set buffers geometry failed";
-	}
-
-	surface = eglCreateWindowSurface(display, config, window, NULL);
-	if (surface == EGL_NO_SURFACE) {
-		return "EGL create surface failed";
-	}
-
-	const EGLint contextAttribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
-	context = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttribs);
-
-	if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE) {
-		return "eglMakeCurrent failed";
-	}
-	return NULL;
-}
-
-char* destroyEGLSurface() {
-	if (!eglDestroySurface(display, surface)) {
-		return "EGL destroy surface failed";
-	}
-	return NULL;
-}
-*/
-import "C"
-import (
-	"fmt"
-	"log"
-	"runtime"
-
-	"golang.org/x/mobile/event/config"
-	"golang.org/x/mobile/event/lifecycle"
-	"golang.org/x/mobile/event/paint"
-	"golang.org/x/mobile/event/touch"
-	"golang.org/x/mobile/geom"
-	"golang.org/x/mobile/gl"
-)
-
-func main(f func(App)) {
-	// Preserve this OS thread for the GL context created below.
-	runtime.LockOSThread()
-
-	donec := make(chan struct{})
-	go func() {
-		f(app{})
-		close(donec)
-	}()
-
-	var q *C.AInputQueue
-
-	// Android can send a windowRedrawNeeded event any time, including
-	// in the middle of a paint cycle. The redraw event may have changed
-	// the size of the screen, so any partial painting is now invalidated.
-	// We must also not return to Android (via sending on windowRedrawDone)
-	// until a complete paint with the new configuration is complete.
-	//
-	// When a windowRedrawNeeded request comes in, we increment redrawGen
-	// (Gen is short for generation number), and do not make a paint cycle
-	// visible on <-endPaint unless Generation agrees. If possible,
-	// windowRedrawDone is signalled, allowing onNativeWindowRedrawNeeded
-	// to return.
-	var redrawGen uint32
-
-	for {
-		if q != nil {
-			processEvents(q)
-		}
-		select {
-		case <-windowCreated:
-		case q = <-inputQueue:
-		case <-donec:
-			return
-		case cfg := <-windowConfigChange:
-			// TODO save orientation
-			pixelsPerPt = cfg.pixelsPerPt
-		case w := <-windowRedrawNeeded:
-			newWindow := C.surface == nil
-			if newWindow {
-				if errStr := C.createEGLSurface(w); errStr != nil {
-					log.Printf("app: %s (%s)", C.GoString(errStr), eglGetError())
-					return
-				}
-			}
-			sendLifecycle(lifecycle.StageFocused)
-			widthPx := int(C.ANativeWindow_getWidth(w))
-			heightPx := int(C.ANativeWindow_getHeight(w))
-			eventsIn <- config.Event{
-				WidthPx:     widthPx,
-				HeightPx:    heightPx,
-				WidthPt:     geom.Pt(float32(widthPx) / pixelsPerPt),
-				HeightPt:    geom.Pt(float32(heightPx) / pixelsPerPt),
-				PixelsPerPt: pixelsPerPt,
-			}
-			redrawGen++
-			if newWindow {
-				// New window, begin paint loop.
-				eventsIn <- paint.Event{redrawGen}
-			}
-		case <-windowDestroyed:
-			if C.surface != nil {
-				if errStr := C.destroyEGLSurface(); errStr != nil {
-					log.Printf("app: %s (%s)", C.GoString(errStr), eglGetError())
-					return
-				}
-			}
-			C.surface = nil
-			sendLifecycle(lifecycle.StageAlive)
-		case <-gl.WorkAvailable:
-			gl.DoWork()
-		case p := <-endPaint:
-			if p.Generation != redrawGen {
-				continue
-			}
-			if C.surface != nil {
-				// eglSwapBuffers blocks until vsync.
-				if C.eglSwapBuffers(C.display, C.surface) == C.EGL_FALSE {
-					log.Printf("app: failed to swap buffers (%s)", eglGetError())
-				}
-			}
-			select {
-			case windowRedrawDone <- struct{}{}:
-			default:
-			}
-			if C.surface != nil {
-				redrawGen++
-				eventsIn <- paint.Event{redrawGen}
-			}
-		}
-	}
-}
-
-func processEvents(queue *C.AInputQueue) {
-	var event *C.AInputEvent
-	for C.AInputQueue_getEvent(queue, &event) >= 0 {
-		if C.AInputQueue_preDispatchEvent(queue, event) != 0 {
-			continue
-		}
-		processEvent(event)
-		C.AInputQueue_finishEvent(queue, event, 0)
-	}
-}
-
-func processEvent(e *C.AInputEvent) {
-	switch C.AInputEvent_getType(e) {
-	case C.AINPUT_EVENT_TYPE_KEY:
-		log.Printf("TODO input event: key")
-	case C.AINPUT_EVENT_TYPE_MOTION:
-		// At most one of the events in this batch is an up or down event; get its index and change.
-		upDownIndex := C.size_t(C.AMotionEvent_getAction(e)&C.AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> C.AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT
-		upDownType := touch.TypeMove
-		switch C.AMotionEvent_getAction(e) & C.AMOTION_EVENT_ACTION_MASK {
-		case C.AMOTION_EVENT_ACTION_DOWN, C.AMOTION_EVENT_ACTION_POINTER_DOWN:
-			upDownType = touch.TypeBegin
-		case C.AMOTION_EVENT_ACTION_UP, C.AMOTION_EVENT_ACTION_POINTER_UP:
-			upDownType = touch.TypeEnd
-		}
-
-		for i, n := C.size_t(0), C.AMotionEvent_getPointerCount(e); i < n; i++ {
-			t := touch.TypeMove
-			if i == upDownIndex {
-				t = upDownType
-			}
-			eventsIn <- touch.Event{
-				X:        float32(C.AMotionEvent_getX(e, i)),
-				Y:        float32(C.AMotionEvent_getY(e, i)),
-				Sequence: touch.Sequence(C.AMotionEvent_getPointerId(e, i)),
-				Type:     t,
-			}
-		}
-	default:
-		log.Printf("unknown input event, type=%d", C.AInputEvent_getType(e))
-	}
-}
-
-func eglGetError() string {
-	switch errNum := C.eglGetError(); errNum {
-	case C.EGL_SUCCESS:
-		return "EGL_SUCCESS"
-	case C.EGL_NOT_INITIALIZED:
-		return "EGL_NOT_INITIALIZED"
-	case C.EGL_BAD_ACCESS:
-		return "EGL_BAD_ACCESS"
-	case C.EGL_BAD_ALLOC:
-		return "EGL_BAD_ALLOC"
-	case C.EGL_BAD_ATTRIBUTE:
-		return "EGL_BAD_ATTRIBUTE"
-	case C.EGL_BAD_CONTEXT:
-		return "EGL_BAD_CONTEXT"
-	case C.EGL_BAD_CONFIG:
-		return "EGL_BAD_CONFIG"
-	case C.EGL_BAD_CURRENT_SURFACE:
-		return "EGL_BAD_CURRENT_SURFACE"
-	case C.EGL_BAD_DISPLAY:
-		return "EGL_BAD_DISPLAY"
-	case C.EGL_BAD_SURFACE:
-		return "EGL_BAD_SURFACE"
-	case C.EGL_BAD_MATCH:
-		return "EGL_BAD_MATCH"
-	case C.EGL_BAD_PARAMETER:
-		return "EGL_BAD_PARAMETER"
-	case C.EGL_BAD_NATIVE_PIXMAP:
-		return "EGL_BAD_NATIVE_PIXMAP"
-	case C.EGL_BAD_NATIVE_WINDOW:
-		return "EGL_BAD_NATIVE_WINDOW"
-	case C.EGL_CONTEXT_LOST:
-		return "EGL_CONTEXT_LOST"
-	default:
-		return fmt.Sprintf("Unknown EGL err: %d", errNum)
-	}
-}