901a0e2409d2c0a7f8a474eac8388af5877ad1cf
[nit.git] / lib / android / service / service.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 # Android service support for _app.nit_ centered around the class `Service`
16 module service is
17 extra_java_files "NitService.java"
18 android_manifest_application """<service android:name="nit.app.NitService"></service>"""
19 end
20
21 import android::nit_activity
22
23 in "C" `{
24 // Nit's App running instance, declared in `nit_activity`
25 extern App global_app;
26
27 JNIEXPORT jint JNICALL Java_nit_app_NitService_nitNewService
28 (JNIEnv *env, jobject java_service)
29 {
30 // Pin a ref to the Java service in the Java GC
31 java_service = (*env)->NewGlobalRef(env, java_service);
32
33 // Create the service in Nit and pin it in the Nit GC
34 Service nit_service = App_register_service(global_app, java_service);
35
36 // FIXME replace the previous call to register_service by
37 // the following line when #1941 is fixed:
38 //Service nit_service = new_Service(java_service);
39
40 Service_incr_ref(nit_service);
41
42 return (jint)(void*)nit_service;
43 }
44
45 JNIEXPORT jint JNICALL Java_nit_app_NitService_nitOnStartCommand
46 (JNIEnv *env, jobject java_service, jint nit_service, jobject intent, jint flags, jint id)
47 {
48 return Service_on_start_command((Service)nit_service, intent, flags, id);
49 }
50
51 JNIEXPORT void JNICALL Java_nit_app_NitService_nitOnCreate
52 (JNIEnv *env, jobject java_service, jint nit_service)
53 {
54 Service_on_create((Service)nit_service);
55 }
56
57 JNIEXPORT void JNICALL Java_nit_app_NitService_nitOnDestroy
58 (JNIEnv *env, jobject java_service, jint nit_service)
59 {
60 Service_on_destroy((Service)nit_service);
61
62 // Unpin the service instances in both Nit and Java
63 java_service = Service_native((Service)nit_service);
64 (*env)->DeleteGlobalRef(env, java_service);
65 Service_decr_ref(nit_service);
66 }
67 `}
68
69 redef class App
70
71 # Current instance of `Service`, if any
72 var service: nullable Service = null
73
74 # Launch `Service` in the background, it will be set as `service` when ready
75 fun start_service do native_context.start_service
76
77 # Register a service from Java/C
78 #
79 # FIXME remove when #1941 is fixed
80 private fun register_service(java_service: NativeService): Service
81 do
82 return new Service(java_service.new_global_ref)
83 end
84
85 # Prioritize an activity context if one is running, fallback on a service
86 redef fun native_context
87 do
88 if activities.not_empty then return super
89
90 var service = service
91 assert service != null
92 return service.native
93 end
94
95 # Dummy method to force the compilation of callbacks from C
96 #
97 # The callbacks are used in the launch of a Nit service from C code.
98 private fun force_service_callbacks_in_c import Service, register_service,
99 Service.on_start_command, Service.on_create, Service.on_destroy, Service.native `{ `}
100
101 redef fun setup
102 do
103 super
104
105 # Call the dummy method to force their compilation in global compilation
106 force_service_callbacks_in_c
107 end
108 end
109
110 # Android service with its life-cycle callbacks
111 class Service
112 # Java service with the Android context of this service
113 var native: NativeService
114
115 # The service has been created
116 fun on_create do app.service = self
117
118 # The service received a start command (may happen more then once per service)
119 #
120 # Should return either `start_sticky`, `start_not_sticky` or `start_redeliver_intent`.
121 fun on_start_command(intent: JavaObject, flags, id: Int): Int do return start_sticky
122
123 # The service is being destroyed
124 fun on_destroy do app.service = null
125 end
126
127 # Wrapper of Java class `android.app.Service`
128 extern class NativeService in "Java" `{ android.app.Service `}
129 super NativeContext
130
131 redef fun new_global_ref import sys, Sys.jni_env `{
132 Sys sys = NativeService_sys(self);
133 JNIEnv *env = Sys_jni_env(sys);
134 return (*env)->NewGlobalRef(env, self);
135 `}
136 end
137
138 redef class NativeContext
139 private fun start_service in "Java" `{
140 android.content.Intent intent =
141 new android.content.Intent(self, nit.app.NitService.class);
142 self.startService(intent);
143 `}
144 end
145
146 # The service is explicitly started and stopped, it is restarted if stopped by the system
147 #
148 # Return value of `Service::on_start_command`.
149 fun start_sticky: Int in "Java" `{ return android.app.Service.START_STICKY; `}
150
151 # The service may be stopped by the system and will not be restarted
152 #
153 # Return value of `Service::on_start_command`.
154 fun start_not_sticky: Int in "Java" `{ return android.app.Service.START_NOT_STICKY; `}
155
156 # The service is explicitly started and stopped, it is restarted with the last intent if stopped by the system
157 #
158 # Return value of `Service::on_start_command`.
159 fun start_redeliver_intent: Int in "Java" `{ return android.app.Service.START_REDELIVER_INTENT; `}