Reorganize the code
Make it more readable Prepare non-SSO ApiProvider
This commit is contained in:
parent
76521cac7f
commit
9db96919bd
@ -2,6 +2,9 @@ package org.unifiedpush.distributor.nextpush.account
|
|||||||
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.content.DialogInterface
|
||||||
|
import android.content.Intent
|
||||||
|
import android.net.Uri
|
||||||
import android.text.SpannableString
|
import android.text.SpannableString
|
||||||
import android.text.method.LinkMovementMethod
|
import android.text.method.LinkMovementMethod
|
||||||
import android.text.util.Linkify
|
import android.text.util.Linkify
|
||||||
@ -16,12 +19,8 @@ import com.nextcloud.android.sso.exceptions.NoCurrentAccountSelectedException
|
|||||||
import com.nextcloud.android.sso.helper.SingleAccountHelper
|
import com.nextcloud.android.sso.helper.SingleAccountHelper
|
||||||
import com.nextcloud.android.sso.model.SingleSignOnAccount
|
import com.nextcloud.android.sso.model.SingleSignOnAccount
|
||||||
import com.nextcloud.android.sso.ui.UiExceptionManager
|
import com.nextcloud.android.sso.ui.UiExceptionManager
|
||||||
import android.content.DialogInterface
|
|
||||||
import android.content.Intent
|
|
||||||
import android.net.Uri
|
|
||||||
import org.unifiedpush.distributor.nextpush.R
|
import org.unifiedpush.distributor.nextpush.R
|
||||||
|
import org.unifiedpush.distributor.nextpush.utils.TAG
|
||||||
private const val TAG = "AccountUtils"
|
|
||||||
|
|
||||||
private const val PREF_NAME = "NextPush"
|
private const val PREF_NAME = "NextPush"
|
||||||
private const val PREF_DEVICE_ID = "deviceId"
|
private const val PREF_DEVICE_ID = "deviceId"
|
||||||
@ -99,7 +98,7 @@ object AccountUtils {
|
|||||||
context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
|
context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
|
||||||
.edit()
|
.edit()
|
||||||
.putString(PREF_DEVICE_ID, deviceId)
|
.putString(PREF_DEVICE_ID, deviceId)
|
||||||
.commit()
|
.apply()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getDeviceId(context: Context): String? {
|
fun getDeviceId(context: Context): String? {
|
||||||
@ -111,14 +110,14 @@ object AccountUtils {
|
|||||||
context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
|
context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
|
||||||
.edit()
|
.edit()
|
||||||
.remove(PREF_DEVICE_ID)
|
.remove(PREF_DEVICE_ID)
|
||||||
.commit()
|
.apply()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun saveUrl(context: Context, url: String) {
|
fun saveUrl(context: Context, url: String) {
|
||||||
context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
|
context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
|
||||||
.edit()
|
.edit()
|
||||||
.putString(PREF_URL, url)
|
.putString(PREF_URL, url)
|
||||||
.commit()
|
.apply()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getUrl(context: Context): String? {
|
fun getUrl(context: Context): String? {
|
||||||
@ -130,6 +129,6 @@ object AccountUtils {
|
|||||||
context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
|
context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
|
||||||
.edit()
|
.edit()
|
||||||
.remove(PREF_URL)
|
.remove(PREF_URL)
|
||||||
.commit()
|
.apply()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,36 +12,35 @@ import android.util.Log
|
|||||||
import android.view.Menu
|
import android.view.Menu
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.*
|
import android.widget.* // ktlint-disable no-wildcard-imports
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import com.nextcloud.android.sso.AccountImporter
|
|
||||||
import com.nextcloud.android.sso.ui.UiExceptionManager
|
|
||||||
|
|
||||||
import com.nextcloud.android.sso.helper.SingleAccountHelper
|
|
||||||
|
|
||||||
import androidx.constraintlayout.widget.ConstraintLayout
|
import androidx.constraintlayout.widget.ConstraintLayout
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
|
import com.nextcloud.android.sso.AccountImporter
|
||||||
import com.nextcloud.android.sso.AccountImporter.clearAllAuthTokens
|
import com.nextcloud.android.sso.AccountImporter.clearAllAuthTokens
|
||||||
import com.nextcloud.android.sso.exceptions.*
|
import com.nextcloud.android.sso.exceptions.AccountImportCancelledException
|
||||||
|
import com.nextcloud.android.sso.exceptions.NextcloudFilesAppAccountNotFoundException
|
||||||
|
import com.nextcloud.android.sso.exceptions.NoCurrentAccountSelectedException
|
||||||
|
import com.nextcloud.android.sso.helper.SingleAccountHelper
|
||||||
|
import com.nextcloud.android.sso.ui.UiExceptionManager
|
||||||
import org.unifiedpush.distributor.nextpush.R
|
import org.unifiedpush.distributor.nextpush.R
|
||||||
import org.unifiedpush.distributor.nextpush.account.AccountUtils.connect
|
import org.unifiedpush.distributor.nextpush.account.AccountUtils.connect
|
||||||
import org.unifiedpush.distributor.nextpush.account.AccountUtils.isConnected
|
import org.unifiedpush.distributor.nextpush.account.AccountUtils.isConnected
|
||||||
import org.unifiedpush.distributor.nextpush.account.AccountUtils.nextcloudAppNotInstalledDialog
|
import org.unifiedpush.distributor.nextpush.account.AccountUtils.nextcloudAppNotInstalledDialog
|
||||||
import org.unifiedpush.distributor.nextpush.account.AccountUtils.ssoAccount
|
import org.unifiedpush.distributor.nextpush.account.AccountUtils.ssoAccount
|
||||||
import org.unifiedpush.distributor.nextpush.api.ApiUtils.apiDeleteApp
|
import org.unifiedpush.distributor.nextpush.distributor.Distributor.deleteApp
|
||||||
import org.unifiedpush.distributor.nextpush.api.ApiUtils.apiDeleteDevice
|
import org.unifiedpush.distributor.nextpush.distributor.Distributor.deleteDevice
|
||||||
import org.unifiedpush.distributor.nextpush.distributor.DistributorUtils.sendUnregistered
|
import org.unifiedpush.distributor.nextpush.distributor.Distributor.getDb
|
||||||
import org.unifiedpush.distributor.nextpush.distributor.DistributorUtils.getDb
|
import org.unifiedpush.distributor.nextpush.services.RestartWorker
|
||||||
import org.unifiedpush.distributor.nextpush.services.*
|
import org.unifiedpush.distributor.nextpush.services.StartService
|
||||||
|
import org.unifiedpush.distributor.nextpush.utils.TAG
|
||||||
import java.lang.String.format
|
import java.lang.String.format
|
||||||
|
|
||||||
private const val TAG = "NextPush-MainActivity"
|
|
||||||
|
|
||||||
class MainActivity : AppCompatActivity() {
|
class MainActivity : AppCompatActivity() {
|
||||||
|
|
||||||
private lateinit var listView : ListView
|
private lateinit var listView: ListView
|
||||||
private var showLogout = false
|
private var showLogout = false
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
@ -106,7 +105,8 @@ class MainActivity : AppCompatActivity() {
|
|||||||
private fun requestPermissions() {
|
private fun requestPermissions() {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||||
if (checkSelfPermission(Manifest.permission.POST_NOTIFICATIONS)
|
if (checkSelfPermission(Manifest.permission.POST_NOTIFICATIONS)
|
||||||
!= PackageManager.PERMISSION_GRANTED) {
|
!= PackageManager.PERMISSION_GRANTED
|
||||||
|
) {
|
||||||
Log.d(TAG, "Requesting POST_NOTIFICATIONS permission")
|
Log.d(TAG, "Requesting POST_NOTIFICATIONS permission")
|
||||||
registerForActivityResult(
|
registerForActivityResult(
|
||||||
ActivityResultContracts.RequestPermission()
|
ActivityResultContracts.RequestPermission()
|
||||||
@ -132,7 +132,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
override fun onWindowFocusChanged(hasFocus: Boolean) {
|
override fun onWindowFocusChanged(hasFocus: Boolean) {
|
||||||
super.onWindowFocusChanged(hasFocus)
|
super.onWindowFocusChanged(hasFocus)
|
||||||
if(hasFocus) {
|
if (hasFocus) {
|
||||||
setListView()
|
setListView()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -175,7 +175,8 @@ class MainActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
private fun logout() {
|
private fun logout() {
|
||||||
val alert: android.app.AlertDialog.Builder = android.app.AlertDialog.Builder(
|
val alert: android.app.AlertDialog.Builder = android.app.AlertDialog.Builder(
|
||||||
this)
|
this
|
||||||
|
)
|
||||||
alert.setTitle(getString(R.string.logout_alert_title))
|
alert.setTitle(getString(R.string.logout_alert_title))
|
||||||
alert.setMessage(R.string.logout_alert_content)
|
alert.setMessage(R.string.logout_alert_content)
|
||||||
alert.setPositiveButton(R.string.ok) { dialog, _ ->
|
alert.setPositiveButton(R.string.ok) { dialog, _ ->
|
||||||
@ -185,7 +186,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
.edit()
|
.edit()
|
||||||
.remove("PREF_CURRENT_ACCOUNT_STRING")
|
.remove("PREF_CURRENT_ACCOUNT_STRING")
|
||||||
.apply()
|
.apply()
|
||||||
apiDeleteDevice(this)
|
deleteDevice(this)
|
||||||
showStart()
|
showStart()
|
||||||
finish()
|
finish()
|
||||||
startActivity(intent)
|
startActivity(intent)
|
||||||
@ -194,42 +195,46 @@ class MainActivity : AppCompatActivity() {
|
|||||||
alert.show()
|
alert.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setListView(){
|
private fun setListView() {
|
||||||
listView = findViewById(R.id.applications_list)
|
listView = findViewById(R.id.applications_list)
|
||||||
val db = getDb(this)
|
|
||||||
val tokenList = db.listTokens().toMutableList()
|
val tokenList = emptyList<String>().toMutableList()
|
||||||
val appList = emptyArray<String>().toMutableList()
|
val appList = emptyList<String>().toMutableList()
|
||||||
tokenList.forEach {
|
|
||||||
appList.add(db.getPackageName(it))
|
getDb(this).let { db ->
|
||||||
|
db.listTokens().forEach {
|
||||||
|
tokenList.add(it)
|
||||||
|
appList.add(db.getPackageName(it) ?: it)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
listView.adapter = ArrayAdapter(
|
listView.adapter = ArrayAdapter(
|
||||||
this,
|
this,
|
||||||
android.R.layout.simple_list_item_1,
|
android.R.layout.simple_list_item_1,
|
||||||
appList
|
appList
|
||||||
)
|
)
|
||||||
|
|
||||||
listView.setOnItemLongClickListener(
|
listView.setOnItemLongClickListener(
|
||||||
fun(_: AdapterView<*>, _: View, position: Int, _: Long): Boolean {
|
fun(_: AdapterView<*>, _: View, position: Int, _: Long): Boolean {
|
||||||
val alert: android.app.AlertDialog.Builder = android.app.AlertDialog.Builder(
|
val alert: android.app.AlertDialog.Builder = android.app.AlertDialog.Builder(
|
||||||
this)
|
this
|
||||||
alert.setTitle("Unregistering")
|
)
|
||||||
alert.setMessage("Are you sure to unregister ${appList[position]} ?")
|
alert.setTitle("Unregistering")
|
||||||
alert.setPositiveButton("YES") { dialog, _ ->
|
alert.setMessage("Are you sure to unregister ${appList[position]} ?")
|
||||||
val connectorToken = tokenList[position]
|
alert.setPositiveButton("YES") { dialog, _ ->
|
||||||
sendUnregistered(this, connectorToken)
|
val connectorToken = tokenList[position]
|
||||||
val database = getDb(this)
|
deleteApp(this, connectorToken) {
|
||||||
val appToken = database.getAppToken(connectorToken)
|
Log.d(TAG, "Unregistration is finished")
|
||||||
database.unregisterApp(connectorToken)
|
this@MainActivity.runOnUiThread {
|
||||||
apiDeleteApp(this, appToken) {
|
setListView()
|
||||||
Log.d(TAG,"Unregistration is finished")
|
|
||||||
}
|
}
|
||||||
tokenList.removeAt(position)
|
|
||||||
appList.removeAt(position)
|
|
||||||
dialog.dismiss()
|
|
||||||
}
|
}
|
||||||
alert.setNegativeButton("NO") { dialog, _ -> dialog.dismiss() }
|
dialog.dismiss()
|
||||||
alert.show()
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
alert.setNegativeButton("NO") { dialog, _ -> dialog.dismiss() }
|
||||||
|
alert.show()
|
||||||
|
return true
|
||||||
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,211 @@
|
|||||||
|
package org.unifiedpush.distributor.nextpush.api
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.os.Build
|
||||||
|
import android.util.Log
|
||||||
|
import io.reactivex.Observer
|
||||||
|
import io.reactivex.disposables.Disposable
|
||||||
|
import io.reactivex.schedulers.Schedulers
|
||||||
|
import okhttp3.OkHttpClient
|
||||||
|
import okhttp3.Request
|
||||||
|
import okhttp3.sse.EventSource
|
||||||
|
import okhttp3.sse.EventSources
|
||||||
|
import org.unifiedpush.distributor.nextpush.account.AccountUtils.getDeviceId
|
||||||
|
import org.unifiedpush.distributor.nextpush.account.AccountUtils.removeDeviceId
|
||||||
|
import org.unifiedpush.distributor.nextpush.account.AccountUtils.removeUrl
|
||||||
|
import org.unifiedpush.distributor.nextpush.account.AccountUtils.saveDeviceId
|
||||||
|
import org.unifiedpush.distributor.nextpush.account.AccountUtils.saveUrl
|
||||||
|
import org.unifiedpush.distributor.nextpush.account.AccountUtils.ssoAccount
|
||||||
|
import org.unifiedpush.distributor.nextpush.api.provider.ApiProvider
|
||||||
|
import org.unifiedpush.distributor.nextpush.api.provider.ApiProvider.Companion.mApiEndpoint
|
||||||
|
import org.unifiedpush.distributor.nextpush.api.provider.ApiProviderFactory
|
||||||
|
import org.unifiedpush.distributor.nextpush.api.provider.ApiSSOFactory
|
||||||
|
import org.unifiedpush.distributor.nextpush.api.response.ApiResponse
|
||||||
|
import org.unifiedpush.distributor.nextpush.services.SSEListener
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
|
object Api {
|
||||||
|
|
||||||
|
private val TAG = Api::class.java.simpleName
|
||||||
|
private var provider: ApiProviderFactory? = null
|
||||||
|
private var source: EventSource? = null
|
||||||
|
|
||||||
|
private fun Context.withApiProvider(block: (ApiProvider) -> Unit) {
|
||||||
|
(
|
||||||
|
provider ?: run {
|
||||||
|
Log.d(TAG, "Setting SSOProvider")
|
||||||
|
ApiSSOFactory(this).apply {
|
||||||
|
provider = this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
).getProviderAndExecute(block)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun apiDestroy() {
|
||||||
|
provider?.destroyProvider()
|
||||||
|
provider = null
|
||||||
|
source?.cancel()
|
||||||
|
source = null
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Context.apiSync() {
|
||||||
|
getDeviceId(this)?.let {
|
||||||
|
syncDevice(it)
|
||||||
|
}
|
||||||
|
?: run {
|
||||||
|
Log.d(TAG, "No deviceId found.")
|
||||||
|
var deviceId: String? = null
|
||||||
|
|
||||||
|
val parameters = mapOf("deviceName" to Build.MODEL)
|
||||||
|
|
||||||
|
withApiProvider { apiProvider ->
|
||||||
|
apiProvider.createDevice(parameters)
|
||||||
|
?.subscribeOn(Schedulers.newThread())
|
||||||
|
?.observeOn(Schedulers.newThread())
|
||||||
|
?.subscribe(object : Observer<ApiResponse?> {
|
||||||
|
override fun onSubscribe(d: Disposable) {
|
||||||
|
Log.d(TAG, "onSubscribe")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onNext(response: ApiResponse) {
|
||||||
|
response.deviceId.let {
|
||||||
|
saveDeviceId(this@apiSync, it)
|
||||||
|
deviceId = it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onError(e: Throwable) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onComplete() {
|
||||||
|
saveUrl(this@apiSync, "${ssoAccount.url}$mApiEndpoint")
|
||||||
|
// Sync once it is registered
|
||||||
|
deviceId?.let {
|
||||||
|
syncDevice(it)
|
||||||
|
}
|
||||||
|
Log.d(TAG, "mApi register: onComplete")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Context.syncDevice(deviceId: String) {
|
||||||
|
val client = OkHttpClient.Builder()
|
||||||
|
.readTimeout(0, TimeUnit.SECONDS)
|
||||||
|
.retryOnConnectionFailure(false)
|
||||||
|
.build()
|
||||||
|
val url = "${ssoAccount.url}$mApiEndpoint/device/$deviceId"
|
||||||
|
|
||||||
|
val request = Request.Builder().url(url)
|
||||||
|
.get()
|
||||||
|
.build()
|
||||||
|
|
||||||
|
source = EventSources.createFactory(client).newEventSource(request, SSEListener(this))
|
||||||
|
Log.d(TAG, "cSync done.")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Context.apiDeleteDevice() {
|
||||||
|
val deviceId = getDeviceId(this) ?: return
|
||||||
|
|
||||||
|
withApiProvider { apiProvider ->
|
||||||
|
apiProvider.deleteDevice(deviceId)
|
||||||
|
?.subscribeOn(Schedulers.newThread())
|
||||||
|
?.observeOn(Schedulers.newThread())
|
||||||
|
?.subscribe(object : Observer<ApiResponse?> {
|
||||||
|
override fun onSubscribe(d: Disposable) {
|
||||||
|
Log.d(TAG, "Subscribed to deleteDevice.")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onNext(response: ApiResponse) {
|
||||||
|
if (response.success) {
|
||||||
|
Log.d(TAG, "Device successfully deleted.")
|
||||||
|
} else {
|
||||||
|
Log.d(TAG, "An error occurred while deleting the device.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onError(e: Throwable) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onComplete() {
|
||||||
|
removeUrl(this@apiDeleteDevice)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
removeDeviceId(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Context.apiCreateApp(
|
||||||
|
appName: String,
|
||||||
|
block: (String?) -> Unit
|
||||||
|
) {
|
||||||
|
// The unity of connector token must already be checked here
|
||||||
|
val parameters = getDeviceId(this)?.let {
|
||||||
|
mutableMapOf(
|
||||||
|
"deviceId" to it,
|
||||||
|
"appName" to appName
|
||||||
|
)
|
||||||
|
} ?: return
|
||||||
|
|
||||||
|
withApiProvider { apiProvider ->
|
||||||
|
apiProvider.createApp(parameters)
|
||||||
|
?.subscribeOn(Schedulers.newThread())
|
||||||
|
?.observeOn(Schedulers.newThread())
|
||||||
|
?.subscribe(object : Observer<ApiResponse?> {
|
||||||
|
override fun onSubscribe(d: Disposable) {
|
||||||
|
Log.d(TAG, "Subscribed to createApp.")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onNext(response: ApiResponse) {
|
||||||
|
val nextpushToken = if (response.success) {
|
||||||
|
Log.d(TAG, "App successfully created.")
|
||||||
|
response.token
|
||||||
|
} else {
|
||||||
|
Log.d(TAG, "An error occurred while creating the application.")
|
||||||
|
null
|
||||||
|
}
|
||||||
|
block(nextpushToken)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onError(e: Throwable) {
|
||||||
|
block(null)
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onComplete() {}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Context.apiDeleteApp(nextpushToken: String, block: () -> Unit) {
|
||||||
|
withApiProvider { apiProvider ->
|
||||||
|
apiProvider.deleteApp(nextpushToken)
|
||||||
|
?.subscribeOn(Schedulers.newThread())
|
||||||
|
?.observeOn(Schedulers.newThread())
|
||||||
|
?.subscribe(object : Observer<ApiResponse?> {
|
||||||
|
override fun onSubscribe(d: Disposable) {
|
||||||
|
Log.d(TAG, "Subscribed to deleteApp.")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onNext(response: ApiResponse) {
|
||||||
|
if (response.success) {
|
||||||
|
Log.d(TAG, "App successfully deleted.")
|
||||||
|
} else {
|
||||||
|
Log.d(TAG, "An error occurred while deleting the application.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onError(e: Throwable) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onComplete() {
|
||||||
|
block()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,271 +0,0 @@
|
|||||||
package org.unifiedpush.distributor.nextpush.api
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.os.Build
|
|
||||||
import android.util.Log
|
|
||||||
import com.google.gson.GsonBuilder
|
|
||||||
import com.nextcloud.android.sso.api.NextcloudAPI
|
|
||||||
import io.reactivex.Observer
|
|
||||||
import io.reactivex.disposables.Disposable
|
|
||||||
import io.reactivex.schedulers.Schedulers
|
|
||||||
import okhttp3.OkHttpClient
|
|
||||||
import okhttp3.Request
|
|
||||||
import okhttp3.sse.EventSource
|
|
||||||
import okhttp3.sse.EventSources
|
|
||||||
import org.unifiedpush.distributor.nextpush.account.AccountUtils.getDeviceId
|
|
||||||
import org.unifiedpush.distributor.nextpush.account.AccountUtils.removeDeviceId
|
|
||||||
import org.unifiedpush.distributor.nextpush.account.AccountUtils.removeUrl
|
|
||||||
import org.unifiedpush.distributor.nextpush.account.AccountUtils.saveDeviceId
|
|
||||||
import org.unifiedpush.distributor.nextpush.account.AccountUtils.saveUrl
|
|
||||||
import org.unifiedpush.distributor.nextpush.account.AccountUtils.ssoAccount
|
|
||||||
import org.unifiedpush.distributor.nextpush.api.ProviderApi.Companion.mApiEndpoint
|
|
||||||
import org.unifiedpush.distributor.nextpush.distributor.DistributorUtils.getDb
|
|
||||||
import org.unifiedpush.distributor.nextpush.distributor.DistributorUtils.sendUnregistered
|
|
||||||
import org.unifiedpush.distributor.nextpush.services.SSEListener
|
|
||||||
import retrofit2.NextcloudRetrofitApiBuilder
|
|
||||||
import java.util.concurrent.TimeUnit
|
|
||||||
|
|
||||||
private const val TAG = "ApiUtils"
|
|
||||||
|
|
||||||
object ApiUtils {
|
|
||||||
|
|
||||||
val createQueue = emptyList<String>().toMutableList()
|
|
||||||
val delQueue = emptyList<String>().toMutableList()
|
|
||||||
|
|
||||||
private var mApi: ProviderApi? = null
|
|
||||||
private var nextcloudAPI: NextcloudAPI? = null
|
|
||||||
private var source: EventSource? = null
|
|
||||||
|
|
||||||
fun apiDestroy() {
|
|
||||||
nextcloudAPI?.stop()
|
|
||||||
source?.cancel()
|
|
||||||
nextcloudAPI = null
|
|
||||||
source = null
|
|
||||||
mApi = null
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun cApi(context: Context, callback: () -> Unit) {
|
|
||||||
mApi?.let {
|
|
||||||
callback()
|
|
||||||
} ?: run {
|
|
||||||
val nCallback = object : NextcloudAPI.ApiConnectedListener {
|
|
||||||
override fun onConnected() {
|
|
||||||
Log.d(TAG, "Api connected.")
|
|
||||||
callback()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onError(ex: Exception) {
|
|
||||||
Log.d(TAG, "Cannot connect to API: ex = [$ex]")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
NextcloudAPI(context, ssoAccount, GsonBuilder().create(), nCallback).let {
|
|
||||||
nextcloudAPI = it
|
|
||||||
mApi = NextcloudRetrofitApiBuilder(it, mApiEndpoint)
|
|
||||||
.create(ProviderApi::class.java)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun apiSync(context: Context) {
|
|
||||||
cApi(context) { cSync(context) }
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun cSync(context: Context) {
|
|
||||||
var deviceId = getDeviceId(context)
|
|
||||||
// Register the device if it is not yet registered
|
|
||||||
if (deviceId.isNullOrEmpty()) {
|
|
||||||
Log.d(TAG, "No deviceId found.")
|
|
||||||
val parameters: MutableMap<String, String> = HashMap()
|
|
||||||
parameters["deviceName"] = Build.MODEL
|
|
||||||
mApi?.createDevice(parameters)
|
|
||||||
?.subscribeOn(Schedulers.newThread())
|
|
||||||
?.observeOn(Schedulers.newThread())
|
|
||||||
?.subscribe(object : Observer<ApiResponse?> {
|
|
||||||
override fun onSubscribe(d: Disposable) {
|
|
||||||
Log.d(TAG, "onSubscribe")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onNext(response: ApiResponse) {
|
|
||||||
response.deviceId.let {
|
|
||||||
saveDeviceId(context, it)
|
|
||||||
deviceId = it
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onError(e: Throwable) {
|
|
||||||
e.printStackTrace()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onComplete() {
|
|
||||||
saveUrl(context, "${ssoAccount.url}${mApiEndpoint}")
|
|
||||||
// Sync once it is registered
|
|
||||||
deviceId?.let {
|
|
||||||
cSync(context, it)
|
|
||||||
}
|
|
||||||
Log.d(TAG, "mApi register: onComplete")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
// Sync directly
|
|
||||||
Log.d(TAG, "Found saved deviceId")
|
|
||||||
deviceId?.let {
|
|
||||||
cSync(context, it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private fun cSync(context: Context, deviceId: String) {
|
|
||||||
val client = OkHttpClient.Builder()
|
|
||||||
.readTimeout(0, TimeUnit.SECONDS)
|
|
||||||
.retryOnConnectionFailure(false)
|
|
||||||
.build()
|
|
||||||
val url = "${ssoAccount.url}$mApiEndpoint/device/$deviceId"
|
|
||||||
|
|
||||||
val request = Request.Builder().url(url)
|
|
||||||
.get()
|
|
||||||
.build()
|
|
||||||
|
|
||||||
source = EventSources.createFactory(client).newEventSource(request, SSEListener(context))
|
|
||||||
Log.d(TAG, "cSync done.")
|
|
||||||
}
|
|
||||||
|
|
||||||
fun apiDeleteDevice(context: Context) {
|
|
||||||
val db = getDb(context)
|
|
||||||
db.listTokens().forEach {
|
|
||||||
sendUnregistered(context, it)
|
|
||||||
db.unregisterApp(it)
|
|
||||||
}
|
|
||||||
cApi(context) { cDeleteDevice(context) }
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun cDeleteDevice(context: Context) {
|
|
||||||
val deviceId = getDeviceId(context) ?: return
|
|
||||||
|
|
||||||
mApi?.deleteDevice(deviceId)
|
|
||||||
?.subscribeOn(Schedulers.newThread())
|
|
||||||
?.observeOn(Schedulers.newThread())
|
|
||||||
?.subscribe(object : Observer<ApiResponse?> {
|
|
||||||
override fun onSubscribe(d: Disposable) {
|
|
||||||
Log.d(TAG, "Subscribed to deleteDevice.")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onNext(response: ApiResponse) {
|
|
||||||
if (response.success) {
|
|
||||||
Log.d(TAG, "Device successfully deleted.")
|
|
||||||
} else {
|
|
||||||
Log.d(TAG, "An error occurred while deleting the device.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onError(e: Throwable) {
|
|
||||||
e.printStackTrace()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onComplete() {
|
|
||||||
removeUrl(context)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
removeDeviceId(context)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun apiCreateApp(
|
|
||||||
context: Context,
|
|
||||||
appName: String,
|
|
||||||
connectorToken: String,
|
|
||||||
callback: () -> Unit
|
|
||||||
) {
|
|
||||||
cApi(context) {
|
|
||||||
cCreateApp(context, appName, connectorToken) {
|
|
||||||
callback()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun cCreateApp(
|
|
||||||
context: Context,
|
|
||||||
appName: String,
|
|
||||||
connectorToken: String,
|
|
||||||
callback: () -> Unit
|
|
||||||
) {
|
|
||||||
// The unity of connector token must already be checked here
|
|
||||||
val parameters = getDeviceId(context)?.let {
|
|
||||||
mutableMapOf(
|
|
||||||
"deviceId" to it,
|
|
||||||
"appName" to appName
|
|
||||||
)
|
|
||||||
} ?: return
|
|
||||||
|
|
||||||
mApi?.createApp(parameters)
|
|
||||||
?.subscribeOn(Schedulers.newThread())
|
|
||||||
?.observeOn(Schedulers.newThread())
|
|
||||||
?.subscribe(object : Observer<ApiResponse?> {
|
|
||||||
override fun onSubscribe(d: Disposable) {
|
|
||||||
Log.d(TAG, "Subscribed to createApp.")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onNext(response: ApiResponse) {
|
|
||||||
if (response.success) {
|
|
||||||
Log.d(TAG, "App successfully created.")
|
|
||||||
/**
|
|
||||||
* Ignore printed error for SQLiteContstraintException.
|
|
||||||
* It is printed and not thrown by SQLiteDatabase.java
|
|
||||||
* So we can't catch it
|
|
||||||
*/
|
|
||||||
val db = getDb(context)
|
|
||||||
db.registerApp(appName, connectorToken, response.token)
|
|
||||||
} else {
|
|
||||||
Log.d(TAG, "An error occurred while creating the application.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onError(e: Throwable) {
|
|
||||||
createQueue.remove(connectorToken)
|
|
||||||
e.printStackTrace()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onComplete() {
|
|
||||||
createQueue.remove(connectorToken)
|
|
||||||
callback()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fun apiDeleteApp(context: Context, connectorToken: String, callback: () -> Unit) {
|
|
||||||
cApi(context) {
|
|
||||||
cDeleteApp(context, connectorToken) {
|
|
||||||
callback()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun cDeleteApp(context: Context, connectorToken: String, callback: () -> Unit) {
|
|
||||||
val appToken = getDb(context).getAppToken(connectorToken)
|
|
||||||
mApi?.deleteApp(appToken)
|
|
||||||
?.subscribeOn(Schedulers.newThread())
|
|
||||||
?.observeOn(Schedulers.newThread())
|
|
||||||
?.subscribe(object : Observer<ApiResponse?> {
|
|
||||||
override fun onSubscribe(d: Disposable) {
|
|
||||||
Log.d(TAG, "Subscribed to deleteApp.")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onNext(response: ApiResponse) {
|
|
||||||
if (response.success) {
|
|
||||||
Log.d(TAG, "App successfully deleted.")
|
|
||||||
} else {
|
|
||||||
Log.d(TAG, "An error occurred while deleting the application.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onError(e: Throwable) {
|
|
||||||
delQueue.remove(connectorToken)
|
|
||||||
e.printStackTrace()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onComplete() {
|
|
||||||
delQueue.remove(connectorToken)
|
|
||||||
callback()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,16 +1,17 @@
|
|||||||
package org.unifiedpush.distributor.nextpush.api
|
package org.unifiedpush.distributor.nextpush.api.provider
|
||||||
|
|
||||||
import io.reactivex.Observable
|
import io.reactivex.Observable
|
||||||
import retrofit2.http.PUT
|
import org.unifiedpush.distributor.nextpush.api.response.ApiResponse
|
||||||
import retrofit2.http.DELETE
|
|
||||||
import retrofit2.http.Body
|
import retrofit2.http.Body
|
||||||
|
import retrofit2.http.DELETE
|
||||||
|
import retrofit2.http.PUT
|
||||||
import retrofit2.http.Path
|
import retrofit2.http.Path
|
||||||
|
|
||||||
interface ProviderApi {
|
interface ApiProvider {
|
||||||
|
|
||||||
@PUT("/device/")
|
@PUT("/device/")
|
||||||
fun createDevice(
|
fun createDevice(
|
||||||
@Body subscribeMap: MutableMap<String, String>
|
@Body subscribeMap: Map<String, String>
|
||||||
): Observable<ApiResponse>?
|
): Observable<ApiResponse>?
|
||||||
|
|
||||||
@DELETE("/device/{deviceId}")
|
@DELETE("/device/{deviceId}")
|
||||||
@ -18,7 +19,7 @@ interface ProviderApi {
|
|||||||
|
|
||||||
@PUT("/app/")
|
@PUT("/app/")
|
||||||
fun createApp(
|
fun createApp(
|
||||||
@Body authorizeMap: MutableMap<String, String>
|
@Body authorizeMap: Map<String, String>
|
||||||
): Observable<ApiResponse>?
|
): Observable<ApiResponse>?
|
||||||
|
|
||||||
@DELETE("/app/{token}")
|
@DELETE("/app/{token}")
|
@ -0,0 +1,6 @@
|
|||||||
|
package org.unifiedpush.distributor.nextpush.api.provider
|
||||||
|
|
||||||
|
interface ApiProviderFactory {
|
||||||
|
fun getProviderAndExecute(block: (ApiProvider) -> Unit)
|
||||||
|
fun destroyProvider()
|
||||||
|
}
|
@ -0,0 +1,46 @@
|
|||||||
|
package org.unifiedpush.distributor.nextpush.api.provider
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.util.Log
|
||||||
|
import com.google.gson.GsonBuilder
|
||||||
|
import com.nextcloud.android.sso.api.NextcloudAPI
|
||||||
|
import org.unifiedpush.distributor.nextpush.account.AccountUtils
|
||||||
|
import retrofit2.NextcloudRetrofitApiBuilder
|
||||||
|
|
||||||
|
class ApiSSOFactory(val context: Context) : ApiProviderFactory {
|
||||||
|
|
||||||
|
private val TAG = ApiSSOFactory::class.java.simpleName
|
||||||
|
private var apiProvider: ApiProvider? = null
|
||||||
|
private lateinit var nextcloudAPI: NextcloudAPI
|
||||||
|
|
||||||
|
override fun getProviderAndExecute(block: (ApiProvider) -> Unit) {
|
||||||
|
apiProvider?.let(block)
|
||||||
|
?: run {
|
||||||
|
Log.d(TAG, "Creating new provider")
|
||||||
|
val ssoApiCallback = object : NextcloudAPI.ApiConnectedListener {
|
||||||
|
override fun onConnected() {
|
||||||
|
Log.d(TAG, "Api connected.")
|
||||||
|
NextcloudRetrofitApiBuilder(nextcloudAPI, ApiProvider.mApiEndpoint)
|
||||||
|
.create(ApiProvider::class.java).let {
|
||||||
|
apiProvider = it
|
||||||
|
block(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onError(ex: Exception) {
|
||||||
|
Log.d(TAG, "Cannot connect to API: ex = [$ex]")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nextcloudAPI = NextcloudAPI(
|
||||||
|
context,
|
||||||
|
AccountUtils.ssoAccount,
|
||||||
|
GsonBuilder().create(),
|
||||||
|
ssoApiCallback
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun destroyProvider() {
|
||||||
|
nextcloudAPI.stop()
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
package org.unifiedpush.distributor.nextpush.api
|
package org.unifiedpush.distributor.nextpush.api.response
|
||||||
|
|
||||||
data class ApiResponse(
|
data class ApiResponse(
|
||||||
val success: Boolean = false,
|
val success: Boolean = false,
|
||||||
val deviceId: String = "",
|
val deviceId: String = "",
|
||||||
val token: String = "",
|
val token: String = ""
|
||||||
)
|
)
|
@ -1,8 +1,8 @@
|
|||||||
package org.unifiedpush.distributor.nextpush.api
|
package org.unifiedpush.distributor.nextpush.api.response
|
||||||
|
|
||||||
data class SSEResponse (
|
data class SSEResponse(
|
||||||
val type: String = "",
|
val type: String = "",
|
||||||
val token: String = "",
|
val token: String = "",
|
||||||
val message: String = "",
|
val message: String = "",
|
||||||
val keepalive: Int = 900
|
val keepalive: Int = 900
|
||||||
)
|
)
|
@ -13,12 +13,12 @@ private const val FIELD_PACKAGE_NAME = "packageName"
|
|||||||
private const val FIELD_CONNECTOR_TOKEN = "connectorToken"
|
private const val FIELD_CONNECTOR_TOKEN = "connectorToken"
|
||||||
private const val FIELD_APP_TOKEN = "appToken"
|
private const val FIELD_APP_TOKEN = "appToken"
|
||||||
private const val CREATE_TABLE_APPS = "CREATE TABLE apps (" +
|
private const val CREATE_TABLE_APPS = "CREATE TABLE apps (" +
|
||||||
"$FIELD_PACKAGE_NAME TEXT," +
|
"$FIELD_PACKAGE_NAME TEXT," +
|
||||||
"$FIELD_CONNECTOR_TOKEN TEXT," +
|
"$FIELD_CONNECTOR_TOKEN TEXT," +
|
||||||
"$FIELD_APP_TOKEN TEXT," +
|
"$FIELD_APP_TOKEN TEXT," +
|
||||||
"PRIMARY KEY ($FIELD_CONNECTOR_TOKEN));"
|
"PRIMARY KEY ($FIELD_CONNECTOR_TOKEN));"
|
||||||
|
|
||||||
class MessagingDatabase(context: Context):
|
class ConnectionsDatabase(context: Context) :
|
||||||
SQLiteOpenHelper(context, DB_NAME, null, DB_VERSION) {
|
SQLiteOpenHelper(context, DB_NAME, null, DB_VERSION) {
|
||||||
|
|
||||||
override fun onCreate(db: SQLiteDatabase) {
|
override fun onCreate(db: SQLiteDatabase) {
|
||||||
@ -51,19 +51,19 @@ class MessagingDatabase(context: Context):
|
|||||||
val selection = "$FIELD_PACKAGE_NAME = ? AND $FIELD_CONNECTOR_TOKEN = ?"
|
val selection = "$FIELD_PACKAGE_NAME = ? AND $FIELD_CONNECTOR_TOKEN = ?"
|
||||||
val selectionArgs = arrayOf(packageName, connectorToken)
|
val selectionArgs = arrayOf(packageName, connectorToken)
|
||||||
return db.query(
|
return db.query(
|
||||||
TABLE_APPS,
|
TABLE_APPS,
|
||||||
null,
|
null,
|
||||||
selection,
|
selection,
|
||||||
selectionArgs,
|
selectionArgs,
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
null
|
null
|
||||||
).use { cursor ->
|
).use { cursor ->
|
||||||
(cursor != null && cursor.count > 0)
|
(cursor != null && cursor.count > 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getPackageName(connectorToken: String): String {
|
fun getPackageName(connectorToken: String): String? {
|
||||||
val db = readableDatabase
|
val db = readableDatabase
|
||||||
val projection = arrayOf(FIELD_PACKAGE_NAME)
|
val projection = arrayOf(FIELD_PACKAGE_NAME)
|
||||||
val selection = "$FIELD_CONNECTOR_TOKEN = ?"
|
val selection = "$FIELD_CONNECTOR_TOKEN = ?"
|
||||||
@ -78,11 +78,11 @@ class MessagingDatabase(context: Context):
|
|||||||
null
|
null
|
||||||
).use { cursor ->
|
).use { cursor ->
|
||||||
val column = cursor.getColumnIndex(FIELD_PACKAGE_NAME)
|
val column = cursor.getColumnIndex(FIELD_PACKAGE_NAME)
|
||||||
if (cursor.moveToFirst() && column >= 0) cursor.getString(column) else ""
|
if (cursor.moveToFirst() && column >= 0) cursor.getString(column) else null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getAppToken(connectorToken: String): String {
|
fun getAppToken(connectorToken: String): String? {
|
||||||
val db = readableDatabase
|
val db = readableDatabase
|
||||||
val projection = arrayOf(FIELD_APP_TOKEN)
|
val projection = arrayOf(FIELD_APP_TOKEN)
|
||||||
val selection = "$FIELD_CONNECTOR_TOKEN = ?"
|
val selection = "$FIELD_CONNECTOR_TOKEN = ?"
|
||||||
@ -97,11 +97,11 @@ class MessagingDatabase(context: Context):
|
|||||||
null
|
null
|
||||||
).use { cursor ->
|
).use { cursor ->
|
||||||
val column = cursor.getColumnIndex(FIELD_APP_TOKEN)
|
val column = cursor.getColumnIndex(FIELD_APP_TOKEN)
|
||||||
if (cursor.moveToFirst() && column >= 0) cursor.getString(column) else ""
|
if (cursor.moveToFirst() && column >= 0) cursor.getString(column) else null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getConnectorToken(appToken: String): String {
|
fun getConnectorToken(appToken: String): String? {
|
||||||
val db = readableDatabase
|
val db = readableDatabase
|
||||||
val projection = arrayOf(FIELD_CONNECTOR_TOKEN)
|
val projection = arrayOf(FIELD_CONNECTOR_TOKEN)
|
||||||
val selection = "$FIELD_APP_TOKEN = ?"
|
val selection = "$FIELD_APP_TOKEN = ?"
|
||||||
@ -116,7 +116,7 @@ class MessagingDatabase(context: Context):
|
|||||||
null
|
null
|
||||||
).use { cursor ->
|
).use { cursor ->
|
||||||
val column = cursor.getColumnIndex(FIELD_CONNECTOR_TOKEN)
|
val column = cursor.getColumnIndex(FIELD_CONNECTOR_TOKEN)
|
||||||
if (cursor.moveToFirst() && column >= 0) cursor.getString(column) else ""
|
if (cursor.moveToFirst() && column >= 0) cursor.getString(column) else null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,11 +131,12 @@ class MessagingDatabase(context: Context):
|
|||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
null
|
null
|
||||||
).use{ cursor ->
|
).use { cursor ->
|
||||||
generateSequence { if (cursor.moveToNext()) cursor else null }
|
generateSequence { if (cursor.moveToNext()) cursor else null }
|
||||||
.mapNotNull{
|
.mapNotNull {
|
||||||
val column = cursor.getColumnIndex(FIELD_CONNECTOR_TOKEN)
|
val column = cursor.getColumnIndex(FIELD_CONNECTOR_TOKEN)
|
||||||
if (column >= 0) it.getString(column) else null }
|
if (column >= 0) it.getString(column) else null
|
||||||
|
}
|
||||||
.toList()
|
.toList()
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -4,35 +4,35 @@ import android.content.Context
|
|||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import org.unifiedpush.distributor.nextpush.account.AccountUtils.getUrl
|
import org.unifiedpush.distributor.nextpush.account.AccountUtils.getUrl
|
||||||
|
import org.unifiedpush.distributor.nextpush.api.Api.apiCreateApp
|
||||||
|
import org.unifiedpush.distributor.nextpush.api.Api.apiDeleteApp
|
||||||
|
import org.unifiedpush.distributor.nextpush.api.Api.apiDeleteDevice
|
||||||
|
import org.unifiedpush.distributor.nextpush.utils.TAG
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* These functions are used to send messages to other apps
|
* These functions are used to send messages to other apps
|
||||||
*/
|
*/
|
||||||
|
|
||||||
private const val TAG = "DistributorUtils"
|
object Distributor {
|
||||||
|
|
||||||
object DistributorUtils {
|
|
||||||
|
|
||||||
const val TOKEN_NEW = "token_new"
|
const val TOKEN_NEW = "token_new"
|
||||||
const val TOKEN_REGISTERED_OK = "token_registered_ok"
|
const val TOKEN_REGISTERED_OK = "token_registered_ok"
|
||||||
const val TOKEN_NOK = "token_nok"
|
const val TOKEN_NOK = "token_nok"
|
||||||
|
|
||||||
private lateinit var db: MessagingDatabase
|
private lateinit var db: ConnectionsDatabase
|
||||||
|
|
||||||
fun getDb(context: Context): MessagingDatabase {
|
fun getDb(context: Context): ConnectionsDatabase {
|
||||||
if (!this::db.isInitialized) {
|
if (!this::db.isInitialized) {
|
||||||
db = MessagingDatabase(context)
|
db = ConnectionsDatabase(context)
|
||||||
}
|
}
|
||||||
return db
|
return db
|
||||||
}
|
}
|
||||||
|
|
||||||
fun sendMessage(context: Context, appToken: String, message: ByteArray) {
|
fun sendMessage(context: Context, appToken: String, message: ByteArray) {
|
||||||
val db = getDb(context)
|
val db = getDb(context)
|
||||||
val connectorToken = db.getConnectorToken(appToken)
|
val connectorToken = db.getConnectorToken(appToken) ?: return
|
||||||
val application = getApp(context, connectorToken)
|
val application = getApp(context, connectorToken)
|
||||||
if (application.isNullOrBlank()) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
val broadcastIntent = Intent()
|
val broadcastIntent = Intent()
|
||||||
broadcastIntent.`package` = application
|
broadcastIntent.`package` = application
|
||||||
broadcastIntent.action = ACTION_MESSAGE
|
broadcastIntent.action = ACTION_MESSAGE
|
||||||
@ -73,7 +73,7 @@ object DistributorUtils {
|
|||||||
context.sendBroadcast(broadcastIntent)
|
context.sendBroadcast(broadcastIntent)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun sendUnregistered(context: Context, connectorToken: String) {
|
private fun sendUnregistered(context: Context, connectorToken: String) {
|
||||||
val application = getApp(context, connectorToken)
|
val application = getApp(context, connectorToken)
|
||||||
if (application.isNullOrBlank()) {
|
if (application.isNullOrBlank()) {
|
||||||
return
|
return
|
||||||
@ -88,10 +88,7 @@ object DistributorUtils {
|
|||||||
private fun getApp(context: Context, connectorToken: String): String? {
|
private fun getApp(context: Context, connectorToken: String): String? {
|
||||||
val db = getDb(context)
|
val db = getDb(context)
|
||||||
val app = db.getPackageName(connectorToken)
|
val app = db.getPackageName(connectorToken)
|
||||||
return app.ifBlank {
|
return app
|
||||||
Log.w(TAG, "No app found for this token")
|
|
||||||
null
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getEndpoint(context: Context, connectorToken: String): String {
|
private fun getEndpoint(context: Context, connectorToken: String): String {
|
||||||
@ -110,4 +107,41 @@ object DistributorUtils {
|
|||||||
}
|
}
|
||||||
return TOKEN_NOK
|
return TOKEN_NOK
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
fun deleteDevice(context: Context) {
|
||||||
|
val db = getDb(context)
|
||||||
|
db.listTokens().forEach {
|
||||||
|
sendUnregistered(context, it)
|
||||||
|
db.unregisterApp(it)
|
||||||
|
}
|
||||||
|
context.apiDeleteDevice()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun createApp(context: Context, appName: String, connectorToken: String, block: () -> Unit) {
|
||||||
|
context.apiCreateApp(appName) { nextpushToken ->
|
||||||
|
nextpushToken?.let {
|
||||||
|
getDb(context).registerApp(appName, connectorToken, it)
|
||||||
|
}
|
||||||
|
block()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun deleteApp(context: Context, connectorToken: String, block: () -> Unit) {
|
||||||
|
sendUnregistered(context, connectorToken)
|
||||||
|
val db = getDb(context)
|
||||||
|
db.getAppToken(
|
||||||
|
connectorToken
|
||||||
|
)?.let { nextpushToken ->
|
||||||
|
context.apiDeleteApp(nextpushToken) {
|
||||||
|
db.unregisterApp(connectorToken)
|
||||||
|
block()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun deleteAppFromAppToken(context: Context, appToken: String) {
|
||||||
|
getDb(context).getConnectorToken(appToken)?.let {
|
||||||
|
deleteApp(context, it) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -6,33 +6,33 @@ import android.content.Intent
|
|||||||
import android.os.PowerManager
|
import android.os.PowerManager
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import org.unifiedpush.distributor.nextpush.account.AccountUtils.isConnected
|
import org.unifiedpush.distributor.nextpush.account.AccountUtils.isConnected
|
||||||
import org.unifiedpush.distributor.nextpush.api.ApiUtils.apiCreateApp
|
import org.unifiedpush.distributor.nextpush.distributor.* // ktlint-disable no-wildcard-imports
|
||||||
import org.unifiedpush.distributor.nextpush.api.ApiUtils.apiDeleteApp
|
import org.unifiedpush.distributor.nextpush.distributor.Distributor.TOKEN_NEW
|
||||||
import org.unifiedpush.distributor.nextpush.api.ApiUtils.createQueue
|
import org.unifiedpush.distributor.nextpush.distributor.Distributor.TOKEN_NOK
|
||||||
import org.unifiedpush.distributor.nextpush.api.ApiUtils.delQueue
|
import org.unifiedpush.distributor.nextpush.distributor.Distributor.TOKEN_REGISTERED_OK
|
||||||
|
import org.unifiedpush.distributor.nextpush.distributor.Distributor.checkToken
|
||||||
import org.unifiedpush.distributor.nextpush.distributor.*
|
import org.unifiedpush.distributor.nextpush.distributor.Distributor.createApp
|
||||||
import org.unifiedpush.distributor.nextpush.distributor.DistributorUtils.TOKEN_NEW
|
import org.unifiedpush.distributor.nextpush.distributor.Distributor.deleteApp
|
||||||
import org.unifiedpush.distributor.nextpush.distributor.DistributorUtils.TOKEN_NOK
|
import org.unifiedpush.distributor.nextpush.distributor.Distributor.getDb
|
||||||
import org.unifiedpush.distributor.nextpush.distributor.DistributorUtils.TOKEN_REGISTERED_OK
|
import org.unifiedpush.distributor.nextpush.distributor.Distributor.sendEndpoint
|
||||||
import org.unifiedpush.distributor.nextpush.distributor.DistributorUtils.checkToken
|
import org.unifiedpush.distributor.nextpush.distributor.Distributor.sendRegistrationFailed
|
||||||
import org.unifiedpush.distributor.nextpush.distributor.DistributorUtils.getDb
|
import org.unifiedpush.distributor.nextpush.utils.TAG
|
||||||
import org.unifiedpush.distributor.nextpush.distributor.DistributorUtils.sendEndpoint
|
|
||||||
import org.unifiedpush.distributor.nextpush.distributor.DistributorUtils.sendRegistrationFailed
|
|
||||||
import org.unifiedpush.distributor.nextpush.distributor.DistributorUtils.sendUnregistered
|
|
||||||
import java.lang.Exception
|
import java.lang.Exception
|
||||||
|
import java.util.Timer
|
||||||
|
import kotlin.concurrent.schedule
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* THIS SERVICE IS USED BY OTHER APPS TO REGISTER
|
* THIS SERVICE IS USED BY OTHER APPS TO REGISTER
|
||||||
*/
|
*/
|
||||||
|
|
||||||
private const val TAG = "RegisterBroadcastReceiver"
|
private val createQueue = emptyList<String>().toMutableList()
|
||||||
|
private val delQueue = emptyList<String>().toMutableList()
|
||||||
|
|
||||||
class RegisterBroadcastReceiver : BroadcastReceiver() {
|
class RegisterBroadcastReceiver : BroadcastReceiver() {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val WAKE_LOCK_TAG = "NextPush:RegisterBroadcastReceiver:lock"
|
private const val WAKE_LOCK_TAG = "NextPush:RegisterBroadcastReceiver:lock"
|
||||||
private var wakeLock : PowerManager.WakeLock? = null
|
private var wakeLock: PowerManager.WakeLock? = null
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onReceive(context: Context, intent: Intent?) {
|
override fun onReceive(context: Context, intent: Intent?) {
|
||||||
@ -41,25 +41,27 @@ class RegisterBroadcastReceiver : BroadcastReceiver() {
|
|||||||
}
|
}
|
||||||
wakeLock?.acquire(30000L /*30 secs*/)
|
wakeLock?.acquire(30000L /*30 secs*/)
|
||||||
when (intent?.action) {
|
when (intent?.action) {
|
||||||
ACTION_REGISTER ->{
|
ACTION_REGISTER -> {
|
||||||
Log.i(TAG,"REGISTER")
|
Log.i(TAG, "REGISTER")
|
||||||
val connectorToken = intent.getStringExtra(EXTRA_TOKEN)?: ""
|
val connectorToken = intent.getStringExtra(EXTRA_TOKEN) ?: run {
|
||||||
val application = intent.getStringExtra(EXTRA_APPLICATION)?: ""
|
Log.w(TAG, "Trying to register an app without connector token")
|
||||||
if (application.isBlank()) {
|
|
||||||
Log.w(TAG,"Trying to register an app without packageName")
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
when (checkToken(context, connectorToken, application)) {
|
val application = intent.getStringExtra(EXTRA_APPLICATION) ?: run {
|
||||||
|
Log.w(TAG, "Trying to register an app without packageName")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
when (checkToken(context.applicationContext, connectorToken, application)) {
|
||||||
TOKEN_REGISTERED_OK -> sendEndpoint(context.applicationContext, connectorToken)
|
TOKEN_REGISTERED_OK -> sendEndpoint(context.applicationContext, connectorToken)
|
||||||
TOKEN_NOK -> sendRegistrationFailed(
|
TOKEN_NOK -> sendRegistrationFailed(
|
||||||
context,
|
context.applicationContext,
|
||||||
application,
|
application,
|
||||||
connectorToken
|
connectorToken
|
||||||
)
|
)
|
||||||
TOKEN_NEW -> {
|
TOKEN_NEW -> {
|
||||||
if (!isConnected(context, showDialog = false)) {
|
if (!isConnected(context.applicationContext, showDialog = false)) {
|
||||||
sendRegistrationFailed(
|
sendRegistrationFailed(
|
||||||
context,
|
context.applicationContext,
|
||||||
application,
|
application,
|
||||||
connectorToken,
|
connectorToken,
|
||||||
message = "NextPush is not connected"
|
message = "NextPush is not connected"
|
||||||
@ -68,12 +70,14 @@ class RegisterBroadcastReceiver : BroadcastReceiver() {
|
|||||||
}
|
}
|
||||||
if (connectorToken !in createQueue) {
|
if (connectorToken !in createQueue) {
|
||||||
createQueue.add(connectorToken)
|
createQueue.add(connectorToken)
|
||||||
apiCreateApp(
|
delayRemove(createQueue, connectorToken)
|
||||||
|
createApp(
|
||||||
context.applicationContext,
|
context.applicationContext,
|
||||||
application,
|
application,
|
||||||
connectorToken
|
connectorToken
|
||||||
) {
|
) {
|
||||||
sendEndpoint(context.applicationContext, connectorToken)
|
sendEndpoint(context.applicationContext, connectorToken)
|
||||||
|
createQueue.remove(connectorToken)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Log.d(TAG, "Already registering this token")
|
Log.d(TAG, "Already registering this token")
|
||||||
@ -81,21 +85,18 @@ class RegisterBroadcastReceiver : BroadcastReceiver() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ACTION_UNREGISTER ->{
|
ACTION_UNREGISTER -> {
|
||||||
Log.i(TAG,"UNREGISTER")
|
Log.i(TAG, "UNREGISTER")
|
||||||
val connectorToken = intent.getStringExtra(EXTRA_TOKEN)?: ""
|
val connectorToken = intent.getStringExtra(EXTRA_TOKEN) ?: ""
|
||||||
val application = getDb(context).getPackageName(connectorToken)
|
getDb(context.applicationContext).getPackageName(connectorToken) ?: return
|
||||||
if (application.isBlank()) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (connectorToken !in delQueue) {
|
if (connectorToken !in delQueue) {
|
||||||
delQueue.add(connectorToken)
|
delQueue.add(connectorToken)
|
||||||
sendUnregistered(context.applicationContext, connectorToken)
|
delayRemove(delQueue, connectorToken)
|
||||||
try {
|
try {
|
||||||
apiDeleteApp(context.applicationContext, connectorToken) {
|
deleteApp(context.applicationContext, connectorToken) {
|
||||||
val db = getDb(context.applicationContext)
|
|
||||||
db.unregisterApp(connectorToken)
|
|
||||||
Log.d(TAG, "Unregistration is finished")
|
Log.d(TAG, "Unregistration is finished")
|
||||||
|
delQueue.remove(connectorToken)
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.d(TAG, "Could not delete app")
|
Log.d(TAG, "Could not delete app")
|
||||||
@ -111,4 +112,10 @@ class RegisterBroadcastReceiver : BroadcastReceiver() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
private fun delayRemove(list: MutableList<String>, token: String) {
|
||||||
|
Timer().schedule(1_000L /* 1sec */) {
|
||||||
|
list.remove(token)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -13,4 +13,3 @@ class StartReceiver : BroadcastReceiver() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,32 +3,33 @@ package org.unifiedpush.distributor.nextpush.services
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import okhttp3.sse.EventSource
|
import okhttp3.sse.EventSource
|
||||||
import org.unifiedpush.distributor.nextpush.services.NotificationUtils.createWarningNotification
|
import org.unifiedpush.distributor.nextpush.utils.NotificationUtils.createWarningNotification
|
||||||
import org.unifiedpush.distributor.nextpush.services.NotificationUtils.deleteWarningNotification
|
import org.unifiedpush.distributor.nextpush.utils.NotificationUtils.deleteWarningNotification
|
||||||
|
import org.unifiedpush.distributor.nextpush.utils.TAG
|
||||||
private const val TAG = "FailureHandler"
|
|
||||||
|
|
||||||
interface FailureHandler {
|
interface FailureHandler {
|
||||||
|
|
||||||
var nFails: Int
|
var nFails: Int
|
||||||
|
|
||||||
// This is the last eventSource opened
|
// This is the last eventSource opened
|
||||||
var eventSource: EventSource?
|
var eventSource: EventSource?
|
||||||
|
|
||||||
fun newEventSource(context: Context, eventSource: EventSource) {
|
fun newEventSource(context: Context, eventSource: EventSource) {
|
||||||
Log.d(TAG,"newEvent/Eventsource: $eventSource")
|
Log.d(TAG, "newEvent/Eventsource: $eventSource")
|
||||||
this.eventSource = eventSource
|
this.eventSource = eventSource
|
||||||
nFails = 0
|
nFails = 0
|
||||||
deleteWarningNotification(context)
|
deleteWarningNotification(context)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun newFail(context: Context, eventSource: EventSource?) {
|
fun newFail(context: Context, eventSource: EventSource?) {
|
||||||
Log.d(TAG,"newFail/Eventsource: $eventSource")
|
Log.d(TAG, "newFail/Eventsource: $eventSource")
|
||||||
// no eventSource or the last opened
|
// no eventSource or the last opened
|
||||||
if (this.eventSource == null || this.eventSource == eventSource) {
|
if (this.eventSource == null || this.eventSource == eventSource) {
|
||||||
Log.d(TAG, "EventSource is known or null")
|
Log.d(TAG, "EventSource is known or null")
|
||||||
nFails++
|
nFails++
|
||||||
if (hasFailed(twice = true))
|
if (hasFailed(twice = true)) {
|
||||||
createWarningNotification(context)
|
createWarningNotification(context)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,10 +45,10 @@ interface FailureHandler {
|
|||||||
nFails = 0
|
nFails = 0
|
||||||
eventSource = null
|
eventSource = null
|
||||||
}
|
}
|
||||||
|
|
||||||
fun hasFailed(twice: Boolean = false, orNeverStart: Boolean = true): Boolean {
|
fun hasFailed(twice: Boolean = false, orNeverStart: Boolean = true): Boolean {
|
||||||
// nFails > 0 to be sure it is not actually restarting
|
// nFails > 0 to be sure it is not actually restarting
|
||||||
return if (orNeverStart) { eventSource == null } else { false } ||
|
return if (orNeverStart) { eventSource == null } else { false } ||
|
||||||
nFails > if (twice) { 1 } else { 0 }
|
nFails > if (twice) { 1 } else { 0 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,18 +2,18 @@ package org.unifiedpush.distributor.nextpush.services
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.work.*
|
import androidx.work.* // ktlint-disable no-wildcard-imports
|
||||||
import org.unifiedpush.distributor.nextpush.services.SSEListener.Companion.keepalive
|
import org.unifiedpush.distributor.nextpush.services.SSEListener.Companion.keepalive
|
||||||
import org.unifiedpush.distributor.nextpush.services.SSEListener.Companion.lastEventDate
|
import org.unifiedpush.distributor.nextpush.services.SSEListener.Companion.lastEventDate
|
||||||
|
import org.unifiedpush.distributor.nextpush.utils.TAG
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
private const val UNIQUE_WORK_TAG = "nextpush::RestartWorker::unique"
|
private const val UNIQUE_WORK_TAG = "nextpush::RestartWorker::unique"
|
||||||
|
|
||||||
class RestartWorker (ctx: Context, params: WorkerParameters) : Worker(ctx, params) {
|
class RestartWorker(ctx: Context, params: WorkerParameters) : Worker(ctx, params) {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val TAG = "RestartWorker"
|
|
||||||
fun start(context: Context, delay: Long? = null) {
|
fun start(context: Context, delay: Long? = null) {
|
||||||
val work = PeriodicWorkRequestBuilder<RestartWorker>(16, TimeUnit.MINUTES)
|
val work = PeriodicWorkRequestBuilder<RestartWorker>(16, TimeUnit.MINUTES)
|
||||||
if (delay != null) {
|
if (delay != null) {
|
||||||
@ -42,10 +42,10 @@ class RestartWorker (ctx: Context, params: WorkerParameters) : Worker(ctx, param
|
|||||||
StartService.setMaxFails(applicationContext) // Max, will keep using the current worker
|
StartService.setMaxFails(applicationContext) // Max, will keep using the current worker
|
||||||
StartService.startListener(applicationContext)
|
StartService.startListener(applicationContext)
|
||||||
}
|
}
|
||||||
}?:run {
|
} ?: run {
|
||||||
Log.d(TAG, "Restarting")
|
Log.d(TAG, "Restarting")
|
||||||
StartService.startListener(applicationContext)
|
StartService.startListener(applicationContext)
|
||||||
}
|
}
|
||||||
return Result.success()
|
return Result.success()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,24 +2,22 @@ package org.unifiedpush.distributor.nextpush.services
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.util.Base64
|
import android.util.Base64
|
||||||
import okhttp3.sse.EventSourceListener
|
|
||||||
import okhttp3.sse.EventSource
|
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import okhttp3.Response
|
|
||||||
import java.lang.Exception
|
|
||||||
import com.google.gson.Gson
|
import com.google.gson.Gson
|
||||||
import org.unifiedpush.distributor.nextpush.api.SSEResponse
|
import okhttp3.Response
|
||||||
import org.unifiedpush.distributor.nextpush.distributor.DistributorUtils.getDb
|
import okhttp3.sse.EventSource
|
||||||
import org.unifiedpush.distributor.nextpush.distributor.DistributorUtils.sendMessage
|
import okhttp3.sse.EventSourceListener
|
||||||
import org.unifiedpush.distributor.nextpush.distributor.DistributorUtils.sendUnregistered
|
import org.unifiedpush.distributor.nextpush.api.response.SSEResponse
|
||||||
import java.util.*
|
import org.unifiedpush.distributor.nextpush.distributor.Distributor.deleteAppFromAppToken
|
||||||
|
import org.unifiedpush.distributor.nextpush.distributor.Distributor.sendMessage
|
||||||
|
import org.unifiedpush.distributor.nextpush.utils.TAG
|
||||||
|
import java.lang.Exception
|
||||||
|
import java.util.Calendar
|
||||||
|
|
||||||
private const val TAG = "SSEListener"
|
class SSEListener(val context: Context) : EventSourceListener() {
|
||||||
|
|
||||||
class SSEListener (val context: Context) : EventSourceListener() {
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
var lastEventDate : Calendar? = null
|
var lastEventDate: Calendar? = null
|
||||||
var keepalive = 900
|
var keepalive = 900
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,12 +56,7 @@ class SSEListener (val context: Context) : EventSourceListener() {
|
|||||||
}
|
}
|
||||||
"deleteApp" -> {
|
"deleteApp" -> {
|
||||||
val message = Gson().fromJson(data, SSEResponse::class.java)
|
val message = Gson().fromJson(data, SSEResponse::class.java)
|
||||||
val db = getDb(context.applicationContext)
|
deleteAppFromAppToken(context, message.token)
|
||||||
val connectorToken = db.getConnectorToken(message.token)
|
|
||||||
if (connectorToken.isEmpty())
|
|
||||||
return
|
|
||||||
sendUnregistered(context.applicationContext, connectorToken)
|
|
||||||
db.unregisterApp(connectorToken)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
StartService.wakeLock?.let {
|
StartService.wakeLock?.let {
|
||||||
@ -74,16 +67,18 @@ class SSEListener (val context: Context) : EventSourceListener() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onClosed(eventSource: EventSource) {
|
override fun onClosed(eventSource: EventSource) {
|
||||||
if (!StartService.isServiceStarted)
|
if (!StartService.isServiceStarted) {
|
||||||
return
|
return
|
||||||
|
}
|
||||||
Log.d(TAG, "onClosed: $eventSource")
|
Log.d(TAG, "onClosed: $eventSource")
|
||||||
StartService.newFail(context, eventSource)
|
StartService.newFail(context, eventSource)
|
||||||
RestartWorker.start(context, delay = 0)
|
RestartWorker.start(context, delay = 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onFailure(eventSource: EventSource, t: Throwable?, response: Response?) {
|
override fun onFailure(eventSource: EventSource, t: Throwable?, response: Response?) {
|
||||||
if (!StartService.isServiceStarted)
|
if (!StartService.isServiceStarted) {
|
||||||
return
|
return
|
||||||
|
}
|
||||||
Log.d(TAG, "onFailure")
|
Log.d(TAG, "onFailure")
|
||||||
t?.let {
|
t?.let {
|
||||||
Log.d(TAG, "An error occurred: $t")
|
Log.d(TAG, "An error occurred: $t")
|
||||||
@ -93,12 +88,12 @@ class SSEListener (val context: Context) : EventSourceListener() {
|
|||||||
}
|
}
|
||||||
StartService.newFail(context, eventSource)
|
StartService.newFail(context, eventSource)
|
||||||
val delay = when (StartService.nFails) {
|
val delay = when (StartService.nFails) {
|
||||||
1 -> 2 // 2sec
|
1 -> 2 // 2sec
|
||||||
2 -> 20 // 20sec
|
2 -> 20 // 20sec
|
||||||
3 -> 60 // 1min
|
3 -> 60 // 1min
|
||||||
4 -> 300 // 5min
|
4 -> 300 // 5min
|
||||||
5 -> 600 // 10min
|
5 -> 600 // 10min
|
||||||
else -> return // else keep the worker with its 16min
|
else -> return // else keep the worker with its 16min
|
||||||
}.toLong()
|
}.toLong()
|
||||||
Log.d(TAG, "Retrying in $delay s")
|
Log.d(TAG, "Retrying in $delay s")
|
||||||
RestartWorker.start(context, delay = delay)
|
RestartWorker.start(context, delay = delay)
|
||||||
|
@ -3,41 +3,37 @@ package org.unifiedpush.distributor.nextpush.services
|
|||||||
import android.app.Service
|
import android.app.Service
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import android.net.ConnectivityManager
|
||||||
|
import android.net.ConnectivityManager.NetworkCallback
|
||||||
|
import android.net.Network
|
||||||
|
import android.net.NetworkCapabilities
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.IBinder
|
import android.os.IBinder
|
||||||
import android.os.PowerManager
|
import android.os.PowerManager
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
|
||||||
import com.nextcloud.android.sso.exceptions.NextcloudFilesAppAccountNotFoundException
|
import com.nextcloud.android.sso.exceptions.NextcloudFilesAppAccountNotFoundException
|
||||||
import com.nextcloud.android.sso.exceptions.NoCurrentAccountSelectedException
|
import com.nextcloud.android.sso.exceptions.NoCurrentAccountSelectedException
|
||||||
import com.nextcloud.android.sso.helper.SingleAccountHelper
|
import com.nextcloud.android.sso.helper.SingleAccountHelper
|
||||||
|
|
||||||
import org.unifiedpush.distributor.nextpush.account.AccountUtils.ssoAccount
|
|
||||||
import org.unifiedpush.distributor.nextpush.account.AccountUtils.nextcloudAppNotInstalledDialog
|
|
||||||
|
|
||||||
import android.net.Network
|
|
||||||
|
|
||||||
import android.net.ConnectivityManager
|
|
||||||
import android.net.ConnectivityManager.NetworkCallback
|
|
||||||
import android.net.NetworkCapabilities
|
|
||||||
import okhttp3.sse.EventSource
|
import okhttp3.sse.EventSource
|
||||||
import org.unifiedpush.distributor.nextpush.api.ApiUtils.apiDestroy
|
import org.unifiedpush.distributor.nextpush.account.AccountUtils.nextcloudAppNotInstalledDialog
|
||||||
import org.unifiedpush.distributor.nextpush.api.ApiUtils.apiSync
|
import org.unifiedpush.distributor.nextpush.account.AccountUtils.ssoAccount
|
||||||
import org.unifiedpush.distributor.nextpush.services.NotificationUtils.createForegroundNotification
|
import org.unifiedpush.distributor.nextpush.api.Api.apiDestroy
|
||||||
|
import org.unifiedpush.distributor.nextpush.api.Api.apiSync
|
||||||
|
import org.unifiedpush.distributor.nextpush.utils.NOTIFICATION_ID_FOREGROUND
|
||||||
|
import org.unifiedpush.distributor.nextpush.utils.NotificationUtils.createForegroundNotification
|
||||||
|
import org.unifiedpush.distributor.nextpush.utils.TAG
|
||||||
import java.lang.Exception
|
import java.lang.Exception
|
||||||
|
|
||||||
private const val TAG = "StartService"
|
class StartService : Service() {
|
||||||
|
|
||||||
class StartService: Service(){
|
companion object : FailureHandler {
|
||||||
|
|
||||||
companion object: FailureHandler {
|
|
||||||
private const val WAKE_LOCK_TAG = "NextPush:StartService:lock"
|
private const val WAKE_LOCK_TAG = "NextPush:StartService:lock"
|
||||||
const val SERVICE_STOPPED_ACTION = "org.unifiedpush.distributor.nextpush.services.STOPPED"
|
const val SERVICE_STOPPED_ACTION = "org.unifiedpush.distributor.nextpush.services.STOPPED"
|
||||||
|
|
||||||
var isServiceStarted = false
|
var isServiceStarted = false
|
||||||
var wakeLock: PowerManager.WakeLock? = null
|
var wakeLock: PowerManager.WakeLock? = null
|
||||||
|
|
||||||
fun startListener(context: Context){
|
fun startListener(context: Context) {
|
||||||
if (isServiceStarted && !hasFailed()) return
|
if (isServiceStarted && !hasFailed()) return
|
||||||
Log.d(TAG, "Starting the Listener")
|
Log.d(TAG, "Starting the Listener")
|
||||||
Log.d(TAG, "Service is started: $isServiceStarted")
|
Log.d(TAG, "Service is started: $isServiceStarted")
|
||||||
@ -45,7 +41,7 @@ class StartService: Service(){
|
|||||||
val serviceIntent = Intent(context, StartService::class.java)
|
val serviceIntent = Intent(context, StartService::class.java)
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
context.startForegroundService(serviceIntent)
|
context.startForegroundService(serviceIntent)
|
||||||
}else{
|
} else {
|
||||||
context.startService(serviceIntent)
|
context.startService(serviceIntent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -59,9 +55,9 @@ class StartService: Service(){
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreate(){
|
override fun onCreate() {
|
||||||
super.onCreate()
|
super.onCreate()
|
||||||
Log.i(TAG,"StartService created")
|
Log.i(TAG, "StartService created")
|
||||||
val notification = createForegroundNotification(this)
|
val notification = createForegroundNotification(this)
|
||||||
startForeground(NOTIFICATION_ID_FOREGROUND, notification)
|
startForeground(NOTIFICATION_ID_FOREGROUND, notification)
|
||||||
}
|
}
|
||||||
@ -124,12 +120,13 @@ class StartService: Service(){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
apiSync(this)
|
apiSync()
|
||||||
}
|
}
|
||||||
|
|
||||||
private var connectivityManager = null as ConnectivityManager?
|
private var connectivityManager = null as ConnectivityManager?
|
||||||
|
|
||||||
private val networkCallback = object : NetworkCallback() {
|
private val networkCallback = object : NetworkCallback() {
|
||||||
|
val TAG = this@StartService.TAG
|
||||||
override fun onAvailable(network: Network) {
|
override fun onAvailable(network: Network) {
|
||||||
Log.d(TAG, "Network is CONNECTED")
|
Log.d(TAG, "Network is CONNECTED")
|
||||||
if (StartService.hasFailed(twice = true, orNeverStart = false)) {
|
if (StartService.hasFailed(twice = true, orNeverStart = false)) {
|
||||||
@ -154,13 +151,12 @@ class StartService: Service(){
|
|||||||
Log.d(TAG, "Registering Network Callback")
|
Log.d(TAG, "Registering Network Callback")
|
||||||
try {
|
try {
|
||||||
connectivityManager = (
|
connectivityManager = (
|
||||||
this.getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager
|
this.getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager
|
||||||
).apply {
|
).apply {
|
||||||
registerDefaultNetworkCallback(networkCallback)
|
registerDefaultNetworkCallback(networkCallback)
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package org.unifiedpush.distributor.nextpush.services
|
package org.unifiedpush.distributor.nextpush.utils
|
||||||
|
|
||||||
import android.Manifest
|
import android.Manifest
|
||||||
import android.app.Notification
|
import android.app.Notification
|
||||||
@ -50,10 +50,14 @@ object NotificationUtils {
|
|||||||
)
|
)
|
||||||
|
|
||||||
val builder: Notification.Builder =
|
val builder: Notification.Builder =
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) Notification.Builder(
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
context,
|
Notification.Builder(
|
||||||
notificationChannelId
|
context,
|
||||||
) else Notification.Builder(context)
|
notificationChannelId
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
Notification.Builder(context)
|
||||||
|
}
|
||||||
|
|
||||||
return builder
|
return builder
|
||||||
.setContentTitle(context.getString(R.string.app_name))
|
.setContentTitle(context.getString(R.string.app_name))
|
||||||
@ -67,8 +71,9 @@ object NotificationUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun createWarningNotification(context: Context) {
|
fun createWarningNotification(context: Context) {
|
||||||
if (warningShown)
|
if (warningShown) {
|
||||||
return
|
return
|
||||||
|
}
|
||||||
val notificationChannelId = "${context.getString(R.string.app_name)}.Warning"
|
val notificationChannelId = "${context.getString(R.string.app_name)}.Warning"
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
@ -97,12 +102,15 @@ object NotificationUtils {
|
|||||||
)
|
)
|
||||||
|
|
||||||
val builder: Notification.Builder = (
|
val builder: Notification.Builder = (
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) Notification.Builder(
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
|
Notification.Builder(
|
||||||
context,
|
context,
|
||||||
notificationChannelId
|
notificationChannelId
|
||||||
)
|
)
|
||||||
else Notification.Builder(context)
|
} else {
|
||||||
).setContentTitle(context.getString(R.string.app_name))
|
Notification.Builder(context)
|
||||||
|
}
|
||||||
|
).setContentTitle(context.getString(R.string.app_name))
|
||||||
.setContentText(context.getString(R.string.warning_notif_description))
|
.setContentText(context.getString(R.string.warning_notif_description))
|
||||||
.setSmallIcon(R.drawable.ic_launcher_notification)
|
.setSmallIcon(R.drawable.ic_launcher_notification)
|
||||||
.setTicker(context.getString(R.string.warning_notif_ticker))
|
.setTicker(context.getString(R.string.warning_notif_ticker))
|
||||||
@ -128,4 +136,4 @@ object NotificationUtils {
|
|||||||
notificationManager.cancel(NOTIFICATION_ID_WARNING)
|
notificationManager.cancel(NOTIFICATION_ID_WARNING)
|
||||||
warningShown = false
|
warningShown = false
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
package org.unifiedpush.distributor.nextpush.utils
|
||||||
|
|
||||||
|
val Any.TAG: String
|
||||||
|
get() {
|
||||||
|
val tag = javaClass.simpleName
|
||||||
|
return if (tag.length <= 23) tag else tag.substring(0, 23)
|
||||||
|
}
|
@ -4,11 +4,17 @@ buildscript {
|
|||||||
repositories {
|
repositories {
|
||||||
google()
|
google()
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
|
maven {
|
||||||
|
url "https://plugins.gradle.org/m2/"
|
||||||
|
content {
|
||||||
|
includeModule 'org.jlleitschuh.gradle', 'ktlint-gradle'
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:7.4.0'
|
classpath 'com.android.tools.build:gradle:7.4.0'
|
||||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||||
|
classpath "org.jlleitschuh.gradle:ktlint-gradle:11.2.0"
|
||||||
// NOTE: Do not place your application dependencies here; they belong
|
// NOTE: Do not place your application dependencies here; they belong
|
||||||
// in the individual module build.gradle files
|
// in the individual module build.gradle files
|
||||||
}
|
}
|
||||||
@ -25,6 +31,7 @@ allprojects {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
apply plugin: "org.jlleitschuh.gradle.ktlint"
|
||||||
}
|
}
|
||||||
|
|
||||||
task clean(type: Delete) {
|
task clean(type: Delete) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user