oh foreground worker and some edgecases

This commit is contained in:
Geoffrey Hansen 2020-09-03 19:39:43 +02:00
parent 8a6a3d2283
commit ae980e12f4
5 changed files with 68 additions and 15 deletions

View file

@ -1,12 +1,19 @@
package info.nightscout.androidaps.plugins.general.openhumans package info.nightscout.androidaps.plugins.general.openhumans
import android.app.Notification
import android.content.Context import android.content.Context
import android.net.wifi.WifiManager import android.net.wifi.WifiManager
import androidx.core.app.NotificationCompat
import androidx.work.ForegroundInfo
import androidx.work.RxWorker import androidx.work.RxWorker
import androidx.work.WorkerParameters import androidx.work.WorkerParameters
import info.nightscout.androidaps.MainApp import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.plugins.general.openhumans.OpenHumansUploader.Companion.NOTIFICATION_CHANNEL
import info.nightscout.androidaps.plugins.general.openhumans.OpenHumansUploader.Companion.UPLOAD_NOTIFICATION_ID
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.sharedPreferences.SP import info.nightscout.androidaps.utils.sharedPreferences.SP
import io.reactivex.Single import io.reactivex.Single
import java.util.concurrent.TimeUnit
import javax.inject.Inject import javax.inject.Inject
class OHUploadWorker(context: Context, workerParameters: WorkerParameters) class OHUploadWorker(context: Context, workerParameters: WorkerParameters)
@ -18,6 +25,9 @@ class OHUploadWorker(context: Context, workerParameters: WorkerParameters)
@Inject @Inject
lateinit var openHumansUploader: OpenHumansUploader lateinit var openHumansUploader: OpenHumansUploader
@Inject
lateinit var resourceHelper: ResourceHelper
override fun createWork(): Single<Result> = Single.defer { override fun createWork(): Single<Result> = Single.defer {
// Here we inject every time we create work // Here we inject every time we create work
@ -31,7 +41,8 @@ class OHUploadWorker(context: Context, workerParameters: WorkerParameters)
val wifiOnly = sp.getBoolean("key_oh_wifi_only", true) val wifiOnly = sp.getBoolean("key_oh_wifi_only", true)
val isConnectedToWifi = wifiManager?.isWifiEnabled ?: false && wifiManager?.connectionInfo?.networkId != -1 val isConnectedToWifi = wifiManager?.isWifiEnabled ?: false && wifiManager?.connectionInfo?.networkId != -1
if (!wifiOnly || (wifiOnly && isConnectedToWifi)) { if (!wifiOnly || (wifiOnly && isConnectedToWifi)) {
openHumansUploader.uploadData() setForegroundAsync(createForegroundInfo())
openHumansUploader.uploadData().delay(12, TimeUnit.MINUTES) //TODO OH: No Delay
.andThen(Single.just(Result.success())) .andThen(Single.just(Result.success()))
.onErrorResumeNext { Single.just(Result.retry()) } .onErrorResumeNext { Single.just(Result.retry()) }
} else { } else {
@ -39,4 +50,17 @@ class OHUploadWorker(context: Context, workerParameters: WorkerParameters)
} }
} }
private fun createForegroundInfo(): ForegroundInfo {
val title = resourceHelper.gs(info.nightscout.androidaps.R.string.open_humans)
val notification: Notification = NotificationCompat.Builder(applicationContext, NOTIFICATION_CHANNEL)
.setContentTitle(title)
.setTicker(title)
.setContentTitle(resourceHelper.gs(info.nightscout.androidaps.R.string.open_humans))
.setSmallIcon(info.nightscout.androidaps.R.drawable.notif_icon)
.setOngoing(true)
.build()
return ForegroundInfo(UPLOAD_NOTIFICATION_ID, notification)
}
} }

View file

@ -7,7 +7,6 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.Button import android.widget.Button
import android.widget.TextView import android.widget.TextView
import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer import androidx.lifecycle.Observer
import androidx.work.WorkInfo import androidx.work.WorkInfo
import androidx.work.WorkManager import androidx.work.WorkManager
@ -16,7 +15,9 @@ import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.events.Event import info.nightscout.androidaps.events.Event
import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.androidaps.utils.extensions.plusAssign import info.nightscout.androidaps.utils.extensions.plusAssign
import info.nightscout.androidaps.utils.resources.ResourceHelper
import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.CompositeDisposable
import io.reactivex.schedulers.Schedulers import io.reactivex.schedulers.Schedulers
@ -40,6 +41,9 @@ class OpenHumansFragment : DaggerFragment() {
@Inject @Inject
lateinit var openHumansUploader: OpenHumansUploader lateinit var openHumansUploader: OpenHumansUploader
@Inject
lateinit var resourceHelper: ResourceHelper
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
compositeDisposable += rxBus.toObservable(UpdateQueueEvent::class.java) compositeDisposable += rxBus.toObservable(UpdateQueueEvent::class.java)
@ -85,7 +89,9 @@ class OpenHumansFragment : DaggerFragment() {
queueSize = view.findViewById(R.id.queue_size) queueSize = view.findViewById(R.id.queue_size)
workerState = view.findViewById(R.id.worker_state) workerState = view.findViewById(R.id.worker_state)
login!!.setOnClickListener { startActivity(Intent(context, OpenHumansLoginActivity::class.java)) } login!!.setOnClickListener { startActivity(Intent(context, OpenHumansLoginActivity::class.java)) }
logout!!.setOnClickListener { openHumansUploader.logout() } logout!!.setOnClickListener {
activity?.let { activity -> OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.oh_logout_confirmation), Runnable { openHumansUploader.logout() }) }
}
viewsCreated = true viewsCreated = true
updateGUI() updateGUI()
return view return view

View file

@ -24,6 +24,7 @@ import info.nightscout.androidaps.interfaces.PluginType
import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
import info.nightscout.androidaps.utils.extensions.plusAssign import info.nightscout.androidaps.utils.extensions.plusAssign
import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.sharedPreferences.SP import info.nightscout.androidaps.utils.sharedPreferences.SP
@ -53,7 +54,8 @@ class OpenHumansUploader @Inject constructor(
aapsLogger: AAPSLogger, aapsLogger: AAPSLogger,
val sp: SP, val sp: SP,
val rxBus: RxBusWrapper, val rxBus: RxBusWrapper,
val context: Context val context: Context,
val treatmentsPlugin: TreatmentsPlugin
) : PluginBase( ) : PluginBase(
PluginDescription() PluginDescription()
.mainType(PluginType.GENERAL) .mainType(PluginType.GENERAL)
@ -72,10 +74,12 @@ class OpenHumansUploader @Inject constructor(
private const val REDIRECT_URL = "androidaps://setup-openhumans" private const val REDIRECT_URL = "androidaps://setup-openhumans"
const val AUTH_URL = "https://www.openhumans.org/direct-sharing/projects/oauth2/authorize/?client_id=$CLIENT_ID&response_type=code" const val AUTH_URL = "https://www.openhumans.org/direct-sharing/projects/oauth2/authorize/?client_id=$CLIENT_ID&response_type=code"
const val WORK_NAME = "Open Humans" const val WORK_NAME = "Open Humans"
const val NOTIFICATION_CHANNEL = "OpenHumans"
private const val COPY_NOTIFICATION_ID = 3122 private const val COPY_NOTIFICATION_ID = 3122
private const val FAILURE_NOTIFICATION_ID = 3123 private const val FAILURE_NOTIFICATION_ID = 3123
private const val SUCCESS_NOTIFICATION_ID = 3124 private const val SUCCESS_NOTIFICATION_ID = 3124
private const val SIGNED_OUT_NOTIFICATION_ID = 3125 private const val SIGNED_OUT_NOTIFICATION_ID = 3125
const val UPLOAD_NOTIFICATION_ID = 3126
} }
private val openHumansAPI = OpenHumansAPI(OPEN_HUMANS_URL, CLIENT_ID, CLIENT_SECRET, REDIRECT_URL) private val openHumansAPI = OpenHumansAPI(OPEN_HUMANS_URL, CLIENT_ID, CLIENT_SECRET, REDIRECT_URL)
@ -323,7 +327,7 @@ class OpenHumansUploader @Inject constructor(
.flatMap { openHumansAPI.getProjectMemberId(it.accessToken) } .flatMap { openHumansAPI.getProjectMemberId(it.accessToken) }
.doOnSuccess { .doOnSuccess {
projectMemberId = it projectMemberId = it
// TODO: halted for now. Might create too much upload data. copyExistingDataToQueue() copyExistingDataToQueue()
rxBus.send(OpenHumansFragment.UpdateViewEvent) rxBus.send(OpenHumansFragment.UpdateViewEvent)
} }
.doOnError { .doOnError {
@ -353,7 +357,10 @@ class OpenHumansUploader @Inject constructor(
copyDisposable = Completable.fromCallable { MainApp.getDbHelper().clearOpenHumansQueue() } copyDisposable = Completable.fromCallable { MainApp.getDbHelper().clearOpenHumansQueue() }
.andThen(Single.defer { Single.just(MainApp.getDbHelper().countOfAllRows) }) .andThen(Single.defer { Single.just(MainApp.getDbHelper().countOfAllRows) })
.doOnSuccess { maxProgress = it } .doOnSuccess { maxProgress = it }
.flatMapObservable { Observable.defer { Observable.fromIterable(MainApp.getDbHelper().allBgReadings) } } .flatMapObservable { Observable.defer { Observable.fromIterable(treatmentsPlugin.service.treatmentData) } }
.map { enqueueTreatment(it); increaseCounter() }
.ignoreElements()
.andThen(Observable.defer { Observable.fromIterable(MainApp.getDbHelper().allBgReadings) })
.map { enqueueBGReading(it); increaseCounter() } .map { enqueueBGReading(it); increaseCounter() }
.ignoreElements() .ignoreElements()
.andThen(Observable.defer { Observable.fromIterable(MainApp.getDbHelper().allCareportalEvents) }) .andThen(Observable.defer { Observable.fromIterable(MainApp.getDbHelper().allCareportalEvents) })
@ -384,6 +391,7 @@ class OpenHumansUploader @Inject constructor(
showSetupFinishedNotification() showSetupFinishedNotification()
} }
.doOnError { .doOnError {
logout()
showSetupFailedNotification() showSetupFailedNotification()
} }
.doFinally { .doFinally {
@ -397,7 +405,7 @@ class OpenHumansUploader @Inject constructor(
} }
private fun showOngoingNotification(maxProgress: Long? = null, currentProgress: Long? = null) { private fun showOngoingNotification(maxProgress: Long? = null, currentProgress: Long? = null) {
val notification = NotificationCompat.Builder(context, "OpenHumans") val notification = NotificationCompat.Builder(context, NOTIFICATION_CHANNEL)
.setContentTitle(resourceHelper.gs(R.string.finishing_open_humans_setup)) .setContentTitle(resourceHelper.gs(R.string.finishing_open_humans_setup))
.setContentText(resourceHelper.gs(R.string.this_may_take_a_while)) .setContentText(resourceHelper.gs(R.string.this_may_take_a_while))
.setStyle(NotificationCompat.BigTextStyle()) .setStyle(NotificationCompat.BigTextStyle())
@ -411,9 +419,9 @@ class OpenHumansUploader @Inject constructor(
} }
private fun showSetupFinishedNotification() { private fun showSetupFinishedNotification() {
val notification = NotificationCompat.Builder(context, "OpenHumans") val notification = NotificationCompat.Builder(context, NOTIFICATION_CHANNEL)
.setContentTitle(resourceHelper.gs(R.string.setup_finished)) .setContentTitle(resourceHelper.gs(R.string.setup_finished))
.setContentText(resourceHelper.gs(R.string.your_phone_is_upload_data)) .setContentText(resourceHelper.gs(R.string.your_phone_will_upload_data))
.setStyle(NotificationCompat.BigTextStyle()) .setStyle(NotificationCompat.BigTextStyle())
.setSmallIcon(R.drawable.notif_icon) .setSmallIcon(R.drawable.notif_icon)
.build() .build()
@ -422,7 +430,7 @@ class OpenHumansUploader @Inject constructor(
} }
private fun showSetupFailedNotification() { private fun showSetupFailedNotification() {
val notification = NotificationCompat.Builder(context, "OpenHumans") val notification = NotificationCompat.Builder(context, NOTIFICATION_CHANNEL)
.setContentTitle(resourceHelper.gs(R.string.setup_failed)) .setContentTitle(resourceHelper.gs(R.string.setup_failed))
.setContentText(resourceHelper.gs(R.string.there_was_an_error)) .setContentText(resourceHelper.gs(R.string.there_was_an_error))
.setStyle(NotificationCompat.BigTextStyle()) .setStyle(NotificationCompat.BigTextStyle())
@ -559,7 +567,7 @@ class OpenHumansUploader @Inject constructor(
} }
private fun handleSignOut() { private fun handleSignOut() {
val notification = NotificationCompat.Builder(context, "OpenHumans") val notification = NotificationCompat.Builder(context, NOTIFICATION_CHANNEL)
.setContentTitle(resourceHelper.gs(R.string.you_have_been_signed_out_of_open_humans)) .setContentTitle(resourceHelper.gs(R.string.you_have_been_signed_out_of_open_humans))
.setContentText(resourceHelper.gs(R.string.click_here_to_sign_in_again_if_this_wasnt_on_purpose)) .setContentText(resourceHelper.gs(R.string.click_here_to_sign_in_again_if_this_wasnt_on_purpose))
.setStyle(NotificationCompat.BigTextStyle()) .setStyle(NotificationCompat.BigTextStyle())
@ -587,9 +595,9 @@ class OpenHumansUploader @Inject constructor(
.setRequiredNetworkType(NetworkType.CONNECTED) .setRequiredNetworkType(NetworkType.CONNECTED)
.setRequiresCharging(sp.getBoolean("key_oh_charging_only", false)) .setRequiresCharging(sp.getBoolean("key_oh_charging_only", false))
.build() .build()
val workRequest = PeriodicWorkRequestBuilder<OHUploadWorker>(1, TimeUnit.DAYS) val workRequest = PeriodicWorkRequestBuilder<OHUploadWorker>(1, TimeUnit.MINUTES) // TODO OH: DAYS
.setConstraints(constraints) .setConstraints(constraints)
.setBackoffCriteria(BackoffPolicy.LINEAR, 1, TimeUnit.HOURS) .setBackoffCriteria(BackoffPolicy.LINEAR, 1, TimeUnit.MINUTES) //TODO OH: HOURS
.build() .build()
WorkManager.getInstance(context).enqueueUniquePeriodicWork(WORK_NAME, if (replace) ExistingPeriodicWorkPolicy.REPLACE else ExistingPeriodicWorkPolicy.KEEP, workRequest) WorkManager.getInstance(context).enqueueUniquePeriodicWork(WORK_NAME, if (replace) ExistingPeriodicWorkPolicy.REPLACE else ExistingPeriodicWorkPolicy.KEEP, workRequest)
} }
@ -598,7 +606,7 @@ class OpenHumansUploader @Inject constructor(
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val notificationManagerCompat = NotificationManagerCompat.from(context) val notificationManagerCompat = NotificationManagerCompat.from(context)
notificationManagerCompat.createNotificationChannel(NotificationChannel( notificationManagerCompat.createNotificationChannel(NotificationChannel(
"OpenHumans", NOTIFICATION_CHANNEL,
resourceHelper.gs(R.string.open_humans), resourceHelper.gs(R.string.open_humans),
NotificationManager.IMPORTANCE_DEFAULT NotificationManager.IMPORTANCE_DEFAULT
)) ))

View file

@ -160,6 +160,10 @@ public class TreatmentService extends OrmLiteBaseService<DatabaseHelper> {
public List<Treatment> query(PreparedQuery<Treatment> data) throws SQLException { public List<Treatment> query(PreparedQuery<Treatment> data) throws SQLException {
return wrapped.query(data); return wrapped.query(data);
} }
public long countOf() throws SQLException {
return wrapped.countOf();
}
} }
@Override @Override
@ -295,6 +299,15 @@ public class TreatmentService extends OrmLiteBaseService<DatabaseHelper> {
return new ArrayList<>(); return new ArrayList<>();
} }
public long count() {
try {
return this.getDao().countOf();
} catch (SQLException e) {
aapsLogger.error("Unhandled exception", e);
}
return 0L;
}
/* /*
{ {
"_id": "551ee3ad368e06e80856e6a9", "_id": "551ee3ad368e06e80856e6a9",

View file

@ -1411,13 +1411,15 @@
<string name="finishing_open_humans_setup">Finishing Open Humans setup…</string> <string name="finishing_open_humans_setup">Finishing Open Humans setup…</string>
<string name="this_may_take_a_while">This may take a while. Do not turn your phone off.</string> <string name="this_may_take_a_while">This may take a while. Do not turn your phone off.</string>
<string name="setup_finished">Setup finished</string> <string name="setup_finished">Setup finished</string>
<string name="your_phone_will_upload_data">Your phone will upload data to Open Humans soon.</string>
<string name="your_phone_is_upload_data">Your phone is uploading data to Open Humans now.</string> <string name="your_phone_is_upload_data">Your phone is uploading data to Open Humans now.</string>
<string name="setup_failed">Setup failed</string> <string name="setup_failed">Setup failed</string>
<string name="there_was_an_error">There was an error.</string> <string name="there_was_an_error">There was an error. Please try to log in again in order to proceed. Sorry &amp; Thank you!</string>
<string name="open_humans_terms">This is an open source tool that will copy your data to Open Humans. We retain no rights to share your data with third parties without your explicit authorization. The data the project and app receive are identified via a random user ID and will only be securely transmitted to an Open Humans account with your authorization of that process. You can stop uploading and delete your upload data at any time via www.openhumans.org.</string> <string name="open_humans_terms">This is an open source tool that will copy your data to Open Humans. We retain no rights to share your data with third parties without your explicit authorization. The data the project and app receive are identified via a random user ID and will only be securely transmitted to an Open Humans account with your authorization of that process. You can stop uploading and delete your upload data at any time via www.openhumans.org.</string>
<string name="i_understand_and_agree">I understand and agree.</string> <string name="i_understand_and_agree">I understand and agree.</string>
<string name="login">Login</string> <string name="login">Login</string>
<string name="logout">Logout</string> <string name="logout">Logout</string>
<string name="oh_logout_confirmation">Do you really want to log out and stop donating data to science?</string>
<string name="project_member_id">Project Member ID: %s</string> <string name="project_member_id">Project Member ID: %s</string>
<string name="queue_size">Queue Size: %d</string> <string name="queue_size">Queue Size: %d</string>
<string name="terms_of_use">Terms of Use</string> <string name="terms_of_use">Terms of Use</string>