aboutsummaryrefslogtreecommitdiffhomepage
path: root/tools/viewer/sk_app/android/surface_glue_android.cpp
diff options
context:
space:
mode:
authorGravatar liyuqian <liyuqian@google.com>2016-05-09 08:49:29 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2016-05-09 08:49:29 -0700
commit796c5bb4655a511553970e111c96d90963fb9ae4 (patch)
treec6ac0daf5a9a1756ddc55ec09728b2c0d3b31b29 /tools/viewer/sk_app/android/surface_glue_android.cpp
parent5a493cdbeca87f85e2b08914c176c29d914083d9 (diff)
Initial commit of our new Android app to demo Skia.
Currently, there's only a simple Activity with a title bar and a surface view that connects with Skia viewer native application. Before integrating user action events, I want to make sure that the design and implementation so far are good. Note that the old NativeApplication-based Activity (ViewerActivity) is still there for reference and test purposes. It will be removed eventually. BUG=skia: GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1952323004 Review-Url: https://codereview.chromium.org/1952323004
Diffstat (limited to 'tools/viewer/sk_app/android/surface_glue_android.cpp')
-rw-r--r--tools/viewer/sk_app/android/surface_glue_android.cpp174
1 files changed, 174 insertions, 0 deletions
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 0000000000..b1d0029a10
--- /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