Improves streaming service

This commit is contained in:
tom79 2017-09-22 19:49:25 +02:00
parent 5c06197b58
commit 58865f8a7a
5 changed files with 145 additions and 204 deletions

View File

@ -16,12 +16,10 @@ package fr.gouv.etalab.mastodon.activities;
import android.annotation.SuppressLint;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.PorterDuff;
@ -29,7 +27,6 @@ import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.support.annotation.NonNull;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.TabLayout;
@ -41,7 +38,6 @@ import android.support.v4.view.ViewPager;
import android.support.v7.app.AlertDialog;
import android.support.v7.widget.SearchView;
import android.support.v7.widget.SwitchCompat;
import android.util.Log;
import android.util.Patterns;
import android.view.LayoutInflater;
import android.view.View;
@ -70,7 +66,6 @@ import com.nostra13.universalimageloader.core.display.RoundedBitmapDisplayer;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Stack;
import java.util.regex.Matcher;
@ -144,6 +139,7 @@ public class MainActivity extends AppCompatActivity
public static int countNewStatus = 0;
public static int countNewNotifications = 0;
private String userIdService;
private Intent streamingIntent;
public MainActivity() {
}
@ -192,8 +188,8 @@ public class MainActivity extends AppCompatActivity
}
}
};
Intent intentService = new Intent(this, StreamingService.class);
bindService(intentService, serviceConnection, Context.BIND_AUTO_CREATE);
streamingIntent = new Intent(this, StreamingService.class);
startService(streamingIntent);
LocalBroadcastManager.getInstance(this).registerReceiver(receive_data, new IntentFilter(Helper.RECEIVE_DATA));
@ -909,35 +905,7 @@ public class MainActivity extends AppCompatActivity
}
StreamingService streamingService = null;
boolean mBound = false;
private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName className, IBinder service) {
StreamingService.StreamingServiceBinder binder = (StreamingService.StreamingServiceBinder) service;
streamingService = binder.getService();
mBound = true;
SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null);
SQLiteDatabase db = Sqlite.getInstance(MainActivity.this, Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open();
Account account = new AccountDAO(getApplicationContext(), db).getAccountByID(userId);
streamingService.connect(account);
}
@Override
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
}
};
@Override
protected void onStart() {
super.onStart();
}
@Override
protected void onStop() {
super.onStop();
}
@Override
protected void onPause() {
@ -948,10 +916,8 @@ public class MainActivity extends AppCompatActivity
@Override
public void onDestroy(){
super.onDestroy();
if (mBound) {
unbindService(serviceConnection);
mBound = false;
}
if( streamingIntent != null)
stopService(streamingIntent);
LocalBroadcastManager.getInstance(this).unregisterReceiver(receive_data);
}

View File

@ -37,7 +37,12 @@
<service
android:name="fr.gouv.etalab.mastodon.services.StreamingService"
android:exported="false"/>
<receiver android:name="fr.gouv.etalab.mastodon.services.RestartServiceReceiver"
android:exported="false">
<intent-filter>
<action android:name="RestartStreamingService" />
</intent-filter>
</receiver>
<activity
android:name="fr.gouv.etalab.mastodon.activities.MainActivity"
android:label="@string/app_name"

View File

@ -0,0 +1,33 @@
package fr.gouv.etalab.mastodon.services;
/* Copyright 2017 Thomas Schneider
*
* This file is a part of Mastalab
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* Mastalab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Mastalab; if not,
* see <http://www.gnu.org/licenses>. */
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
/**
* Created by Thomas on 22/09/2017.
* BroadcastReceiver for restarting the service
*/
public class RestartServiceReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Intent streamingServiceIntent = new Intent(context.getApplicationContext(), StreamingService.class);
context.startService(streamingServiceIntent);
}
}

View File

@ -13,14 +13,12 @@ package fr.gouv.etalab.mastodon.services;
*
* You should have received a copy of the GNU General Public License along with Mastalab; if not,
* see <http://www.gnu.org/licenses>. */
import android.app.Service;
import android.app.IntentService;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.AsyncTask;
import android.os.Binder;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.os.IBinder;
import android.os.SystemClock;
import android.support.annotation.Nullable;
import android.support.v4.content.LocalBroadcastManager;
@ -35,13 +33,17 @@ import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.ArrayList;
import javax.net.ssl.HttpsURLConnection;
import fr.gouv.etalab.mastodon.client.API;
import fr.gouv.etalab.mastodon.client.Entities.Account;
import fr.gouv.etalab.mastodon.client.Entities.Notification;
import fr.gouv.etalab.mastodon.client.Entities.Status;
import fr.gouv.etalab.mastodon.client.TLSSocketFactory;
import fr.gouv.etalab.mastodon.helper.Helper;
import fr.gouv.etalab.mastodon.sqlite.AccountDAO;
import fr.gouv.etalab.mastodon.sqlite.Sqlite;
/**
@ -49,156 +51,123 @@ import fr.gouv.etalab.mastodon.helper.Helper;
* Manage service for streaming api and new notifications
*/
public class StreamingService extends Service {
public class StreamingService extends IntentService {
private static HttpsURLConnection httpsURLConnection;
private static boolean isRunning = false;
private AsyncTask<Void, Void, Void> callToStreaming;
private EventStreaming lastEvent;
/**
* Creates an IntentService. Invoked by your subclass's constructor.
*
* @param name Used to name the worker thread, important only for debugging.
*/
public StreamingService(String name) {
super(name);
}
public StreamingService() {
super("StreamingService");
}
private static HttpsURLConnection httpsURLConnection;
public enum EventStreaming{
UPDATE,
NOTIFICATION,
DELETE,
NONE
}
private final IBinder iBinder = new StreamingServiceBinder();
protected Account account;
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
public void onCreate() {
super.onCreate();
}
public class StreamingServiceBinder extends Binder {
public StreamingService getService() {
return StreamingService.this;
}
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return iBinder;
}
/**
* Task in background starts here.
*/
public void connect(final Account account) {
this.account = account;
//If an Internet connection and user agrees with notification refresh
final SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
//Check which notifications the user wants to see
boolean notif_follow = sharedpreferences.getBoolean(Helper.SET_NOTIF_FOLLOW, true);
boolean notif_add = sharedpreferences.getBoolean(Helper.SET_NOTIF_ADD, true);
boolean notif_ask = sharedpreferences.getBoolean(Helper.SET_NOTIF_ASK, true);
boolean notif_mention = sharedpreferences.getBoolean(Helper.SET_NOTIF_MENTION, true);
boolean notif_share = sharedpreferences.getBoolean(Helper.SET_NOTIF_SHARE, true);
boolean notif_home = sharedpreferences.getBoolean(Helper.SET_NOTIF_HOMETIMELINE, true);
//User disagree with all notifications
if( !notif_home && !notif_follow && !notif_add && !notif_ask && !notif_mention && !notif_share) {
return; //Nothing is done
}
if( callToStreaming != null)
callToStreaming.cancel(true);
//No account connected, the service is stopped
//If WIFI only and on WIFI OR user defined any connections to use the service.
if (!sharedpreferences.getBoolean(Helper.SET_WIFI_ONLY, false) || Helper.isOnWIFI(getApplicationContext())) {
if (!isRunning)
callToStreaming = new CallToStreaming().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
}
@Override
public void onDestroy(){
super.onDestroy();
}
public void longPolling() {
//noinspection InfiniteLoopStatement
protected void onHandleIntent(@Nullable Intent intent) {
SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null);
InputStream inputStream;
BufferedReader reader = null;
try {
URL url = new URL("https://" + this.account.getInstance() + "/api/v1/streaming/user");
if( httpsURLConnection != null){
httpsURLConnection.disconnect();
}
httpsURLConnection = (HttpsURLConnection) url.openConnection();
httpsURLConnection.setRequestProperty("Content-Type", "application/json");
httpsURLConnection.setRequestProperty("Authorization", "Bearer " + this.account.getToken());
httpsURLConnection.setRequestProperty("Connection", "Keep-Alive");
httpsURLConnection.setRequestProperty("Keep-Alive", "header");
httpsURLConnection.setRequestProperty("Connection", "close");
httpsURLConnection.setSSLSocketFactory(new TLSSocketFactory());
httpsURLConnection.setRequestMethod("GET");
httpsURLConnection.setConnectTimeout(70000);
httpsURLConnection.setReadTimeout(70000);
// httpsURLConnection.connect();
inputStream = new BufferedInputStream(httpsURLConnection.getInputStream());
reader = new BufferedReader(new InputStreamReader(inputStream));
String event;
EventStreaming eventStreaming;
//noinspection InfiniteLoopStatement
while((event = reader.readLine()) != null) {
if ((lastEvent == EventStreaming.NONE || lastEvent == null) && !event.startsWith("data: ")) {
switch (event.trim()) {
case "event: update":
lastEvent = EventStreaming.UPDATE;
break;
case "event: notification":
lastEvent = EventStreaming.NOTIFICATION;
break;
case "event: delete":
lastEvent = EventStreaming.DELETE;
break;
default:
lastEvent = EventStreaming.NONE;
}
} else {
if (!event.startsWith("data: ")) {
lastEvent = EventStreaming.NONE;
continue;
}
event = event.substring(6);
if (lastEvent == EventStreaming.UPDATE) {
eventStreaming = EventStreaming.UPDATE;
} else if (lastEvent == EventStreaming.NOTIFICATION) {
eventStreaming = EventStreaming.NOTIFICATION;
} else if (lastEvent == EventStreaming.DELETE) {
eventStreaming = EventStreaming.DELETE;
event = "{id:" + event + "}";
Account accountStream = null;
if( httpsURLConnection != null)
httpsURLConnection.disconnect();
if( userId != null) {
SQLiteDatabase db = Sqlite.getInstance(getApplicationContext(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open();
accountStream = new AccountDAO(getApplicationContext(), db).getAccountByID(userId);
}
if( accountStream != null){
try {
URL url = new URL("https://" + accountStream.getInstance() + "/api/v1/streaming/user");
httpsURLConnection = (HttpsURLConnection) url.openConnection();
httpsURLConnection.setRequestProperty("Content-Type", "application/json");
httpsURLConnection.setRequestProperty("Authorization", "Bearer " + accountStream.getToken());
httpsURLConnection.setRequestProperty("Connection", "Keep-Alive");
httpsURLConnection.setRequestProperty("Keep-Alive", "header");
httpsURLConnection.setRequestProperty("Connection", "close");
httpsURLConnection.setSSLSocketFactory(new TLSSocketFactory());
httpsURLConnection.setRequestMethod("GET");
httpsURLConnection.setConnectTimeout(70000);
httpsURLConnection.setReadTimeout(70000);
inputStream = new BufferedInputStream(httpsURLConnection.getInputStream());
reader = new BufferedReader(new InputStreamReader(inputStream));
String event;
EventStreaming eventStreaming;
while((event = reader.readLine()) != null) {
if ((lastEvent == EventStreaming.NONE || lastEvent == null) && !event.startsWith("data: ")) {
switch (event.trim()) {
case "event: update":
lastEvent = EventStreaming.UPDATE;
break;
case "event: notification":
lastEvent = EventStreaming.NOTIFICATION;
break;
case "event: delete":
lastEvent = EventStreaming.DELETE;
break;
default:
lastEvent = EventStreaming.NONE;
}
} else {
eventStreaming = EventStreaming.UPDATE;
if (!event.startsWith("data: ")) {
lastEvent = EventStreaming.NONE;
continue;
}
event = event.substring(6);
if (lastEvent == EventStreaming.UPDATE) {
eventStreaming = EventStreaming.UPDATE;
} else if (lastEvent == EventStreaming.NOTIFICATION) {
eventStreaming = EventStreaming.NOTIFICATION;
} else if (lastEvent == EventStreaming.DELETE) {
eventStreaming = EventStreaming.DELETE;
event = "{id:" + event + "}";
} else {
eventStreaming = EventStreaming.UPDATE;
}
lastEvent = EventStreaming.NONE;
try {
JSONObject eventJson = new JSONObject(event);
onRetrieveStreaming(eventStreaming, eventJson);
} catch (JSONException e) {
e.printStackTrace();
}
}
lastEvent = EventStreaming.NONE;
try {
JSONObject eventJson = new JSONObject(event);
onRetrieveStreaming(eventStreaming, eventJson);
} catch (JSONException e) {
}
} catch (Exception e) {
e.printStackTrace();
}finally {
if(reader != null){
try{
reader.close();
}catch (IOException e){
e.printStackTrace();
}
}
SystemClock.sleep(1000);
sendBroadcast(new Intent("RestartStreamingService"));
}
} catch (Exception e) {
e.printStackTrace();
}finally {
if(reader != null){
try{
reader.close();
}catch (IOException e){
e.printStackTrace();
}
}
isRunning = false;
connect(this.account);
}
}
public void onRetrieveStreaming(EventStreaming event, JSONObject response) {
if( response == null )
return;
@ -230,30 +199,4 @@ public class StreamingService extends Service {
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intentBC);
}
private class CallToStreaming extends AsyncTask<Void, Void, Void> {
CallToStreaming(){
isRunning = true;
}
@Override
protected Void doInBackground(Void... params) {
if(!Helper.isConnectedToInternet(getApplicationContext(), account.getInstance())) {
SystemClock.sleep(2000);
isRunning = false;
connect(account);
}else {
longPolling();
}
return null;
}
@Override
protected void onPostExecute(Void result) {
isRunning = false;
}
}
}

View File

@ -16,12 +16,10 @@ package fr.gouv.etalab.mastodon.activities;
import android.annotation.SuppressLint;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.PorterDuff;
@ -29,7 +27,6 @@ import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.support.annotation.NonNull;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.TabLayout;
@ -71,7 +68,6 @@ import com.nostra13.universalimageloader.core.display.RoundedBitmapDisplayer;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Stack;
import java.util.regex.Matcher;
@ -193,8 +189,8 @@ public class MainActivity extends AppCompatActivity
}
}
};
Intent intentService = new Intent(this, StreamingService.class);
bindService(intentService, serviceConnection, Context.BIND_AUTO_CREATE);
streamingIntent = new Intent(this, StreamingService.class);
startService(streamingIntent);
LocalBroadcastManager.getInstance(this).registerReceiver(receive_data, new IntentFilter(Helper.RECEIVE_DATA));
@ -950,10 +946,8 @@ public class MainActivity extends AppCompatActivity
@Override
public void onDestroy(){
super.onDestroy();
if (mBound) {
unbindService(serviceConnection);
mBound = false;
}
if( streamingIntent != null)
stopService(streamingIntent);
LocalBroadcastManager.getInstance(this).unregisterReceiver(receive_data);
}