1
0
mirror of https://gitlab.com/comunic/comunicmobile synced 2024-11-25 22:39:22 +00:00

Create a service

This commit is contained in:
Pierre HUBERT 2021-04-14 18:03:27 +02:00
parent 0af31bc3a0
commit bf53babf53
8 changed files with 206 additions and 12 deletions

View File

@ -48,7 +48,6 @@ android {
} }
defaultConfig { defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "org.communiquons.comunic" applicationId "org.communiquons.comunic"
minSdkVersion 21 minSdkVersion 21
targetSdkVersion 30 targetSdkVersion 30

View File

@ -15,6 +15,11 @@
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" /> <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" /> <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<!-- This is required for independent push notifications service to work
(when FCM service can not be used) -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<!-- This is required on Android 11+ for image picker --> <!-- This is required on Android 11+ for image picker -->
<queries> <queries>
<intent> <intent>
@ -26,9 +31,6 @@
</intent> </intent>
</queries> </queries>
<!-- This is required for independent push notifications service to work
(when FCM service can not be used) -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<!-- io.flutter.app.FlutterApplication is an android.app.Application that <!-- io.flutter.app.FlutterApplication is an android.app.Application that
calls FlutterMain.startInitialization(this); in its onCreate method. calls FlutterMain.startInitialization(this); in its onCreate method.
@ -79,5 +81,18 @@
android:name="com.yalantis.ucrop.UCropActivity" android:name="com.yalantis.ucrop.UCropActivity"
android:screenOrientation="portrait" android:screenOrientation="portrait"
android:theme="@style/Theme.AppCompat.Light.NoActionBar" /> android:theme="@style/Theme.AppCompat.Light.NoActionBar" />
<!-- Independent push notifications service -->
<service android:name=".independentnotifications.NotificationsService" />
<!-- Boot receiver to start independent push notifications service -->
<receiver android:name=".BootReceiver"
android:enabled="true"
android:exported="false">
<intent-filter>
<!-- Cold boot -->
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</receiver>
</application> </application>
</manifest> </manifest>

View File

@ -0,0 +1,24 @@
package org.communiquons.comunic;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import org.communiquons.comunic.independentnotifications.NotificationsService;
public class BootReceiver extends BroadcastReceiver {
private static final String TAG = BootReceiver.class.getSimpleName();
@Override
public void onReceive(Context context, Intent intent) {
if (intent == null || !intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
Log.e(TAG, "Invalid call to intent!");
return;
}
Log.v(TAG, "Boot received, starting independent push notifications service if required...");
NotificationsService.startService(context);
}
}

View File

@ -12,6 +12,7 @@ import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel; import io.flutter.plugin.common.MethodChannel;
public class NotificationsChannel implements MethodChannel.MethodCallHandler { public class NotificationsChannel implements MethodChannel.MethodCallHandler {
private final Context context; private final Context context;
public NotificationsChannel(Activity context) { public NotificationsChannel(Activity context) {
@ -21,14 +22,27 @@ public class NotificationsChannel implements MethodChannel.MethodCallHandler {
@Override @Override
public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) { public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
try { try {
if (call.method.equals("needPreConfiguration")) switch (call.method) {
case "needPreConfiguration":
result.success(needPreConfiguration()); result.success(needPreConfiguration());
break;
else if (call.method.equals("preConfigure")) case "preConfigure":
preConfigure(result); preConfigure(result);
break;
else case "configure":
configure((String) call.arguments, result);
break;
case "disable":
disable(result);
break;
default:
result.notImplemented(); result.notImplemented();
break;
}
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
result.error("Failed to execute native code!", e.getMessage(), null); result.error("Failed to execute native code!", e.getMessage(), null);
@ -60,4 +74,21 @@ public class NotificationsChannel implements MethodChannel.MethodCallHandler {
result.success(null); result.success(null);
} }
/**
* Configure Independent Push Notifications service
*
* @param wsURL The URL this service will have to connect to
*/
private void configure(@NonNull String wsURL, @NonNull MethodChannel.Result result) {
NotificationsService.configure(wsURL, context);
result.success(null);
}
/**
* Disable push notifications service
*/
private void disable(@NonNull MethodChannel.Result result) {
NotificationsService.disable(context);
result.success(null);
}
} }

View File

@ -0,0 +1,107 @@
package org.communiquons.comunic.independentnotifications;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Build;
import android.os.IBinder;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.app.NotificationCompat;
import androidx.core.content.ContextCompat;
import org.communiquons.comunic.MainActivity;
import org.communiquons.comunic.R;
public class NotificationsService extends Service {
public static final String CHANNEL_ID = "IndependentPushServiceChannel";
private static final String INDEPENDENT_PUSH_NOTIFICATIONS_SERVICE = "independent-push-notifications-service";
private static final String WS_URL_PREF_KEY = "ws_url";
public static void configure(@NonNull String wsURL, @NonNull Context context) {
SharedPreferences prefs = context.getSharedPreferences(INDEPENDENT_PUSH_NOTIFICATIONS_SERVICE, MODE_PRIVATE);
if (prefs.getString(WS_URL_PREF_KEY, "").equals(wsURL))
return;
stopService(context);
prefs.edit().putString(WS_URL_PREF_KEY, wsURL).apply();
startService(context);
}
public static void disable(@NonNull Context context) {
SharedPreferences prefs = context.getSharedPreferences(INDEPENDENT_PUSH_NOTIFICATIONS_SERVICE, MODE_PRIVATE);
prefs.edit().remove(WS_URL_PREF_KEY).apply();
stopService(context);
}
public static void stopService(@NonNull Context context) {
Intent serviceIntent = new Intent(context, NotificationsService.class);
context.stopService(serviceIntent);
}
public static void startService(@NonNull Context context) {
SharedPreferences prefs = context.getSharedPreferences(INDEPENDENT_PUSH_NOTIFICATIONS_SERVICE, MODE_PRIVATE);
if (!prefs.contains(WS_URL_PREF_KEY)) {
System.err.println("Independent push notifications service not configured ! Skipping!");
return;
}
Intent intent = new Intent(context, NotificationsService.class);
ContextCompat.startForegroundService(context, intent);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
createNotificationChannel();
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this,
0, notificationIntent, 0);
Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("Comunic")
.setContentText(getText(R.string.independent_push_notification_notification_text))
.setSmallIcon(R.drawable.splash_icon)
.setContentIntent(pendingIntent)
.build();
startForeground(1, notification);
initService();
return START_STICKY;
}
private void createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel serviceChannel = new NotificationChannel(
CHANNEL_ID,
"Foreground Service Channel",
NotificationManager.IMPORTANCE_DEFAULT
);
NotificationManager manager = getSystemService(NotificationManager.class);
manager.createNotificationChannel(serviceChannel);
}
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
private void initService() {
String url = getSharedPreferences(INDEPENDENT_PUSH_NOTIFICATIONS_SERVICE, MODE_PRIVATE)
.getString(WS_URL_PREF_KEY, null);
System.out.println("START HEAVY WORK HERE !!!!");
System.out.println("Connect to " + url);
}
}

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="independent_push_notification_notification_text">Push notifications service is running</string>
</resources>

View File

@ -26,4 +26,14 @@ class IndependentPushNotificationsHelper {
await platform.invokeMethod("preConfigure"); await platform.invokeMethod("preConfigure");
} }
/// Configure independent push notification services with a pull URL
static Future<void> configure(String wsURL) async {
await platform.invokeMethod("configure", wsURL);
}
/// Disable independent push notifications service
static Future<void> disable() async {
await platform.invokeMethod("disable");
}
} }

View File

@ -1,3 +1,4 @@
import 'package:comunic/helpers/independent_push_notifications_helper.dart';
import 'package:comunic/helpers/preferences_helper.dart'; import 'package:comunic/helpers/preferences_helper.dart';
import 'package:comunic/helpers/server_config_helper.dart'; import 'package:comunic/helpers/server_config_helper.dart';
import 'package:comunic/models/api_request.dart'; import 'package:comunic/models/api_request.dart';
@ -39,7 +40,9 @@ class PushNotificationsHelper {
if (status == null) status = PushNotificationsStatus.UNDEFINED; if (status == null) status = PushNotificationsStatus.UNDEFINED;
if (status == PushNotificationsStatus.INDEPENDENT) { if (status == PushNotificationsStatus.INDEPENDENT) {
// TODO : Invoke plugin to apply new WebSocket URL // Invoke plugin to apply new WebSocket URL
await IndependentPushNotificationsHelper.configure(
response["independent_push_url"]);
} }
await (await PreferencesHelper.getInstance()).setString( await (await PreferencesHelper.getInstance()).setString(
@ -51,7 +54,8 @@ class PushNotificationsHelper {
await (await PreferencesHelper.getInstance()) await (await PreferencesHelper.getInstance())
.removeKey(PreferencesKeyList.PUSH_NOTIFICATIONS_STATUS); .removeKey(PreferencesKeyList.PUSH_NOTIFICATIONS_STATUS);
// TODO : stop local refresh notification refresh // Stop local refresh notification refresh
IndependentPushNotificationsHelper.disable();
} }
/// Set new push notification status on the server /// Set new push notification status on the server