diff --git a/ic_launcher-web.png b/ic_launcher-web.png new file mode 100644 index 0000000..a169e78 Binary files /dev/null and b/ic_launcher-web.png differ diff --git a/res/menu/main.xml b/res/menu/main.xml new file mode 100644 index 0000000..30213a9 --- /dev/null +++ b/res/menu/main.xml @@ -0,0 +1,13 @@ + + + + + + diff --git a/res/values-en/strings.xml b/res/values-en/strings.xml index 9011565..45750f6 100644 --- a/res/values-en/strings.xml +++ b/res/values-en/strings.xml @@ -27,7 +27,7 @@ --> - 2 + 3 @@ -131,5 +131,6 @@ Error #13: Unable to perform a connection to ownCloud instance Error #14: Unable to parse server response Error #15: Unable to parse server response + Error #16: No data connection available diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml index c8b2a76..433b0ea 100644 --- a/res/values-fr/strings.xml +++ b/res/values-fr/strings.xml @@ -27,7 +27,7 @@ --> - 2 + 3 @@ -90,4 +90,6 @@ Processus de synchronisation Synchonisation en cours... Erreur fatale ! + + Erreur #16: Aucune connexion data disponible diff --git a/res/values/strings.xml b/res/values/strings.xml index d6cfa6c..adcabad 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -27,7 +27,7 @@ --> - 2 + 3 ownCloud-SMS @@ -142,5 +142,6 @@ Error #13: Unable to perform a connection to ownCloud instance Error #14: Unable to parse server response Error #15: Unable to parse server response + Error #16: No data connection available diff --git a/src/fr/unix_experience/owncloud_sms/broadcast_receivers/ConnectivityChanged.java b/src/fr/unix_experience/owncloud_sms/broadcast_receivers/ConnectivityChanged.java index 335d970..55fe4fa 100644 --- a/src/fr/unix_experience/owncloud_sms/broadcast_receivers/ConnectivityChanged.java +++ b/src/fr/unix_experience/owncloud_sms/broadcast_receivers/ConnectivityChanged.java @@ -1,30 +1,63 @@ package fr.unix_experience.owncloud_sms.broadcast_receivers; +/* + * Copyright (c) 2014, Loic Blot + * + * 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 . + */ + +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.Context; import android.content.Intent; import android.net.ConnectivityManager; import android.util.Log; -public class ConnectivityChanged extends BroadcastReceiver { +public class ConnectivityChanged extends BroadcastReceiver implements ASyncTask { @Override - public void onReceive(Context context, Intent intent) { - // Check the connectivity - 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); - + public void onReceive(Context context, Intent intent) { + ConnectivityMonitor cMon = new ConnectivityMonitor(context); // 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; 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 - else if (dataConnectionAvailable == true && !niWiFi.isAvailable() && !niMobile.isAvailable()) { + else if (dataConnectionAvailable == true && !cMon.isValid()) { 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(); } } diff --git a/src/fr/unix_experience/owncloud_sms/engine/ASyncTask.java b/src/fr/unix_experience/owncloud_sms/engine/ASyncTask.java new file mode 100644 index 0000000..e8a6ed3 --- /dev/null +++ b/src/fr/unix_experience/owncloud_sms/engine/ASyncTask.java @@ -0,0 +1,65 @@ +package fr.unix_experience.owncloud_sms.engine; + +/* + * Copyright (c) 2014, Loic Blot + * + * 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 . + */ + +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{ + 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(); +} diff --git a/src/fr/unix_experience/owncloud_sms/engine/ConnectivityMonitor.java b/src/fr/unix_experience/owncloud_sms/engine/ConnectivityMonitor.java new file mode 100644 index 0000000..e5101a9 --- /dev/null +++ b/src/fr/unix_experience/owncloud_sms/engine/ConnectivityMonitor.java @@ -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; +} diff --git a/src/fr/unix_experience/owncloud_sms/engine/OCSMSOwnCloudClient.java b/src/fr/unix_experience/owncloud_sms/engine/OCSMSOwnCloudClient.java index 9440aea..4dc2272 100644 --- a/src/fr/unix_experience/owncloud_sms/engine/OCSMSOwnCloudClient.java +++ b/src/fr/unix_experience/owncloud_sms/engine/OCSMSOwnCloudClient.java @@ -32,7 +32,6 @@ import org.json.JSONException; import org.json.JSONObject; import android.content.Context; -import android.content.SharedPreferences; import android.net.Uri; import android.util.Log; @@ -274,10 +273,19 @@ public class OCSMSOwnCloudClient { // We try maximumHttpReqTries because sometimes network is slow or unstable int tryNb = 0; + ConnectivityMonitor cMon = new ConnectivityMonitor(_context); while (tryNb < maximumHttpReqTries) { tryNb++; + if (!cMon.isValid()) { + if (tryNb == maximumHttpReqTries) { + req.releaseConnection(); + throw new OCSyncException(R.string.err_sync_no_connection_available, OCSyncErrorType.IO); + } + continue; + } + try { status = _ocClient.executeMethod(req); diff --git a/src/fr/unix_experience/owncloud_sms/engine/SmsFetcher.java b/src/fr/unix_experience/owncloud_sms/engine/SmsFetcher.java index 9d8f466..2873664 100644 --- a/src/fr/unix_experience/owncloud_sms/engine/SmsFetcher.java +++ b/src/fr/unix_experience/owncloud_sms/engine/SmsFetcher.java @@ -17,7 +17,6 @@ package fr.unix_experience.owncloud_sms.engine; * along with this program. If not, see . */ -import java.util.Date; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; @@ -40,47 +39,34 @@ public class SmsFetcher { public JSONArray fetchAllMessages() { _jsonDataDump = new JSONArray(); - fetchInboxMessages(); - fetchSentMessages(); - fetchDraftMessages(); + bufferizeMailboxMessages(MailboxID.INBOX); + bufferizeMailboxMessages(MailboxID.SENT); + bufferizeMailboxMessages(MailboxID.DRAFTS); return _jsonDataDump; } - public void fetchInboxMessages() { - bufferizeMailboxMessages("content://sms/inbox", MailboxID.INBOX); - } - - public void fetchSentMessages() { - 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) { + private void bufferizeMailboxMessages(MailboxID mbID) { + String mbURI = mapMailboxIDToURI(mbID); + + if (_context == null || mbURI == null) { return; } - if (_mbID != MailboxID.INBOX && _mbID != MailboxID.SENT && - _mbID != MailboxID.DRAFTS) { - Log.e(TAG,"Unhandled MailboxID " + _mbID.ordinal()); + if (mbID != MailboxID.INBOX && mbID != MailboxID.SENT && + mbID != MailboxID.DRAFTS) { + Log.e(TAG,"Unhandled MailboxID " + mbID.ordinal()); return; } - - Date startDate = new Date(); - // Fetch Sent SMS Message from Built-in Content Provider - + // We generate a ID list for this message box - String existingIDs = buildExistingMessagesString(_mbID); + String existingIDs = buildExistingMessagesString(mbID); Cursor c = null; 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 { - c = (new SmsDataProvider(_context)).query(_mb); + c = (new SmsDataProvider(_context)).query(mbURI); } // Reading mailbox @@ -90,8 +76,6 @@ public class SmsFetcher { JSONObject entry = new JSONObject(); try { - // Reading each mail element - int msgId = -1; for(int idx=0;idxgetMailboxMessages() Time spent: " + diffInMs + "ms"); } // Used by Content Observer - public JSONArray getLastMessage(String _mb) { - if (_context == null || _mb.length() == 0) { + public JSONArray getLastMessage(MailboxID mbID) { + String mbURI = mapMailboxIDToURI(mbID); + + if (_context == null || mbURI == null) { return null; } - + // 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(); @@ -184,11 +165,8 @@ public class SmsFetcher { } // Mailbox ID is required by server - switch (entry.getInt("type")) { - 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; - } + entry.put("mbox", mbID.ordinal()); + results.put(entry); } catch (JSONException e) { Log.e(TAG, "JSON Exception when reading SMS Mailbox", e); @@ -200,6 +178,96 @@ public class SmsFetcher { 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 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) { JSONArray existingMessages = null; if (_mbID == MailboxID.INBOX) { diff --git a/src/fr/unix_experience/owncloud_sms/enums/MailboxID.java b/src/fr/unix_experience/owncloud_sms/enums/MailboxID.java index f77f84d..b6dbe01 100644 --- a/src/fr/unix_experience/owncloud_sms/enums/MailboxID.java +++ b/src/fr/unix_experience/owncloud_sms/enums/MailboxID.java @@ -29,4 +29,5 @@ public enum MailboxID { INBOX, SENT, DRAFTS, + ALL, } diff --git a/src/fr/unix_experience/owncloud_sms/observers/SmsObserver.java b/src/fr/unix_experience/owncloud_sms/observers/SmsObserver.java index 6768b0d..0be1ca7 100644 --- a/src/fr/unix_experience/owncloud_sms/observers/SmsObserver.java +++ b/src/fr/unix_experience/owncloud_sms/observers/SmsObserver.java @@ -19,20 +19,16 @@ package fr.unix_experience.owncloud_sms.observers; 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.SmsFetcher; -import fr.unix_experience.owncloud_sms.exceptions.OCSyncException; -import android.accounts.Account; -import android.accounts.AccountManager; +import fr.unix_experience.owncloud_sms.enums.MailboxID; import android.content.Context; import android.database.ContentObserver; -import android.net.Uri; -import android.os.AsyncTask; import android.os.Handler; import android.util.Log; -public class SmsObserver extends ContentObserver { +public class SmsObserver extends ContentObserver implements ASyncTask { public SmsObserver(Handler handler) { super(handler); @@ -46,53 +42,20 @@ public class SmsObserver extends ContentObserver { public void onChange(boolean selfChange) { super.onChange(selfChange); Log.d(TAG, "onChange SmsObserver"); - - if (_accountMgr == null && _context != null) { - _accountMgr = AccountManager.get(_context); - } - String smsURI = "content://sms"; - - SmsFetcher sFetch = new SmsFetcher(_context); - JSONArray smsList = sFetch.getLastMessage(smsURI); + + SmsFetcher fetcher = new SmsFetcher(_context); + JSONArray smsList = fetcher.getLastMessage(MailboxID.ALL); if (smsList != null) { - new SyncTask(smsList).execute(); + new SyncTask(_context, smsList).execute(); } } - - private class SyncTask extends AsyncTask{ - 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) { _context = context; } private Context _context; - private static AccountManager _accountMgr; private static final String TAG = OCSMSOwnCloudClient.class.getSimpleName(); }