diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
new file mode 100644
index 0000000000000000000000000000000000000000..2ffaa1897d994ba9a9d767faee5f5d0ade7da0c1
--- /dev/null
+++ b/.gitlab-ci.yml
@@ -0,0 +1,21 @@
+image: "registry.gitlab.e.foundation:5000/e/apps/docker-android-apps-cicd:latest"
+
+stages:
+- build
+
+before_script:
+- export GRADLE_USER_HOME=$(pwd)/.gradle
+- chmod +x ./gradlew
+
+cache:
+ key: ${CI_PROJECT_ID}
+ paths:
+ - .gradle/
+
+build:
+ stage: build
+ script:
+ - ./gradlew build
+ artifacts:
+ paths:
+ - build/outputs/apk
diff --git a/build.gradle b/build.gradle
index dfb1e3f6eec0115411ea0a3b530207933de17f70..d47c91bbb775f9758d7354762532020839ea54d6 100644
--- a/build.gradle
+++ b/build.gradle
@@ -27,7 +27,7 @@ android {
}
defaultConfig {
- applicationId "fr.unix_experience.owncloud_sms"
+ applicationId "e.foundation.sms_sync"
versionCode 70
versionName "2.0.6"
minSdkVersion 16
diff --git a/ncsms-android.iml b/ncsms-android.iml
new file mode 100644
index 0000000000000000000000000000000000000000..eee803d24ac73362720a6b3daa12b85b36ce4d48
--- /dev/null
+++ b/ncsms-android.iml
@@ -0,0 +1,133 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ generateDebugSources
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ncsmsgo/ncsmsgo.aar b/ncsmsgo/ncsmsgo.aar
index fd4719f888b2d89ab7c674370fafe313d119750a..bb4e15bc176a8bffed7b5b29de52e1ac795afb45 100644
Binary files a/ncsmsgo/ncsmsgo.aar and b/ncsmsgo/ncsmsgo.aar differ
diff --git a/ncsmsgo/ncsmsgo.iml b/ncsmsgo/ncsmsgo.iml
index 3599347fbbf2b831a9902bc286435f95b206c6cc..39cbca89a4ece69fde4ec05b844c196e170fb566 100644
--- a/ncsmsgo/ncsmsgo.iml
+++ b/ncsmsgo/ncsmsgo.iml
@@ -4,6 +4,8 @@
+
+
diff --git a/src/main/AndroidManifest.xml b/src/main/AndroidManifest.xml
index 7a9f8d0c5f1431677a7d6dfae53c022d9b8d04cb..cf4155c88a631e36322d8b7ebcaee4680edc7396 100644
--- a/src/main/AndroidManifest.xml
+++ b/src/main/AndroidManifest.xml
@@ -33,13 +33,53 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
+
+
+
+ android:label="@string/title_activity_select_contact" />
+ android:label="@string/account_actions" />
+ android:label="@string/restore_all_messages" />
+ android:theme="@style/OcSmsTheme.NoActionBar" />
\ No newline at end of file
diff --git a/src/main/aidl/foundation/e/message/IRestoreService.aidl b/src/main/aidl/foundation/e/message/IRestoreService.aidl
new file mode 100644
index 0000000000000000000000000000000000000000..36c9651a03aeb20a40a0f2ae7e4a816e30fdd88a
--- /dev/null
+++ b/src/main/aidl/foundation/e/message/IRestoreService.aidl
@@ -0,0 +1,7 @@
+package foundation.e.message;
+
+
+interface IRestoreService {
+ oneway void restoreMessages(in String messagesJson);
+
+}
diff --git a/src/main/java/fr/unix_experience/owncloud_sms/activities/MainActivity.java b/src/main/java/fr/unix_experience/owncloud_sms/activities/MainActivity.java
index 585d5796e0f16ab64ff0279402b9753e7237a6fd..dd65f2ddca9541c84a87740f3d30389204a5c1c2 100644
--- a/src/main/java/fr/unix_experience/owncloud_sms/activities/MainActivity.java
+++ b/src/main/java/fr/unix_experience/owncloud_sms/activities/MainActivity.java
@@ -30,7 +30,9 @@ import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
+import android.os.Build;
import android.os.Bundle;
+import android.os.PowerManager;
import android.provider.Settings;
import android.support.annotation.NonNull;
import android.support.design.widget.NavigationView;
@@ -48,6 +50,7 @@ import fr.unix_experience.owncloud_sms.R;
import fr.unix_experience.owncloud_sms.activities.remote_account.AccountListActivity;
import fr.unix_experience.owncloud_sms.engine.ASyncSMSSync.SyncTask;
import fr.unix_experience.owncloud_sms.engine.ConnectivityMonitor;
+import fr.unix_experience.owncloud_sms.engine.SmsSenderService;
import fr.unix_experience.owncloud_sms.enums.PermissionID;
import fr.unix_experience.owncloud_sms.prefs.PermissionChecker;
@@ -81,6 +84,17 @@ public class MainActivity extends AppCompatActivity
drawer = findViewById(R.id.drawer_layout);
setupDrawer();
drawer.openDrawer(GravityCompat.START);
+ startService(new Intent(this, SmsSenderService.class));
+ if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ Intent intent = new Intent();
+ String packageName = getPackageName();
+ PowerManager pm = (PowerManager) getSystemService(POWER_SERVICE);
+ if (!pm.isIgnoringBatteryOptimizations(packageName)) {
+ intent.setAction(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
+ intent.setData(Uri.parse("package:" + packageName));
+ startActivity(intent);
+ }
+ }
}
protected void setupToolbar() {
diff --git a/src/main/java/fr/unix_experience/owncloud_sms/activities/remote_account/RestoreMessagesActivity.java b/src/main/java/fr/unix_experience/owncloud_sms/activities/remote_account/RestoreMessagesActivity.java
index 616771800e75d449ed21ac189187f44081e17e5f..cab1cf01671d848809b0966f226294d4c3f3b163 100644
--- a/src/main/java/fr/unix_experience/owncloud_sms/activities/remote_account/RestoreMessagesActivity.java
+++ b/src/main/java/fr/unix_experience/owncloud_sms/activities/remote_account/RestoreMessagesActivity.java
@@ -17,15 +17,12 @@ package fr.unix_experience.owncloud_sms.activities.remote_account;
* along with this program. If not, see .
*/
-import android.Manifest;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.app.Activity;
import android.content.Intent;
-import android.content.pm.PackageManager;
import android.os.Bundle;
import android.provider.Telephony;
-import android.support.v4.app.ActivityCompat;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
@@ -37,6 +34,7 @@ import android.widget.TextView;
import fr.unix_experience.owncloud_sms.R;
import fr.unix_experience.owncloud_sms.engine.ASyncSMSRecovery;
+import fr.unix_experience.owncloud_sms.engine.ASyncSMSSender;
import fr.unix_experience.owncloud_sms.engine.ConnectivityMonitor;
public class RestoreMessagesActivity extends AppCompatActivity {
diff --git a/src/main/java/fr/unix_experience/owncloud_sms/broadcast_receivers/SmsSenderIntentReceiver.java b/src/main/java/fr/unix_experience/owncloud_sms/broadcast_receivers/SmsSenderIntentReceiver.java
new file mode 100644
index 0000000000000000000000000000000000000000..40eaa1b7ca652be48a4f5eaec53a66d7fa885ab2
--- /dev/null
+++ b/src/main/java/fr/unix_experience/owncloud_sms/broadcast_receivers/SmsSenderIntentReceiver.java
@@ -0,0 +1,136 @@
+package fr.unix_experience.owncloud_sms.broadcast_receivers;
+
+import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Bundle;
+import android.preference.PreferenceManager;
+import android.util.Log;
+
+import org.json.JSONException;
+
+import fr.unix_experience.owncloud_sms.R;
+import fr.unix_experience.owncloud_sms.engine.ASyncSMSSender;
+import fr.unix_experience.owncloud_sms.engine.AndroidSmsFetcher;
+import fr.unix_experience.owncloud_sms.engine.OCSMSOwnCloudClient;
+import fr.unix_experience.owncloud_sms.engine.SmsEntry;
+import fr.unix_experience.owncloud_sms.engine.SmsSenderService;
+import fr.unix_experience.owncloud_sms.enums.MailboxID;
+import fr.unix_experience.owncloud_sms.exceptions.OCSyncException;
+import fr.unix_experience.owncloud_sms.providers.SmsDataProvider;
+import fr.unix_experience.owncloud_sms.providers.SmsSendStackProvider;
+import ncsmsgo.SmsBuffer;
+import ncsmsgo.SmsMessage;
+
+public class SmsSenderIntentReceiver extends BroadcastReceiver {
+ private static final int ALARM_ID = 1001;
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if(intent.getStringExtra("sms") != null){
+ SmsMessage message = null;
+ try {
+ Account account = null;
+ for (Account account1: AccountManager.get(context).getAccountsByType(intent.getStringExtra("account_type"))){
+ if(account1.name.equals(intent.getStringExtra("account_name"))){
+ account = account1;
+ break;
+ }
+ }
+ if(account == null){
+ return;
+ }
+
+ OCSMSOwnCloudClient client = new OCSMSOwnCloudClient(context, account);
+ message = SmsSendStackProvider.smsMessageFromString(intent.getStringExtra("sms"));
+ SmsBuffer smsBuffer = new SmsBuffer();
+ SmsEntry entry = readMailBox(context, smsBuffer, message.getId(), Uri.parse(intent.getStringExtra("uri")));
+ SmsSendStackProvider stackProvider = SmsSendStackProvider.getInstance(context);
+ if(entry != null) {
+ stackProvider.setSent(message, entry.sent ? 3 : 5);
+ client.deleteMessage(message.getAddress(), message.getDate());
+ client.doPushRequest(smsBuffer);
+ if(entry.sent)
+ stackProvider.setSent(message, 2);
+ } else {
+ stackProvider.setSent(message, 6);
+ client.deleteMessage(message.getAddress(), message.getDate());
+ smsBuffer.push(message.getId(),
+ message.getId(),
+ MailboxID.SENT.ordinal(),
+ message.getType(),
+ System.currentTimeMillis(),
+ message.getAddress(),
+ message.getCardNumber(),
+ message.getCardSlot(),
+ message.getIccId(),
+ message.getDeviceName(),
+ message.getCarrierName(),
+ message.getMessage(),
+ 6,
+ "true",
+ "true") ;
+ client.doPushRequest(smsBuffer);
+
+ }
+
+ } catch (JSONException | OCSyncException e) {
+ e.printStackTrace();
+ }
+
+ } else
+ context.startService(new Intent(context, SmsSenderService.class));
+ }
+
+
+
+
+ private SmsEntry readMailBox(Context context, SmsBuffer smsBuffer,long nc_id, Uri uri) {
+ Cursor c = new SmsDataProvider(context).query(Uri.parse(MailboxID.SENT.getURI()), SmsDataProvider.messageFields, "_id = ?", new String[] { uri.getLastPathSegment() }, null);
+ SmsEntry entry = null;
+ if(c!=null) {
+ do {
+ entry = new SmsEntry();
+ for (int idx = 0; idx < c.getColumnCount(); idx++) {
+ AndroidSmsFetcher.handleProviderColumn(context, c, idx, entry);
+ }
+ entry.device_name = Build.MODEL;
+ // Mailbox ID is required by server
+ entry.mailboxId = MailboxID.SENT.ordinal();
+
+ break;
+
+ }
+ while (c.moveToNext());
+ c.close();
+ }
+
+ if(entry != null) {
+ smsBuffer.push(entry.id,
+ nc_id,
+ MailboxID.SENT.ordinal(),
+ entry.type,
+ entry.date,
+ entry.address,
+ entry.card_number,
+ entry.card_slot,
+ entry.icc_id,
+ entry.device_name,
+ entry.carrier_name,
+ entry.body,
+ 1,
+ "true",
+ "true") ;
+ return entry;
+ }
+ return null;
+ }
+
+}
diff --git a/src/main/java/fr/unix_experience/owncloud_sms/engine/ASyncSMSSender.java b/src/main/java/fr/unix_experience/owncloud_sms/engine/ASyncSMSSender.java
new file mode 100644
index 0000000000000000000000000000000000000000..abca65950d0046aa6677a6b39bf43ee362797b7f
--- /dev/null
+++ b/src/main/java/fr/unix_experience/owncloud_sms/engine/ASyncSMSSender.java
@@ -0,0 +1,220 @@
+package fr.unix_experience.owncloud_sms.engine;
+
+import android.accounts.Account;
+import android.app.PendingIntent;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.os.Build;
+import android.preference.PreferenceManager;
+import android.provider.Telephony;
+import android.telephony.SmsManager;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
+import android.util.Log;
+
+import java.util.List;
+import java.util.Random;
+
+import fr.unix_experience.owncloud_sms.activities.remote_account.RestoreMessagesActivity;
+import fr.unix_experience.owncloud_sms.broadcast_receivers.SmsSenderIntentReceiver;
+import fr.unix_experience.owncloud_sms.enums.MailboxID;
+import fr.unix_experience.owncloud_sms.providers.SmsDataProvider;
+import fr.unix_experience.owncloud_sms.providers.SmsSendStackProvider;
+import ncsmsgo.SmsMessage;
+import ncsmsgo.SmsMessagesResponse;
+
+/*
+ * Copyright (c) 2014-2016, 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 .
+ */
+
+public interface ASyncSMSSender {
+ class SMSSenderSyncTask extends AsyncTask {
+ private final Context _context;
+ private final Account _account;
+
+ public SMSSenderSyncTask(Context context, Account account) {
+ _context = context;
+ _account = account;
+ }
+
+ @Override
+ protected Void doInBackground(Void... params) {
+ // This feature is only available for Android 4.4 and greater
+ if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.KITKAT) {
+ return null;
+ }
+
+ if (!new ConnectivityMonitor(_context).isValid()) {
+ Log.e(ASyncSMSSender.TAG, "Restore connectivity problems, aborting");
+ return null;
+ }
+ Log.i(ASyncSMSSender.TAG, "Starting background recovery");
+ Long start = PreferenceManager.getDefaultSharedPreferences(_context).getLong("last_sync_sender_"+_account.name,0);
+
+ OCSMSOwnCloudClient client = new OCSMSOwnCloudClient(_context, _account);
+ SmsDataProvider smsDataProvider = new SmsDataProvider(_context);
+ SmsMessagesResponse obj = client.retrieveSomeMessages(start, 500);
+ if (obj == null) {
+ Log.i(ASyncSMSSender.TAG, "Retrieved returns failure");
+ return null;
+ }
+ SmsSendStackProvider stackProvider = SmsSendStackProvider.getInstance(_context);
+
+ Integer nb = 0;
+ while ((obj != null) && (obj.getLastID() != start)) {
+ Log.i(TAG, "Retrieving messages from " + Long.toString(start)
+ + " to " + Long.toString(obj.getLastID()));
+ SmsMessage message;
+ while ((message = obj.getNextMessage()) != null) {
+ int mbid = (int) message.getMailbox();
+ // Ignore invalid mailbox
+ if (mbid > MailboxID.ALL.getId()) {
+ Log.e(ASyncSMSSender.TAG, "Invalid mailbox found: " + mbid);
+ continue;
+ }
+
+
+ String address = message.getAddress();
+ String body = message.getMessage();
+ int type = (int) message.getType();
+ if (address.isEmpty() || body.isEmpty()) {
+ Log.e(ASyncSMSSender.TAG, "Invalid SMS message found: " + message.toString());
+ continue;
+ }
+
+ MailboxID mailbox_id = MailboxID.fromInt(mbid);
+
+ String date = Long.toString(message.getDate());
+
+ // Ignore already existing messages
+
+ if(message.getSent() == 0 && message.getMailbox() == 1){
+ if (stackProvider.messageExists(address, body, date) || smsDataProvider.messageExists(address, body, date, mailbox_id)) {
+ continue;
+ }
+
+ stackProvider.addMessage(message, _account.name);
+ nb++;
+ if ((nb % 10) == 0) {
+ publishProgress(nb);
+ }
+
+ }
+
+ }
+
+ start = obj.getLastID();
+ PreferenceManager.getDefaultSharedPreferences(_context).edit().putLong("last_sync_sender_"+_account.name,start).apply();
+
+ if (!new ConnectivityMonitor(_context).isValid()) {
+ Log.e(ASyncSMSSender.TAG, "Restore connectivity problems, aborting");
+ return null;
+ }
+ obj = client.retrieveSomeMessages(start, 500);
+ }
+
+ // Force this refresh to fix dates
+ _context.getContentResolver().delete(Uri.parse("content://sms/conversations/-1"),
+ null, null);
+
+ publishProgress(nb);
+
+ Log.i(ASyncSMSSender.TAG, "Finishing background recovery");
+ return null;
+ }
+
+ @Override
+ protected void onProgressUpdate(Integer... values) {
+ super.onProgressUpdate(values);
+ }
+
+ @Override
+ protected void onPostExecute(Void aVoid) {
+ super.onPostExecute(aVoid);
+ SMSSendTask smsSendTask = new SMSSendTask(_context, _account);
+ smsSendTask.execute();
+ }
+ }
+
+ class SMSSendTask extends AsyncTask {
+ private final Context _context;
+ private final Account _account;
+
+ public SMSSendTask(Context context, Account account) {
+ _context = context;
+ _account = account;
+
+ }
+
+ @Override
+ protected Void doInBackground(Void... params) {
+ SmsSendStackProvider stackProvider = SmsSendStackProvider.getInstance(_context);
+ List smsToSend = stackProvider.getMessagestoSend(_account.name);
+ for (SmsMessage message : smsToSend) {
+ if(message.getSent() == 0){
+ int subscriptionId = -1;
+ if (Build.VERSION.SDK_INT>=22) {
+ SubscriptionManager subscriptionManager = (SubscriptionManager) _context.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
+ for(SubscriptionInfo i: subscriptionManager.getActiveSubscriptionInfoList()){
+ if((message.getCardNumber().isEmpty() || i.getNumber() == null || i.getNumber().equals(message.getCardNumber()))
+ && (message.getCarrierName().isEmpty() || i.getCarrierName().equals(message.getCarrierName()))
+ && (message.getCardSlot() == -1 || i.getSimSlotIndex() == message.getCardSlot())){
+ subscriptionId = i.getSubscriptionId();
+ break;
+ }
+ }
+
+ } else subscriptionId = -2;
+ Intent intent = new Intent();
+ intent.putExtra("sms", SmsSendStackProvider.smsMessageToJsonString(message));
+ intent.putExtra("account_type", _account.type);
+ intent.putExtra("account_name", _account.name);
+ intent.putExtra("sent_time",System.currentTimeMillis());
+ intent.setClass(_context, SmsSenderIntentReceiver.class);
+ SmsManager smsManager;
+ if(subscriptionId >=0)
+ smsManager = SmsManager.getSmsManagerForSubscriptionId(subscriptionId);
+ else if (subscriptionId == -2)
+ smsManager = SmsManager.getDefault();
+ else{
+ stackProvider.setSent(message, 5);
+ continue;
+ }
+ smsManager.sendTextMessage(message.getAddress(), null, message.getMessage(),
+ PendingIntent.getBroadcast(_context, new Random().nextInt(1000)+1200, intent,PendingIntent.FLAG_UPDATE_CURRENT), null);
+ stackProvider.setSent(message, 2);
+
+ }
+
+ }
+
+
+ return null;
+ }
+
+
+
+ @Override
+ protected void onPostExecute(Void aVoid) {
+ super.onPostExecute(aVoid);
+ }
+ }
+
+ String TAG = ASyncSMSSender.class.getSimpleName();
+}
diff --git a/src/main/java/fr/unix_experience/owncloud_sms/engine/ASyncSMSSync.java b/src/main/java/fr/unix_experience/owncloud_sms/engine/ASyncSMSSync.java
index 77ca15aae3bd2669a6b026c3a39cc820942fc459..3b3157e8105745662ae03c036b957bf1176d838b 100644
--- a/src/main/java/fr/unix_experience/owncloud_sms/engine/ASyncSMSSync.java
+++ b/src/main/java/fr/unix_experience/owncloud_sms/engine/ASyncSMSSync.java
@@ -20,6 +20,7 @@ package fr.unix_experience.owncloud_sms.engine;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.app.Activity;
+import android.content.ContentResolver;
import android.content.Context;
import android.os.AsyncTask;
import android.util.Log;
@@ -109,6 +110,9 @@ public interface ASyncSMSSync {
// Notify that we are syncing SMS
for (Account element : myAccountList) {
+ if(!ContentResolver.getSyncAutomatically(element, _context.getString(R.string.account_authority))){
+ continue;
+ }
try {
OCSMSOwnCloudClient _client = new OCSMSOwnCloudClient(_context, element);
// Fetch API version first to do some early verifications
diff --git a/src/main/java/fr/unix_experience/owncloud_sms/engine/AndroidSmsFetcher.java b/src/main/java/fr/unix_experience/owncloud_sms/engine/AndroidSmsFetcher.java
index f149b592ad90dc3790b0aadcb5ca5aac520d81a5..d1f68e6681e064850216b24a5db2d2e49ab87486 100644
--- a/src/main/java/fr/unix_experience/owncloud_sms/engine/AndroidSmsFetcher.java
+++ b/src/main/java/fr/unix_experience/owncloud_sms/engine/AndroidSmsFetcher.java
@@ -19,6 +19,9 @@ package fr.unix_experience.owncloud_sms.engine;
import android.content.Context;
import android.database.Cursor;
+import android.os.Build;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
import android.util.Log;
import org.json.JSONArray;
@@ -48,17 +51,25 @@ public class AndroidSmsFetcher {
SmsEntry entry = new SmsEntry();
for (int idx = 0; idx < c.getColumnCount(); idx++) {
- handleProviderColumn(c, idx, entry);
+ handleProviderColumn(_context, c, idx, entry);
}
-
+ entry.device_name = Build.MODEL;
// Mailbox ID is required by server
entry.mailboxId = mbID.ordinal();
+ entry.sent = true;
smsBuffer.push(entry.id,
+ -1,
mbID.ordinal(),
entry.type,
entry.date,
entry.address,
+ entry.card_number,
+ entry.card_slot,
+ entry.icc_id,
+ entry.device_name,
+ entry.carrier_name,
entry.body,
+ entry.sent ? 1 : 0,
entry.read ? "true" : "false",
entry.seen ? "true" : "false");
}
@@ -106,10 +117,11 @@ public class AndroidSmsFetcher {
// We create a list of strings to store results
SmsEntry entry = new SmsEntry();
SmsBuffer results = new SmsBuffer();
+ entry.device_name = Build.MODEL;
Integer mboxId = -1;
for (int idx = 0; idx < c.getColumnCount(); idx++) {
- Integer rid = handleProviderColumn(c, idx, entry);
+ Integer rid = handleProviderColumn(_context, c, idx, entry);
if (rid != -1) {
mboxId = rid;
}
@@ -120,13 +132,21 @@ public class AndroidSmsFetcher {
* mboxId is greater than server mboxId by 1 because types
* aren't indexed in the same mean
*/
+ entry.sent = true;
entry.mailboxId = mboxId - 1;
results.push(entry.id,
+ -1,
mbID.ordinal(),
entry.type,
entry.date,
entry.address,
+ entry.card_number,
+ entry.card_slot,
+ entry.icc_id,
+ entry.device_name,
+ entry.carrier_name,
entry.body,
+ entry.sent ? 1 : 0,
entry.read ? "true" : "false",
entry.seen ? "true" : "false");
@@ -164,7 +184,7 @@ public class AndroidSmsFetcher {
c.close();
}
- private Integer handleProviderColumn(Cursor c, int idx, SmsEntry entry) {
+ public static Integer handleProviderColumn(Context context, Cursor c, int idx, SmsEntry entry) {
String colName = c.getColumnName(idx);
// Id column is must be an integer
@@ -172,6 +192,19 @@ public class AndroidSmsFetcher {
case "_id":
entry.id = c.getInt(idx);
break;
+ case "sub_id":
+ if(Build.VERSION.SDK_INT>=22) {
+ SubscriptionManager subscriptionManager = (SubscriptionManager) context.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
+ SubscriptionInfo info = subscriptionManager.getActiveSubscriptionInfo(c.getInt(idx));
+ if(info!=null) {
+ entry.card_number = info.getNumber();
+ entry.card_slot = info.getSimSlotIndex();
+ entry.carrier_name = info.getCarrierName().toString();
+ } else
+ entry.card_number = "";
+ }
+ else entry.card_number = "";
+ break;
case "type":
entry.type = c.getInt(idx);
return c.getInt(idx);
diff --git a/src/main/java/fr/unix_experience/owncloud_sms/engine/OCHttpClient.java b/src/main/java/fr/unix_experience/owncloud_sms/engine/OCHttpClient.java
index 56050a1e878e2e14aa3698dd371e6968753427c3..c20688aea9e5cad733a2047f97dbdf1714611523 100644
--- a/src/main/java/fr/unix_experience/owncloud_sms/engine/OCHttpClient.java
+++ b/src/main/java/fr/unix_experience/owncloud_sms/engine/OCHttpClient.java
@@ -27,6 +27,7 @@ import fr.unix_experience.owncloud_sms.enums.OCSyncErrorType;
import fr.unix_experience.owncloud_sms.exceptions.OCSyncException;
import fr.unix_experience.owncloud_sms.providers.AndroidVersionProvider;
import ncsmsgo.SmsBuffer;
+import ncsmsgo.SmsDeleteResponse;
import ncsmsgo.SmsHTTPClient;
import ncsmsgo.SmsIDListResponse;
import ncsmsgo.SmsMessagesResponse;
@@ -111,4 +112,11 @@ public class OCHttpClient {
handleEarlyHTTPStatus(httpStatus);
return new Pair<>(httpStatus, smr);
}
+
+ Pair deleteMessage(String address, long date) throws OCSyncException {
+ SmsDeleteResponse spr = _smsHttpClient.doDeleteMessageCall(address, date);
+ int httpStatus = (int) _smsHttpClient.getLastHTTPStatus();
+ handleEarlyHTTPStatus(httpStatus);
+ return new Pair<>(httpStatus, spr);
+ }
}
diff --git a/src/main/java/fr/unix_experience/owncloud_sms/engine/OCSMSOwnCloudClient.java b/src/main/java/fr/unix_experience/owncloud_sms/engine/OCSMSOwnCloudClient.java
index fb68247aad87d94f26473837ade6d20f47d80368..75f1e5ee3c94e79ed66557a40efd9e58dbf3bde7 100644
--- a/src/main/java/fr/unix_experience/owncloud_sms/engine/OCSMSOwnCloudClient.java
+++ b/src/main/java/fr/unix_experience/owncloud_sms/engine/OCSMSOwnCloudClient.java
@@ -31,6 +31,7 @@ import fr.unix_experience.owncloud_sms.enums.OCSyncErrorType;
import fr.unix_experience.owncloud_sms.exceptions.OCSyncException;
import fr.unix_experience.owncloud_sms.prefs.OCSMSSharedPrefs;
import ncsmsgo.SmsBuffer;
+import ncsmsgo.SmsDeleteResponse;
import ncsmsgo.SmsIDListResponse;
import ncsmsgo.SmsMessagesResponse;
import ncsmsgo.SmsPhoneListResponse;
@@ -46,7 +47,7 @@ public class OCSMSOwnCloudClient {
_serverAPIVersion = 1;
AccountManager accountManager = AccountManager.get(context);
- String ocURI = accountManager.getUserData(account, "ocURI");
+ String ocURI = accountManager.getUserData(account, "oc_base_url");
if (ocURI == null) {
throw new IllegalStateException(context.getString(R.string.err_sync_account_unparsable));
}
@@ -54,7 +55,7 @@ public class OCSMSOwnCloudClient {
try {
URL serverURL = new URL(ocURI);
_http = new OCHttpClient(context,
- serverURL, accountManager.getUserData(account, "ocLogin"),
+ serverURL, accountManager.getUserData(account, "email_address"),
accountManager.getPassword(account));
} catch (MalformedURLException e) {
throw new IllegalStateException(context.getString(R.string.err_sync_account_unparsable));
@@ -121,7 +122,7 @@ public class OCSMSOwnCloudClient {
Log.i(OCSMSOwnCloudClient.TAG, "LastMessageDate set to: " + smsBuffer.getLastMessageDate());
}
- SmsMessagesResponse retrieveSomeMessages(Long start, Integer limit) {
+ public SmsMessagesResponse retrieveSomeMessages(Long start, Integer limit) {
// This is not allowed by server
if (limit > OCSMSOwnCloudClient.SERVER_RECOVERY_MSG_LIMIT) {
Log.e(OCSMSOwnCloudClient.TAG, "Message recovery limit exceeded");
@@ -153,4 +154,21 @@ public class OCSMSOwnCloudClient {
private static final String TAG = OCSMSOwnCloudClient.class.getSimpleName();
+ public void deleteMessage(String address, long date) {
+ address = address.replace("+", "%2B");
+ Pair response;
+ try {
+ response = _http.deleteMessage(address, date);
+ } catch (OCSyncException e) {
+ Log.e(OCSMSOwnCloudClient.TAG, "Request failed.");
+ return;
+ }
+
+ if (response.second == null) {
+ Log.e(OCSMSOwnCloudClient.TAG,
+ "Invalid response received from server, either messages or last_id field is missing.");
+ return;
+ }
+
+ }
}
diff --git a/src/main/java/fr/unix_experience/owncloud_sms/engine/SmsEntry.java b/src/main/java/fr/unix_experience/owncloud_sms/engine/SmsEntry.java
index 5319c7a9c2e16c04e6d18f4a9062ec8bf7915254..9fd6dfaebd47b5cf0fa65666bf8545c072fe852d 100644
--- a/src/main/java/fr/unix_experience/owncloud_sms/engine/SmsEntry.java
+++ b/src/main/java/fr/unix_experience/owncloud_sms/engine/SmsEntry.java
@@ -23,7 +23,14 @@ public class SmsEntry {
public int type;
public boolean read;
public boolean seen;
+ public boolean sent;
public long date;
public String address;
public String body;
+ public String card_number;
+ public int card_slot;
+ public String device_name;
+ public String carrier_name;
+ public String icc_id;
+
}
diff --git a/src/main/java/fr/unix_experience/owncloud_sms/engine/SmsSenderService.java b/src/main/java/fr/unix_experience/owncloud_sms/engine/SmsSenderService.java
new file mode 100644
index 0000000000000000000000000000000000000000..077374fd038c8604c9e4ef8adc330991b25de469
--- /dev/null
+++ b/src/main/java/fr/unix_experience/owncloud_sms/engine/SmsSenderService.java
@@ -0,0 +1,113 @@
+package fr.unix_experience.owncloud_sms.engine;
+
+import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.app.Service;
+import android.content.AbstractThreadedSyncAdapter;
+import android.content.ContentProviderClient;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SyncResult;
+import android.os.Binder;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.preference.PreferenceManager;
+import android.support.v4.app.JobIntentService;
+import android.util.Log;
+
+import fr.unix_experience.owncloud_sms.R;
+import fr.unix_experience.owncloud_sms.broadcast_receivers.SmsSenderIntentReceiver;
+
+public class SmsSenderService extends Service {
+ private static final int ALARM_ID = 1002;
+ private static final int JOB_ID = 1040;
+
+ public SmsSenderService() {
+ }
+
+
+ // Storage for an instance of the sync adapter
+ private static SmsSenderSyncAdapter _adapter = null;
+ // Object to use as a thread-safe lock
+ private static final Object sSyncAdapterLock = new Object();
+ /*
+ * Instantiate the sync adapter object.
+ */
+ @Override
+ public void onCreate() {
+ /*
+ * Create the sync adapter as a singleton.
+ * Set the sync adapter as syncable
+ * Disallow parallel syncs
+ */
+ synchronized (sSyncAdapterLock) {
+ if (_adapter == null) {
+ _adapter = new SmsSenderSyncAdapter(getApplicationContext(), true);
+ }
+ }
+ }
+ /**
+ * Return an object that allows the system to invoke
+ * the sync adapter.
+ *
+ */
+ @Override
+ public IBinder onBind(Intent intent) {
+ /*
+ * Get the object that allows external processes
+ * to call onPerformSync(). The object is created
+ * in the base class code when the SyncAdapter
+ * constructors call super()
+ */
+ return _adapter.getSyncAdapterBinder();
+ }
+
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ int re = super.onStartCommand(intent, flags, startId);
+ startSenderProcess(this);
+ return re;
+ }
+
+ public static void startSenderProcess(Context context){
+ Account[] accountList =
+ AccountManager.get(context).getAccountsByType(context.getString(R.string.account_type));
+ for(Account account:accountList){
+
+ if(!ContentResolver.getSyncAutomatically(account, context.getString(R.string.account_sender_authority))){
+ continue;
+ }
+
+ new ASyncSMSSender.SMSSenderSyncTask(context,account).execute();
+ }
+
+ // planNextLaunch(context);
+ }
+
+
+
+ public static void planNextLaunch(Context context){
+ AlarmManager alarmMgr = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
+ Intent intent = new Intent(context, SmsSenderService.class);
+ int next = Integer.valueOf(PreferenceManager.getDefaultSharedPreferences(context).getString("sync_frequency", "2"));
+ if(next == -1)
+ return;
+ PendingIntent alarmIntent = PendingIntent.getService(context, ALARM_ID, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+ if(Build.VERSION.SDK_INT>Build.VERSION_CODES.M)
+ alarmMgr.setAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + next*10*1000, alarmIntent);
+ }
+
+ private class SmsSenderSyncAdapter extends AbstractThreadedSyncAdapter {
+ public SmsSenderSyncAdapter(Context applicationContext, boolean b) {
+ super(applicationContext, b);
+ }
+
+ @Override
+ public void onPerformSync(Account account, Bundle bundle, String s, ContentProviderClient contentProviderClient, SyncResult syncResult) {
+ new ASyncSMSSender.SMSSenderSyncTask(getContext(),account).execute();
+ }
+ }
+}
diff --git a/src/main/java/fr/unix_experience/owncloud_sms/observers/SmsObserver.java b/src/main/java/fr/unix_experience/owncloud_sms/observers/SmsObserver.java
index 0b1289561e609c4679715c79d19a70a511b288a4..41f7a691c17bde4bd93707fbdd633438026211d2 100644
--- a/src/main/java/fr/unix_experience/owncloud_sms/observers/SmsObserver.java
+++ b/src/main/java/fr/unix_experience/owncloud_sms/observers/SmsObserver.java
@@ -20,6 +20,7 @@ package fr.unix_experience.owncloud_sms.observers;
import android.Manifest;
import android.accounts.Account;
import android.accounts.AccountManager;
+import android.content.ContentResolver;
import android.content.Context;
import android.database.ContentObserver;
import android.os.Handler;
@@ -47,7 +48,6 @@ public class SmsObserver extends ContentObserver implements ASyncSMSSync {
PermissionID.REQUEST_SMS)) {
return;
}
-
super.onChange(selfChange);
Log.i(SmsObserver.TAG, "onChange SmsObserver");
diff --git a/src/main/java/fr/unix_experience/owncloud_sms/providers/SmsBackupProvider.java b/src/main/java/fr/unix_experience/owncloud_sms/providers/SmsBackupProvider.java
new file mode 100644
index 0000000000000000000000000000000000000000..8f7019d4871d3dd6eb829c2437d7a2bb23b7f712
--- /dev/null
+++ b/src/main/java/fr/unix_experience/owncloud_sms/providers/SmsBackupProvider.java
@@ -0,0 +1,74 @@
+package fr.unix_experience.owncloud_sms.providers;
+
+/*
+ * Copyright (c) 2014-2015, 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 android.content.ContentProvider;
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.net.Uri;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+public class SmsBackupProvider extends ContentProvider {
+ // WARNING: mandatory
+ public SmsBackupProvider() {}
+ public SmsBackupProvider(Context ct) {
+ super();
+ _context = ct;
+ }
+
+ @Override
+ public boolean onCreate() {
+ return true;
+ }
+
+ @Nullable
+ @Override
+ public Cursor query(@NonNull Uri uri, @Nullable String[] strings, @Nullable String s, @Nullable String[] strings1, @Nullable String s1) {
+ return null;
+ }
+
+ @Override
+ public String getType(@NonNull Uri uri) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Uri insert(@NonNull Uri uri, ContentValues values) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public int delete(@NonNull Uri uri, String selection, String[] selectionArgs) {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public int update(@NonNull Uri uri, ContentValues values, String selection,
+ String[] selectionArgs) {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ private Context _context;
+ private static final String TAG = SmsBackupProvider.class.getSimpleName();
+}
diff --git a/src/main/java/fr/unix_experience/owncloud_sms/providers/SmsDataProvider.java b/src/main/java/fr/unix_experience/owncloud_sms/providers/SmsDataProvider.java
index 5ff733df3ae6b2bd0bd1921ab113dd4f2d393c0b..66d69326f5d67e582d1503c8de39ce4ef16e1a93 100644
--- a/src/main/java/fr/unix_experience/owncloud_sms/providers/SmsDataProvider.java
+++ b/src/main/java/fr/unix_experience/owncloud_sms/providers/SmsDataProvider.java
@@ -29,7 +29,7 @@ import fr.unix_experience.owncloud_sms.enums.MailboxID;
import fr.unix_experience.owncloud_sms.prefs.OCSMSSharedPrefs;
public class SmsDataProvider extends ContentProvider {
- static String[] messageFields = {
+ public static String[] messageFields = {
"read",
"date",
"address",
@@ -37,6 +37,7 @@ public class SmsDataProvider extends ContentProvider {
"body",
"_id",
"type",
+ "sub_id",
//"length(address)" // For debug purposes
};
diff --git a/src/main/java/fr/unix_experience/owncloud_sms/providers/SmsRestoreProvider.java b/src/main/java/fr/unix_experience/owncloud_sms/providers/SmsRestoreProvider.java
new file mode 100644
index 0000000000000000000000000000000000000000..3271362f2d97a3f46f9fedce89ca67aa3dfc30f4
--- /dev/null
+++ b/src/main/java/fr/unix_experience/owncloud_sms/providers/SmsRestoreProvider.java
@@ -0,0 +1,74 @@
+package fr.unix_experience.owncloud_sms.providers;
+
+/*
+ * Copyright (c) 2014-2015, 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 android.content.ContentProvider;
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.net.Uri;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+public class SmsRestoreProvider extends ContentProvider {
+ // WARNING: mandatory
+ public SmsRestoreProvider() {}
+ public SmsRestoreProvider(Context ct) {
+ super();
+ _context = ct;
+ }
+
+ @Override
+ public boolean onCreate() {
+ return true;
+ }
+
+ @Nullable
+ @Override
+ public Cursor query(@NonNull Uri uri, @Nullable String[] strings, @Nullable String s, @Nullable String[] strings1, @Nullable String s1) {
+ return null;
+ }
+
+ @Override
+ public String getType(@NonNull Uri uri) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Uri insert(@NonNull Uri uri, ContentValues values) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public int delete(@NonNull Uri uri, String selection, String[] selectionArgs) {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public int update(@NonNull Uri uri, ContentValues values, String selection,
+ String[] selectionArgs) {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ private Context _context;
+ private static final String TAG = SmsRestoreProvider.class.getSimpleName();
+}
diff --git a/src/main/java/fr/unix_experience/owncloud_sms/providers/SmsSendProvider.java b/src/main/java/fr/unix_experience/owncloud_sms/providers/SmsSendProvider.java
new file mode 100644
index 0000000000000000000000000000000000000000..81748c4e1412d9f54d148d1cf9202cc557d1a966
--- /dev/null
+++ b/src/main/java/fr/unix_experience/owncloud_sms/providers/SmsSendProvider.java
@@ -0,0 +1,74 @@
+package fr.unix_experience.owncloud_sms.providers;
+
+/*
+ * Copyright (c) 2014-2015, 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 android.content.ContentProvider;
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.net.Uri;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+public class SmsSendProvider extends ContentProvider {
+ // WARNING: mandatory
+ public SmsSendProvider() {}
+ public SmsSendProvider(Context ct) {
+ super();
+ _context = ct;
+ }
+
+ @Override
+ public boolean onCreate() {
+ return true;
+ }
+
+ @Nullable
+ @Override
+ public Cursor query(@NonNull Uri uri, @Nullable String[] strings, @Nullable String s, @Nullable String[] strings1, @Nullable String s1) {
+ return null;
+ }
+
+ @Override
+ public String getType(@NonNull Uri uri) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Uri insert(@NonNull Uri uri, ContentValues values) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public int delete(@NonNull Uri uri, String selection, String[] selectionArgs) {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public int update(@NonNull Uri uri, ContentValues values, String selection,
+ String[] selectionArgs) {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ private Context _context;
+ private static final String TAG = SmsSendProvider.class.getSimpleName();
+}
diff --git a/src/main/java/fr/unix_experience/owncloud_sms/providers/SmsSendStackProvider.java b/src/main/java/fr/unix_experience/owncloud_sms/providers/SmsSendStackProvider.java
new file mode 100644
index 0000000000000000000000000000000000000000..8bedcfb4e5c787191a19fc464c4d9019271f1cfa
--- /dev/null
+++ b/src/main/java/fr/unix_experience/owncloud_sms/providers/SmsSendStackProvider.java
@@ -0,0 +1,235 @@
+package fr.unix_experience.owncloud_sms.providers;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+import android.net.Uri;
+import android.telephony.SmsManager;
+import android.util.JsonReader;
+import android.util.Log;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import fr.unix_experience.owncloud_sms.enums.MailboxID;
+import ncsmsgo.SmsMessage;
+
+public class SmsSendStackProvider {
+ private static final String DATABASE_NAME = "sms_db";
+ private static final int DATABASE_VERSION = 4
+
+
+ ;
+ private static final String TABLE_NAME = "send_stack";
+ private static final String KEY_MESSAGE = "message";
+ /*
+ 0: not sent,
+ 1: sent,
+ 2: pending,
+ 3: sent but status not synced
+ 5: won't send
+ 5: failed to send
+
+ */
+ private static final String KEY_SENT = "sent";
+ private static final String KEY_ADDRESS = "address";
+ private static final String KEY_MAILBOX_ID = "mb_is";
+ private static final String KEY_DATE = "date";
+ private static final String KEY_BODY = "body";
+ private static final String KEY_ACCOUNT = "account";
+ public static final String CREATE_TABLE = "create table " + TABLE_NAME + "( "
+ + KEY_SENT + " INTEGER,"
+ + KEY_ACCOUNT + " text not null,"
+ + KEY_ADDRESS + " text not null,"
+ + KEY_MAILBOX_ID + " INTEGER not null,"
+ + KEY_DATE + " text not null,"
+ + KEY_BODY + " INTEGER not null,"
+ + KEY_MESSAGE + " text not null,"
+ +" PRIMARY KEY ("+KEY_ADDRESS+","+KEY_BODY+","+KEY_DATE+","+KEY_MAILBOX_ID+" ));";
+ private static SmsSendStackProvider sSmsSendStackProvider;
+ private final Context mContext;
+ private final DatabaseHelper mDatabaseHelper;
+
+ public SmsSendStackProvider(Context context){
+ mContext = context;
+ mDatabaseHelper = new DatabaseHelper(context);
+ }
+
+ public void addMessage(SmsMessage message, String accountName, int conflit) {
+ synchronized (mDatabaseHelper.lock) {
+ SQLiteDatabase sqliteDatabase = mDatabaseHelper.open();
+ ContentValues initialValues = new ContentValues();
+ initialValues.put(KEY_MESSAGE,smsMessageToJsonString(message));
+ initialValues.put(KEY_SENT,message.getSent());
+ initialValues.put(KEY_ADDRESS,message.getAddress());
+ initialValues.put(KEY_MAILBOX_ID,message.getMailbox());
+ initialValues.put(KEY_DATE,message.getDate());
+ initialValues.put(KEY_BODY,message.getMessage());
+ initialValues.put(KEY_ACCOUNT,accountName);
+ sqliteDatabase.insertWithOnConflict(TABLE_NAME, null, initialValues, conflit);
+ mDatabaseHelper.close();
+ }
+
+ }
+
+ public void addMessage(SmsMessage message, String accountName) {
+ try {
+ addMessage(message, accountName, SQLiteDatabase.CONFLICT_NONE);
+ } catch (android.database.sqlite.SQLiteConstraintException e){
+
+ }
+ }
+ public static SmsSendStackProvider getInstance(Context context){
+ if(sSmsSendStackProvider ==null)
+ sSmsSendStackProvider = new SmsSendStackProvider(context);
+ return sSmsSendStackProvider;
+ }
+
+ public boolean messageExists() {
+ List messages = new ArrayList<>();
+ synchronized (mDatabaseHelper.lock) {
+ SQLiteDatabase sqliteDatabase = mDatabaseHelper.open();
+ Cursor cursor = sqliteDatabase.query(TABLE_NAME, new String[]{KEY_MESSAGE, KEY_SENT}, KEY_SENT + "= ?", new String[]{"0"}, null, null, null);
+ if (cursor.getCount() > 0) {
+ mDatabaseHelper.close();
+ cursor.close();
+ return true;
+ }
+ mDatabaseHelper.close();
+ cursor.close();
+ }
+ return false;
+ }
+ public boolean messageExists(String address, String body, String date) {
+ synchronized (mDatabaseHelper.lock) {
+ SQLiteDatabase sqliteDatabase = mDatabaseHelper.open();
+ Cursor c = sqliteDatabase.query(TABLE_NAME, new String[]{KEY_SENT},
+ "address = ? AND body = ? AND date = ?",
+ new String[]{address, body, date}, null, null, null);
+ if (c == null) {
+ return false;
+ }
+
+ boolean exists = c.getCount() > 0;
+ c.close();
+
+ return exists;
+ }
+ }
+ public static SmsMessage smsMessageFromString(String msg) throws JSONException {
+ SmsMessage message = new SmsMessage();
+ JSONObject object = new JSONObject(msg);
+ message.setAddress(object.getString("Address"));
+ message.setId(object.getLong("Id"));
+ message.setMailbox(object.getInt("Mailbox"));
+ message.setMessage(object.getString("Message"));
+ message.setSent(object.getInt("Sent"));
+ message.setCardSlot(object.getLong("CardSlot"));
+ message.setCardNumber(object.getString("CardNumber"));
+ message.setIccId(object.getString("IccId"));
+ message.setDeviceName(object.getString("DeviceName"));
+ message.setCarrierName(object.getString("CarrierName"));
+ message.setType(object.getInt("Type"));
+ message.setDate(object.getLong("Date"));
+
+ return message;
+ }
+ public List getMessagestoSend(String accountName) {
+ List messages = new ArrayList<>();
+ synchronized (mDatabaseHelper.lock) {
+ SQLiteDatabase sqliteDatabase = mDatabaseHelper.open();
+ Cursor cursor = sqliteDatabase.query(TABLE_NAME, new String[]{KEY_MESSAGE, KEY_SENT}, KEY_SENT + "= ? AND "+KEY_ACCOUNT+" = ? ", new String[]{"0", accountName}, null, null, null);
+ if (cursor.getCount() > 0) {
+ while(cursor.moveToNext()){
+ try {
+ messages.add(smsMessageFromString(cursor.getString(cursor.getColumnIndex(KEY_MESSAGE))));
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ cursor.close();
+ mDatabaseHelper.close();
+ }
+
+ return messages;
+ }
+ //Quoting (SmsMessage.toString wasn't quoting)
+ public static String smsMessageToJsonString(SmsMessage message) {
+ StringBuilder var1 = new StringBuilder();
+ var1.append("{");
+ var1.append("Id:").append(message.getId()).append(",");
+ var1.append("Address:").append(JSONObject.quote(message.getAddress())).append(",");
+ var1.append("Mailbox:").append(message.getMailbox()).append(",");
+ var1.append("Message:").append(JSONObject.quote(message.getMessage())).append(",");
+ var1.append("Sent:").append(message.getSent()).append(",");
+ var1.append("CardNumber:").append(JSONObject.quote(message.getCardNumber())).append(",");
+ var1.append("CardSlot:").append(message.getCardSlot()).append(",");
+ var1.append("IccId:").append(JSONObject.quote(message.getIccId())).append(",");
+ var1.append("DeviceName:").append(JSONObject.quote(message.getDeviceName())).append(",");
+ var1.append("CarrierName:").append(JSONObject.quote(message.getCarrierName())).append(",");
+ var1.append("Type:").append(message.getType()).append(",");
+ var1.append("Date:").append(message.getDate());
+ return var1.append("}").toString();
+ }
+
+ public void setSent(SmsMessage message, int sent) {
+ message.setSent(sent);
+ updateMessage(message);
+ }
+
+ private void updateMessage(SmsMessage message) {
+ synchronized (mDatabaseHelper.lock) {
+ SQLiteDatabase sqliteDatabase = mDatabaseHelper.open();
+ ContentValues initialValues = new ContentValues();
+ initialValues.put(KEY_MESSAGE,smsMessageToJsonString(message));
+ initialValues.put(KEY_SENT,message.getSent());
+
+ sqliteDatabase.update(TABLE_NAME, initialValues, KEY_ADDRESS+"=? AND "+KEY_MAILBOX_ID+"= ? AND "+KEY_DATE+"= ? AND "+KEY_BODY +" = ?",
+ new String[]{message.getAddress(), message.getMailbox()+"", message.getDate()+"", message.getMessage()});
+ mDatabaseHelper.close();
+ }
+ }
+
+ private class DatabaseHelper extends SQLiteOpenHelper {
+
+ public Object lock = new Object();
+ private DatabaseHelper mDatabaseHelper;
+
+ DatabaseHelper(Context context) {
+ super(context, DATABASE_NAME, null, DATABASE_VERSION);
+ }
+
+ @Override
+ public void onCreate(SQLiteDatabase db) {
+ // This method is only called once when the database is created for the first time
+ db.execSQL(CREATE_TABLE);
+
+ }
+
+ @Override
+ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+ db.execSQL("drop table "+TABLE_NAME);
+ db.execSQL(CREATE_TABLE);
+
+
+ }
+
+ public SQLiteDatabase open(){
+ if(mDatabaseHelper == null)
+ mDatabaseHelper = new DatabaseHelper(mContext);
+ return mDatabaseHelper.getWritableDatabase();
+ }
+
+ public void close(){
+ if(mDatabaseHelper == null)
+ mDatabaseHelper.close();
+ }
+ }
+}
diff --git a/src/main/java/fr/unix_experience/owncloud_sms/sync_adapters/SmsBackupAdapter.java b/src/main/java/fr/unix_experience/owncloud_sms/sync_adapters/SmsBackupAdapter.java
new file mode 100644
index 0000000000000000000000000000000000000000..666bcd3fede0254806a932e79ebf31f8211fc2e0
--- /dev/null
+++ b/src/main/java/fr/unix_experience/owncloud_sms/sync_adapters/SmsBackupAdapter.java
@@ -0,0 +1,93 @@
+package fr.unix_experience.owncloud_sms.sync_adapters;
+
+/*
+ * Copyright (c) 2014-2015, 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 android.accounts.Account;
+import android.content.AbstractThreadedSyncAdapter;
+import android.content.ContentProviderClient;
+import android.content.Context;
+import android.content.SyncResult;
+import android.os.Bundle;
+import android.preference.PreferenceManager;
+import android.util.Log;
+
+import fr.unix_experience.owncloud_sms.R;
+import fr.unix_experience.owncloud_sms.engine.AndroidSmsFetcher;
+import fr.unix_experience.owncloud_sms.engine.ConnectivityMonitor;
+import fr.unix_experience.owncloud_sms.engine.OCSMSOwnCloudClient;
+import fr.unix_experience.owncloud_sms.enums.OCSMSNotificationType;
+import fr.unix_experience.owncloud_sms.exceptions.OCSyncException;
+import fr.unix_experience.owncloud_sms.notifications.OCSMSNotificationUI;
+import fr.unix_experience.owncloud_sms.prefs.OCSMSSharedPrefs;
+import ncsmsgo.SmsBuffer;
+
+class SmsBackupAdapter extends AbstractThreadedSyncAdapter {
+
+ SmsBackupAdapter(Context context, boolean autoInitialize) {
+ super(context, autoInitialize);
+ }
+
+ @Override
+ public void onPerformSync(Account account, Bundle extras, String authority,
+ ContentProviderClient provider, SyncResult syncResult) {
+
+ if (new OCSMSSharedPrefs(getContext()).showSyncNotifications()) {
+ OCSMSNotificationUI.notify(getContext(), getContext().getString(R.string.sync_title),
+ getContext().getString(R.string.sync_inprogress), OCSMSNotificationType.SYNC.ordinal());
+ }
+
+ try {
+ // This feature is only available for Android 4.4 and greater
+ if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.KITKAT) {
+ return;
+ }
+
+ if (!new ConnectivityMonitor(getContext()).isValid()) {
+ Log.e(TAG, "Restore connectivity problems, aborting");
+ return;
+ }
+
+ Log.i(TAG, "Starting background backup");
+ Long start = PreferenceManager.getDefaultSharedPreferences(getContext()).getLong("last_sync_backup_"+account.name,0);
+ SmsBuffer smsBuffer = new SmsBuffer();
+ new AndroidSmsFetcher(getContext()).bufferMessagesSinceDate(smsBuffer, start);
+ try {
+ OCSMSOwnCloudClient _client = new OCSMSOwnCloudClient(getContext(), account);
+ Log.i(TAG, "Server API version: " + _client.getServerAPIVersion());
+ _client.doPushRequest(smsBuffer);
+ OCSMSNotificationUI.cancel(getContext());
+ PreferenceManager.getDefaultSharedPreferences(getContext()).edit().putLong("last_sync_backup_"+account.name,smsBuffer.getLastMessageDate()).apply();
+
+ Log.i(TAG, "Finishing background backup");
+ } catch (IllegalStateException e) { // Fail to read account data
+ OCSMSNotificationUI.notify(getContext(), getContext().getString(R.string.fatal_error),
+ e.getMessage(), OCSMSNotificationType.SYNC_FAILED.ordinal());
+ } catch (OCSyncException e) {
+ Log.e(TAG, getContext().getString(e.getErrorId()));
+ OCSMSNotificationUI.notify(getContext(), getContext().getString(R.string.fatal_error),
+ e.getMessage(), OCSMSNotificationType.SYNC_FAILED.ordinal());
+ }
+
+ } catch (IllegalStateException e) {
+ OCSMSNotificationUI.notify(getContext(), getContext().getString(R.string.fatal_error),
+ e.getMessage(), OCSMSNotificationType.SYNC_FAILED.ordinal());
+ }
+ }
+
+ private static final String TAG = SmsBackupAdapter.class.getSimpleName();
+}
diff --git a/src/main/java/fr/unix_experience/owncloud_sms/sync_adapters/SmsBackupService.java b/src/main/java/fr/unix_experience/owncloud_sms/sync_adapters/SmsBackupService.java
new file mode 100644
index 0000000000000000000000000000000000000000..0f7c1672d5c40698f54af50cd798bdea80a9de8e
--- /dev/null
+++ b/src/main/java/fr/unix_experience/owncloud_sms/sync_adapters/SmsBackupService.java
@@ -0,0 +1,68 @@
+package fr.unix_experience.owncloud_sms.sync_adapters;
+
+/*
+ * Copyright (c) 2014-2015, Loic Blot
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+
+public class SmsBackupService extends Service {
+ // Storage for an instance of the sync adapter
+ private static SmsBackupAdapter _adapter = null;
+ // Object to use as a thread-safe lock
+ private static final Object sSyncAdapterLock = new Object();
+ /*
+ * Instantiate the sync adapter object.
+ */
+ @Override
+ public void onCreate() {
+ /*
+ * Create the sync adapter as a singleton.
+ * Set the sync adapter as syncable
+ * Disallow parallel syncs
+ */
+ synchronized (SmsBackupService.sSyncAdapterLock) {
+ if (SmsBackupService._adapter == null) {
+ SmsBackupService._adapter = new SmsBackupAdapter(getApplicationContext(), true);
+ }
+ }
+ }
+ /**
+ * Return an object that allows the system to invoke
+ * the sync adapter.
+ *
+ */
+ @Override
+ public IBinder onBind(Intent intent) {
+ /*
+ * Get the object that allows external processes
+ * to call onPerformSync(). The object is created
+ * in the base class code when the SyncAdapter
+ * constructors call super()
+ */
+ return SmsBackupService._adapter.getSyncAdapterBinder();
+ }
+}
diff --git a/src/main/java/fr/unix_experience/owncloud_sms/sync_adapters/SmsRestoreAdapter.java b/src/main/java/fr/unix_experience/owncloud_sms/sync_adapters/SmsRestoreAdapter.java
new file mode 100644
index 0000000000000000000000000000000000000000..75f81bc69a74d62a8f9fd81012e0d514bfeee19a
--- /dev/null
+++ b/src/main/java/fr/unix_experience/owncloud_sms/sync_adapters/SmsRestoreAdapter.java
@@ -0,0 +1,193 @@
+package fr.unix_experience.owncloud_sms.sync_adapters;
+
+/*
+ * Copyright (c) 2014-2015, 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 android.accounts.Account;
+import android.content.AbstractThreadedSyncAdapter;
+import android.content.ComponentName;
+import android.content.ContentProviderClient;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.SyncResult;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.preference.PreferenceManager;
+import android.provider.Telephony;
+import android.util.Log;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+import foundation.e.message.IRestoreService;
+import fr.unix_experience.owncloud_sms.R;
+import fr.unix_experience.owncloud_sms.engine.ConnectivityMonitor;
+import fr.unix_experience.owncloud_sms.engine.OCSMSOwnCloudClient;
+import fr.unix_experience.owncloud_sms.enums.MailboxID;
+import fr.unix_experience.owncloud_sms.enums.OCSMSNotificationType;
+import fr.unix_experience.owncloud_sms.notifications.OCSMSNotificationUI;
+import fr.unix_experience.owncloud_sms.prefs.OCSMSSharedPrefs;
+import fr.unix_experience.owncloud_sms.providers.SmsDataProvider;
+import ncsmsgo.SmsMessage;
+import ncsmsgo.SmsMessagesResponse;
+
+class SmsRestoreAdapter extends AbstractThreadedSyncAdapter {
+
+ private String mMessages;
+
+ SmsRestoreAdapter(Context context, boolean autoInitialize) {
+ super(context, autoInitialize);
+ }
+
+ @Override
+ public void onPerformSync(Account account, Bundle extras, String authority,
+ ContentProviderClient provider, SyncResult syncResult) {
+
+ if (new OCSMSSharedPrefs(getContext()).showSyncNotifications()) {
+ OCSMSNotificationUI.notify(getContext(), getContext().getString(R.string.sync_title),
+ getContext().getString(R.string.sync_inprogress), OCSMSNotificationType.SYNC.ordinal());
+ }
+
+ try {
+ // This feature is only available for Android 4.4 and greater
+ if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.KITKAT) {
+ return;
+ }
+
+ if (!new ConnectivityMonitor(getContext()).isValid()) {
+ Log.e(TAG, "Restore connectivity problems, aborting");
+ return;
+ }
+
+ Log.i(TAG, "Starting background recovery");
+ Long start = PreferenceManager.getDefaultSharedPreferences(getContext()).getLong("last_sync_restore_"+account.name,0);
+
+ OCSMSOwnCloudClient client = new OCSMSOwnCloudClient(getContext(), account);
+ SmsDataProvider smsDataProvider = new SmsDataProvider(getContext());
+ SmsMessagesResponse obj = client.retrieveSomeMessages(start, 500);
+ if (obj == null) {
+ Log.i(TAG, "Retrieved returns failure");
+ return;
+ }
+ Integer nb = 0;
+ JSONArray toRestore = new JSONArray();
+ while ((obj != null) && (obj.getLastID() != start)) {
+ Log.i(TAG, "Retrieving messages from " + Long.toString(start)
+ + " to " + Long.toString(obj.getLastID()));
+ SmsMessage message;
+ while ((message = obj.getNextMessage()) != null) {
+ int mbid = (int) message.getMailbox();
+ // Ignore invalid mailbox
+ if (mbid > MailboxID.ALL.getId()) {
+ Log.e(TAG, "Invalid mailbox found: " + mbid);
+ continue;
+ }
+
+ String address = message.getAddress();
+ String body = message.getMessage();
+ int type = (int) message.getType();
+ if (address.isEmpty() || body.isEmpty()) {
+ Log.e(TAG, "Invalid SMS message found: " + message.toString());
+ continue;
+ }
+
+ MailboxID mailbox_id = MailboxID.fromInt(mbid);
+
+ String date = Long.toString(message.getDate());
+ // Ignore already existing messages
+ if (smsDataProvider.messageExists(address, body, date, mailbox_id)) {
+ Log.i(TAG, "Message exists");
+ continue;
+ }
+ Log.i(TAG, "Adding message");
+ JSONObject messageRestore = new JSONObject();
+ messageRestore.put("address", address);
+ messageRestore.put("body", body);
+ messageRestore.put("date", date);
+ messageRestore.put("type", type);
+ messageRestore.put("mailbox", mailbox_id.getURI());
+ toRestore.put(messageRestore);
+
+ nb++;
+ }
+
+ start = obj.getLastID();
+ PreferenceManager.getDefaultSharedPreferences(getContext()).edit().putLong("last_sync_restore_"+account.name,start).apply();
+ if (!new ConnectivityMonitor(getContext()).isValid()) {
+ Log.e(TAG, "Restore connectivity problems, aborting");
+ }
+ obj = client.retrieveSomeMessages(start, 500);
+ }
+ mMessages = toRestore.toString();
+ connectRestoreService();
+
+ Log.i(TAG, "Finishing background recovery");
+ OCSMSNotificationUI.cancel(getContext());
+ } catch (IllegalStateException e) {
+ OCSMSNotificationUI.notify(getContext(), getContext().getString(R.string.fatal_error),
+ e.getMessage(), OCSMSNotificationType.SYNC_FAILED.ordinal());
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ }
+ private void connectRestoreService() {
+
+ try {
+ Intent intentService = new Intent();
+ intentService.setComponent(new ComponentName("foundation.e.message", "com.moez.QKSMS.feature.service.ESmsRestoreService"));
+
+ if (!getContext().bindService(intentService, mConnection, Context.BIND_AUTO_CREATE)) {
+ Log.d(TAG, "Binding to RestoreService returned false");
+ throw new IllegalStateException("Binding to RestoreService returned false");
+ }
+ } catch (SecurityException e) {
+ Log.e(TAG, "can't bind to RestoreService, check permission in Manifest");
+ }
+ }
+
+ /**
+ * Class for interacting with the main interface of the service.
+ */
+ private ServiceConnection mConnection = new ServiceConnection() {
+ public void onServiceConnected(ComponentName className, IBinder service) {
+ Log.i(TAG, "RestoreService: onServiceConnected");
+
+ IRestoreService mService = IRestoreService.Stub.asInterface(service);
+ try {
+ mService.restoreMessages(mMessages);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ }
+ getContext().unbindService(this);
+ }
+
+ public void onServiceDisconnected(ComponentName className) {
+
+ }
+ };
+
+ private static final String TAG = SmsRestoreAdapter.class.getSimpleName();
+}
diff --git a/src/main/java/fr/unix_experience/owncloud_sms/sync_adapters/SmsRestoreService.java b/src/main/java/fr/unix_experience/owncloud_sms/sync_adapters/SmsRestoreService.java
new file mode 100644
index 0000000000000000000000000000000000000000..c5b547e76f40d92fd9b9b0ca5d59c2412b3ec931
--- /dev/null
+++ b/src/main/java/fr/unix_experience/owncloud_sms/sync_adapters/SmsRestoreService.java
@@ -0,0 +1,68 @@
+package fr.unix_experience.owncloud_sms.sync_adapters;
+
+/*
+ * Copyright (c) 2014-2015, Loic Blot
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+
+public class SmsRestoreService extends Service {
+ // Storage for an instance of the sync adapter
+ private static SmsRestoreAdapter _adapter = null;
+ // Object to use as a thread-safe lock
+ private static final Object sSyncAdapterLock = new Object();
+ /*
+ * Instantiate the sync adapter object.
+ */
+ @Override
+ public void onCreate() {
+ /*
+ * Create the sync adapter as a singleton.
+ * Set the sync adapter as syncable
+ * Disallow parallel syncs
+ */
+ synchronized (SmsRestoreService.sSyncAdapterLock) {
+ if (SmsRestoreService._adapter == null) {
+ SmsRestoreService._adapter = new SmsRestoreAdapter(getApplicationContext(), true);
+ }
+ }
+ }
+ /**
+ * Return an object that allows the system to invoke
+ * the sync adapter.
+ *
+ */
+ @Override
+ public IBinder onBind(Intent intent) {
+ /*
+ * Get the object that allows external processes
+ * to call onPerformSync(). The object is created
+ * in the base class code when the SyncAdapter
+ * constructors call super()
+ */
+ return SmsRestoreService._adapter.getSyncAdapterBinder();
+ }
+}
diff --git a/src/main/res/values-fr/strings.xml b/src/main/res/values-fr/strings.xml
index c5dfd2db50c1530f3a74761e6e821cb8d67807c4..4cc02e83a1ed6d7edb79fa02a502ae5c126c7588 100644
--- a/src/main/res/values-fr/strings.xml
+++ b/src/main/res/values-fr/strings.xml
@@ -30,7 +30,7 @@
7
- Nextcloud SMS
+ E SMS Sync
Logo de connexion
diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml
index 507e5bbed87e50279e37b0b21e6991e3cd187a0a..ba9bc40bd1d8544570f747db00561feca12b732c 100644
--- a/src/main/res/values/strings.xml
+++ b/src/main/res/values/strings.xml
@@ -30,11 +30,14 @@
7
- Nextcloud SMS
- fr.unix_experience.owncloud_sms
- fr.unix_experience.owncloud_sms.datasync.provider
- fr.unix_experience.owncloud_sms.datasync.slowsync_provider
- fr.unix_experience.owncloud_sms
+ E SMS Sync
+ e.foundation.webdav.eelo
+ e.foundation.sms_sync.datasync.provider
+ e.foundation.sms_sender.datasync.provider
+ e.foundation.sms_backup.datasync.provider
+ e.foundation.sms_restore.datasync.provider
+ e.foundation.sms_sync.datasync.slowsync_provider
+ e.foundation.sms_sync
Login logo
@@ -44,6 +47,9 @@
SMS - Fast
+ SMS - Send messages
+ SMS - Backup messages
+ SMS - Restore messages
Fast Sync frequency
SMS - Slow and Secure
Secure Slow Sync frequency
diff --git a/src/main/res/xml/backup_adapter.xml b/src/main/res/xml/backup_adapter.xml
new file mode 100644
index 0000000000000000000000000000000000000000..e5f1a0af286bee0f3efa7f81847f565c1973504b
--- /dev/null
+++ b/src/main/res/xml/backup_adapter.xml
@@ -0,0 +1,9 @@
+
+
\ No newline at end of file
diff --git a/src/main/res/xml/restore_adapter.xml b/src/main/res/xml/restore_adapter.xml
new file mode 100644
index 0000000000000000000000000000000000000000..d71f5db625ea980f068ecd393eaa22e81b5973e1
--- /dev/null
+++ b/src/main/res/xml/restore_adapter.xml
@@ -0,0 +1,9 @@
+
+
\ No newline at end of file
diff --git a/src/main/res/xml/sender_adapter.xml b/src/main/res/xml/sender_adapter.xml
new file mode 100644
index 0000000000000000000000000000000000000000..36f3938bd087e63d5114ecccf7b48224f4a574c7
--- /dev/null
+++ b/src/main/res/xml/sender_adapter.xml
@@ -0,0 +1,9 @@
+
+
\ No newline at end of file