Merge: Prepare for the android UI module
authorJean Privat <jean@pryen.org>
Tue, 25 Nov 2014 01:02:21 +0000 (20:02 -0500)
committerJean Privat <jean@pryen.org>
Tue, 25 Nov 2014 01:02:21 +0000 (20:02 -0500)
* Not all pthreads features are supported on Android, thus the changes.
* Changing the `data_store` signature is enough to support nulls because the APIs of both underlying implementations already supported them.
* Declaring the lines for <activity> in the modules allows for non-fullscreen and non-orientation-locked apps!

Pull-Request: #927
Reviewed-by: Alexandre Terrasa <alexandre@moz-code.org>
Reviewed-by: Jean Privat <jean@pryen.org>

lib/android/platform.nit
lib/app/data_store.nit
lib/mnit_android/android_app.nit
lib/pthreads/extra.nit [new file with mode: 0644]
lib/pthreads/pthreads.nit
src/compiler/android_annotations.nit
src/compiler/android_platform.nit

index dab001d..fca03e0 100644 (file)
@@ -21,6 +21,8 @@ module platform is
        new_annotation max_api_version
        new_annotation target_api_version
        new_annotation android_manifest
+       new_annotation android_manifest_application
+       new_annotation android_manifest_activity
 end
 
 import java
index afb6a1d..13891fc 100644 (file)
@@ -34,5 +34,5 @@ interface DataStore
        fun [](key: String): nullable Object is abstract
 
        # Store `value` at `key`
-       fun []=(key: String, value: Serializable) is abstract
+       fun []=(key: String, value: nullable Serializable) is abstract
 end
index 725c612..87afb4a 100644 (file)
 # limitations under the License.
 
 # Impements the services of `mnit:app` using the API from the Android ndk
-module android_app
+module android_app is
+       android_manifest_activity """
+               android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
+               android:configChanges="orientation|keyboardHidden"
+               android:screenOrientation="portrait""""
+end
 
 import mnit
 import android
diff --git a/lib/pthreads/extra.nit b/lib/pthreads/extra.nit
new file mode 100644 (file)
index 0000000..416b174
--- /dev/null
@@ -0,0 +1,62 @@
+# This file is part of NIT (http://www.nitlanguage.org).
+#
+# Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# 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.
+
+# Offers some POSIX threads services that are not available on all platforms
+module extra is
+       c_compiler_option("-pthread")
+       c_linker_option("-pthread")
+end
+
+intrude import pthreads
+
+in "C" `{
+       // TODO protect with: #ifdef WITH_LIBGC
+       #ifndef ANDROID
+               #define GC_THREADS
+               #include <gc.h>
+       #endif
+`}
+
+redef extern class NativePthread
+       fun cancel: Bool `{
+               return pthread_cancel(*recv);
+       `}
+end
+
+redef class Thread
+       # Cancel the execution of the thread
+       fun cancel
+       do
+               if native == null then return
+               native.cancel
+               native = null
+       end
+end
+
+# Does not return if the running thread is to be cancelled
+fun test_cancel `{ pthread_testcancel(); `}
+
+private extern class NativePthreadBarrier in "C" `{ pthread_barrier_t * `}
+       new(count: Int) `{
+               pthread_barrier_t *barrier = malloc(sizeof(pthread_barrier_t));
+               int res = pthread_barrier_init(barrier, NULL, count);
+               return barrier;
+       `}
+
+       fun destroy `{ pthread_barrier_destroy(recv); `}
+
+       fun wait `{ pthread_barrier_wait(recv); `}
+end
index 1e76e28..94cf078 100644 (file)
@@ -34,9 +34,10 @@ in "C" `{
        // TODO protect with: #ifdef WITH_LIBGC
        // We might have to add the next line to gc_chooser.c too, especially
        // if we get an error like "thread not registered with GC".
+       #ifndef ANDROID
                #define GC_THREADS
                #include <gc.h>
-       //#endif
+       #endif
 `}
 
 redef class Sys
@@ -114,10 +115,6 @@ private extern class NativePthread in "C" `{ pthread_t * `}
                return (nullable_Object)thread_return;
        `}
 
-       fun cancel: Bool `{
-               return pthread_cancel(*recv);
-       `}
-
        fun attr: NativePthreadAttr `{
                pthread_attr_t *pattr = malloc(sizeof(pthread_attr_t));
                pthread_getattr_np(*recv, pattr);
@@ -192,18 +189,6 @@ private extern class NativePthreadMutexAttr in "C" `{ pthread_mutexattr_t * `}
        # pthread_mutexattr_setrobust_np
 end
 
-private extern class NativePthreadBarrier in "C" `{ pthread_barrier_t * `}
-       new(count: Int) `{
-               pthread_barrier_t *barrier = malloc(sizeof(pthread_barrier_t));
-               int res = pthread_barrier_init(barrier, NULL, count);
-               return barrier;
-       `}
-
-       fun destroy `{ pthread_barrier_destroy(recv); `}
-
-       fun wait `{ pthread_barrier_wait(recv); `}
-end
-
 private extern class NativePthreadKey in "C" `{ pthread_key_t * `}
        new `{
                pthread_key_t *key = malloc(sizeof(pthread_key_t));
@@ -222,6 +207,27 @@ private extern class NativePthreadKey in "C" `{ pthread_key_t * `}
        `}
 end
 
+private extern class NativePthreadCond in "C" `{ pthread_cond_t * `}
+       new `{
+               pthread_cond_t cond;
+               int r = pthread_cond_init(&cond, NULL);
+               if (r == 0) {
+                       pthread_cond_t *pcond = malloc(sizeof(pthread_cond_t));
+                       memmove(pcond, &cond, sizeof(pthread_cond_t));
+                       return pcond;
+               }
+               return NULL;
+       `}
+
+       fun destroy `{ pthread_cond_destroy(recv); `}
+
+       fun signal `{ pthread_cond_signal(recv); `}
+
+       fun broadcast `{ pthread_cond_broadcast(recv);  `}
+
+       fun wait(mutex: NativePthreadMutex) `{ pthread_cond_wait(recv, mutex); `}
+end
+
 #
 ## Nity part
 #
@@ -272,14 +278,6 @@ abstract class Thread
                return r
        end
 
-       # Cancel the execution of the thread
-       fun cancel
-       do
-               if native == null then return
-               native.cancel
-               native = null
-       end
-
        redef fun finalize
        do
                if native == null then return
@@ -298,9 +296,6 @@ end
 # Exit current thread and return `value` to caller of `Thread::join`
 fun exit_thread(value: nullable Object) `{ pthread_exit(value); `}
 
-# Does not return if the running thread is to be cancelled
-fun test_cancel `{ pthread_testcancel(); `}
-
 # Returns the handle to the running `Thread`
 fun thread: Thread
 do
@@ -364,24 +359,36 @@ end
 class Barrier
        super Finalizable
 
+       private var mutex = new Mutex
+       private var cond: nullable NativePthreadCond = new NativePthreadCond
+
        # Number of threads that must be waiting for `wait` to unblock
        var count: Int
 
-       private var native: nullable NativePthreadBarrier is noinit
-
-       init do native = new NativePthreadBarrier(count)
+       private var threads_waiting = 0
 
        # Wait at this barrier and block until there are a `count` threads waiting
-       fun wait do native.wait
+       fun wait
+       do
+               mutex.lock
+               threads_waiting += 1
+               if threads_waiting == count then
+                       threads_waiting = 0
+                       cond.broadcast
+               else
+                       cond.wait(mutex.native.as(not null))
+               end
+               mutex.unlock
+       end
 
        redef fun finalize
        do
-               var native = self.native
-               if native != null then
-                       native.destroy
-                       native.free
+               var cond = self.cond
+               if cond != null then
+                       cond.destroy
+                       cond.free
                end
-               self.native = null
+               self.cond = null
        end
 end
 
index cc24d6e..ad34b9a 100644 (file)
@@ -44,6 +44,9 @@ class AndroidProject
        # Custom lines to add to the AndroidManifest.xml in the <application> node
        var manifest_application_lines = new Array[String]
 
+       # Custom lines to add to AndroidManifest.xml as attributes inside the <activity> node
+       var manifest_activity_attributes = new Array[String]
+
        # Minimum API level required for the application to run
        var min_api: nullable Int = null
 
@@ -107,6 +110,9 @@ redef class ModelBuilder
                annots = collect_annotations_on_modules("android_manifest_application", mmodule)
                for an in annots do project.manifest_application_lines.add an.arg_as_string(self) or else ""
 
+               annots = collect_annotations_on_modules("android_manifest_activity", mmodule)
+               for an in annots do project.manifest_activity_attributes.add an.arg_as_string(self) or else ""
+
                # Get the date and time (down to the minute) as string
                var local_time = new Tm.localtime
                var local_time_s = local_time.strftime("%y%m%d%H%M")
index 55468fd..1cf6ba8 100644 (file)
@@ -124,10 +124,12 @@ class AndroidToolchain
 
                # Also copy over the java files
                dir = "{android_project_root}/src/"
-               var extra_java_files = compiler.mainmodule.extra_java_files
-               if extra_java_files != null then for file in extra_java_files do
-                       var path = file.filename
-                       path.file_copy_to("{dir}/{path.basename("")}")
+               for mmodule in compiler.mainmodule.in_importation.greaters do
+                       var extra_java_files = mmodule.extra_java_files
+                       if extra_java_files != null then for file in extra_java_files do
+                               var path = file.filename
+                               path.file_copy_to(dir/path.basename(""))
+                       end
                end
 
                ## Generate delagating makefile
@@ -178,13 +180,11 @@ $(call import-module,android/native_app_glue)
              This will take care of integrating with our NDK code. -->
         <activity android:name="android.app.NativeActivity"
                 android:label="@string/app_name"
-                android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
-                android:configChanges="orientation|keyboardHidden"
-                android:screenOrientation="portrait"
+                {{{project.manifest_activity_attributes.join("\n")}}}
                 {{{icon_declaration}}}>
-            <!-- Tell NativeActivity the name of or .so -->
-            <meta-data android:name=\"{{{app_package}}}\"
-                    android:value=\"{{{app_name}}}\" />
+            <!-- Tell NativeActivity the name of our .so -->
+            <meta-data android:name=\"android.app.lib_name\"
+                    android:value=\"main\" />
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.LAUNCHER" />