1
0
mirror of https://github.com/nerzhul/ownCloud-SMS-App.git synced 2025-06-28 10:16:13 +00:00

Misc fixes and sync on connectivity works.

* Export connectivity monitor.
* Sync works properly when data was available, but we need to find why
there is more messages than we need when we get them.
* add missing files
This commit is contained in:
Loïc Blot (@U-Exp) 2014-12-12 17:22:16 +01:00
parent f588a1ccb1
commit b3710b2e79
12 changed files with 289 additions and 105 deletions

BIN
ic_launcher-web.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

13
res/menu/main.xml Normal file
View File

@ -0,0 +1,13 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context="fr.unix_experience.owncloud_sms.MainActivity" >
<item
android:id="@+id/action_settings"
android:orderInCategory="100"
android:title="@string/action_settings"
app:showAsAction="never"/>
<item android:id="@+id/sync_now" android:title="@string/sync_now"></item>
</menu>

View File

@ -27,7 +27,7 @@
--> -->
<resources> <resources>
<!-- Translation version, reference for translators --> <!-- Translation version, reference for translators -->
<string name="translation_version">2</string> <string name="translation_version">3</string>
<!-- Translations must begin there --> <!-- Translations must begin there -->
<!-- Preferences --> <!-- Preferences -->
@ -131,5 +131,6 @@
<string name="err_sync_http_request_ioexception">Error #13: Unable to perform a connection to ownCloud instance</string> <string name="err_sync_http_request_ioexception">Error #13: Unable to perform a connection to ownCloud instance</string>
<string name="err_sync_http_request_resp">Error #14: Unable to parse server response</string> <string name="err_sync_http_request_resp">Error #14: Unable to parse server response</string>
<string name="err_sync_http_request_parse_resp">Error #15: Unable to parse server response</string> <string name="err_sync_http_request_parse_resp">Error #15: Unable to parse server response</string>
<string name="err_sync_no_connection_available">Error #16: No data connection available</string>
</resources> </resources>

View File

@ -27,7 +27,7 @@
--> -->
<resources> <resources>
<!-- Translation version, reference for translators --> <!-- Translation version, reference for translators -->
<string name="translation_version">2</string> <string name="translation_version">3</string>
<!-- Translations must begin there --> <!-- Translations must begin there -->
@ -90,4 +90,6 @@
<string name="sync_title">Processus de synchronisation</string> <string name="sync_title">Processus de synchronisation</string>
<string name="sync_inprogress">Synchonisation en cours...</string> <string name="sync_inprogress">Synchonisation en cours...</string>
<string name="fatal_error">Erreur fatale ! </string> <string name="fatal_error">Erreur fatale ! </string>
<string name="err_sync_no_connection_available">Erreur #16: Aucune connexion data disponible</string>
</resources> </resources>

View File

@ -27,7 +27,7 @@
--> -->
<resources> <resources>
<!-- Translation version, reference for translators --> <!-- Translation version, reference for translators -->
<string name="translation_version">2</string> <string name="translation_version">3</string>
<!-- System strings, do not translate --> <!-- System strings, do not translate -->
<string name="app_name">ownCloud-SMS</string> <string name="app_name">ownCloud-SMS</string>
@ -142,5 +142,6 @@
<string name="err_sync_http_request_ioexception">Error #13: Unable to perform a connection to ownCloud instance</string> <string name="err_sync_http_request_ioexception">Error #13: Unable to perform a connection to ownCloud instance</string>
<string name="err_sync_http_request_resp">Error #14: Unable to parse server response</string> <string name="err_sync_http_request_resp">Error #14: Unable to parse server response</string>
<string name="err_sync_http_request_parse_resp">Error #15: Unable to parse server response</string> <string name="err_sync_http_request_parse_resp">Error #15: Unable to parse server response</string>
<string name="err_sync_no_connection_available">Error #16: No data connection available</string>
</resources> </resources>

View File

@ -1,30 +1,63 @@
package fr.unix_experience.owncloud_sms.broadcast_receivers; package fr.unix_experience.owncloud_sms.broadcast_receivers;
/*
* Copyright (c) 2014, Loic Blot <loic.blot@unix-experience.fr>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import org.json.JSONArray;
import fr.unix_experience.owncloud_sms.engine.ASyncTask;
import fr.unix_experience.owncloud_sms.engine.ConnectivityMonitor;
import fr.unix_experience.owncloud_sms.engine.SmsFetcher;
import fr.unix_experience.owncloud_sms.prefs.OCSMSSharedPrefs;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.net.ConnectivityManager; import android.net.ConnectivityManager;
import android.util.Log; import android.util.Log;
public class ConnectivityChanged extends BroadcastReceiver { public class ConnectivityChanged extends BroadcastReceiver implements ASyncTask {
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
// Check the connectivity ConnectivityMonitor cMon = new ConnectivityMonitor(context);
final ConnectivityManager connMgr = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
final android.net.NetworkInfo niWiFi = connMgr.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
final android.net.NetworkInfo niMobile = connMgr.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
// If data is available and previous dataConnectionState was false, then we need to sync // If data is available and previous dataConnectionState was false, then we need to sync
if ((niWiFi.isAvailable() || niMobile.isAvailable()) && dataConnectionAvailable == false) { if (cMon.isValid() && dataConnectionAvailable == false) {
dataConnectionAvailable = true; dataConnectionAvailable = true;
Log.d(TAG,"ConnectivityChanged.onReceive, data conn available"); Log.d(TAG,"ConnectivityChanged.onReceive, data conn available");
// @TODO: check if last message is last synced msg (shared preference) checkMessagesToSent(context);
} }
// No data available and previous dataConnectionState was true // No data available and previous dataConnectionState was true
else if (dataConnectionAvailable == true && !niWiFi.isAvailable() && !niMobile.isAvailable()) { else if (dataConnectionAvailable == true && !cMon.isValid()) {
dataConnectionAvailable = false; dataConnectionAvailable = false;
Log.d(TAG,"ConnectivityChanges.onReceive: data conn is off");
}
}
private void checkMessagesToSent(Context context) {
// Get last message synced from preferences
Long lastMessageSynced = (new OCSMSSharedPrefs(context)).getLastMessageDate();
Log.d(TAG,"Synced Last:" + lastMessageSynced);
// Now fetch messages since last stored date
JSONArray smsList = new SmsFetcher(context).bufferizeMessagesSinceDate(lastMessageSynced);
Log.d(TAG,"smsList " + smsList.toString());
if (smsList != null) {
new SyncTask(context, smsList).execute();
} }
} }

View File

@ -0,0 +1,65 @@
package fr.unix_experience.owncloud_sms.engine;
/*
* Copyright (c) 2014, Loic Blot <loic.blot@unix-experience.fr>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import org.json.JSONArray;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.content.Context;
import android.net.Uri;
import android.os.AsyncTask;
import android.util.Log;
import fr.unix_experience.owncloud_sms.R;
import fr.unix_experience.owncloud_sms.exceptions.OCSyncException;
public interface ASyncTask {
class SyncTask extends AsyncTask<Void, Void, Void>{
public SyncTask(Context context, JSONArray smsList) {
_context = context;
_smsList = smsList;
}
@Override
protected Void doInBackground(Void... params) {
// Get ownCloud SMS account list
AccountManager _accountMgr = AccountManager.get(_context);
Account[] myAccountList = _accountMgr.getAccountsByType(_context.getString(R.string.account_type));
for (int i = 0; i < myAccountList.length; i++) {
Uri serverURI = Uri.parse(_accountMgr.getUserData(myAccountList[i], "ocURI"));
OCSMSOwnCloudClient _client = new OCSMSOwnCloudClient(_context,
serverURI, _accountMgr.getUserData(myAccountList[i], "ocLogin"),
_accountMgr.getPassword(myAccountList[i]));
try {
_client.doPushRequest(_smsList);
} catch (OCSyncException e) {
Log.e(TAG, _context.getString(e.getErrorId()));
}
}
return null;
}
private Context _context;
private JSONArray _smsList;
}
static final String TAG = ASyncTask.class.getSimpleName();
}

View File

@ -0,0 +1,29 @@
package fr.unix_experience.owncloud_sms.engine;
import android.content.Context;
import android.net.ConnectivityManager;
public class ConnectivityMonitor {
public ConnectivityMonitor(Context context) {
_context = context;
}
// Valid connection = WiFi or Mobile data
public boolean isValid() {
if (_cMgr == null) {
_cMgr = (ConnectivityManager) _context.getSystemService(Context.CONNECTIVITY_SERVICE);
}
final android.net.NetworkInfo niWiFi = _cMgr.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
final android.net.NetworkInfo niMobile = _cMgr.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
if (niWiFi.isAvailable() || niMobile.isAvailable()) {
return true;
}
return false;
}
private ConnectivityManager _cMgr;
private Context _context;
}

View File

@ -32,7 +32,6 @@ import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences;
import android.net.Uri; import android.net.Uri;
import android.util.Log; import android.util.Log;
@ -274,10 +273,19 @@ public class OCSMSOwnCloudClient {
// We try maximumHttpReqTries because sometimes network is slow or unstable // We try maximumHttpReqTries because sometimes network is slow or unstable
int tryNb = 0; int tryNb = 0;
ConnectivityMonitor cMon = new ConnectivityMonitor(_context);
while (tryNb < maximumHttpReqTries) { while (tryNb < maximumHttpReqTries) {
tryNb++; tryNb++;
if (!cMon.isValid()) {
if (tryNb == maximumHttpReqTries) {
req.releaseConnection();
throw new OCSyncException(R.string.err_sync_no_connection_available, OCSyncErrorType.IO);
}
continue;
}
try { try {
status = _ocClient.executeMethod(req); status = _ocClient.executeMethod(req);

View File

@ -17,7 +17,6 @@ package fr.unix_experience.owncloud_sms.engine;
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
import java.util.Date;
import org.json.JSONArray; import org.json.JSONArray;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
@ -40,47 +39,34 @@ public class SmsFetcher {
public JSONArray fetchAllMessages() { public JSONArray fetchAllMessages() {
_jsonDataDump = new JSONArray(); _jsonDataDump = new JSONArray();
fetchInboxMessages(); bufferizeMailboxMessages(MailboxID.INBOX);
fetchSentMessages(); bufferizeMailboxMessages(MailboxID.SENT);
fetchDraftMessages(); bufferizeMailboxMessages(MailboxID.DRAFTS);
return _jsonDataDump; return _jsonDataDump;
} }
public void fetchInboxMessages() { private void bufferizeMailboxMessages(MailboxID mbID) {
bufferizeMailboxMessages("content://sms/inbox", MailboxID.INBOX); String mbURI = mapMailboxIDToURI(mbID);
}
public void fetchSentMessages() { if (_context == null || mbURI == null) {
bufferizeMailboxMessages("content://sms/sent", MailboxID.SENT);
}
public void fetchDraftMessages() {
bufferizeMailboxMessages("content://sms/drafts", MailboxID.DRAFTS);
}
private void bufferizeMailboxMessages(String _mb, MailboxID _mbID) {
if (_context == null || _mb.length() == 0) {
return; return;
} }
if (_mbID != MailboxID.INBOX && _mbID != MailboxID.SENT && if (mbID != MailboxID.INBOX && mbID != MailboxID.SENT &&
_mbID != MailboxID.DRAFTS) { mbID != MailboxID.DRAFTS) {
Log.e(TAG,"Unhandled MailboxID " + _mbID.ordinal()); Log.e(TAG,"Unhandled MailboxID " + mbID.ordinal());
return; return;
} }
Date startDate = new Date();
// Fetch Sent SMS Message from Built-in Content Provider
// We generate a ID list for this message box // We generate a ID list for this message box
String existingIDs = buildExistingMessagesString(_mbID); String existingIDs = buildExistingMessagesString(mbID);
Cursor c = null; Cursor c = null;
if (existingIDs.length() > 0) { if (existingIDs.length() > 0) {
c = (new SmsDataProvider(_context)).query(_mb, "_id NOT IN (" + existingIDs + ")"); c = (new SmsDataProvider(_context)).query(mbURI, "_id NOT IN (" + existingIDs + ")");
} }
else { else {
c = (new SmsDataProvider(_context)).query(_mb); c = (new SmsDataProvider(_context)).query(mbURI);
} }
// Reading mailbox // Reading mailbox
@ -90,8 +76,6 @@ public class SmsFetcher {
JSONObject entry = new JSONObject(); JSONObject entry = new JSONObject();
try { try {
// Reading each mail element
int msgId = -1;
for(int idx=0;idx<c.getColumnCount();idx++) { for(int idx=0;idx<c.getColumnCount();idx++) {
String colName = c.getColumnName(idx); String colName = c.getColumnName(idx);
@ -102,7 +86,6 @@ public class SmsFetcher {
// bufferize Id for future use // bufferize Id for future use
if (colName.equals(new String("_id"))) { if (colName.equals(new String("_id"))) {
msgId = c.getInt(idx);
} }
} }
// Seen and read must be pseudo boolean // Seen and read must be pseudo boolean
@ -123,7 +106,7 @@ public class SmsFetcher {
} }
// Mailbox ID is required by server // Mailbox ID is required by server
entry.put("mbox", _mbID.ordinal()); entry.put("mbox", mbID.ordinal());
_jsonDataDump.put(entry); _jsonDataDump.put(entry);
@ -134,24 +117,22 @@ public class SmsFetcher {
} }
while(c.moveToNext()); while(c.moveToNext());
Log.d(TAG, c.getCount() + " messages read from " +_mb); Log.d(TAG, c.getCount() + " messages read from " + mbURI);
c.close(); c.close();
} }
long diffInMs = (new Date()).getTime() - startDate.getTime();
Log.d(TAG, "SmsFetcher->getMailboxMessages() Time spent: " + diffInMs + "ms");
} }
// Used by Content Observer // Used by Content Observer
public JSONArray getLastMessage(String _mb) { public JSONArray getLastMessage(MailboxID mbID) {
if (_context == null || _mb.length() == 0) { String mbURI = mapMailboxIDToURI(mbID);
if (_context == null || mbURI == null) {
return null; return null;
} }
// Fetch Sent SMS Message from Built-in Content Provider // Fetch Sent SMS Message from Built-in Content Provider
Cursor c = (new SmsDataProvider(_context)).query(_mb); Cursor c = (new SmsDataProvider(_context)).query(mbURI);
c.moveToNext(); c.moveToNext();
@ -184,11 +165,8 @@ public class SmsFetcher {
} }
// Mailbox ID is required by server // Mailbox ID is required by server
switch (entry.getInt("type")) { entry.put("mbox", mbID.ordinal());
case 1: entry.put("mbox", MailboxID.INBOX.ordinal()); break;
case 2: entry.put("mbox", MailboxID.SENT.ordinal()); break;
case 3: entry.put("mbox", MailboxID.DRAFTS.ordinal()); break;
}
results.put(entry); results.put(entry);
} catch (JSONException e) { } catch (JSONException e) {
Log.e(TAG, "JSON Exception when reading SMS Mailbox", e); Log.e(TAG, "JSON Exception when reading SMS Mailbox", e);
@ -200,6 +178,96 @@ public class SmsFetcher {
return results; return results;
} }
// Used by ConnectivityChanged Event
public JSONArray bufferizeMessagesSinceDate(Long sinceDate) {
_jsonDataDump = new JSONArray();
bufferizeMessagesSinceDate(MailboxID.INBOX, sinceDate);
bufferizeMessagesSinceDate(MailboxID.SENT, sinceDate);
bufferizeMessagesSinceDate(MailboxID.DRAFTS, sinceDate);
return _jsonDataDump;
}
// Used by ConnectivityChanged Event
public void bufferizeMessagesSinceDate(MailboxID mbID, Long sinceDate) {
String mbURI = mapMailboxIDToURI(mbID);
if (_context == null || mbURI == null) {
return;
}
Cursor c = (new SmsDataProvider(_context)).query(mbURI, "date > " + sinceDate);
// Reading mailbox
if (c != null && c.getCount() > 0) {
c.moveToFirst();
do {
JSONObject entry = new JSONObject();
try {
for(int idx=0;idx<c.getColumnCount();idx++) {
String colName = c.getColumnName(idx);
// Id column is must be an integer
if (colName.equals(new String("_id")) ||
colName.equals(new String("type"))) {
entry.put(colName, c.getInt(idx));
// bufferize Id for future use
if (colName.equals(new String("_id"))) {
}
}
// Seen and read must be pseudo boolean
else if (colName.equals(new String("read")) ||
colName.equals(new String("seen"))) {
entry.put(colName, c.getInt(idx) > 0 ? "true" : "false");
}
else {
// Special case for date, we need to record last without searching
if (colName.equals(new String("date"))) {
final Long tmpDate = c.getLong(idx);
if (tmpDate > _lastMsgDate) {
_lastMsgDate = tmpDate;
}
}
entry.put(colName, c.getString(idx));
}
}
// Mailbox ID is required by server
entry.put("mbox", mbID.ordinal());
_jsonDataDump.put(entry);
} catch (JSONException e) {
Log.e(TAG, "JSON Exception when reading SMS Mailbox", e);
c.close();
}
}
while(c.moveToNext());
Log.d(TAG, c.getCount() + " messages read from " + mbURI);
c.close();
}
}
private String mapMailboxIDToURI(MailboxID mbID) {
if (mbID == MailboxID.INBOX) {
return "content://sms/inbox";
}
else if (mbID == MailboxID.DRAFTS) {
return "content://sms/drafts";
}
else if (mbID == MailboxID.SENT) {
return "content://sms/sent";
}
else if (mbID == MailboxID.ALL) {
return "content://sms";
}
return null;
}
private String buildExistingMessagesString(MailboxID _mbID) { private String buildExistingMessagesString(MailboxID _mbID) {
JSONArray existingMessages = null; JSONArray existingMessages = null;
if (_mbID == MailboxID.INBOX) { if (_mbID == MailboxID.INBOX) {

View File

@ -29,4 +29,5 @@ public enum MailboxID {
INBOX, INBOX,
SENT, SENT,
DRAFTS, DRAFTS,
ALL,
} }

View File

@ -19,20 +19,16 @@ package fr.unix_experience.owncloud_sms.observers;
import org.json.JSONArray; import org.json.JSONArray;
import fr.unix_experience.owncloud_sms.R; import fr.unix_experience.owncloud_sms.engine.ASyncTask;
import fr.unix_experience.owncloud_sms.engine.OCSMSOwnCloudClient; import fr.unix_experience.owncloud_sms.engine.OCSMSOwnCloudClient;
import fr.unix_experience.owncloud_sms.engine.SmsFetcher; import fr.unix_experience.owncloud_sms.engine.SmsFetcher;
import fr.unix_experience.owncloud_sms.exceptions.OCSyncException; import fr.unix_experience.owncloud_sms.enums.MailboxID;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.content.Context; import android.content.Context;
import android.database.ContentObserver; import android.database.ContentObserver;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Handler; import android.os.Handler;
import android.util.Log; import android.util.Log;
public class SmsObserver extends ContentObserver { public class SmsObserver extends ContentObserver implements ASyncTask {
public SmsObserver(Handler handler) { public SmsObserver(Handler handler) {
super(handler); super(handler);
@ -47,52 +43,19 @@ public class SmsObserver extends ContentObserver {
super.onChange(selfChange); super.onChange(selfChange);
Log.d(TAG, "onChange SmsObserver"); Log.d(TAG, "onChange SmsObserver");
if (_accountMgr == null && _context != null) { SmsFetcher fetcher = new SmsFetcher(_context);
_accountMgr = AccountManager.get(_context); JSONArray smsList = fetcher.getLastMessage(MailboxID.ALL);
}
String smsURI = "content://sms";
SmsFetcher sFetch = new SmsFetcher(_context);
JSONArray smsList = sFetch.getLastMessage(smsURI);
if (smsList != null) { if (smsList != null) {
new SyncTask(smsList).execute(); new SyncTask(_context, smsList).execute();
} }
} }
private class SyncTask extends AsyncTask<Void, Void, Void>{
public SyncTask(JSONArray smsList) {
_smsList = smsList;
}
@Override
protected Void doInBackground(Void... params) {
// Get ownCloud SMS account list
Account[] myAccountList = _accountMgr.getAccountsByType(_context.getString(R.string.account_type));
for (int i = 0; i < myAccountList.length; i++) {
Log.d(TAG, "int i = 0; i < myAccountList.length; i++" + myAccountList[i] + " SmsObserver");
Uri serverURI = Uri.parse(_accountMgr.getUserData(myAccountList[i], "ocURI"));
OCSMSOwnCloudClient _client = new OCSMSOwnCloudClient(_context,
serverURI, _accountMgr.getUserData(myAccountList[i], "ocLogin"),
_accountMgr.getPassword(myAccountList[i]));
try {
_client.doPushRequest(_smsList);
} catch (OCSyncException e) {
Log.e(TAG, _context.getString(e.getErrorId()));
}
}
return null;
}
private JSONArray _smsList;
}
public void setContext(Context context) { public void setContext(Context context) {
_context = context; _context = context;
} }
private Context _context; private Context _context;
private static AccountManager _accountMgr;
private static final String TAG = OCSMSOwnCloudClient.class.getSimpleName(); private static final String TAG = OCSMSOwnCloudClient.class.getSimpleName();
} }