Commit dfc34fbb authored by Nicolas Richard Walter Boeckh's avatar Nicolas Richard Walter Boeckh 💬
Browse files

Added Kotlin Wake Service Code, needs dart integration and rigorous testing

parent 52eb7efe
{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"battery","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\battery-0.3.1+7\\\\","dependencies":[]},{"name":"geolocator","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\geolocator-5.2.1\\\\","dependencies":["google_api_availability","location_permissions"]},{"name":"google_api_availability","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\google_api_availability-2.0.2\\\\","dependencies":[]},{"name":"location_permissions","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\location_permissions-2.0.4+1\\\\","dependencies":[]},{"name":"path_provider","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\path_provider-1.6.0\\\\","dependencies":[]},{"name":"permission_handler","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\permission_handler-4.2.0+hotfix.3\\\\","dependencies":[]},{"name":"plugin_scaffold","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\plugin_scaffold-1.2.0\\\\","dependencies":[]},{"name":"rx_ble","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\rx_ble-0.6.1\\\\","dependencies":["plugin_scaffold"]},{"name":"sqflite","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\sqflite-1.2.0\\\\","dependencies":[]}],"android":[{"name":"battery","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\battery-0.3.1+7\\\\","dependencies":[]},{"name":"geolocator","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\geolocator-5.2.1\\\\","dependencies":["google_api_availability","location_permissions"]},{"name":"google_api_availability","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\google_api_availability-2.0.2\\\\","dependencies":[]},{"name":"location_permissions","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\location_permissions-2.0.4+1\\\\","dependencies":[]},{"name":"path_provider","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\path_provider-1.6.0\\\\","dependencies":[]},{"name":"permission_handler","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\permission_handler-4.2.0+hotfix.3\\\\","dependencies":[]},{"name":"plugin_scaffold","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\plugin_scaffold-1.2.0\\\\","dependencies":[]},{"name":"rx_ble","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\rx_ble-0.6.1\\\\","dependencies":["plugin_scaffold"]},{"name":"sqflite","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\sqflite-1.2.0\\\\","dependencies":[]}],"macos":[{"name":"sqflite","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\sqflite-1.2.0\\\\","dependencies":[]}],"linux":[],"windows":[],"web":[]},"dependencyGraph":[{"name":"battery","dependencies":[]},{"name":"geolocator","dependencies":["google_api_availability","location_permissions"]},{"name":"google_api_availability","dependencies":[]},{"name":"location_permissions","dependencies":[]},{"name":"path_provider","dependencies":[]},{"name":"permission_handler","dependencies":[]},{"name":"plugin_scaffold","dependencies":[]},{"name":"rx_ble","dependencies":["plugin_scaffold"]},{"name":"sqflite","dependencies":[]}],"date_created":"2020-02-07 07:07:12.872699","version":"1.14.7-pre.83"}
\ No newline at end of file
{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"battery","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\battery-0.3.1+7\\\\","dependencies":[]},{"name":"geolocator","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\geolocator-5.2.1\\\\","dependencies":["google_api_availability","location_permissions"]},{"name":"google_api_availability","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\google_api_availability-2.0.2\\\\","dependencies":[]},{"name":"location_permissions","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\location_permissions-2.0.4+1\\\\","dependencies":[]},{"name":"path_provider","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\path_provider-1.6.0\\\\","dependencies":[]},{"name":"permission_handler","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\permission_handler-4.2.0+hotfix.3\\\\","dependencies":[]},{"name":"plugin_scaffold","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\plugin_scaffold-1.2.0\\\\","dependencies":[]},{"name":"rx_ble","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\rx_ble-0.6.1\\\\","dependencies":["plugin_scaffold"]},{"name":"sqflite","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\sqflite-1.2.0\\\\","dependencies":[]}],"android":[{"name":"battery","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\battery-0.3.1+7\\\\","dependencies":[]},{"name":"geolocator","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\geolocator-5.2.1\\\\","dependencies":["google_api_availability","location_permissions"]},{"name":"google_api_availability","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\google_api_availability-2.0.2\\\\","dependencies":[]},{"name":"location_permissions","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\location_permissions-2.0.4+1\\\\","dependencies":[]},{"name":"path_provider","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\path_provider-1.6.0\\\\","dependencies":[]},{"name":"permission_handler","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\permission_handler-4.2.0+hotfix.3\\\\","dependencies":[]},{"name":"plugin_scaffold","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\plugin_scaffold-1.2.0\\\\","dependencies":[]},{"name":"rx_ble","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\rx_ble-0.6.1\\\\","dependencies":["plugin_scaffold"]},{"name":"sqflite","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\sqflite-1.2.0\\\\","dependencies":[]}],"macos":[{"name":"sqflite","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\sqflite-1.2.0\\\\","dependencies":[]}],"linux":[],"windows":[],"web":[]},"dependencyGraph":[{"name":"battery","dependencies":[]},{"name":"geolocator","dependencies":["google_api_availability","location_permissions"]},{"name":"google_api_availability","dependencies":[]},{"name":"location_permissions","dependencies":[]},{"name":"path_provider","dependencies":[]},{"name":"permission_handler","dependencies":[]},{"name":"plugin_scaffold","dependencies":[]},{"name":"rx_ble","dependencies":["plugin_scaffold"]},{"name":"sqflite","dependencies":[]}],"date_created":"2020-02-10 16:34:46.591794","version":"1.14.7-pre.83"}
\ No newline at end of file
# Collection of thoughts and general development process.
# Collection of thoughts and general development process
## [0.0.2] - current
......@@ -25,6 +25,8 @@ Bluetooth should have at least a few tasks (discovery -> pump all MAC's and disp
Thought of firmware implementation for obfuscation / integrity verification. See issue [here](https://gitlab.unige.ch/Nicolas.Boeckh/la_app_xos/issues/4).
Other option for making the service run in background: make the platform side tick once per second and notify the dart framework, may need to use a sticky notification as well.
### Resources
- [Permissions aaS](https://www.filledstacks.com/snippet/request-permissions-in-flutter-as-a-service/)
......
......@@ -23,6 +23,7 @@ if (flutterVersionName == null) {
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
android {
......
......@@ -12,6 +12,12 @@
android:label="logair_application"
android:icon="@mipmap/ic_launcher"
tools:replace="android:label">
<service
android:name=".WakeService"
android:enabled="true"
android:exported="false">
</service>
<activity
android:name=".MainActivity"
android:launchMode="singleTop"
......
package com.logair.logair_application
enum class Actions {
START,
STOP
}
\ No newline at end of file
package com.logair.logair_application;
class Channels {
companion object {
@JvmStatic val BATTERY_CHANNEL: String = "logair.application/battery";
@JvmStatic val BATTERY_CHARGE: String = "logair.aplication/battery_charge_status";
@JvmStatic val BLUETOOTH_CHANNEL: String = "logair.application/btle";
@JvmStatic val WAKE_CHANNEL: String = "logair.application/wake";
@JvmStatic val WAKE_CHANNEL_NOTIFICATION: String = "logair.application/wake_notification";
}
}
......@@ -14,13 +14,14 @@ import android.os.Build.VERSION
import android.os.Build.VERSION_CODES
import io.flutter.plugin.common.MethodChannel
class Channels {
val BATTERY_CHANNEL = "logair.application/battery";
val BATTERY_CHARGE = "logair.aplication/battery_charge_status";
val BLUETOOTH_CHANNEL = "logair.application/btle";
}
import android.os.Handler;
import java.util.Timer;
import java.util.TimerTask;
class MainActivity: FlutterActivity() {
val timer: Timer = Timer();
val handler: Handler = Handler();
class MainActivity: FlutterActivity() {
override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
GeneratedPluginRegistrant.registerWith(flutterEngine);
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, Channels.BATTERY_CHANNEL).setMethodCallHandler {
......@@ -34,9 +35,14 @@ class MainActivity: FlutterActivity() {
result.error("UNAVAILABLE", "Battery Level unavailable", null)
} else
result.notImplemented()
}
};
// Method Channel Dart to Platform : result is WakeService Starting
}
private fun startWakeService(action: Actions) {
val channel = BasicMessageChannel<String>(flutterView, "foo", StringCodec.INSTANCE);
}
private fun getBatteryLevel(): Int {
......
package com.logair.logair_application;
import android.content.Context;
import android.content.SharedPreferences;
enum class ServiceState {
STARTED,
STOPPED
}
private const val name = "WAKESERVICE_KEY";
private const val key = "WAKESERVICE_STATE";
fun setServiceState(context: Context, state: ServiceState) {
val sharedPreferences: SharedPreferences = getPreferences(context);
sharedPreferences.edit().let {
it.putString(key, state.name);
it.apply();
}
}
fun getServiceState(context: Context): ServiceState {
val sharedPreferences: SharedPreferences = getPreferences(context);
val value: String? = sharedPreferences.getString(key, ServiceState.STOPPED.name);
return ServiceState.valueOf(value!!);
}
private fun getPreferences(context: Context): SharedPreferences {
return context.getSharedPreferences(name, 0);
}
\ No newline at end of file
package com.logair.logair_application;
import android.util.Log;
fun log(message: String) {
Log.d("WAKESERVICE", message);
}
\ No newline at end of file
/*package com.logair.logair_application
import android.app.*
import android.content.Context
import android.content.Intent
import android.graphics.Color
import android.os.Build
import android.os.IBinder
import android.os.PowerManager
import android.provider.Settings
import android.widget.Toast
import java.text.SimpleDateFormat
import java.util.*
import java.util.*
package com.logair.logair_application
import android.app.*;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.os.Build;
import android.os.IBinder;
import android.os.PowerManager;
import android.provider.Settings;
import android.widget.Toast;
import java.text.SimpleDateFormat;
import java.util.*;
import kotlinx.coroutines.*;
import com.logair.logair_application.Channels;
class WakeService : Service() {
private var wakeLock: PowerManager.WakeLock? = null
private var isServiceStarted = false
private var wakeLock: PowerManager.WakeLock? = null;
private var isServiceStarted = false;
override fun onBind(intent: Intent): IBinder? {
log("Some component want to bind with the service")
// We don't provide binding, so return null
return null
return null;
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
if (intent != null) {
val action = intent.action;
when(action) {
Actions.START.name -> startService()
Actions.STOP.name -> stopService()
else -> log("error");
}
} else {
log("with null intent");
}
return START_STICKY;
}
override fun onCreate() {
super.onCreate();
log("Service Created");
val notification = createNotification();
startForeground(1, notification);
}
override fun onDestroy() {
super.onDestroy();
Toast.makeText(this, "Service Destroyed", Toast.LENGTH_SHORT).show();
}
private fun startService() {
if (isServiceStarted) return;
Toast.makeText(this, "LogAir Connector Service Starting", Toast.LENGTH_SHORT).show();
isServiceStarted = true;
setServiceState(this, ServiceState.STARTED);
wakeLock = (getSystemService(Context.POWER_SERVICE) as PowerManager).run {
newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "WakeService::lock").apply {
acquire();
}
}
GlobalScope.launch(Dispatchers.IO) {
while (isServiceStarted) {
launch(Dispatchers.IO) {
// DO PING DART
}
delay(1 * 1000); // 1000ms = 1s
}
}
}
private fun stopService() {
log("Attempting to stop foreground service.");
Toast.makeText(this, "LogAir Connector Service Stopping", Toast.LENGTH_SHORT).show();
try {
wakeLock?.let {
if (it.isHeld)
id.release();
};
stopForeground(true);
stopSelf();
} catch (e: Exception) {
log("Service stopped without starting: ${e.message}");
}
isServiceStarted = false
setServiceState(this, ServiceState.STOPPED)
}
private fun createNotification(): Notification {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager;
val channel = NotificationChannel(
Channels.WAKE_CHANNEL_NOTIFICATION,
"LogAir Connector Notification Channel",
NotificationManager.IMPORTANCE_HIGH
).let {
it.description = "LogAir Connector Service Channel"
it.enableLights(true)
it.lightColor = Color.RED
it.enableVibration(true)
it.vibrationPattern = longArrayOf(100, 200, 300, 400, 500, 400, 300, 200, 400)
it
}
notificationManager.createNotificationChannel(channel);
}
val pendingIntent: PendingIntent = Intent(this, MainActivity::class.java).let {
notificationIntent -> PendingIntent.getActivity(this, 0, notificationIntent, 0);
}
val builder: Notification.Builder =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
Notification.Builder(this, Channels.WAKE_CHANNEL_NOTIFICATION)
else
Notification.Builder(this)
return builder
.setContentTitle("LogAir Connector Service")
.setContentText("LogAir Service")
.setContentIntent(pendingIntent)
.setSmallIcon(R.mipmap.ic_launcher)
.setTicker("TickerText")
.setPriority(Notification.PRIORITY_HIGH)
.build()
}
}*/
\ No newline at end of file
}
\ No newline at end of file
......@@ -8,6 +8,7 @@ buildscript {
dependencies {
classpath 'com.android.tools.build:gradle:3.5.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "org.jetbrains.kotlin:kotlin-android-extensions:$kotlin_version"
}
}
......@@ -27,5 +28,5 @@ subprojects {
}
task clean(type: Delete) {
delete rootProject.buildDir
delete rootProject.buildDir
}
......@@ -4,6 +4,9 @@ import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:logair_application/localization/localization_delegate.dart';
import 'package:logair_application/routes/home.dart';
// TODO Lang service, intialized with the right locale, where accessible from entire program
// TODO USED FOR DEBUGGING
final bool displayMode = false;
void main() => runApp(displayMode ? DevicePreview(child: MyApp()) : MyApp());
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment