This commit is contained in:
sim 2022-02-19 16:19:08 +01:00
parent bfeed9662c
commit 68861956d4
11 changed files with 543 additions and 533 deletions

View File

@ -23,107 +23,113 @@ import org.unifiedpush.distributor.nextpush.R
private const val TAG = "AccountUtils"
const val PREF_NAME = "NextPush"
const val PREF_DEVICE_ID = "deviceId"
const val PREF_URL = "url"
private const val PREF_NAME = "NextPush"
private const val PREF_DEVICE_ID = "deviceId"
private const val PREF_URL = "url"
lateinit var ssoAccount: SingleSignOnAccount
object AccountUtils {
fun nextcloudAppNotInstalledDialog(context: Context) {
val message = TextView(context)
val builder = AlertDialog.Builder(context)
var messageContent = context.getString(R.string.message_missing_nextcloud_app)
val installIntent =
Intent(Intent.ACTION_VIEW, Uri.parse(context.getString(R.string.uri_market_nextcloud_app)))
messageContent += if (
installIntent.resolveActivity(context.applicationContext.packageManager) != null
) {
val callback = {
context.startActivity(
Intent.createChooser(
installIntent,
context.getString(R.string.market_chooser_title))
lateinit var ssoAccount: SingleSignOnAccount
fun nextcloudAppNotInstalledDialog(context: Context) {
val message = TextView(context)
val builder = AlertDialog.Builder(context)
var messageContent = context.getString(R.string.message_missing_nextcloud_app)
val installIntent =
Intent(
Intent.ACTION_VIEW,
Uri.parse(context.getString(R.string.uri_market_nextcloud_app))
)
messageContent += if (
installIntent.resolveActivity(context.applicationContext.packageManager) != null
) {
val callback = {
context.startActivity(
Intent.createChooser(
installIntent,
context.getString(R.string.market_chooser_title)
)
)
}
builder.setPositiveButton(context.getString(R.string.install)) { _: DialogInterface, _: Int ->
callback()
}
builder.setNegativeButton(context.getString(R.string.dismiss)) { _: DialogInterface, _: Int ->
}
"."
} else {
": " + context.getString(R.string.uri_fdroid_nextcloud_app)
}
builder.setPositiveButton(context.getString(R.string.install)) {
_: DialogInterface, _: Int -> callback()
}
builder.setNegativeButton(context.getString(R.string.dismiss)) {
_: DialogInterface, _: Int ->
}
"."
} else {
": " + context.getString(R.string.uri_fdroid_nextcloud_app)
val s = SpannableString(messageContent)
Linkify.addLinks(s, Linkify.ALL)
message.text = s
message.movementMethod = LinkMovementMethod.getInstance()
message.setPadding(32, 32, 32, 32)
builder.setTitle(context.getString(R.string.nextcloud_files_not_found_title))
builder.setView(message)
builder.show()
}
val s = SpannableString(messageContent)
Linkify.addLinks(s, Linkify.ALL)
message.text = s
message.movementMethod = LinkMovementMethod.getInstance()
message.setPadding(32,32,32,32)
builder.setTitle(context.getString(R.string.nextcloud_files_not_found_title))
builder.setView(message)
builder.show()
}
fun isConnected(context: Context, showDialog: Boolean = false) : Boolean {
try {
ssoAccount = SingleAccountHelper.getCurrentSingleSignOnAccount(context)
} catch (e: NextcloudFilesAppAccountNotFoundException) {
if (showDialog) {
nextcloudAppNotInstalledDialog(context)
fun isConnected(context: Context, showDialog: Boolean = false): Boolean {
try {
ssoAccount = SingleAccountHelper.getCurrentSingleSignOnAccount(context)
} catch (e: NextcloudFilesAppAccountNotFoundException) {
if (showDialog) {
nextcloudAppNotInstalledDialog(context)
}
return false
} catch (e: NoCurrentAccountSelectedException) {
Log.d(TAG, "Device is not connected")
return false
}
return false
} catch (e: NoCurrentAccountSelectedException) {
Log.d(TAG,"Device is not connected")
return false
return true
}
return true
}
fun connect(activity: Activity) {
try {
AccountImporter.pickNewAccount(activity)
} catch (e: NextcloudFilesAppNotInstalledException) {
nextcloudAppNotInstalledDialog(activity)
} catch (e: AndroidGetAccountsPermissionNotGranted) {
UiExceptionManager.showDialogForException(activity, e)
fun connect(activity: Activity) {
try {
AccountImporter.pickNewAccount(activity)
} catch (e: NextcloudFilesAppNotInstalledException) {
nextcloudAppNotInstalledDialog(activity)
} catch (e: AndroidGetAccountsPermissionNotGranted) {
UiExceptionManager.showDialogForException(activity, e)
}
}
}
fun saveDeviceId(context: Context, deviceId: String) {
context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
.edit()
.putString(PREF_DEVICE_ID, deviceId)
.commit()
}
fun saveDeviceId(context: Context, deviceId: String) {
context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
.edit()
.putString(PREF_DEVICE_ID, deviceId)
.commit()
}
fun getDeviceId(context: Context) : String? {
return context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
.getString(PREF_DEVICE_ID,null)
}
fun getDeviceId(context: Context): String? {
return context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
.getString(PREF_DEVICE_ID, null)
}
fun removeDeviceId(context: Context) {
context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
.edit()
.remove(PREF_DEVICE_ID)
.commit()
}
fun removeDeviceId(context: Context) {
context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
.edit()
.remove(PREF_DEVICE_ID)
.commit()
}
fun saveUrl(context: Context, url: String) {
context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
.edit()
.putString(PREF_URL, url)
.commit()
}
fun saveUrl(context: Context, url: String) {
context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
.edit()
.putString(PREF_URL, url)
.commit()
}
fun getUrl(context: Context) : String? {
return context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
.getString(PREF_URL,null)
}
fun getUrl(context: Context): String? {
return context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
.getString(PREF_URL, null)
}
fun removeUrl(context: Context) {
context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
.edit()
.remove(PREF_URL)
.commit()
}
fun removeUrl(context: Context) {
context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
.edit()
.remove(PREF_URL)
.commit()
}
}

View File

@ -13,27 +13,22 @@ import android.widget.*
import androidx.appcompat.app.AppCompatActivity
import com.nextcloud.android.sso.AccountImporter
import com.nextcloud.android.sso.ui.UiExceptionManager
import com.nextcloud.android.sso.AccountImporter.IAccountAccessGranted
import com.nextcloud.android.sso.api.NextcloudAPI.ApiConnectedListener
import com.nextcloud.android.sso.helper.SingleAccountHelper
import com.nextcloud.android.sso.model.SingleSignOnAccount
import java.lang.Exception
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.view.isVisible
import com.nextcloud.android.sso.AccountImporter.clearAllAuthTokens
import com.nextcloud.android.sso.exceptions.*
import org.unifiedpush.distributor.nextpush.R
import org.unifiedpush.distributor.nextpush.account.isConnected
import org.unifiedpush.distributor.nextpush.account.connect
import org.unifiedpush.distributor.nextpush.account.nextcloudAppNotInstalledDialog
import org.unifiedpush.distributor.nextpush.account.ssoAccount
import org.unifiedpush.distributor.nextpush.api.apiDeleteApp
import org.unifiedpush.distributor.nextpush.api.apiDeleteDevice
import org.unifiedpush.distributor.nextpush.distributor.sendUnregistered
import org.unifiedpush.distributor.nextpush.distributor.getDb
import org.unifiedpush.distributor.nextpush.account.AccountUtils.connect
import org.unifiedpush.distributor.nextpush.account.AccountUtils.isConnected
import org.unifiedpush.distributor.nextpush.account.AccountUtils.nextcloudAppNotInstalledDialog
import org.unifiedpush.distributor.nextpush.account.AccountUtils.ssoAccount
import org.unifiedpush.distributor.nextpush.api.ApiUtils.apiDeleteApp
import org.unifiedpush.distributor.nextpush.api.ApiUtils.apiDeleteDevice
import org.unifiedpush.distributor.nextpush.distributor.DistributorUtils.sendUnregistered
import org.unifiedpush.distributor.nextpush.distributor.DistributorUtils.getDb
import org.unifiedpush.distributor.nextpush.services.*
import java.lang.String.format
@ -64,35 +59,22 @@ class MainActivity : AppCompatActivity() {
requestCode,
resultCode,
data,
this,
object : IAccountAccessGranted {
var callback: ApiConnectedListener = object : ApiConnectedListener {
override fun onConnected() {}
this
) { account ->
val context = applicationContext
override fun onError(ex: Exception) {
Log.e(TAG, "Cannot get account access", ex)
}
}
SingleAccountHelper.setCurrentAccount(context, account.name)
override fun accountAccessGranted(account: SingleSignOnAccount) {
val context = applicationContext
// As this library supports multiple accounts we created some helper methods if you only want to use one.
// The following line stores the selected account as the "default" account which can be queried by using
// the SingleAccountHelper.getCurrentSingleSignOnAccount(context) method
SingleAccountHelper.setCurrentAccount(context, account.name)
// Get the "default" account
try {
ssoAccount = SingleAccountHelper.getCurrentSingleSignOnAccount(context)
} catch (e: NextcloudFilesAppAccountNotFoundException) {
nextcloudAppNotInstalledDialog(context)
} catch (e: NoCurrentAccountSelectedException) {
UiExceptionManager.showDialogForException(context, e)
}
showMain()
}
})
// Get the "default" account
try {
ssoAccount = SingleAccountHelper.getCurrentSingleSignOnAccount(context)
} catch (e: NextcloudFilesAppAccountNotFoundException) {
nextcloudAppNotInstalledDialog(context)
} catch (e: NoCurrentAccountSelectedException) {
UiExceptionManager.showDialogForException(context, e)
}
showMain()
}
} catch (e: AccountImportCancelledException) {}
super.onActivityResult(requestCode, resultCode, data)
}
@ -173,15 +155,15 @@ class MainActivity : AppCompatActivity() {
.apply()
apiDeleteDevice(this)
showStart()
finish();
startActivity(intent);
finish()
startActivity(intent)
}
alert.setNegativeButton(getString(R.string.discard)) { dialog, _ -> dialog.dismiss() }
alert.show()
}
private fun setListView(){
listView = findViewById<ListView>(R.id.applications_list)
listView = findViewById(R.id.applications_list)
val db = getDb(this)
val tokenList = db.listTokens().toMutableList()
val appList = emptyArray<String>().toMutableList()
@ -194,7 +176,7 @@ class MainActivity : AppCompatActivity() {
appList
)
listView.setOnItemLongClickListener(
fun(parent: AdapterView<*>, v: View, position: Int, id: Long): Boolean {
fun(_: AdapterView<*>, _: View, position: Int, _: Long): Boolean {
val alert: android.app.AlertDialog.Builder = android.app.AlertDialog.Builder(
this)
alert.setTitle("Unregistering")
@ -202,9 +184,9 @@ class MainActivity : AppCompatActivity() {
alert.setPositiveButton("YES") { dialog, _ ->
val connectorToken = tokenList[position]
sendUnregistered(this, connectorToken)
val db = getDb(this)
val appToken = db.getAppToken(connectorToken)
db.unregisterApp(connectorToken)
val database = getDb(this)
val appToken = database.getAppToken(connectorToken)
database.unregisterApp(connectorToken)
apiDeleteApp(this, appToken) {
Log.d(TAG,"Unregistration is finished")
}

View File

@ -12,75 +12,145 @@ import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.sse.EventSource
import okhttp3.sse.EventSources
import org.unifiedpush.distributor.nextpush.account.*
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.getDb
import org.unifiedpush.distributor.nextpush.distributor.sendUnregistered
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"
val createQueue = emptyList<String>().toMutableList()
val delQueue = emptyList<String>().toMutableList()
object ApiUtils {
val createQueue = emptyList<String>().toMutableList()
val delQueue = emptyList<String>().toMutableList()
private lateinit var mApi: ProviderApi
private lateinit var nextcloudAPI: NextcloudAPI
private lateinit var factory: EventSource.Factory
private lateinit var source: EventSource
private lateinit var mApi: ProviderApi
private lateinit var nextcloudAPI: NextcloudAPI
private lateinit var factory: EventSource.Factory
private lateinit var source: EventSource
fun apiDestroy() {
if (::nextcloudAPI.isInitialized)
nextcloudAPI.stop()
if (::source.isInitialized)
source.cancel()
}
private fun cApi(context: Context, callback: ()->Unit) {
if (::mApi.isInitialized and ::nextcloudAPI.isInitialized) {
callback()
} else {
val callback = 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 = NextcloudAPI(context, ssoAccount, GsonBuilder().create(), callback)
mApi = NextcloudRetrofitApiBuilder(nextcloudAPI, mApiEndpoint)
.create(ProviderApi::class.java)
fun apiDestroy() {
if (::nextcloudAPI.isInitialized)
nextcloudAPI.stop()
if (::source.isInitialized)
source.cancel()
}
}
fun apiSync(context: Context) {
cApi(context) { cSync(context) }
}
private fun cApi(context: Context, callback: () -> Unit) {
if (::mApi.isInitialized and ::nextcloudAPI.isInitialized) {
callback()
} else {
val nCallback = object : NextcloudAPI.ApiConnectedListener {
override fun onConnected() {
Log.d(TAG, "Api connected.")
callback()
}
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)
override fun onError(ex: Exception) {
Log.d(TAG, "Cannot connect to API: ex = [$ex]")
}
}
nextcloudAPI = NextcloudAPI(context, ssoAccount, GsonBuilder().create(), nCallback)
mApi = NextcloudRetrofitApiBuilder(nextcloudAPI, 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) {
val deviceIdentifier: String = response.deviceId
Log.d(TAG, "Device Identifier: $deviceIdentifier")
saveDeviceId(context, deviceIdentifier)
deviceId = deviceIdentifier
}
override fun onError(e: Throwable) {
e.printStackTrace()
}
override fun onComplete() {
saveUrl(context, "${ssoAccount.url}${mApiEndpoint}")
// Sync once it is registered
cSync(context, deviceId!!)
Log.d(TAG, "mApi register: onComplete")
}
})
} else {
// Sync directly
Log.d(TAG, "Found deviceId: $deviceId")
cSync(context, deviceId!!)
}
}
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()
factory = EventSources.createFactory(client)
source = factory.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)
mApi.deleteDevice(deviceId)
?.subscribeOn(Schedulers.newThread())
?.observeOn(Schedulers.newThread())
?.subscribe(object : Observer<ApiResponse?> {
override fun onSubscribe(d: Disposable) {
Log.d(TAG, "onSubscribe")
Log.d(TAG, "Subscribed to deleteDevice.")
}
override fun onNext(response: ApiResponse) {
val deviceIdentifier: String = response.deviceId
Log.d(TAG, "Device Identifier: $deviceIdentifier")
saveDeviceId(context,deviceIdentifier)
deviceId = deviceIdentifier
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) {
@ -88,164 +158,106 @@ private fun cSync(context: Context) {
}
override fun onComplete() {
saveUrl(context, "${ssoAccount.url}${mApiEndpoint}")
// Sync once it is registered
cSync(context, deviceId!!)
Log.d(TAG, "mApi register: onComplete")
removeUrl(context)
}
})
} else {
// Sync directly
Log.d(TAG, "Found deviceId: $deviceId")
cSync(context, deviceId!!)
removeDeviceId(context)
}
}
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()
factory = EventSources.createFactory(client)
source = factory.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)
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 = mutableMapOf(
"deviceId" to getDeviceId(context)!!,
"appName" to appName
)
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)
fun apiCreateApp(
context: Context,
appName: String,
connectorToken: String,
callback: () -> Unit
) {
cApi(context) {
cCreateApp(context, appName, 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.")
private fun cCreateApp(
context: Context,
appName: String,
connectorToken: String,
callback: () -> Unit
) {
// The unity of connector token must already be checked here
val parameters = mutableMapOf(
"deviceId" to getDeviceId(context)!!,
"appName" to appName
)
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 onError(e: Throwable) {
delQueue.remove(connectorToken)
e.printStackTrace()
}
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 onComplete() {
delQueue.remove(connectorToken)
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()
}
})
}
}

View File

@ -1,8 +1,7 @@
package org.unifiedpush.distributor.nextpush.api
import io.reactivex.Observable;
import io.reactivex.Observable
import retrofit2.http.PUT
import retrofit2.http.GET
import retrofit2.http.DELETE
import retrofit2.http.Body
import retrofit2.http.Path
@ -14,9 +13,6 @@ interface ProviderApi {
@Body subscribeMap: MutableMap<String, String>?
): Observable<ApiResponse>?
@GET("/device/{deviceId}")
fun syncDevice(@Path("deviceId") devideId: String?): Observable<SSEResponse?>?
@DELETE("/device/{deviceId}")
fun deleteDevice(@Path("deviceId") devideId: String?): Observable<ApiResponse>?

View File

@ -3,7 +3,7 @@ package org.unifiedpush.distributor.nextpush.distributor
import android.content.Context
import android.content.Intent
import android.util.Log
import org.unifiedpush.distributor.nextpush.account.getUrl
import org.unifiedpush.distributor.nextpush.account.AccountUtils.getUrl
/**
* These functions are used to send messages to other apps
@ -11,101 +11,104 @@ import org.unifiedpush.distributor.nextpush.account.getUrl
private const val TAG = "DistributorUtils"
const val TOKEN_NEW = "token_new"
const val TOKEN_REGISTERED_OK = "token_registered_ok"
const val TOKEN_NOK = "token_nok"
object DistributorUtils {
private var db : MessagingDatabase? = null
const val TOKEN_NEW = "token_new"
const val TOKEN_REGISTERED_OK = "token_registered_ok"
const val TOKEN_NOK = "token_nok"
fun getDb(context: Context): MessagingDatabase {
if (db == null) {
db = MessagingDatabase(context)
private var db: MessagingDatabase? = null
fun getDb(context: Context): MessagingDatabase {
if (db == null) {
db = MessagingDatabase(context)
}
return db!!
}
return db!!
}
fun sendMessage(context: Context, appToken: String, message: ByteArray) {
val db = getDb(context)
val connectorToken = db.getConnectorToken(appToken)
val application = getApp(context, connectorToken)
if (application.isNullOrBlank()) {
return
fun sendMessage(context: Context, appToken: String, message: ByteArray) {
val db = getDb(context)
val connectorToken = db.getConnectorToken(appToken)
val application = getApp(context, connectorToken)
if (application.isNullOrBlank()) {
return
}
val broadcastIntent = Intent()
broadcastIntent.`package` = application
broadcastIntent.action = ACTION_MESSAGE
broadcastIntent.putExtra(EXTRA_TOKEN, connectorToken)
broadcastIntent.putExtra(EXTRA_MESSAGE, String(message))
broadcastIntent.putExtra(EXTRA_BYTES_MESSAGE, message)
context.sendBroadcast(broadcastIntent)
}
val broadcastIntent = Intent()
broadcastIntent.`package` = application
broadcastIntent.action = ACTION_MESSAGE
broadcastIntent.putExtra(EXTRA_TOKEN, connectorToken)
broadcastIntent.putExtra(EXTRA_MESSAGE, String(message))
broadcastIntent.putExtra(EXTRA_BYTES_MESSAGE, message)
context.sendBroadcast(broadcastIntent)
}
fun sendEndpoint(context: Context, connectorToken: String) {
val application = getApp(context, connectorToken)
if (application.isNullOrBlank()) {
return
fun sendEndpoint(context: Context, connectorToken: String) {
val application = getApp(context, connectorToken)
if (application.isNullOrBlank()) {
return
}
val broadcastIntent = Intent()
broadcastIntent.`package` = application
broadcastIntent.action = ACTION_NEW_ENDPOINT
broadcastIntent.putExtra(EXTRA_TOKEN, connectorToken)
broadcastIntent.putExtra(EXTRA_ENDPOINT, getEndpoint(context, connectorToken))
context.sendBroadcast(broadcastIntent)
}
val broadcastIntent = Intent()
broadcastIntent.`package` = application
broadcastIntent.action = ACTION_NEW_ENDPOINT
broadcastIntent.putExtra(EXTRA_TOKEN, connectorToken)
broadcastIntent.putExtra(EXTRA_ENDPOINT, getEndpoint(context, connectorToken))
context.sendBroadcast(broadcastIntent)
}
fun sendRegistrationFailed(
context: Context,
application: String,
connectorToken: String,
message: String = ""
fun sendRegistrationFailed(
context: Context,
application: String,
connectorToken: String,
message: String = ""
) {
if (application.isNullOrBlank()) {
return
application.ifBlank {
return
}
val broadcastIntent = Intent()
broadcastIntent.`package` = application
broadcastIntent.action = ACTION_REGISTRATION_FAILED
broadcastIntent.putExtra(EXTRA_TOKEN, connectorToken)
broadcastIntent.putExtra(EXTRA_MESSAGE, message)
context.sendBroadcast(broadcastIntent)
}
val broadcastIntent = Intent()
broadcastIntent.`package` = application
broadcastIntent.action = ACTION_REGISTRATION_FAILED
broadcastIntent.putExtra(EXTRA_TOKEN, connectorToken)
broadcastIntent.putExtra(EXTRA_MESSAGE, message)
context.sendBroadcast(broadcastIntent)
}
fun sendUnregistered(context: Context, connectorToken: String) {
val application = getApp(context, connectorToken)
if (application.isNullOrBlank()) {
return
fun sendUnregistered(context: Context, connectorToken: String) {
val application = getApp(context, connectorToken)
if (application.isNullOrBlank()) {
return
}
val broadcastIntent = Intent()
broadcastIntent.`package` = application
broadcastIntent.action = ACTION_UNREGISTERED
broadcastIntent.putExtra(EXTRA_TOKEN, connectorToken)
context.sendBroadcast(broadcastIntent)
}
val broadcastIntent = Intent()
broadcastIntent.`package` = application
broadcastIntent.action = ACTION_UNREGISTERED
broadcastIntent.putExtra(EXTRA_TOKEN, connectorToken)
context.sendBroadcast(broadcastIntent)
}
fun getApp(context: Context, connectorToken: String): String?{
val db = getDb(context)
val app = db.getPackageName(connectorToken)
return if (app.isBlank()) {
Log.w(TAG, "No app found for $connectorToken")
null
} else {
app
private fun getApp(context: Context, connectorToken: String): String? {
val db = getDb(context)
val app = db.getPackageName(connectorToken)
return if (app.isBlank()) {
Log.w(TAG, "No app found for $connectorToken")
null
} else {
app
}
}
}
fun getEndpoint(context: Context, connectorToken: String): String {
val db = getDb(context)
val appToken = db.getAppToken(connectorToken)
return "${getUrl(context)}/push/$appToken"
}
private fun getEndpoint(context: Context, connectorToken: String): String {
val db = getDb(context)
val appToken = db.getAppToken(connectorToken)
return "${getUrl(context)}/push/$appToken"
}
fun checkToken(context: Context, connectorToken: String, app: String): String {
val db = getDb(context)
if (connectorToken !in db.listTokens()) {
return TOKEN_NEW
fun checkToken(context: Context, connectorToken: String, app: String): String {
val db = getDb(context)
if (connectorToken !in db.listTokens()) {
return TOKEN_NEW
}
if (db.isRegistered(app, connectorToken)) {
return TOKEN_REGISTERED_OK
}
return TOKEN_NOK
}
if (db.isRegistered(app, connectorToken)) {
return TOKEN_REGISTERED_OK
}
return TOKEN_NOK
}
}

View File

@ -8,18 +8,18 @@ import android.database.sqlite.SQLiteOpenHelper
private const val DB_NAME = "apps_db"
private const val DB_VERSION = 1
private const val TABLE_APPS = "apps"
private const val FIELD_PACKAGE_NAME = "packageName"
private const val FIELD_CONNECTOR_TOKEN = "connectorToken"
private const val FIELD_APP_TOKEN = "appToken"
private const val CREATE_TABLE_APPS = "CREATE TABLE apps (" +
"$FIELD_PACKAGE_NAME TEXT," +
"$FIELD_CONNECTOR_TOKEN TEXT," +
"$FIELD_APP_TOKEN TEXT," +
"PRIMARY KEY ($FIELD_CONNECTOR_TOKEN));"
class MessagingDatabase(context: Context):
SQLiteOpenHelper(context, DB_NAME, null, DB_VERSION) {
private val TABLE_APPS = "apps"
private val FIELD_PACKAGE_NAME = "packageName"
private val FIELD_CONNECTOR_TOKEN = "connectorToken"
private val FIELD_APP_TOKEN = "appToken"
private val CREATE_TABLE_APPS = "CREATE TABLE apps (" +
"$FIELD_PACKAGE_NAME TEXT," +
"$FIELD_CONNECTOR_TOKEN TEXT," +
"$FIELD_APP_TOKEN TEXT," +
"PRIMARY KEY ($FIELD_CONNECTOR_TOKEN));"
override fun onCreate(db: SQLiteDatabase) {
db.execSQL(CREATE_TABLE_APPS)

View File

@ -7,19 +7,14 @@ package org.unifiedpush.distributor.nextpush.distributor
const val ACTION_NEW_ENDPOINT = "org.unifiedpush.android.connector.NEW_ENDPOINT"
const val ACTION_REGISTRATION_FAILED = "org.unifiedpush.android.connector.REGISTRATION_FAILED"
const val ACTION_REGISTRATION_REFUSED = "org.unifiedpush.android.connector.REGISTRATION_REFUSED"
const val ACTION_UNREGISTERED = "org.unifiedpush.android.connector.UNREGISTERED"
const val ACTION_MESSAGE = "org.unifiedpush.android.connector.MESSAGE"
const val ACTION_REGISTER = "org.unifiedpush.android.distributor.REGISTER"
const val ACTION_UNREGISTER = "org.unifiedpush.android.distributor.UNREGISTER"
const val ACTION_MESSAGE_ACK = "org.unifiedpush.android.distributor.MESSAGE_ACK"
const val FEATURE_BYTES_MESSAGE = "org.unifiedpush.android.distributor.feature.BYTES_MESSAGE"
const val EXTRA_APPLICATION = "application"
const val EXTRA_TOKEN = "token"
const val EXTRA_ENDPOINT = "endpoint"
const val EXTRA_MESSAGE = "message"
const val EXTRA_BYTES_MESSAGE = "bytesMessage"
const val EXTRA_MESSAGE_ID = "id"

View File

@ -4,13 +4,21 @@ import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.util.Log
import org.unifiedpush.distributor.nextpush.account.isConnected
import org.unifiedpush.distributor.nextpush.account.AccountUtils.isConnected
import org.unifiedpush.distributor.nextpush.api.ApiUtils.apiCreateApp
import org.unifiedpush.distributor.nextpush.api.ApiUtils.apiDeleteApp
import org.unifiedpush.distributor.nextpush.api.ApiUtils.createQueue
import org.unifiedpush.distributor.nextpush.api.ApiUtils.delQueue
import org.unifiedpush.distributor.nextpush.distributor.*
import org.unifiedpush.distributor.nextpush.api.createQueue
import org.unifiedpush.distributor.nextpush.api.delQueue
import org.unifiedpush.distributor.nextpush.api.apiCreateApp
import org.unifiedpush.distributor.nextpush.api.apiDeleteApp
import org.unifiedpush.distributor.nextpush.distributor.DistributorUtils.TOKEN_NEW
import org.unifiedpush.distributor.nextpush.distributor.DistributorUtils.TOKEN_NOK
import org.unifiedpush.distributor.nextpush.distributor.DistributorUtils.TOKEN_REGISTERED_OK
import org.unifiedpush.distributor.nextpush.distributor.DistributorUtils.checkToken
import org.unifiedpush.distributor.nextpush.distributor.DistributorUtils.getDb
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 org.unifiedpush.distributor.nextpush.services.wakeLock
import java.lang.Exception

View File

@ -12,104 +12,110 @@ import android.app.PendingIntent
import android.content.Intent
import org.unifiedpush.distributor.nextpush.activities.MainActivity
const val NOTIF_ID_FOREGROUND = 51115
const val NOTIF_ID_WARNING = 51215
const val NOTIFICATION_ID_FOREGROUND = 51115
const val NOTIFICATION_ID_WARNING = 51215
private var warningShown = false
object NotificationUtils {
fun createForegroundNotification(context: Context): Notification {
val appName = context.getString(R.string.app_name)
val notificationChannelId = "$appName.Listener"
private var warningShown = false
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager;
val channel = NotificationChannel(
notificationChannelId,
appName,
NotificationManager.IMPORTANCE_LOW
).let {
it.description = context.getString(R.string.foreground_notif_description)
it
fun createForegroundNotification(context: Context): Notification {
val appName = context.getString(R.string.app_name)
val notificationChannelId = "$appName.Listener"
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val notificationManager =
context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
val channel = NotificationChannel(
notificationChannelId,
appName,
NotificationManager.IMPORTANCE_LOW
).let {
it.description = context.getString(R.string.foreground_notif_description)
it
}
notificationManager.createNotificationChannel(channel)
}
notificationManager.createNotificationChannel(channel)
}
val notificationIntent = Intent(context, MainActivity::class.java)
val notificationIntent = Intent(context, MainActivity::class.java)
notificationIntent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP
notificationIntent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP
val intent = PendingIntent.getActivity(
context, 0,
notificationIntent, 0
)
val intent = PendingIntent.getActivity(
context, 0,
notificationIntent, 0
)
val builder: Notification.Builder = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) Notification.Builder(
context,
notificationChannelId
) else Notification.Builder(context)
return builder
.setContentTitle(context.getString(R.string.app_name))
.setContentText(context.getString(R.string.foreground_notif_description))
.setSmallIcon(R.drawable.ic_launcher_notification)
.setTicker(context.getString(R.string.foreground_notif_ticker))
.setPriority(Notification.PRIORITY_LOW) // for under android 26 compatibility
.setContentIntent(intent)
.setOngoing(true)
.build()
}
fun createWarningNotification(context: Context) {
if (warningShown)
return
val appName = context.getString(R.string.app_name)
val notificationChannelId = "$appName.Warning"
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val notificationManager =
context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager;
val channel = NotificationChannel(
notificationChannelId,
appName,
NotificationManager.IMPORTANCE_HIGH
).let {
it.description = context.getString(R.string.warning_notif_description)
it
}
notificationManager.createNotificationChannel(channel)
}
val notificationIntent = Intent(context, MainActivity::class.java)
notificationIntent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP
val intent = PendingIntent.getActivity(
context, 0,
notificationIntent, 0
)
val builder: Notification.Builder = (
val builder: Notification.Builder =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) Notification.Builder(
context,
notificationChannelId
)
else Notification.Builder(context)
).setContentTitle(context.getString(R.string.app_name))
.setContentText(context.getString(R.string.warning_notif_description))
.setSmallIcon(R.drawable.ic_launcher_notification)
.setTicker(context.getString(R.string.warning_notif_ticker))
.setPriority(Notification.PRIORITY_HIGH) // for under android 26 compatibility
.setContentIntent(intent)
.setOngoing(true)
) else Notification.Builder(context)
with(NotificationManagerCompat.from(context)) {
notify(NOTIF_ID_WARNING, builder.build())
return builder
.setContentTitle(context.getString(R.string.app_name))
.setContentText(context.getString(R.string.foreground_notif_description))
.setSmallIcon(R.drawable.ic_launcher_notification)
.setTicker(context.getString(R.string.foreground_notif_ticker))
.setPriority(Notification.PRIORITY_LOW) // for under android 26 compatibility
.setContentIntent(intent)
.setOngoing(true)
.build()
}
warningShown = true
}
fun deleteWarningNotification(context: Context) {
val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager;
notificationManager.cancel(NOTIF_ID_WARNING)
warningShown = false
fun createWarningNotification(context: Context) {
if (warningShown)
return
val appName = context.getString(R.string.app_name)
val notificationChannelId = "$appName.Warning"
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val notificationManager =
context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
val channel = NotificationChannel(
notificationChannelId,
appName,
NotificationManager.IMPORTANCE_HIGH
).let {
it.description = context.getString(R.string.warning_notif_description)
it
}
notificationManager.createNotificationChannel(channel)
}
val notificationIntent = Intent(context, MainActivity::class.java)
notificationIntent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP
val intent = PendingIntent.getActivity(
context, 0,
notificationIntent, 0
)
val builder: Notification.Builder = (
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) Notification.Builder(
context,
notificationChannelId
)
else Notification.Builder(context)
).setContentTitle(context.getString(R.string.app_name))
.setContentText(context.getString(R.string.warning_notif_description))
.setSmallIcon(R.drawable.ic_launcher_notification)
.setTicker(context.getString(R.string.warning_notif_ticker))
.setPriority(Notification.PRIORITY_HIGH) // for under android 26 compatibility
.setContentIntent(intent)
.setOngoing(true)
with(NotificationManagerCompat.from(context)) {
notify(NOTIFICATION_ID_WARNING, builder.build())
}
warningShown = true
}
fun deleteWarningNotification(context: Context) {
val notificationManager =
context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.cancel(NOTIFICATION_ID_WARNING)
warningShown = false
}
}

View File

@ -11,9 +11,11 @@ import okhttp3.Response
import java.lang.Exception
import com.google.gson.Gson
import org.unifiedpush.distributor.nextpush.api.SSEResponse
import org.unifiedpush.distributor.nextpush.distributor.getDb
import org.unifiedpush.distributor.nextpush.distributor.sendMessage
import org.unifiedpush.distributor.nextpush.distributor.sendUnregistered
import org.unifiedpush.distributor.nextpush.distributor.DistributorUtils.getDb
import org.unifiedpush.distributor.nextpush.distributor.DistributorUtils.sendMessage
import org.unifiedpush.distributor.nextpush.distributor.DistributorUtils.sendUnregistered
import org.unifiedpush.distributor.nextpush.services.NotificationUtils.createWarningNotification
import org.unifiedpush.distributor.nextpush.services.NotificationUtils.deleteWarningNotification
private const val TAG = "SSEListener"

View File

@ -12,16 +12,17 @@ import com.nextcloud.android.sso.exceptions.NextcloudFilesAppAccountNotFoundExce
import com.nextcloud.android.sso.exceptions.NoCurrentAccountSelectedException
import com.nextcloud.android.sso.helper.SingleAccountHelper
import org.unifiedpush.distributor.nextpush.account.ssoAccount
import org.unifiedpush.distributor.nextpush.account.nextcloudAppNotInstalledDialog
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 org.unifiedpush.distributor.nextpush.api.apiDestroy
import org.unifiedpush.distributor.nextpush.api.apiSync
import org.unifiedpush.distributor.nextpush.api.ApiUtils.apiDestroy
import org.unifiedpush.distributor.nextpush.api.ApiUtils.apiSync
import org.unifiedpush.distributor.nextpush.services.NotificationUtils.createForegroundNotification
import java.lang.Exception
private const val TAG = "StartService"
@ -54,7 +55,7 @@ class StartService: Service(){
super.onCreate()
Log.i(TAG,"StartService created")
val notification = createForegroundNotification(this)
startForeground(NOTIF_ID_FOREGROUND, notification)
startForeground(NOTIFICATION_ID_FOREGROUND, notification)
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
@ -141,6 +142,5 @@ class StartService: Service(){
e.printStackTrace()
}
}
}