Index: tools/viewer/sk_app/android/surface_glue_android.cpp |
diff --git a/tools/viewer/sk_app/android/surface_glue_android.cpp b/tools/viewer/sk_app/android/surface_glue_android.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..b1d0029a108759588e21351f7fe868e078dc1151 |
--- /dev/null |
+++ b/tools/viewer/sk_app/android/surface_glue_android.cpp |
@@ -0,0 +1,174 @@ |
+/* |
+* Copyright 2016 Google Inc. |
+* |
+* Use of this source code is governed by a BSD-style license that can be |
+* found in the LICENSE file. |
+*/ |
+ |
+#include "surface_glue_android.h" |
+ |
+#include <jni.h> |
+#include <pthread.h> |
+#include <stdio.h> |
+#include <unistd.h> |
+ |
+#include <android/looper.h> |
+#include <android/native_window_jni.h> |
+ |
+#include "../Application.h" |
+#include "SkTypes.h" |
+#include "SkUtils.h" |
+#include "Window_android.h" |
+ |
+namespace sk_app { |
+ |
+static const int LOOPER_ID_MESSAGEPIPE = 1; |
+ |
+void* pthread_main(void* arg); |
+ |
+SkiaAndroidApp::SkiaAndroidApp() { |
+ fNativeWindow = nullptr; |
+ pthread_create(&fThread, nullptr, pthread_main, this); |
+} |
+ |
+SkiaAndroidApp::~SkiaAndroidApp() { |
+ if (fWindow) { |
+ fWindow->detach(); |
+ } |
+ if (fNativeWindow) { |
+ ANativeWindow_release(fNativeWindow); |
+ fNativeWindow = nullptr; |
+ } |
+ if (fApp) { |
+ delete fApp; |
+ } |
+} |
+ |
+void SkiaAndroidApp::paintIfNeeded() { |
+ if (fNativeWindow && fWindow) { |
+ fWindow->onPaint(); |
+ } |
+} |
+ |
+void SkiaAndroidApp::postMessage(const Message& message) { |
+ auto writeSize = write(fPipes[1], &message, sizeof(message)); |
+ SkASSERT(writeSize == sizeof(message)); |
+} |
+ |
+void SkiaAndroidApp::readMessage(Message* message) { |
+ auto readSize = read(fPipes[0], message, sizeof(Message)); |
+ SkASSERT(readSize == sizeof(Message)); |
+} |
+ |
+static int message_callback(int fd, int events, void* data) { |
+ auto skiaAndroidApp = (SkiaAndroidApp*)data; |
+ Message message; |
+ skiaAndroidApp->readMessage(&message); |
+ SkDebugf("message_callback %d", message.fType); |
+ SkASSERT(message.fType != kUndefined); |
+ |
+ switch (message.fType) { |
+ case kDestroyApp: { |
+ delete skiaAndroidApp; |
+ pthread_exit(nullptr); |
+ return 0; |
+ } |
+ case kContentInvalidated: { |
+ skiaAndroidApp->paintIfNeeded(); |
+ break; |
+ } |
+ case kSurfaceCreated: { |
+ SkASSERT(!skiaAndroidApp->fNativeWindow && message.fNativeWindow); |
+ skiaAndroidApp->fNativeWindow = message.fNativeWindow; |
+ auto window_android = (Window_android*)skiaAndroidApp->fWindow; |
+ window_android->initDisplay(skiaAndroidApp->fNativeWindow); |
+ skiaAndroidApp->paintIfNeeded(); |
+ break; |
+ } |
+ case kSurfaceChanged: { |
+ SkASSERT(message.fNativeWindow == skiaAndroidApp->fNativeWindow && |
+ message.fNativeWindow); |
+ int width = ANativeWindow_getWidth(skiaAndroidApp->fNativeWindow); |
+ int height = ANativeWindow_getHeight(skiaAndroidApp->fNativeWindow); |
+ skiaAndroidApp->fWindow->onResize(width, height); |
+ auto window_android = (Window_android*)skiaAndroidApp->fWindow; |
+ window_android->setContentRect(0, 0, width, height); |
+ skiaAndroidApp->paintIfNeeded(); |
+ break; |
+ } |
+ case kSurfaceDestroyed: { |
+ if (skiaAndroidApp->fNativeWindow) { |
+ auto window_android = (Window_android*)skiaAndroidApp->fWindow; |
+ window_android->onDisplayDestroyed(); |
+ ANativeWindow_release(skiaAndroidApp->fNativeWindow); |
+ skiaAndroidApp->fNativeWindow = nullptr; |
+ } |
+ break; |
+ } |
+ default: { |
+ // do nothing |
+ } |
+ } |
+ |
+ return 1; // continue receiving callbacks |
+} |
+ |
+void* pthread_main(void* arg) { |
+ SkDebugf("pthread_main begins"); |
+ |
+ auto skiaAndroidApp = (SkiaAndroidApp*)arg; |
+ |
+ ALooper* looper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS); |
+ pipe(skiaAndroidApp->fPipes); |
+ ALooper_addFd(looper, skiaAndroidApp->fPipes[0], LOOPER_ID_MESSAGEPIPE, ALOOPER_EVENT_INPUT, |
+ message_callback, skiaAndroidApp); |
+ |
+ int ident; |
+ int events; |
+ struct android_poll_source* source; |
+ |
+ skiaAndroidApp->fApp = Application::Create(0, nullptr, skiaAndroidApp); |
+ |
+ while ((ident = ALooper_pollAll(-1, nullptr, &events, (void**)&source)) >= 0) { |
+ SkDebugf("ALooper_pollAll ident=%d", ident); |
+ } |
+ |
+ return nullptr; |
+} |
+ |
+extern "C" // extern "C" is needed for JNI (although the method itself is in C++) |
+ JNIEXPORT jlong JNICALL |
+ Java_org_skia_viewer_ViewerApplication_createNativeApp(JNIEnv* env, jobject activity) { |
+ SkiaAndroidApp* skiaAndroidApp = new SkiaAndroidApp; |
+ return (jlong)((size_t)skiaAndroidApp); |
+} |
+ |
+extern "C" JNIEXPORT void JNICALL Java_org_skia_viewer_ViewerApplication_destroyNativeApp( |
+ JNIEnv* env, jobject activity, jlong handle) { |
+ auto skiaAndroidApp = (SkiaAndroidApp*)handle; |
+ skiaAndroidApp->postMessage(Message(kDestroyApp)); |
+} |
+ |
+extern "C" JNIEXPORT void JNICALL Java_org_skia_viewer_ViewerActivity_onSurfaceCreated( |
+ JNIEnv* env, jobject activity, jlong handle, jobject surface) { |
+ auto skiaAndroidApp = (SkiaAndroidApp*)handle; |
+ Message message(kSurfaceCreated); |
+ message.fNativeWindow = ANativeWindow_fromSurface(env, surface); |
+ skiaAndroidApp->postMessage(message); |
+} |
+ |
+extern "C" JNIEXPORT void JNICALL Java_org_skia_viewer_ViewerActivity_onSurfaceChanged( |
+ JNIEnv* env, jobject activity, jlong handle, jobject surface) { |
+ auto skiaAndroidApp = (SkiaAndroidApp*)handle; |
+ Message message(kSurfaceChanged); |
+ message.fNativeWindow = ANativeWindow_fromSurface(env, surface); |
+ skiaAndroidApp->postMessage(message); |
+} |
+ |
+extern "C" JNIEXPORT void JNICALL Java_org_skia_viewer_ViewerActivity_onSurfaceDestroyed( |
+ JNIEnv* env, jobject activity, jlong handle) { |
+ auto skiaAndroidApp = (SkiaAndroidApp*)handle; |
+ skiaAndroidApp->postMessage(Message(kSurfaceDestroyed)); |
+} |
+ |
+} // namespace sk_app |