Merge branch 'dev'
This commit is contained in:
commit
02bb2c0318
|
@ -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)
|
||||||
|
|
|
@ -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"
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
|
@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
- Improve battery management
|
||||||
|
- Change foreground notif wording
|
||||||
|
- Follow spec 2.0.0
|
Loading…
Reference in New Issue