From: Alexis Laferrière Date: Thu, 18 Feb 2016 04:08:17 +0000 (-0500) Subject: lib/android: intro service support X-Git-Url: http://nitlanguage.org lib/android: intro service support Signed-off-by: Alexis Laferrière --- diff --git a/lib/android/service/NitService.java b/lib/android/service/NitService.java new file mode 100644 index 0000000..6603b8e --- /dev/null +++ b/lib/android/service/NitService.java @@ -0,0 +1,58 @@ +/* This file is part of NIT ( http://www.nitlanguage.org ). + * + * 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. + */ + +package nit.app; + +import android.app.Service; +import android.content.Intent; +import android.os.IBinder; + +// Service implemented in Nit +public class NitService extends Service { + + protected int nitService = 0; + + static { + System.loadLibrary("main"); + } + + @Override + public int onStartCommand(Intent intent, int flags, int id) { + return nitOnStartCommand(nitService, intent, flags, id); + } + + @Override + public void onCreate() { + nitService = nitNewService(); + nitOnCreate(nitService); + super.onCreate(); + } + + @Override + public void onDestroy() { + nitOnDestroy(nitService); + super.onDestroy(); + } + + @Override + public IBinder onBind(Intent arg) { + return null; + } + + protected native int nitNewService(); + protected native int nitOnStartCommand(int nitService, Intent intent, int flags, int id); + protected native void nitOnCreate(int nitService); + protected native void nitOnDestroy(int nitService); +} diff --git a/lib/android/service/service.nit b/lib/android/service/service.nit new file mode 100644 index 0000000..b27bdac --- /dev/null +++ b/lib/android/service/service.nit @@ -0,0 +1,159 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# 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. + +# Android service support for _app.nit_ centered around the class `Service` +module service is + extra_java_files "NitService.java" + android_manifest_application """""" +end + +import android::nit_activity + +in "C" `{ + // Nit's App running instance, declared in `nit_activity` + extern App global_app; + + JNIEXPORT jint JNICALL Java_nit_app_NitService_nitNewService + (JNIEnv *env, jobject java_service) + { + // Pin a ref to the Java service in the Java GC + java_service = (*env)->NewGlobalRef(env, java_service); + + // Create the service in Nit and pin it in the Nit GC + Service nit_service = App_register_service(global_app, java_service); + + // FIXME replace the previous call to register_service by + // the following line when #1941 is fixed: + //Service nit_service = new_Service(java_service); + + Service_incr_ref(nit_service); + + return (jint)(void*)nit_service; + } + + JNIEXPORT jint JNICALL Java_nit_app_NitService_nitOnStartCommand + (JNIEnv *env, jobject java_service, jint nit_service, jobject intent, jint flags, jint id) + { + return Service_on_start_command((Service)nit_service, intent, flags, id); + } + + JNIEXPORT void JNICALL Java_nit_app_NitService_nitOnCreate + (JNIEnv *env, jobject java_service, jint nit_service) + { + Service_on_create((Service)nit_service); + } + + JNIEXPORT void JNICALL Java_nit_app_NitService_nitOnDestroy + (JNIEnv *env, jobject java_service, jint nit_service) + { + Service_on_destroy((Service)nit_service); + + // Unpin the service instances in both Nit and Java + java_service = Service_native((Service)nit_service); + (*env)->DeleteGlobalRef(env, java_service); + Service_decr_ref(nit_service); + } +`} + +redef class App + + # Current instance of `Service`, if any + var service: nullable Service = null + + # Launch `Service` in the background, it will be set as `service` when ready + fun start_service do native_context.start_service + + # Register a service from Java/C + # + # FIXME remove when #1941 is fixed + private fun register_service(java_service: NativeService): Service + do + return new Service(java_service.new_global_ref) + end + + # Prioritize an activity context if one is running, fallback on a service + redef fun native_context + do + if activities.not_empty then return super + + var service = service + assert service != null + return service.native + end + + # Dummy method to force the compilation of callbacks from C + # + # The callbacks are used in the launch of a Nit service from C code. + private fun force_service_callbacks_in_c import Service, register_service, + Service.on_start_command, Service.on_create, Service.on_destroy, Service.native `{ `} + + redef fun setup + do + super + + # Call the dummy method to force their compilation in global compilation + force_service_callbacks_in_c + end +end + +# Android service with its life-cycle callbacks +class Service + # Java service with the Android context of this service + var native: NativeService + + # The service has been created + fun on_create do app.service = self + + # The service received a start command (may happen more then once per service) + # + # Should return either `start_sticky`, `start_not_sticky` or `start_redeliver_intent`. + fun on_start_command(intent: JavaObject, flags, id: Int): Int do return start_sticky + + # The service is being destroyed + fun on_destroy do app.service = null +end + +# Wrapper of Java class `android.app.Service` +extern class NativeService in "Java" `{ android.app.Service `} + super NativeContext + + redef fun new_global_ref import sys, Sys.jni_env `{ + Sys sys = NativeService_sys(self); + JNIEnv *env = Sys_jni_env(sys); + return (*env)->NewGlobalRef(env, self); + `} +end + +redef class NativeContext + private fun start_service in "Java" `{ + android.content.Intent indent = + new android.content.Intent(self, nit.app.NitService.class); + self.startService(intent); + `} +end + +# The service is explicitly started and stopped, it is restarted if stopped by the system +# +# Return value of `Service::on_start_command`. +fun start_sticky: Int in "Java" `{ return android.app.Service.START_STICKY; `} + +# The service may be stopped by the system and will not be restarted +# +# Return value of `Service::on_start_command`. +fun start_not_sticky: Int in "Java" `{ return android.app.Service.START_NOT_STICKY; `} + +# The service is explicitly started and stopped, it is restarted with the last intent if stopped by the system +# +# Return value of `Service::on_start_command`. +fun start_redeliver_intent: Int in "Java" `{ return android.app.Service.START_REDELIVER_INTENT; `}