summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AndroidManifest.xml5
-rw-r--r--res/values/strings.xml4
-rw-r--r--src/org/fox/ttrss/MainActivity.java355
-rw-r--r--src/org/fox/ttrss/OfflineDownloadService.java157
-rw-r--r--src/org/fox/ttrss/OfflineUploadService.java256
5 files changed, 393 insertions, 384 deletions
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index cb75cb37..20282d97 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.fox.ttrss"
- android:versionCode="35"
- android:versionName="0.3.2" >
+ android:versionCode="36"
+ android:versionName="0.3.3" >
<uses-sdk android:minSdkVersion="4" />
@@ -37,6 +37,7 @@
</activity>
<service android:enabled="true" android:name=".OfflineDownloadService" />
+ <service android:enabled="true" android:name=".OfflineUploadService" />
<activity
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize"
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 49a27530..5a37df58 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -106,4 +106,8 @@
<string name="notify_downloading_articles">Downloading articles (%1$d)...</string>
<string name="notify_downloading_init">Starting download...</string>
<string name="notify_downloading_feeds">Downloading feeds...</string>
+ <string name="notify_uploading_sending_data">Sending data to server...</string>
+ <string name="notify_downloading_title">Preparing offline mode</string>
+ <string name="notify_uploading_title">Synchronizing offline data</string>
+ <string name="offline_sync_success">Finished synchronizing your offline data</string>
</resources> \ No newline at end of file
diff --git a/src/org/fox/ttrss/MainActivity.java b/src/org/fox/ttrss/MainActivity.java
index 27c46108..53075466 100644
--- a/src/org/fox/ttrss/MainActivity.java
+++ b/src/org/fox/ttrss/MainActivity.java
@@ -8,12 +8,10 @@ import java.util.TimerTask;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.BroadcastReceiver;
-import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.content.pm.PackageInfo;
import android.database.Cursor;
@@ -21,7 +19,6 @@ import android.database.sqlite.SQLiteDatabase;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Bundle;
-import android.os.IBinder;
import android.preference.PreferenceManager;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentTransaction;
@@ -36,6 +33,7 @@ import android.view.animation.AnimationUtils;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.LinearLayout;
import android.widget.TextView;
+import android.widget.Toast;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
@@ -60,6 +58,7 @@ public class MainActivity extends FragmentActivity implements OnlineServices {
private int m_isLicensed = -1;
private int m_apiLevel = 0;
private boolean m_isOffline = false;
+ private boolean m_offlineModeReady = false;
private SQLiteDatabase m_readableDb;
private SQLiteDatabase m_writableDb;
@@ -69,30 +68,23 @@ public class MainActivity extends FragmentActivity implements OnlineServices {
@Override
public void onReceive(Context content, Intent intent) {
- AlertDialog.Builder builder = new AlertDialog.Builder(
- MainActivity.this)
- .setMessage(R.string.dialog_offline_success)
- .setPositiveButton(R.string.dialog_offline_go,
- new Dialog.OnClickListener() {
- public void onClick(DialogInterface dialog,
- int which) {
- Intent refresh = new Intent(
- MainActivity.this,
- OfflineActivity.class);
- startActivity(refresh);
- finish();
- }
- })
- .setNegativeButton(R.string.dialog_cancel,
- new Dialog.OnClickListener() {
- public void onClick(DialogInterface dialog,
- int which) {
- //
- }
- });
+ if (intent.getAction().equals(OfflineDownloadService.INTENT_ACTION_SUCCESS)) {
+
+ m_offlineModeReady = true;
+
+ switchOffline();
+
+ } else if (intent.getAction().equals(OfflineUploadService.INTENT_ACTION_SUCCESS)) {
+ //Log.d(TAG, "offline upload service reports success");
+
+ if (!m_enableCats || m_activeCategory != null)
+ refreshFeeds();
+ else
+ refreshCategories();
- AlertDialog dlg = builder.create();
- dlg.show();
+ Toast toast = Toast.makeText(MainActivity.this, R.string.offline_sync_success, Toast.LENGTH_SHORT);
+ toast.show();
+ }
}
};
@@ -133,10 +125,6 @@ public class MainActivity extends FragmentActivity implements OnlineServices {
return false;
}
- public void clearPendingOfflineData() {
- getWritableDb().execSQL("UPDATE articles SET modified = 0");
- }
-
private boolean hasOfflineData() {
try {
Cursor c = getReadableDb().query("articles",
@@ -425,6 +413,7 @@ public class MainActivity extends FragmentActivity implements OnlineServices {
.getParcelable("activeCategory");
m_apiLevel = savedInstanceState.getInt("apiLevel");
m_isLicensed = savedInstanceState.getInt("isLicensed");
+ m_offlineModeReady = savedInstanceState.getBoolean("offlineModeReady");
}
m_enableCats = m_prefs.getBoolean("enable_cats", false);
@@ -446,8 +435,9 @@ public class MainActivity extends FragmentActivity implements OnlineServices {
initDatabase();
- IntentFilter filter = new IntentFilter(
- "org.fox.ttrss.intent.action.DownloadComplete");
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(OfflineDownloadService.INTENT_ACTION_SUCCESS);
+ filter.addAction(OfflineUploadService.INTENT_ACTION_SUCCESS);
filter.addCategory(Intent.CATEGORY_DEFAULT);
registerReceiver(m_broadcastReceiver, filter);
@@ -552,60 +542,65 @@ public class MainActivity extends FragmentActivity implements OnlineServices {
@SuppressWarnings("unchecked")
private void switchOffline() {
-
- AlertDialog.Builder builder = new AlertDialog.Builder(this)
- .setMessage(R.string.dialog_offline_switch_prompt)
- .setPositiveButton(R.string.dialog_offline_go,
- new Dialog.OnClickListener() {
- public void onClick(DialogInterface dialog,
- int which) {
-
- if (m_sessionId != null) {
- Log.d(TAG, "offline: starting");
-
- ServiceConnection m_serviceConnection = new ServiceConnection() {
-
- @Override
- public void onServiceDisconnected(
- ComponentName name) {
- Log.d(TAG,
- "download service disconnected");
- }
-
- @Override
- public void onServiceConnected(
- ComponentName name,
- IBinder service) {
- Log.d(TAG,
- "download service connected");
- // ((OfflineDownloadService.LocalBinder)service).getService().download();
- }
- };
-
- Intent intent = new Intent(
+ if (m_offlineModeReady) {
+
+ AlertDialog.Builder builder = new AlertDialog.Builder(
+ MainActivity.this)
+ .setMessage(R.string.dialog_offline_success)
+ .setPositiveButton(R.string.dialog_offline_go,
+ new Dialog.OnClickListener() {
+ public void onClick(DialogInterface dialog,
+ int which) {
+ Intent refresh = new Intent(
MainActivity.this,
- OfflineDownloadService.class);
- intent.putExtra("sessionId", m_sessionId);
-
- startService(intent);
-
- // bindService(intent, m_serviceConnection,
- // Context.BIND_AUTO_CREATE);
-
+ OfflineActivity.class);
+ startActivity(refresh);
+ finish();
}
- }
- })
- .setNegativeButton(R.string.dialog_cancel,
- new Dialog.OnClickListener() {
- public void onClick(DialogInterface dialog,
- int which) {
- //
- }
- });
-
- AlertDialog dlg = builder.create();
- dlg.show();
+ })
+ .setNegativeButton(R.string.dialog_cancel,
+ new Dialog.OnClickListener() {
+ public void onClick(DialogInterface dialog,
+ int which) {
+ //
+ }
+ });
+ AlertDialog dlg = builder.create();
+ dlg.show();
+
+ } else {
+
+ AlertDialog.Builder builder = new AlertDialog.Builder(this)
+ .setMessage(R.string.dialog_offline_switch_prompt)
+ .setPositiveButton(R.string.dialog_offline_go,
+ new Dialog.OnClickListener() {
+ public void onClick(DialogInterface dialog,
+ int which) {
+
+ if (m_sessionId != null) {
+ Log.d(TAG, "offline: starting");
+
+ Intent intent = new Intent(
+ MainActivity.this,
+ OfflineDownloadService.class);
+ intent.putExtra("sessionId", m_sessionId);
+
+ startService(intent);
+ }
+ }
+ })
+ .setNegativeButton(R.string.dialog_cancel,
+ new Dialog.OnClickListener() {
+ public void onClick(DialogInterface dialog,
+ int which) {
+ //
+ }
+ });
+
+ AlertDialog dlg = builder.create();
+ dlg.show();
+ }
}
private void switchOfflineSuccess() {
@@ -648,6 +643,7 @@ public class MainActivity extends FragmentActivity implements OnlineServices {
out.putParcelable("activeCategory", m_activeCategory);
out.putInt("apiLevel", m_apiLevel);
out.putInt("isLicensed", m_isLicensed);
+ out.putBoolean("offlineModeReady", m_offlineModeReady);
}
@Override
@@ -1095,133 +1091,16 @@ public class MainActivity extends FragmentActivity implements OnlineServices {
}
- private void syncOfflineRead() {
- Log.d(TAG, "syncing modified offline data... (read)");
-
- final String ids = getOfflineModifiedIds(ModifiedCriteria.READ);
-
- if (ids.length() > 0) {
- ApiRequest req = new ApiRequest(getApplicationContext()) {
- @Override
- protected void onPostExecute(JsonElement result) {
- if (result != null) {
- syncOfflineMarked();
- } else {
- setLoadingStatus(getErrorMessage(), false);
- }
- }
- };
-
- @SuppressWarnings("serial")
- HashMap<String, String> map = new HashMap<String, String>() {
- {
- put("sid", m_sessionId);
- put("op", "updateArticle");
- put("article_ids", ids);
- put("mode", "0");
- put("field", "2");
- }
- };
-
- req.execute(map);
- } else {
- syncOfflineMarked();
- }
- }
-
- private void syncOfflineMarked() {
- Log.d(TAG, "syncing modified offline data... (marked)");
-
- final String ids = getOfflineModifiedIds(ModifiedCriteria.MARKED);
-
- if (ids.length() > 0) {
- ApiRequest req = new ApiRequest(getApplicationContext()) {
- @Override
- protected void onPostExecute(JsonElement result) {
- if (result != null) {
- syncOfflinePublished();
- } else {
- setLoadingStatus(getErrorMessage(), false);
- }
- }
- };
-
- @SuppressWarnings("serial")
- HashMap<String, String> map = new HashMap<String, String>() {
- {
- put("sid", m_sessionId);
- put("op", "updateArticle");
- put("article_ids", ids);
- put("mode", "0");
- put("field", "0");
- }
- };
-
- req.execute(map);
- } else {
- syncOfflinePublished();
- }
- }
-
- private void syncOfflinePublished() {
- Log.d(TAG, "syncing modified offline data... (published)");
-
- final String ids = getOfflineModifiedIds(ModifiedCriteria.MARKED);
-
- if (ids.length() > 0) {
- ApiRequest req = new ApiRequest(getApplicationContext()) {
- @Override
- protected void onPostExecute(JsonElement result) {
- if (result != null) {
- loginSuccessInitUI();
- loginSuccess();
- clearPendingOfflineData();
- } else {
- setLoadingStatus(getErrorMessage(), false);
- }
- }
- };
-
- @SuppressWarnings("serial")
- HashMap<String, String> map = new HashMap<String, String>() {
- {
- put("sid", m_sessionId);
- put("op", "updateArticle");
- put("article_ids", ids);
- put("mode", "0");
- put("field", "1");
- }
- };
-
- req.execute(map);
- } else {
- loginSuccessInitUI();
- loginSuccess();
- clearPendingOfflineData();
- }
- }
-
private void syncOfflineData() {
- setLoadingStatus(R.string.syncing_offline_data, true);
- syncOfflineRead();
- }
-
- private void loginSuccessInitUI() {
- FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
-
- if (m_enableCats) {
- FeedCategoriesFragment frag = new FeedCategoriesFragment();
- ft.replace(R.id.cats_fragment, frag);
- } else {
- FeedsFragment frag = new FeedsFragment();
- ft.replace(R.id.feeds_fragment, frag);
- }
-
- try {
- ft.commit();
- } catch (IllegalStateException e) {
- e.printStackTrace();
- }
+ Log.d(TAG, "offlineSync: starting");
+
+ Intent intent = new Intent(
+ MainActivity.this,
+ OfflineUploadService.class);
+
+ intent.putExtra("sessionId", m_sessionId);
+
+ startService(intent);
}
private void loginSuccess() {
@@ -1248,43 +1127,6 @@ public class MainActivity extends FragmentActivity implements OnlineServices {
m_refreshTimer.schedule(m_refreshTask, 60 * 1000L, 120 * 1000L);
}
- private enum ModifiedCriteria {
- READ, MARKED, PUBLISHED
- };
-
- private String getOfflineModifiedIds(ModifiedCriteria criteria) {
-
- String criteriaStr = "";
-
- switch (criteria) {
- case READ:
- criteriaStr = "unread = 0";
- break;
- case MARKED:
- criteriaStr = "marked = 1";
- break;
- case PUBLISHED:
- criteriaStr = "published = 1";
- break;
- }
-
- Cursor c = getReadableDb().query("articles", null,
- "modified = 1 AND " + criteriaStr, null, null, null, null);
-
- String tmp = "";
-
- while (c.moveToNext()) {
- tmp += c.getInt(0) + ",";
- }
-
- tmp = tmp.replaceAll(",$", "");
-
- // Log.d(TAG, "getOfflineModifiedIds " + criteria + " = " + tmp);
-
- c.close();
-
- return tmp;
- }
private class LoginRequest extends ApiRequest {
public LoginRequest(Context context) {
@@ -1312,15 +1154,26 @@ public class MainActivity extends FragmentActivity implements OnlineServices {
Log.d(TAG, "Received API level: " + m_apiLevel);
- if (hasPendingOfflineData()) {
-
+ if (hasPendingOfflineData())
syncOfflineData();
- // loginSuccess();
+ FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
+
+ if (m_enableCats) {
+ FeedCategoriesFragment frag = new FeedCategoriesFragment();
+ ft.replace(R.id.cats_fragment, frag);
} else {
- loginSuccessInitUI();
- loginSuccess();
+ FeedsFragment frag = new FeedsFragment();
+ ft.replace(R.id.feeds_fragment, frag);
+ }
+
+ try {
+ ft.commit();
+ } catch (IllegalStateException e) {
+ e.printStackTrace();
}
+
+ loginSuccess();
}
};
diff --git a/src/org/fox/ttrss/OfflineDownloadService.java b/src/org/fox/ttrss/OfflineDownloadService.java
index 55dacced..7a44d48b 100644
--- a/src/org/fox/ttrss/OfflineDownloadService.java
+++ b/src/org/fox/ttrss/OfflineDownloadService.java
@@ -13,7 +13,6 @@ import android.content.Intent;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteStatement;
import android.os.Bundle;
-import android.os.IBinder;
import android.provider.BaseColumns;
import android.util.Log;
@@ -26,6 +25,7 @@ public class OfflineDownloadService extends IntentService {
private final String TAG = this.getClass().getSimpleName();
public static final int NOTIFY_DOWNLOADING = 1;
+ public static final String INTENT_ACTION_SUCCESS = "org.fox.ttrss.intent.action.DownloadComplete";
private static final int OFFLINE_SYNC_SEQ = 60;
private static final int OFFLINE_SYNC_MAX = 500;
@@ -42,10 +42,6 @@ public class OfflineDownloadService extends IntentService {
super("OfflineDownloadService");
}
- public OfflineDownloadService(String name) {
- super(name);
- }
-
@Override
public void onCreate() {
super.onCreate();
@@ -53,18 +49,18 @@ public class OfflineDownloadService extends IntentService {
initDatabase();
}
- public boolean getDownloadInProgress() {
+ /* public boolean getDownloadInProgress() {
return m_downloadInProgress;
- }
+ } */
private void updateNotification(String msg) {
Notification notification = new Notification(R.drawable.icon,
- getString(R.string.app_name), System.currentTimeMillis());
+ getString(R.string.notify_downloading_title), System.currentTimeMillis());
PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
new Intent(this, MainActivity.class), 0);
- notification.setLatestEventInfo(this, getString(R.string.go_offline), msg, contentIntent);
+ notification.setLatestEventInfo(this, getString(R.string.notify_downloading_title), msg, contentIntent);
m_nmgr.notify(NOTIFY_DOWNLOADING, notification);
}
@@ -73,9 +69,13 @@ public class OfflineDownloadService extends IntentService {
updateNotification(getString(msgResId));
}
- @Override
- public IBinder onBind(Intent intent) {
- return null;
+ private void downloadFailed() {
+ m_readableDb.close();
+ m_writableDb.close();
+
+ // TODO send notification to activity?
+
+ m_downloadInProgress = false;
}
public void downloadComplete() {
@@ -84,7 +84,7 @@ public class OfflineDownloadService extends IntentService {
m_nmgr.cancel(NOTIFY_DOWNLOADING);
Intent intent = new Intent();
- intent.setAction("org.fox.ttrss.intent.action.DownloadComplete");
+ intent.setAction(INTENT_ACTION_SUCCESS);
intent.addCategory(Intent.CATEGORY_DEFAULT);
sendBroadcast(intent);
@@ -98,11 +98,11 @@ public class OfflineDownloadService extends IntentService {
m_readableDb = dh.getReadableDatabase();
}
- public synchronized SQLiteDatabase getReadableDb() {
+ private synchronized SQLiteDatabase getReadableDb() {
return m_readableDb;
}
- public synchronized SQLiteDatabase getWritableDb() {
+ private synchronized SQLiteDatabase getWritableDb() {
return m_writableDb;
}
@@ -131,13 +131,7 @@ public class OfflineDownloadService extends IntentService {
}
private void downloadFeeds() {
- //findViewById(R.id.loading_container).setVisibility(View.VISIBLE);
- //findViewById(R.id.main).setVisibility(View.INVISIBLE);
-
- //setLoadingStatus(R.string.offline_downloading, true);
-
- // Download feeds
-
+
updateNotification(R.string.notify_downloading_feeds);
getWritableDb().execSQL("DELETE FROM feeds;");
@@ -176,14 +170,12 @@ public class OfflineDownloadService extends IntentService {
} catch (Exception e) {
e.printStackTrace();
updateNotification(R.string.offline_switch_error);
- m_downloadInProgress = false;
- //setLoadingStatus(R.string.offline_switch_error, false);
+ downloadFailed();
}
} else {
updateNotification(getErrorMessage());
- m_downloadInProgress = false;
- // TODO error, could not download feeds, properly report API error (toast)
+ downloadFailed();
}
}
@@ -201,106 +193,6 @@ public class OfflineDownloadService extends IntentService {
req.execute(map);
}
-
- /* @SuppressWarnings("unchecked")
- private void switchOffline() {
-
- AlertDialog.Builder builder = new AlertDialog.Builder(this).
- setMessage(R.string.dialog_offline_switch_prompt).
- setPositiveButton(R.string.dialog_offline_go, new Dialog.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
-
- Log.d(TAG, "offline: starting");
-
- if (m_sessionId != null) {
-
- //findViewById(R.id.loading_container).setVisibility(View.VISIBLE);
- //findViewById(R.id.main).setVisibility(View.INVISIBLE);
-
- //setLoadingStatus(R.string.offline_downloading, true);
-
- // Download feeds
-
- getWritableDb().execSQL("DELETE FROM feeds;");
-
- ApiRequest req = new ApiRequest(getApplicationContext()) {
- @Override
- protected void onPostExecute(JsonElement content) {
- if (content != null) {
-
- try {
- Type listType = new TypeToken<List<Feed>>() {}.getType();
- List<Feed> feeds = new Gson().fromJson(content, listType);
-
- SQLiteStatement stmtInsert = getWritableDb().compileStatement("INSERT INTO feeds " +
- "("+BaseColumns._ID+", title, feed_url, has_icon, cat_id) " +
- "VALUES (?, ?, ?, ?, ?);");
-
- for (Feed feed : feeds) {
- stmtInsert.bindLong(1, feed.id);
- stmtInsert.bindString(2, feed.title);
- stmtInsert.bindString(3, feed.feed_url);
- stmtInsert.bindLong(4, feed.has_icon ? 1 : 0);
- stmtInsert.bindLong(5, feed.cat_id);
-
- stmtInsert.execute();
- }
-
- stmtInsert.close();
-
- Log.d(TAG, "offline: done downloading feeds");
-
- m_articleOffset = 0;
-
- getWritableDb().execSQL("DELETE FROM articles;");
-
- downloadArticles();
- } catch (Exception e) {
- e.printStackTrace();
- //setLoadingStatus(R.string.offline_switch_error, false);
- }
-
- } else {
- //setLoadingStatus(getErrorMessage(), false);
- // TODO error, could not download feeds, properly report API error (toast)
- }
- }
- };
-
- HashMap<String,String> map = new HashMap<String,String>() {
- {
- put("op", "getFeeds");
- put("sid", m_sessionId);
- put("cat_id", "-3");
- put("unread_only", "true");
- }
- };
-
- req.execute(map);
- } else {
- downloadComplete();
- }
- }
- }).
- setNegativeButton(R.string.dialog_cancel, new Dialog.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- //
- }
- });
-
- AlertDialog dlg = builder.create();
- dlg.show();
-
- } */
-
- public void download() {
- if (!m_downloadInProgress) {
- updateNotification(R.string.notify_downloading_init);
- m_downloadInProgress = true;
-
- downloadFeeds();
- }
- }
@Override
public void onDestroy() {
@@ -377,23 +269,26 @@ public class OfflineDownloadService extends IntentService {
updateNotification(R.string.offline_switch_error);
Log.d(TAG, "offline: failed: exception when loading articles");
e.printStackTrace();
- m_downloadInProgress = false;
+ downloadFailed();
}
} else {
Log.d(TAG, "offline: failed: " + getErrorMessage());
- m_downloadInProgress = false;
updateNotification(getErrorMessage());
+ downloadFailed();
}
}
}
@Override
protected void onHandleIntent(Intent intent) {
- Bundle extras = intent.getExtras();
+ m_sessionId = intent.getStringExtra("sessionId");
- m_sessionId = extras.getString("sessionId");
+ if (!m_downloadInProgress) {
+ updateNotification(R.string.notify_downloading_init);
+ m_downloadInProgress = true;
- download();
+ downloadFeeds();
+ }
}
}
diff --git a/src/org/fox/ttrss/OfflineUploadService.java b/src/org/fox/ttrss/OfflineUploadService.java
new file mode 100644
index 00000000..90e0543b
--- /dev/null
+++ b/src/org/fox/ttrss/OfflineUploadService.java
@@ -0,0 +1,256 @@
+package org.fox.ttrss;
+
+import java.util.HashMap;
+
+import com.google.gson.JsonElement;
+
+import android.app.IntentService;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.Intent;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.util.Log;
+
+public class OfflineUploadService extends IntentService {
+ private final String TAG = this.getClass().getSimpleName();
+
+ public static final int NOTIFY_UPLOADING = 2;
+ public static final String INTENT_ACTION_SUCCESS = "org.fox.ttrss.intent.action.UploadComplete";
+
+ private SQLiteDatabase m_writableDb;
+ private SQLiteDatabase m_readableDb;
+ private String m_sessionId;
+ private NotificationManager m_nmgr;
+ private boolean m_uploadInProgress = false;
+
+ public OfflineUploadService() {
+ super("OfflineUploadService");
+ }
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ m_nmgr = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
+ initDatabase();
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+
+ m_nmgr.cancel(NOTIFY_UPLOADING);
+ }
+
+ private void updateNotification(String msg) {
+ Notification notification = new Notification(R.drawable.icon,
+ getString(R.string.notify_uploading_title), System.currentTimeMillis());
+
+ PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
+ new Intent(this, MainActivity.class), 0);
+
+ notification.setLatestEventInfo(this, getString(R.string.notify_uploading_title), msg, contentIntent);
+
+ m_nmgr.notify(NOTIFY_UPLOADING, notification);
+ }
+
+ private void updateNotification(int msgResId) {
+ updateNotification(getString(msgResId));
+ }
+
+ private void initDatabase() {
+ DatabaseHelper dh = new DatabaseHelper(getApplicationContext());
+ m_writableDb = dh.getWritableDatabase();
+ m_readableDb = dh.getReadableDatabase();
+ }
+
+ private synchronized SQLiteDatabase getReadableDb() {
+ return m_readableDb;
+ }
+
+ private synchronized SQLiteDatabase getWritableDb() {
+ return m_writableDb;
+ }
+
+ private void uploadRead() {
+ Log.d(TAG, "syncing modified offline data... (read)");
+
+ final String ids = getModifiedIds(ModifiedCriteria.READ);
+
+ if (ids.length() > 0) {
+ ApiRequest req = new ApiRequest(getApplicationContext()) {
+ @Override
+ protected void onPostExecute(JsonElement result) {
+ if (result != null) {
+ uploadMarked();
+ } else {
+ updateNotification(getErrorMessage());
+ uploadFailed();
+ }
+ }
+ };
+
+ @SuppressWarnings("serial")
+ HashMap<String, String> map = new HashMap<String, String>() {
+ {
+ put("sid", m_sessionId);
+ put("op", "updateArticle");
+ put("article_ids", ids);
+ put("mode", "0");
+ put("field", "2");
+ }
+ };
+
+ req.execute(map);
+ } else {
+ uploadMarked();
+ }
+ }
+
+ private enum ModifiedCriteria {
+ READ, MARKED, PUBLISHED
+ };
+
+ private String getModifiedIds(ModifiedCriteria criteria) {
+
+ String criteriaStr = "";
+
+ switch (criteria) {
+ case READ:
+ criteriaStr = "unread = 0";
+ break;
+ case MARKED:
+ criteriaStr = "marked = 1";
+ break;
+ case PUBLISHED:
+ criteriaStr = "published = 1";
+ break;
+ }
+
+ Cursor c = getReadableDb().query("articles", null,
+ "modified = 1 AND " + criteriaStr, null, null, null, null);
+
+ String tmp = "";
+
+ while (c.moveToNext()) {
+ tmp += c.getInt(0) + ",";
+ }
+
+ tmp = tmp.replaceAll(",$", "");
+
+ c.close();
+
+ return tmp;
+ }
+
+ private void uploadMarked() {
+ Log.d(TAG, "syncing modified offline data... (marked)");
+
+ final String ids = getModifiedIds(ModifiedCriteria.MARKED);
+
+ if (ids.length() > 0) {
+ ApiRequest req = new ApiRequest(getApplicationContext()) {
+ @Override
+ protected void onPostExecute(JsonElement result) {
+ if (result != null) {
+ uploadPublished();
+ } else {
+ updateNotification(getErrorMessage());
+ uploadFailed();
+ }
+ }
+ };
+
+ @SuppressWarnings("serial")
+ HashMap<String, String> map = new HashMap<String, String>() {
+ {
+ put("sid", m_sessionId);
+ put("op", "updateArticle");
+ put("article_ids", ids);
+ put("mode", "0");
+ put("field", "0");
+ }
+ };
+
+ req.execute(map);
+ } else {
+ uploadPublished();
+ }
+ }
+
+ private void uploadFailed() {
+ m_readableDb.close();
+ m_writableDb.close();
+
+ // TODO send notification to activity?
+
+ m_uploadInProgress = false;
+ }
+
+ private void uploadSuccess() {
+ getWritableDb().execSQL("UPDATE articles SET modified = 0");
+
+ Intent intent = new Intent();
+ intent.setAction(INTENT_ACTION_SUCCESS);
+ intent.addCategory(Intent.CATEGORY_DEFAULT);
+ sendBroadcast(intent);
+
+ m_readableDb.close();
+ m_writableDb.close();
+
+ m_uploadInProgress = false;
+
+ m_nmgr.cancel(NOTIFY_UPLOADING);
+ }
+
+ private void uploadPublished() {
+ Log.d(TAG, "syncing modified offline data... (published)");
+
+ final String ids = getModifiedIds(ModifiedCriteria.MARKED);
+
+ if (ids.length() > 0) {
+ ApiRequest req = new ApiRequest(getApplicationContext()) {
+ @Override
+ protected void onPostExecute(JsonElement result) {
+ if (result != null) {
+ uploadSuccess();
+ } else {
+ updateNotification(getErrorMessage());
+ uploadFailed();
+ }
+ }
+ };
+
+ @SuppressWarnings("serial")
+ HashMap<String, String> map = new HashMap<String, String>() {
+ {
+ put("sid", m_sessionId);
+ put("op", "updateArticle");
+ put("article_ids", ids);
+ put("mode", "0");
+ put("field", "1");
+ }
+ };
+
+ req.execute(map);
+ } else {
+ uploadSuccess();
+ }
+ }
+
+
+ @Override
+ protected void onHandleIntent(Intent intent) {
+ m_sessionId = intent.getStringExtra("sessionId");
+
+ if (!m_uploadInProgress) {
+ m_uploadInProgress = true;
+
+ updateNotification(R.string.notify_uploading_sending_data);
+
+ uploadRead();
+ }
+ }
+
+}