Change Android activity title from JNI call
authorliyuqian <liyuqian@google.com>
Fri, 13 May 2016 16:57:44 +0000 (09:57 -0700)
committerCommit bot <commit-bot@chromium.org>
Fri, 13 May 2016 16:57:44 +0000 (09:57 -0700)
BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1978843002

Review-Url: https://codereview.chromium.org/1978843002

platform_tools/android/apps/viewer/src/main/java/org/skia/viewer/ViewerActivity.java
platform_tools/android/apps/viewer/src/main/java/org/skia/viewer/ViewerApplication.java
tools/viewer/sk_app/android/Window_android.cpp
tools/viewer/sk_app/android/surface_glue_android.cpp
tools/viewer/sk_app/android/surface_glue_android.h

index e3260c2..d6fe710 100644 (file)
@@ -60,6 +60,7 @@ public class ViewerActivity
         setContentView(R.layout.activity_main);
 
         mApplication = (ViewerApplication) getApplication();
+        mApplication.setViewerActivity(this);
         mView = (SurfaceView) findViewById(R.id.surfaceView);
         mView.getHolder().addCallback(this);
 
@@ -67,6 +68,12 @@ public class ViewerActivity
     }
 
     @Override
+    protected void onDestroy() {
+        mApplication.setViewerActivity(null);
+        super.onDestroy();
+    }
+
+    @Override
     public void surfaceCreated(SurfaceHolder holder) {
         if (mApplication.getNativeHandle() != 0) {
             onSurfaceCreated(mApplication.getNativeHandle(), holder.getSurface());
index 9389f72..4b890bd 100644 (file)
@@ -11,6 +11,7 @@ import android.app.Application;
 
 public class ViewerApplication extends Application {
     private long mNativeHandle = 0;
+    private ViewerActivity mViewerActivity;
 
     static {
         System.loadLibrary("skia_android");
@@ -38,4 +39,20 @@ public class ViewerApplication extends Application {
     public long getNativeHandle() {
         return mNativeHandle;
     }
+
+    public void setViewerActivity(ViewerActivity viewerActivity) {
+        this.mViewerActivity = viewerActivity;
+    }
+
+    public void setTitle(String title) {
+        final String finalTitle = title;
+        if (mViewerActivity != null) {
+            mViewerActivity.runOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    mViewerActivity.setTitle(finalTitle);
+                }
+            });
+        }
+    }
 }
index 0156ea1..f16e567 100644 (file)
@@ -38,8 +38,7 @@ const DisplayParams& Window_android::getDisplayParams() {
 }
 
 void Window_android::setTitle(const char* title) {
-    //todo
-    SkDebugf("Title: %s", title);
+    fSkiaAndroidApp->setTitle(title);
 }
 
 bool Window_android::attach(BackEndType attachType, const DisplayParams& params) {
index acee839..3d8617f 100644 (file)
@@ -31,14 +31,17 @@ static const std::unordered_map<int, Window::Key> ANDROID_TO_WINDOW_KEYMAP({
     {AKEYCODE_SOFT_RIGHT, Window::Key::kRight}
 });
 
-void* pthread_main(void* arg);
-
-SkiaAndroidApp::SkiaAndroidApp() {
+SkiaAndroidApp::SkiaAndroidApp(JNIEnv* env, jobject androidApp) {
+    env->GetJavaVM(&fJavaVM);
+    fAndroidApp = env->NewGlobalRef(androidApp);
+    jclass cls = env->GetObjectClass(fAndroidApp);
+    fSetTitleMethodID = env->GetMethodID(cls, "setTitle", "(Ljava/lang/String;)V");
     fNativeWindow = nullptr;
     pthread_create(&fThread, nullptr, pthread_main, this);
 }
 
 SkiaAndroidApp::~SkiaAndroidApp() {
+    fPThreadEnv->DeleteGlobalRef(fAndroidApp);
     if (fWindow) {
         fWindow->detach();
     }
@@ -51,23 +54,29 @@ SkiaAndroidApp::~SkiaAndroidApp() {
     }
 }
 
+void SkiaAndroidApp::setTitle(const char* title) const {
+    jstring titleString = fPThreadEnv->NewStringUTF(title);
+    fPThreadEnv->CallVoidMethod(fAndroidApp, fSetTitleMethodID, titleString);
+    fPThreadEnv->DeleteLocalRef(titleString);
+}
+
 void SkiaAndroidApp::paintIfNeeded() {
     if (fNativeWindow && fWindow) {
         fWindow->onPaint();
     }
 }
 
-void SkiaAndroidApp::postMessage(const Message& message) {
+void SkiaAndroidApp::postMessage(const Message& message) const {
     auto writeSize = write(fPipes[1], &message, sizeof(message));
     SkASSERT(writeSize == sizeof(message));
 }
 
-void SkiaAndroidApp::readMessage(Message* message) {
+void SkiaAndroidApp::readMessage(Message* message) const {
     auto readSize = read(fPipes[0], message, sizeof(Message));
     SkASSERT(readSize == sizeof(Message));
 }
 
-static int message_callback(int fd, int events, void* data) {
+int SkiaAndroidApp::message_callback(int fd, int events, void* data) {
     auto skiaAndroidApp = (SkiaAndroidApp*)data;
     Message message;
     skiaAndroidApp->readMessage(&message);
@@ -127,11 +136,14 @@ static int message_callback(int fd, int events, void* data) {
     return 1;  // continue receiving callbacks
 }
 
-void* pthread_main(void* arg) {
+void* SkiaAndroidApp::pthread_main(void* arg) {
     SkDebugf("pthread_main begins");
 
     auto skiaAndroidApp = (SkiaAndroidApp*)arg;
 
+    // Because JNIEnv is thread sensitive, we need AttachCurrentThread to set our fPThreadEnv
+    skiaAndroidApp->fJavaVM->AttachCurrentThread(&(skiaAndroidApp->fPThreadEnv), nullptr);
+
     ALooper* looper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS);
     pipe(skiaAndroidApp->fPipes);
     ALooper_addFd(looper, skiaAndroidApp->fPipes[0], LOOPER_ID_MESSAGEPIPE, ALOOPER_EVENT_INPUT,
@@ -152,13 +164,13 @@ void* pthread_main(void* arg) {
 
 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;
+    Java_org_skia_viewer_ViewerApplication_createNativeApp(JNIEnv* env, jobject application) {
+    SkiaAndroidApp* skiaAndroidApp = new SkiaAndroidApp(env, application);
     return (jlong)((size_t)skiaAndroidApp);
 }
 
 extern "C" JNIEXPORT void JNICALL Java_org_skia_viewer_ViewerApplication_destroyNativeApp(
-    JNIEnv* env, jobject activity, jlong handle) {
+    JNIEnv* env, jobject application, jlong handle) {
     auto skiaAndroidApp = (SkiaAndroidApp*)handle;
     skiaAndroidApp->postMessage(Message(kDestroyApp));
 }
index 2961122..1ce0667 100644 (file)
@@ -37,19 +37,31 @@ struct Message {
 };
 
 struct SkiaAndroidApp {
-    int fPipes[2];  // 0 is the read message pipe, 1 is the write message pipe
     Application* fApp;
     Window* fWindow;
-    ANativeWindow* fNativeWindow;
+    jobject fAndroidApp;
 
-    SkiaAndroidApp();
-    ~SkiaAndroidApp();
-    void postMessage(const Message& message);
-    void readMessage(Message* message);
+    SkiaAndroidApp(JNIEnv* env, jobject androidApp);
+
+    void postMessage(const Message& message) const;
+    void readMessage(Message* message) const;
     void paintIfNeeded();
 
+    // This must be called in SkiaAndroidApp's own pthread because the JNIEnv is thread sensitive
+    void setTitle(const char* title) const;
 private:
     pthread_t fThread;
+    ANativeWindow* fNativeWindow;
+    int fPipes[2];  // 0 is the read message pipe, 1 is the write message pipe
+    JavaVM* fJavaVM;
+    JNIEnv* fPThreadEnv;
+    jmethodID fSetTitleMethodID;
+
+    // This must be called in SkiaAndroidApp's own pthread because the JNIEnv is thread sensitive
+    ~SkiaAndroidApp();
+
+    static int message_callback(int fd, int events, void* data);
+    static void* pthread_main(void*);
 };
 
 }  // namespace sk_app