Merge branch 'dev'

This commit is contained in:
sim 2022-01-16 22:40:04 +01:00
commit 02bb2c0318
11 changed files with 111 additions and 25 deletions

View File

@ -6,7 +6,7 @@ UnifiedPush provider for Nextcloud - android application
height="80">](https://f-droid.org/packages/org.unifiedpush.distributor.nextpush/) height="80">](https://f-droid.org/packages/org.unifiedpush.distributor.nextpush/)
## Usage ## Usage
This application require the [server application](https://github.com/UP-NextPush/server-app) to be intalled on the server and the [Nextcloud application](https://apps.nextcloud.com/apps/android_nextcloud_app) on the mobile phone. This application require the [server application](https://github.com/UP-NextPush/server-app) to be installed on the server and the [Nextcloud application](https://apps.nextcloud.com/apps/android_nextcloud_app) on the mobile phone.
## Credit ## Credit
This application has been inspired by [Nextcloud Push Notifier](https://gitlab.com/Nextcloud-Push/nextcloud-push-notifier) This application has been inspired by [Nextcloud Push Notifier](https://gitlab.com/Nextcloud-Push/nextcloud-push-notifier)

View File

@ -17,8 +17,8 @@ android {
applicationId "org.unifiedpush.distributor.nextpush" applicationId "org.unifiedpush.distributor.nextpush"
minSdkVersion 24 minSdkVersion 24
targetSdkVersion 30 targetSdkVersion 30
versionCode 6 versionCode 7
versionName "1.0.1" versionName "1.1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
} }

View File

@ -65,11 +65,14 @@ fun nextcloudAppNotInstalledDialog(context: Context) {
builder.show() builder.show()
} }
fun isConnected(context: Context) : Boolean { fun isConnected(context: Context, showDialog: Boolean = false) : Boolean {
try { try {
ssoAccount = SingleAccountHelper.getCurrentSingleSignOnAccount(context) ssoAccount = SingleAccountHelper.getCurrentSingleSignOnAccount(context)
} catch (e: NextcloudFilesAppAccountNotFoundException) { } catch (e: NextcloudFilesAppAccountNotFoundException) {
nextcloudAppNotInstalledDialog(context) if (showDialog) {
nextcloudAppNotInstalledDialog(context)
}
return false
} catch (e: NoCurrentAccountSelectedException) { } catch (e: NoCurrentAccountSelectedException) {
Log.d(TAG,"Device is not connected") Log.d(TAG,"Device is not connected")
return false return false

View File

@ -46,7 +46,7 @@ class MainActivity : AppCompatActivity() {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main) setContentView(R.layout.activity_main)
setSupportActionBar(findViewById(R.id.toolbar)) setSupportActionBar(findViewById(R.id.toolbar))
if (isConnected(this)) { if (isConnected(this, showDialog = true)) {
showMain() showMain()
} else { } else {
findViewById<Button>(R.id.button_connection).setOnClickListener { findViewById<Button>(R.id.button_connection).setOnClickListener {

View File

@ -48,6 +48,23 @@ fun sendEndpoint(context: Context, connectorToken: String) {
context.sendBroadcast(broadcastIntent) context.sendBroadcast(broadcastIntent)
} }
fun sendRegistrationFailed(
context: Context,
application: String,
connectorToken: String,
message: String = ""
) {
if (application.isNullOrBlank()) {
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)
}
fun sendUnregistered(context: Context, connectorToken: String) { fun sendUnregistered(context: Context, connectorToken: String) {
val application = getApp(context, connectorToken) val application = getApp(context, connectorToken)
if (application.isNullOrBlank()) { if (application.isNullOrBlank()) {
@ -75,4 +92,12 @@ fun getEndpoint(context: Context, connectorToken: String): String {
val db = getDb(context) val db = getDb(context)
val appToken = db.getAppToken(connectorToken) val appToken = db.getAppToken(connectorToken)
return "${getUrl(context)}/push/$appToken" return "${getUrl(context)}/push/$appToken"
} }
fun isTokenOk(context: Context, connectorToken: String, app: String): Boolean {
val db = getDb(context)
if (connectorToken !in db.listTokens()) {
return true
}
return db.getPackageName(connectorToken) == app
}

View File

@ -4,12 +4,15 @@ import android.content.BroadcastReceiver
import android.content.Context 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.isConnected
import org.unifiedpush.distributor.nextpush.distributor.* import org.unifiedpush.distributor.nextpush.distributor.*
import org.unifiedpush.distributor.nextpush.api.createQueue import org.unifiedpush.distributor.nextpush.api.createQueue
import org.unifiedpush.distributor.nextpush.api.delQueue import org.unifiedpush.distributor.nextpush.api.delQueue
import org.unifiedpush.distributor.nextpush.api.apiCreateApp import org.unifiedpush.distributor.nextpush.api.apiCreateApp
import org.unifiedpush.distributor.nextpush.api.apiDeleteApp import org.unifiedpush.distributor.nextpush.api.apiDeleteApp
import org.unifiedpush.distributor.nextpush.services.wakeLock
import java.lang.Exception
/** /**
* THIS SERVICE IS USED BY OTHER APPS TO REGISTER * THIS SERVICE IS USED BY OTHER APPS TO REGISTER
@ -20,6 +23,7 @@ private const val TAG = "RegisterBroadcastReceiver"
class RegisterBroadcastReceiver : BroadcastReceiver() { class RegisterBroadcastReceiver : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) { override fun onReceive(context: Context?, intent: Intent?) {
wakeLock?.acquire(10000L /*10 secs*/)
when (intent!!.action) { when (intent!!.action) {
ACTION_REGISTER ->{ ACTION_REGISTER ->{
Log.i(TAG,"REGISTER") Log.i(TAG,"REGISTER")
@ -29,10 +33,27 @@ class RegisterBroadcastReceiver : BroadcastReceiver() {
Log.w(TAG,"Trying to register an app without packageName") Log.w(TAG,"Trying to register an app without packageName")
return return
} }
if (!isConnected(context!!, showDialog = false)) {
sendRegistrationFailed(
context,
application,
connectorToken,
message = "NextPush is not connected"
)
return
}
if (!isTokenOk(context, connectorToken, application)) {
sendRegistrationFailed(
context,
application,
connectorToken
)
return
}
if (connectorToken !in createQueue) { if (connectorToken !in createQueue) {
createQueue.add(connectorToken) createQueue.add(connectorToken)
apiCreateApp( apiCreateApp(
context!!.applicationContext, context.applicationContext,
application, application,
connectorToken connectorToken
) { ) {
@ -52,15 +73,24 @@ class RegisterBroadcastReceiver : BroadcastReceiver() {
if (connectorToken !in delQueue) { if (connectorToken !in delQueue) {
delQueue.add(connectorToken) delQueue.add(connectorToken)
sendUnregistered(context.applicationContext, connectorToken) sendUnregistered(context.applicationContext, connectorToken)
apiDeleteApp(context.applicationContext, connectorToken) { try {
val db = getDb(context.applicationContext) apiDeleteApp(context.applicationContext, connectorToken) {
db.unregisterApp(connectorToken) val db = getDb(context.applicationContext)
Log.d(TAG, "Unregistration is finished") db.unregisterApp(connectorToken)
Log.d(TAG, "Unregistration is finished")
}
} catch (e: Exception) {
Log.d(TAG, "Could not delete app")
} }
} else { } else {
Log.d(TAG, "Already deleting $connectorToken") Log.d(TAG, "Already deleting $connectorToken")
} }
} }
} }
wakeLock?.let {
if (it.isHeld) {
it.release()
}
}
} }
} }

View File

@ -28,7 +28,7 @@ fun createForegroundNotification(context: Context): Notification {
appName, appName,
NotificationManager.IMPORTANCE_LOW NotificationManager.IMPORTANCE_LOW
).let { ).let {
it.description = context.getString(R.string.listening_notif_description) it.description = context.getString(R.string.foreground_notif_description)
it it
} }
notificationManager.createNotificationChannel(channel) notificationManager.createNotificationChannel(channel)
@ -50,9 +50,9 @@ fun createForegroundNotification(context: Context): Notification {
return builder return builder
.setContentTitle(context.getString(R.string.app_name)) .setContentTitle(context.getString(R.string.app_name))
.setContentText(context.getString(R.string.listening_notif_description)) .setContentText(context.getString(R.string.foreground_notif_description))
.setSmallIcon(R.drawable.ic_launcher_notification) .setSmallIcon(R.drawable.ic_launcher_notification)
.setTicker(context.getString(R.string.listening_notif_ticker)) .setTicker(context.getString(R.string.foreground_notif_ticker))
.setPriority(Notification.PRIORITY_LOW) // for under android 26 compatibility .setPriority(Notification.PRIORITY_LOW) // for under android 26 compatibility
.setContentIntent(intent) .setContentIntent(intent)
.setOngoing(true) .setOngoing(true)

View File

@ -22,6 +22,11 @@ class SSEListener (val context: Context) : EventSourceListener() {
override fun onOpen(eventSource: EventSource, response: Response) { override fun onOpen(eventSource: EventSource, response: Response) {
deleteWarningNotification(context) deleteWarningNotification(context)
nFails = 0 nFails = 0
wakeLock?.let {
while (it.isHeld) {
it.release()
}
}
try { try {
Log.d(TAG, "onOpen: " + response.code) Log.d(TAG, "onOpen: " + response.code)
} catch (e: Exception) { } catch (e: Exception) {
@ -31,6 +36,7 @@ class SSEListener (val context: Context) : EventSourceListener() {
override fun onEvent(eventSource: EventSource, id: String?, type: String?, data: String) { override fun onEvent(eventSource: EventSource, id: String?, type: String?, data: String) {
Log.d(TAG, "New SSE message event=$type message=$data") Log.d(TAG, "New SSE message event=$type message=$data")
wakeLock?.acquire(10000L /*10 secs*/)
when (type) { when (type) {
"warning" -> Log.d(TAG, "Warning event received.") "warning" -> Log.d(TAG, "Warning event received.")
"ping" -> Log.d(TAG, "SSE ping received.") "ping" -> Log.d(TAG, "SSE ping received.")
@ -53,18 +59,22 @@ class SSEListener (val context: Context) : EventSourceListener() {
db.unregisterApp(connectorToken) db.unregisterApp(connectorToken)
} }
} }
wakeLock?.let {
if (it.isHeld) {
it.release()
}
}
} }
override fun onClosed(eventSource: EventSource) { override fun onClosed(eventSource: EventSource) {
Log.d(TAG, "onClosed: $eventSource") Log.d(TAG, "onClosed: $eventSource")
isServiceStarted = false nFails += 1
createWarningNotification(context) createWarningNotification(context)
startListener(context) startListener(context)
} }
override fun onFailure(eventSource: EventSource, t: Throwable?, response: Response?) { override fun onFailure(eventSource: EventSource, t: Throwable?, response: Response?) {
Log.d(TAG, "onFailure") Log.d(TAG, "onFailure")
isServiceStarted = false
nFails += 1 nFails += 1
if (nFails > 1) if (nFails > 1)
createWarningNotification(context) createWarningNotification(context)

View File

@ -24,8 +24,10 @@ import org.unifiedpush.distributor.nextpush.api.apiSync
import java.lang.Exception import java.lang.Exception
private const val TAG = "StartService" private const val TAG = "StartService"
const val WAKE_LOCK_TAG = "NextPush:StartService:lock"
var isServiceStarted = false var isServiceStarted = false
var nFails = 0 var nFails = 0
var wakeLock: PowerManager.WakeLock? = null
fun startListener(context: Context){ fun startListener(context: Context){
Log.d(TAG, "Starting the Listener") Log.d(TAG, "Starting the Listener")
@ -39,7 +41,6 @@ fun startListener(context: Context){
class StartService: Service(){ class StartService: Service(){
private var wakeLock: PowerManager.WakeLock? = null
private var isCallbackRegistered = false private var isCallbackRegistered = false
override fun onBind(intent: Intent?): IBinder? { override fun onBind(intent: Intent?): IBinder? {
@ -65,12 +66,26 @@ class StartService: Service(){
override fun onDestroy() { override fun onDestroy() {
Log.d(TAG, "Destroyed") Log.d(TAG, "Destroyed")
if (isServiceStarted) {
startListener(this)
} else {
stopService()
}
}
private fun stopService() {
Log.d(TAG, "Stopping Service")
apiDestroy() apiDestroy()
super.onDestroy() wakeLock?.let {
while (it.isHeld) {
it.release()
}
}
stopSelf()
} }
private fun startService() { private fun startService() {
if (isServiceStarted) return if (isServiceStarted && nFails == 0) return
isServiceStarted = true isServiceStarted = true
try { try {
@ -83,8 +98,8 @@ class StartService: Service(){
// we need this lock so our service gets not affected by Doze Mode // we need this lock so our service gets not affected by Doze Mode
wakeLock = (getSystemService(Context.POWER_SERVICE) as PowerManager).run { wakeLock = (getSystemService(Context.POWER_SERVICE) as PowerManager).run {
newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "EndlessService::lock").apply { newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKE_LOCK_TAG).apply {
acquire() acquire(10000L /*10 secs*/)
} }
} }
@ -98,7 +113,7 @@ class StartService: Service(){
connectivityManager.registerDefaultNetworkCallback(object : NetworkCallback() { connectivityManager.registerDefaultNetworkCallback(object : NetworkCallback() {
override fun onAvailable(network: Network) { override fun onAvailable(network: Network) {
Log.d(TAG, "Network is CONNECTED") Log.d(TAG, "Network is CONNECTED")
startService() startListener(this@StartService)
} }
override fun onLost(network: Network) { override fun onLost(network: Network) {

View File

@ -5,7 +5,7 @@
<string name="main_applications_title">Registered applications</string> <string name="main_applications_title">Registered applications</string>
<string name="help"></string> <string name="help"></string>
<string name="listening_notif_description">Listening for incoming notifications</string> <string name="foreground_notif_description">Notification to run in the foreground</string>
<string name="connection_button">Login</string> <string name="connection_button">Login</string>
<string name="connection_description">You are not connected to Nextcloud yet</string> <string name="connection_description">You are not connected to Nextcloud yet</string>
<string name="action_logout">Logout</string> <string name="action_logout">Logout</string>
@ -18,7 +18,7 @@
<string name="action_restart">Restart Service</string> <string name="action_restart">Restart Service</string>
<string name="warning_notif_description">NextPush is disconnected</string> <string name="warning_notif_description">NextPush is disconnected</string>
<string name="warning_notif_ticker">Warning</string> <string name="warning_notif_ticker">Warning</string>
<string name="listening_notif_ticker">Listening</string> <string name="foreground_notif_ticker">Foreground</string>
<string name="message_missing_nextcloud_app">Nextcloud Files is not installed on your device.\nPlease install it</string> <string name="message_missing_nextcloud_app">Nextcloud Files is not installed on your device.\nPlease install it</string>
<string name="uri_market_nextcloud_app">market://details?id=com.nextcloud.client</string> <string name="uri_market_nextcloud_app">market://details?id=com.nextcloud.client</string>
<string name="market_chooser_title">Market</string> <string name="market_chooser_title">Market</string>

View File

@ -0,0 +1,3 @@
- Improve battery management
- Change foreground notif wording
- Follow spec 2.0.0