move offline data synchronization to an intentservice, bump version
This commit is contained in:
parent
24f0b1617a
commit
14461fa146
@ -1,8 +1,8 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
package="org.fox.ttrss"
|
package="org.fox.ttrss"
|
||||||
android:versionCode="35"
|
android:versionCode="36"
|
||||||
android:versionName="0.3.2" >
|
android:versionName="0.3.3" >
|
||||||
|
|
||||||
<uses-sdk android:minSdkVersion="4" />
|
<uses-sdk android:minSdkVersion="4" />
|
||||||
|
|
||||||
@ -37,6 +37,7 @@
|
|||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<service android:enabled="true" android:name=".OfflineDownloadService" />
|
<service android:enabled="true" android:name=".OfflineDownloadService" />
|
||||||
|
<service android:enabled="true" android:name=".OfflineUploadService" />
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize"
|
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize"
|
||||||
|
@ -106,4 +106,8 @@
|
|||||||
<string name="notify_downloading_articles">Downloading articles (%1$d)...</string>
|
<string name="notify_downloading_articles">Downloading articles (%1$d)...</string>
|
||||||
<string name="notify_downloading_init">Starting download...</string>
|
<string name="notify_downloading_init">Starting download...</string>
|
||||||
<string name="notify_downloading_feeds">Downloading feeds...</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>
|
</resources>
|
@ -8,12 +8,10 @@ import java.util.TimerTask;
|
|||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
import android.app.Dialog;
|
import android.app.Dialog;
|
||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
import android.content.ComponentName;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.IntentFilter;
|
import android.content.IntentFilter;
|
||||||
import android.content.ServiceConnection;
|
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.content.pm.PackageInfo;
|
import android.content.pm.PackageInfo;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
@ -21,7 +19,6 @@ import android.database.sqlite.SQLiteDatabase;
|
|||||||
import android.net.ConnectivityManager;
|
import android.net.ConnectivityManager;
|
||||||
import android.net.NetworkInfo;
|
import android.net.NetworkInfo;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.IBinder;
|
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
import android.support.v4.app.FragmentActivity;
|
import android.support.v4.app.FragmentActivity;
|
||||||
import android.support.v4.app.FragmentTransaction;
|
import android.support.v4.app.FragmentTransaction;
|
||||||
@ -36,6 +33,7 @@ import android.view.animation.AnimationUtils;
|
|||||||
import android.widget.AdapterView.AdapterContextMenuInfo;
|
import android.widget.AdapterView.AdapterContextMenuInfo;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
import com.google.gson.JsonElement;
|
import com.google.gson.JsonElement;
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
@ -60,6 +58,7 @@ public class MainActivity extends FragmentActivity implements OnlineServices {
|
|||||||
private int m_isLicensed = -1;
|
private int m_isLicensed = -1;
|
||||||
private int m_apiLevel = 0;
|
private int m_apiLevel = 0;
|
||||||
private boolean m_isOffline = false;
|
private boolean m_isOffline = false;
|
||||||
|
private boolean m_offlineModeReady = false;
|
||||||
|
|
||||||
private SQLiteDatabase m_readableDb;
|
private SQLiteDatabase m_readableDb;
|
||||||
private SQLiteDatabase m_writableDb;
|
private SQLiteDatabase m_writableDb;
|
||||||
@ -69,30 +68,23 @@ public class MainActivity extends FragmentActivity implements OnlineServices {
|
|||||||
@Override
|
@Override
|
||||||
public void onReceive(Context content, Intent intent) {
|
public void onReceive(Context content, Intent intent) {
|
||||||
|
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(
|
if (intent.getAction().equals(OfflineDownloadService.INTENT_ACTION_SUCCESS)) {
|
||||||
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) {
|
|
||||||
//
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
AlertDialog dlg = builder.create();
|
m_offlineModeReady = true;
|
||||||
dlg.show();
|
|
||||||
|
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();
|
||||||
|
|
||||||
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clearPendingOfflineData() {
|
|
||||||
getWritableDb().execSQL("UPDATE articles SET modified = 0");
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean hasOfflineData() {
|
private boolean hasOfflineData() {
|
||||||
try {
|
try {
|
||||||
Cursor c = getReadableDb().query("articles",
|
Cursor c = getReadableDb().query("articles",
|
||||||
@ -425,6 +413,7 @@ public class MainActivity extends FragmentActivity implements OnlineServices {
|
|||||||
.getParcelable("activeCategory");
|
.getParcelable("activeCategory");
|
||||||
m_apiLevel = savedInstanceState.getInt("apiLevel");
|
m_apiLevel = savedInstanceState.getInt("apiLevel");
|
||||||
m_isLicensed = savedInstanceState.getInt("isLicensed");
|
m_isLicensed = savedInstanceState.getInt("isLicensed");
|
||||||
|
m_offlineModeReady = savedInstanceState.getBoolean("offlineModeReady");
|
||||||
}
|
}
|
||||||
|
|
||||||
m_enableCats = m_prefs.getBoolean("enable_cats", false);
|
m_enableCats = m_prefs.getBoolean("enable_cats", false);
|
||||||
@ -446,8 +435,9 @@ public class MainActivity extends FragmentActivity implements OnlineServices {
|
|||||||
|
|
||||||
initDatabase();
|
initDatabase();
|
||||||
|
|
||||||
IntentFilter filter = new IntentFilter(
|
IntentFilter filter = new IntentFilter();
|
||||||
"org.fox.ttrss.intent.action.DownloadComplete");
|
filter.addAction(OfflineDownloadService.INTENT_ACTION_SUCCESS);
|
||||||
|
filter.addAction(OfflineUploadService.INTENT_ACTION_SUCCESS);
|
||||||
filter.addCategory(Intent.CATEGORY_DEFAULT);
|
filter.addCategory(Intent.CATEGORY_DEFAULT);
|
||||||
|
|
||||||
registerReceiver(m_broadcastReceiver, filter);
|
registerReceiver(m_broadcastReceiver, filter);
|
||||||
@ -552,60 +542,65 @@ public class MainActivity extends FragmentActivity implements OnlineServices {
|
|||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private void switchOffline() {
|
private void switchOffline() {
|
||||||
|
if (m_offlineModeReady) {
|
||||||
|
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(this)
|
AlertDialog.Builder builder = new AlertDialog.Builder(
|
||||||
.setMessage(R.string.dialog_offline_switch_prompt)
|
MainActivity.this)
|
||||||
.setPositiveButton(R.string.dialog_offline_go,
|
.setMessage(R.string.dialog_offline_success)
|
||||||
new Dialog.OnClickListener() {
|
.setPositiveButton(R.string.dialog_offline_go,
|
||||||
public void onClick(DialogInterface dialog,
|
new Dialog.OnClickListener() {
|
||||||
int which) {
|
public void onClick(DialogInterface dialog,
|
||||||
|
int which) {
|
||||||
if (m_sessionId != null) {
|
Intent refresh = new Intent(
|
||||||
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(
|
|
||||||
MainActivity.this,
|
MainActivity.this,
|
||||||
OfflineDownloadService.class);
|
OfflineActivity.class);
|
||||||
intent.putExtra("sessionId", m_sessionId);
|
startActivity(refresh);
|
||||||
|
finish();
|
||||||
startService(intent);
|
|
||||||
|
|
||||||
// bindService(intent, m_serviceConnection,
|
|
||||||
// Context.BIND_AUTO_CREATE);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
})
|
.setNegativeButton(R.string.dialog_cancel,
|
||||||
.setNegativeButton(R.string.dialog_cancel,
|
new Dialog.OnClickListener() {
|
||||||
new Dialog.OnClickListener() {
|
public void onClick(DialogInterface dialog,
|
||||||
public void onClick(DialogInterface dialog,
|
int which) {
|
||||||
int which) {
|
//
|
||||||
//
|
}
|
||||||
}
|
});
|
||||||
});
|
|
||||||
|
|
||||||
AlertDialog dlg = builder.create();
|
AlertDialog dlg = builder.create();
|
||||||
dlg.show();
|
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() {
|
private void switchOfflineSuccess() {
|
||||||
@ -648,6 +643,7 @@ public class MainActivity extends FragmentActivity implements OnlineServices {
|
|||||||
out.putParcelable("activeCategory", m_activeCategory);
|
out.putParcelable("activeCategory", m_activeCategory);
|
||||||
out.putInt("apiLevel", m_apiLevel);
|
out.putInt("apiLevel", m_apiLevel);
|
||||||
out.putInt("isLicensed", m_isLicensed);
|
out.putInt("isLicensed", m_isLicensed);
|
||||||
|
out.putBoolean("offlineModeReady", m_offlineModeReady);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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() {
|
private void syncOfflineData() {
|
||||||
setLoadingStatus(R.string.syncing_offline_data, true);
|
Log.d(TAG, "offlineSync: starting");
|
||||||
syncOfflineRead();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void loginSuccessInitUI() {
|
Intent intent = new Intent(
|
||||||
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
|
MainActivity.this,
|
||||||
|
OfflineUploadService.class);
|
||||||
|
|
||||||
if (m_enableCats) {
|
intent.putExtra("sessionId", m_sessionId);
|
||||||
FeedCategoriesFragment frag = new FeedCategoriesFragment();
|
|
||||||
ft.replace(R.id.cats_fragment, frag);
|
|
||||||
} else {
|
|
||||||
FeedsFragment frag = new FeedsFragment();
|
|
||||||
ft.replace(R.id.feeds_fragment, frag);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
startService(intent);
|
||||||
ft.commit();
|
|
||||||
} catch (IllegalStateException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loginSuccess() {
|
private void loginSuccess() {
|
||||||
@ -1248,43 +1127,6 @@ public class MainActivity extends FragmentActivity implements OnlineServices {
|
|||||||
m_refreshTimer.schedule(m_refreshTask, 60 * 1000L, 120 * 1000L);
|
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 {
|
private class LoginRequest extends ApiRequest {
|
||||||
public LoginRequest(Context context) {
|
public LoginRequest(Context context) {
|
||||||
@ -1312,16 +1154,27 @@ public class MainActivity extends FragmentActivity implements OnlineServices {
|
|||||||
|
|
||||||
Log.d(TAG, "Received API level: " + m_apiLevel);
|
Log.d(TAG, "Received API level: " + m_apiLevel);
|
||||||
|
|
||||||
if (hasPendingOfflineData()) {
|
if (hasPendingOfflineData())
|
||||||
|
|
||||||
syncOfflineData();
|
syncOfflineData();
|
||||||
|
|
||||||
// loginSuccess();
|
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
|
||||||
|
|
||||||
|
if (m_enableCats) {
|
||||||
|
FeedCategoriesFragment frag = new FeedCategoriesFragment();
|
||||||
|
ft.replace(R.id.cats_fragment, frag);
|
||||||
} else {
|
} else {
|
||||||
loginSuccessInitUI();
|
FeedsFragment frag = new FeedsFragment();
|
||||||
loginSuccess();
|
ft.replace(R.id.feeds_fragment, frag);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
ft.commit();
|
||||||
|
} catch (IllegalStateException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
loginSuccess();
|
||||||
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -13,7 +13,6 @@ import android.content.Intent;
|
|||||||
import android.database.sqlite.SQLiteDatabase;
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
import android.database.sqlite.SQLiteStatement;
|
import android.database.sqlite.SQLiteStatement;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.IBinder;
|
|
||||||
import android.provider.BaseColumns;
|
import android.provider.BaseColumns;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
@ -26,6 +25,7 @@ public class OfflineDownloadService extends IntentService {
|
|||||||
private final String TAG = this.getClass().getSimpleName();
|
private final String TAG = this.getClass().getSimpleName();
|
||||||
|
|
||||||
public static final int NOTIFY_DOWNLOADING = 1;
|
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_SEQ = 60;
|
||||||
private static final int OFFLINE_SYNC_MAX = 500;
|
private static final int OFFLINE_SYNC_MAX = 500;
|
||||||
@ -42,10 +42,6 @@ public class OfflineDownloadService extends IntentService {
|
|||||||
super("OfflineDownloadService");
|
super("OfflineDownloadService");
|
||||||
}
|
}
|
||||||
|
|
||||||
public OfflineDownloadService(String name) {
|
|
||||||
super(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate() {
|
public void onCreate() {
|
||||||
super.onCreate();
|
super.onCreate();
|
||||||
@ -53,18 +49,18 @@ public class OfflineDownloadService extends IntentService {
|
|||||||
initDatabase();
|
initDatabase();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean getDownloadInProgress() {
|
/* public boolean getDownloadInProgress() {
|
||||||
return m_downloadInProgress;
|
return m_downloadInProgress;
|
||||||
}
|
} */
|
||||||
|
|
||||||
private void updateNotification(String msg) {
|
private void updateNotification(String msg) {
|
||||||
Notification notification = new Notification(R.drawable.icon,
|
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,
|
PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
|
||||||
new Intent(this, MainActivity.class), 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);
|
m_nmgr.notify(NOTIFY_DOWNLOADING, notification);
|
||||||
}
|
}
|
||||||
@ -73,9 +69,13 @@ public class OfflineDownloadService extends IntentService {
|
|||||||
updateNotification(getString(msgResId));
|
updateNotification(getString(msgResId));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private void downloadFailed() {
|
||||||
public IBinder onBind(Intent intent) {
|
m_readableDb.close();
|
||||||
return null;
|
m_writableDb.close();
|
||||||
|
|
||||||
|
// TODO send notification to activity?
|
||||||
|
|
||||||
|
m_downloadInProgress = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void downloadComplete() {
|
public void downloadComplete() {
|
||||||
@ -84,7 +84,7 @@ public class OfflineDownloadService extends IntentService {
|
|||||||
m_nmgr.cancel(NOTIFY_DOWNLOADING);
|
m_nmgr.cancel(NOTIFY_DOWNLOADING);
|
||||||
|
|
||||||
Intent intent = new Intent();
|
Intent intent = new Intent();
|
||||||
intent.setAction("org.fox.ttrss.intent.action.DownloadComplete");
|
intent.setAction(INTENT_ACTION_SUCCESS);
|
||||||
intent.addCategory(Intent.CATEGORY_DEFAULT);
|
intent.addCategory(Intent.CATEGORY_DEFAULT);
|
||||||
sendBroadcast(intent);
|
sendBroadcast(intent);
|
||||||
|
|
||||||
@ -98,11 +98,11 @@ public class OfflineDownloadService extends IntentService {
|
|||||||
m_readableDb = dh.getReadableDatabase();
|
m_readableDb = dh.getReadableDatabase();
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized SQLiteDatabase getReadableDb() {
|
private synchronized SQLiteDatabase getReadableDb() {
|
||||||
return m_readableDb;
|
return m_readableDb;
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized SQLiteDatabase getWritableDb() {
|
private synchronized SQLiteDatabase getWritableDb() {
|
||||||
return m_writableDb;
|
return m_writableDb;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,12 +131,6 @@ public class OfflineDownloadService extends IntentService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void downloadFeeds() {
|
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);
|
updateNotification(R.string.notify_downloading_feeds);
|
||||||
|
|
||||||
@ -176,14 +170,12 @@ public class OfflineDownloadService extends IntentService {
|
|||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
updateNotification(R.string.offline_switch_error);
|
updateNotification(R.string.offline_switch_error);
|
||||||
m_downloadInProgress = false;
|
downloadFailed();
|
||||||
//setLoadingStatus(R.string.offline_switch_error, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
updateNotification(getErrorMessage());
|
updateNotification(getErrorMessage());
|
||||||
m_downloadInProgress = false;
|
downloadFailed();
|
||||||
// TODO error, could not download feeds, properly report API error (toast)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -202,106 +194,6 @@ public class OfflineDownloadService extends IntentService {
|
|||||||
req.execute(map);
|
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
|
@Override
|
||||||
public void onDestroy() {
|
public void onDestroy() {
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
@ -377,23 +269,26 @@ public class OfflineDownloadService extends IntentService {
|
|||||||
updateNotification(R.string.offline_switch_error);
|
updateNotification(R.string.offline_switch_error);
|
||||||
Log.d(TAG, "offline: failed: exception when loading articles");
|
Log.d(TAG, "offline: failed: exception when loading articles");
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
m_downloadInProgress = false;
|
downloadFailed();
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
Log.d(TAG, "offline: failed: " + getErrorMessage());
|
Log.d(TAG, "offline: failed: " + getErrorMessage());
|
||||||
m_downloadInProgress = false;
|
|
||||||
updateNotification(getErrorMessage());
|
updateNotification(getErrorMessage());
|
||||||
|
downloadFailed();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onHandleIntent(Intent intent) {
|
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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
256
src/org/fox/ttrss/OfflineUploadService.java
Normal file
256
src/org/fox/ttrss/OfflineUploadService.java
Normal file
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user