diff --git a/app/build.gradle b/app/build.gradle index 9c2cd87..f09c3b4 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -44,6 +44,7 @@ dependencies { androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' implementation 'com.github.invissvenska:NumberPickerPreference:1.0.3' implementation "com.github.nextcloud:Android-SingleSignOn:0.6.1" + implementation 'org.java-websocket:Java-WebSocket:1.5.4' // Image Loading Library:Glide implementation 'com.github.bumptech.glide:glide:4.15.1' diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index f07f75b..69e9d27 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -5,8 +5,7 @@ - - + @@ -21,18 +20,24 @@ android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" - android:usesCleartextTraffic="true" - android:theme="@style/Theme.NextcloudServices"> + android:theme="@style/Theme.NextcloudServices" + android:usesCleartextTraffic="true"> + - - @@ -44,9 +49,10 @@ android:exported="true"> + - + \ No newline at end of file diff --git a/app/src/main/java/com/polar/nextcloudservices/API/NextcloudAbstractAPI.java b/app/src/main/java/com/polar/nextcloudservices/API/NextcloudAbstractAPI.java index 0f10356..8aa65a8 100644 --- a/app/src/main/java/com/polar/nextcloudservices/API/NextcloudAbstractAPI.java +++ b/app/src/main/java/com/polar/nextcloudservices/API/NextcloudAbstractAPI.java @@ -2,15 +2,16 @@ import android.graphics.Bitmap; -import com.polar.nextcloudservices.Services.PollUpdateListener; +import com.polar.nextcloudservices.Services.NotificationListener; import com.polar.nextcloudservices.Services.Status.StatusCheckable; +import org.java_websocket.client.WebSocketClient; import org.json.JSONObject; import java.io.IOException; /* - * Nextcloud abstract API crates possibility to use different libraries for + * Nextcloud abstract API creates possibility to use different libraries for * polling for notifications. This is needed to use Nextcloud SSO library * since it does not give per-app key. * The inheritors of this interface should be passed to NotificationService. @@ -21,7 +22,7 @@ public interface NextcloudAbstractAPI extends StatusCheckable { * @param service PollUpdateListener which handles notifications * @return notifications response as a JSONObject */ - JSONObject getNotifications(PollUpdateListener service); + JSONObject getNotifications(NotificationListener service); /** * Removes notification from server @@ -67,4 +68,12 @@ public interface NextcloudAbstractAPI extends StatusCheckable { * @throws Exception in case of any error */ boolean checkNewNotifications() throws Exception; + + /** + * @doc Gets websocket client which is authorized and receives notification updates + * @return WebsocketClient instance which holds pre-authorized connection + * @throws Exception in case of any unhandlable error + */ + WebSocketClient getNotificationsWebsocket() throws Exception; + } diff --git a/app/src/main/java/com/polar/nextcloudservices/API/NextcloudHttpAPI.java b/app/src/main/java/com/polar/nextcloudservices/API/NextcloudHttpAPI.java index 54aff56..54dfdf5 100644 --- a/app/src/main/java/com/polar/nextcloudservices/API/NextcloudHttpAPI.java +++ b/app/src/main/java/com/polar/nextcloudservices/API/NextcloudHttpAPI.java @@ -9,10 +9,11 @@ import androidx.annotation.NonNull; import com.polar.nextcloudservices.BuildConfig; -import com.polar.nextcloudservices.Services.PollUpdateListener; +import com.polar.nextcloudservices.Services.NotificationListener; import com.polar.nextcloudservices.Services.Settings.ServiceSettings; import com.polar.nextcloudservices.Services.Status.Status; +import org.java_websocket.client.WebSocketClient; import org.json.JSONException; import org.json.JSONObject; @@ -196,7 +197,12 @@ public boolean checkNewNotifications() throws Exception { } @Override - public JSONObject getNotifications(PollUpdateListener service) { + public WebSocketClient getNotificationsWebsocket() throws Exception { + return null; + } + + @Override + public JSONObject getNotifications(NotificationListener service) { try { HttpURLConnection conn = request("/ocs/v2.php/apps/notifications/api/v2/notifications", "GET", true); @@ -216,7 +222,7 @@ public JSONObject getNotifications(PollUpdateListener service) { JSONObject response = new JSONObject(buffer.toString()); lastPollSuccessful = true; - service.onPollFinished(response); + service.onNewNotifications(response); return response; } catch (JSONException e) { Log.e(TAG, "Error parsing JSON"); diff --git a/app/src/main/java/com/polar/nextcloudservices/API/NextcloudSSOAPI.java b/app/src/main/java/com/polar/nextcloudservices/API/NextcloudSSOAPI.java index 897d128..bc2d77e 100644 --- a/app/src/main/java/com/polar/nextcloudservices/API/NextcloudSSOAPI.java +++ b/app/src/main/java/com/polar/nextcloudservices/API/NextcloudSSOAPI.java @@ -14,11 +14,11 @@ import com.nextcloud.android.sso.QueryParam; import com.nextcloud.android.sso.aidl.NextcloudRequest; import com.nextcloud.android.sso.api.NextcloudAPI; -import com.nextcloud.android.sso.api.Response; import com.nextcloud.android.sso.model.SingleSignOnAccount; -import com.polar.nextcloudservices.Services.PollUpdateListener; +import com.polar.nextcloudservices.Services.NotificationListener; import com.polar.nextcloudservices.Services.Status.Status; +import org.java_websocket.client.WebSocketClient; import org.json.JSONException; import org.json.JSONObject; @@ -30,7 +30,6 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; -import java.util.Objects; public class NextcloudSSOAPI implements NextcloudAbstractAPI { final private NextcloudAPI API; @@ -56,7 +55,7 @@ public void onError(Exception ex) { } @Override - public JSONObject getNotifications(PollUpdateListener service) { + public JSONObject getNotifications(NotificationListener service) { Log.d(TAG, "getNotifications"); Map> header = new HashMap<>(); LinkedList values = new LinkedList<>(); @@ -85,7 +84,7 @@ public JSONObject getNotifications(PollUpdateListener service) { try { JSONObject response = new JSONObject(buffer.toString()); - service.onPollFinished(response); + service.onNewNotifications(response); Log.d(TAG, "Setting lastPollSuccessful as true"); lastPollSuccessful = true; return response; @@ -175,6 +174,11 @@ public boolean checkNewNotifications() throws Exception { return true; } + @Override + public WebSocketClient getNotificationsWebsocket() throws Exception { + return null; + } + @Override public Status getStatus(Context context) { if(lastPollSuccessful){ diff --git a/app/src/main/java/com/polar/nextcloudservices/BootReceiver.java b/app/src/main/java/com/polar/nextcloudservices/BootReceiver.java index 1d30bc9..c22f5a7 100644 --- a/app/src/main/java/com/polar/nextcloudservices/BootReceiver.java +++ b/app/src/main/java/com/polar/nextcloudservices/BootReceiver.java @@ -6,7 +6,7 @@ import android.util.Log; import android.os.Build; -import com.polar.nextcloudservices.Services.NotificationService; +import com.polar.nextcloudservices.Services.NotificationPollService; public class BootReceiver extends BroadcastReceiver { @@ -14,7 +14,7 @@ public class BootReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) { - Intent _intent = new Intent(context, NotificationService.class); + Intent _intent = new Intent(context, NotificationPollService.class); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { context.startForegroundService(_intent); } else { diff --git a/app/src/main/java/com/polar/nextcloudservices/Notification/NotificationBuilder.java b/app/src/main/java/com/polar/nextcloudservices/Notification/NotificationBuilder.java index 2cfe31a..43ed033 100644 --- a/app/src/main/java/com/polar/nextcloudservices/Notification/NotificationBuilder.java +++ b/app/src/main/java/com/polar/nextcloudservices/Notification/NotificationBuilder.java @@ -1,6 +1,5 @@ package com.polar.nextcloudservices.Notification; -import android.app.Notification; import android.app.NotificationManager; import android.content.Context; import android.content.Intent; @@ -8,8 +7,6 @@ import androidx.core.app.NotificationCompat; -import com.polar.nextcloudservices.Services.NotificationService; - import org.json.JSONObject; import java.util.Vector; diff --git a/app/src/main/java/com/polar/nextcloudservices/Services/NotificationListener.java b/app/src/main/java/com/polar/nextcloudservices/Services/NotificationListener.java new file mode 100644 index 0000000..13ec58a --- /dev/null +++ b/app/src/main/java/com/polar/nextcloudservices/Services/NotificationListener.java @@ -0,0 +1,7 @@ +package com.polar.nextcloudservices.Services; + +import org.json.JSONObject; + +public interface NotificationListener { + void onNewNotifications(JSONObject response); +} diff --git a/app/src/main/java/com/polar/nextcloudservices/Services/NotificationService.java b/app/src/main/java/com/polar/nextcloudservices/Services/NotificationPollService.java similarity index 92% rename from app/src/main/java/com/polar/nextcloudservices/Services/NotificationService.java rename to app/src/main/java/com/polar/nextcloudservices/Services/NotificationPollService.java index ea2c2be..0f04297 100644 --- a/app/src/main/java/com/polar/nextcloudservices/Services/NotificationService.java +++ b/app/src/main/java/com/polar/nextcloudservices/Services/NotificationPollService.java @@ -28,10 +28,10 @@ import com.polar.nextcloudservices.Services.Settings.ServiceSettings; import com.polar.nextcloudservices.Services.Status.StatusController; -class PollTask extends AsyncTask { - private static final String TAG = "NotificationService.PollTask"; +class PollTask extends AsyncTask { + private static final String TAG = "Services.NotificationPollService.PollTask"; @Override - protected JSONObject doInBackground(NotificationService... services) { + protected JSONObject doInBackground(NotificationPollService... services) { Log.d(TAG, "Checking notifications"); NextcloudAbstractAPI api = services[0].getAPI(); try { @@ -47,10 +47,10 @@ protected JSONObject doInBackground(NotificationService... services) { } } -public class NotificationService extends Service implements PollUpdateListener { +public class NotificationPollService extends Service implements NotificationListener { // constant public Integer pollingInterval = null; - public static final String TAG = "Services.NotificationService"; + public static final String TAG = "Services.NotificationPollService"; private Binder mBinder; private PollTimerTask task; public NextcloudAbstractAPI mAPI; @@ -67,7 +67,7 @@ public String getStatus() { return mStatusController.getStatusString(); } - public void onPollFinished(JSONObject response) { + public void onNewNotifications(JSONObject response) { if(response != null) { mNotificationController.onNotificationsUpdated(response); } @@ -203,7 +203,7 @@ public void run() { // run on another thread mHandler.post(() -> { if (mConnectionController.checkConnection(getApplicationContext())) { - new PollTask().execute(NotificationService.this); + new PollTask().execute(NotificationPollService.this); } }); } diff --git a/app/src/main/java/com/polar/nextcloudservices/Services/NotificationWebsocketService.java b/app/src/main/java/com/polar/nextcloudservices/Services/NotificationWebsocketService.java new file mode 100644 index 0000000..137ee94 --- /dev/null +++ b/app/src/main/java/com/polar/nextcloudservices/Services/NotificationWebsocketService.java @@ -0,0 +1,23 @@ +package com.polar.nextcloudservices.Services; + +import android.app.Service; +import android.content.Intent; +import android.os.IBinder; + +import org.json.JSONObject; + +public class NotificationWebsocketService extends Service implements NotificationListener { + public NotificationWebsocketService() { + } + + @Override + public IBinder onBind(Intent intent) { + // TODO: Return the communication channel to the service. + throw new UnsupportedOperationException("Not yet implemented"); + } + + @Override + public void onNewNotifications(JSONObject response) { + + } +} \ No newline at end of file diff --git a/app/src/main/java/com/polar/nextcloudservices/Services/PollUpdateListener.java b/app/src/main/java/com/polar/nextcloudservices/Services/PollUpdateListener.java deleted file mode 100644 index b7381d0..0000000 --- a/app/src/main/java/com/polar/nextcloudservices/Services/PollUpdateListener.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.polar.nextcloudservices.Services; - -import org.json.JSONObject; - -public interface PollUpdateListener { - void onPollFinished(JSONObject response); -} diff --git a/app/src/main/java/com/polar/nextcloudservices/SettingsActivity.java b/app/src/main/java/com/polar/nextcloudservices/SettingsActivity.java index a08ac79..3adfea6 100644 --- a/app/src/main/java/com/polar/nextcloudservices/SettingsActivity.java +++ b/app/src/main/java/com/polar/nextcloudservices/SettingsActivity.java @@ -45,7 +45,7 @@ import com.nextcloud.android.sso.exceptions.NextcloudFilesAppNotInstalledException; import com.nextcloud.android.sso.model.SingleSignOnAccount; import com.nextcloud.android.sso.ui.UiExceptionManager; -import com.polar.nextcloudservices.Services.NotificationService; +import com.polar.nextcloudservices.Services.NotificationPollService; import nl.invissvenska.numberpickerpreference.NumberDialogPreference; import nl.invissvenska.numberpickerpreference.NumberPickerPreferenceDialogFragment; @@ -54,7 +54,7 @@ class NotificationServiceConnection implements ServiceConnection { private final String TAG = "SettingsActivity.NotificationServiceConnection"; private final SettingsActivity.SettingsFragment settings; - private NotificationService.Binder mService; + private NotificationPollService.Binder mService; public boolean isConnected = false; public NotificationServiceConnection(SettingsActivity.SettingsFragment _settings) { @@ -63,9 +63,9 @@ public NotificationServiceConnection(SettingsActivity.SettingsFragment _settings @Override public void onServiceConnected(ComponentName name, IBinder service) { - if (service instanceof NotificationService.Binder) { - mService = (NotificationService.Binder) service; - settings.setStatus(((NotificationService.Binder) service).getServiceStatus()); + if (service instanceof NotificationPollService.Binder) { + mService = (NotificationPollService.Binder) service; + settings.setStatus(((NotificationPollService.Binder) service).getServiceStatus()); isConnected = true; } else { Log.wtf(TAG, "Bad Binder type passed!"); @@ -151,7 +151,7 @@ public void stopNotificationService() { //mServiceConnection = null; unbindService(mServiceConnection); mServiceConnection = null; - context.stopService(new Intent(context, NotificationService.class)); + context.stopService(new Intent(context, NotificationPollService.class)); } } public void startNotificationService() { @@ -159,7 +159,7 @@ public void startNotificationService() { //Log.d(TAG, "startService: ENTERING"); if (!isNotificationServiceRunning() && getBoolPreference("enable_polling",true)) { Log.d(TAG, "Service is not running: creating intent to start it"); - startService(new Intent(getApplicationContext(), NotificationService.class)); + startService(new Intent(getApplicationContext(), NotificationPollService.class)); } } @@ -176,7 +176,7 @@ private void updateNotificationServiceStatus(SettingsFragment settings) { } else if(mServiceConnection == null && isNotificationServiceRunning()) { Log.d(TAG, "Service is running but disconnected"); mServiceConnection = new NotificationServiceConnection(settings); - bindService(new Intent(getApplicationContext(), NotificationService.class), + bindService(new Intent(getApplicationContext(), NotificationPollService.class), mServiceConnection, 0); } else { mServiceConnection.updateStatus();