Skip to content
This repository was archived by the owner on Mar 26, 2019. It is now read-only.

Commit c6dbe31

Browse files
author
Bademus
committed
added file fetching
1 parent a8ddeec commit c6dbe31

File tree

7 files changed

+132
-31
lines changed

7 files changed

+132
-31
lines changed

feedly-andrss/src/main/AndroidManifest.xml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,13 @@
1111
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
1212
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
1313
<uses-permission android:name="android.permission.BATTERY_STATS"/>
14+
<uses-permission android:name="android.permission.DOWNLOAD_WITHOUT_NOTIFICATION"/>
15+
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
1416

1517
<application android:icon="@drawable/ic_launcher"
1618
android:label="@string/app_name"
1719
android:theme="@style/AppTheme"
18-
android:allowBackup="true"
19-
android:debuggable="true">
20+
android:allowBackup="true">
2021

2122
<activity android:name="org.github.bademux.feedly.andrss.MainActivity"
2223
android:label="@string/app_name">
@@ -37,6 +38,7 @@
3738
<action android:name="android.intent.action.ACTION_POWER_CONNECTED"/>
3839
<action android:name="android.intent.action.ACTION_POWER_DISCONNECTED"/>
3940
<action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
41+
<action android:name="android.intent.action.DOWNLOAD_COMPLETE"/>
4042
</intent-filter>
4143
</receiver>
4244

feedly-andrss/src/main/java/org/github/bademux/feedly/andrss/helpers/FeedlyContentAdapter.java

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
import android.net.Uri;
4343
import android.text.Html;
4444
import android.view.View;
45+
import android.widget.ImageView;
4546
import android.widget.SimpleCursorAdapter;
4647
import android.widget.TextView;
4748

@@ -53,6 +54,7 @@
5354

5455
import static org.github.bademux.feedly.api.provider.FeedlyContract.Entries;
5556
import static org.github.bademux.feedly.api.provider.FeedlyContract.EntriesByCategory;
57+
import static org.github.bademux.feedly.api.provider.FeedlyContract.Files;
5658
import static org.github.bademux.feedly.api.util.db.BackgroundQueryHandler.AsyncQueryListener;
5759

5860
public class FeedlyContentAdapter extends SimpleCursorAdapter implements AsyncQueryListener {
@@ -87,13 +89,17 @@ public ViewBinder createBinder() {
8789
public boolean setViewValue(final View view, final Cursor cursor, final int columnIndex) {
8890
switch (view.getId()) {
8991
case R.id.content_list_visual:
90-
// ImageView view = (ImageView) findViewById(R.id.imageView1);
91-
// String uriString = c.getString(c.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI));
92-
// view.setImageURI(Uri.parse(uriString));
92+
String uriString = cursor.getString(columnIndex);
93+
if (uriString != null) {
94+
Uri uri = Files.CONTENT_URI.buildUpon().appendPath(uriString).build();
95+
((ImageView) view).setImageURI(uri);
96+
}
9397
return true;
9498
case R.id.content_list_summary:
9599
String text = cursor.getString(columnIndex);
96-
if (text != null) { ((TextView) view).setText(Html.fromHtml(text) + "..."); }
100+
if (text != null) {
101+
((TextView) view).setText(Html.fromHtml(text) + "...");
102+
}
97103
return true;
98104
case R.id.content_list_meta_crawled:
99105
Long timestamp = cursor.getLong(columnIndex);

feedly-andrss/src/main/java/org/github/bademux/feedly/provider/FeedlyCacheProvider.java

Lines changed: 91 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,13 @@
3030
import android.database.sqlite.SQLiteDatabase;
3131
import android.database.sqlite.SQLiteOpenHelper;
3232
import android.net.Uri;
33+
import android.os.ParcelFileDescriptor;
3334
import android.util.Log;
3435

3536
import org.github.bademux.feedly.api.util.db.FeedlyDbUtils;
3637

38+
import java.io.File;
39+
import java.io.FileNotFoundException;
3740
import java.lang.ref.WeakReference;
3841
import java.util.ArrayList;
3942
import java.util.HashSet;
@@ -71,6 +74,8 @@ public class FeedlyCacheProvider extends ContentProvider {
7174
URI_MATCHER.addURI(AUTHORITY, EntriesTags.TBL_NAME, Code.ENTRIES_TAGS);
7275
URI_MATCHER.addURI(AUTHORITY, Tags.TBL_NAME + "/#", Code.TAG);
7376
URI_MATCHER.addURI(AUTHORITY, Tags.TBL_NAME, Code.TAGS);
77+
URI_MATCHER.addURI(AUTHORITY, Files.TBL_NAME + "/notcached", Code.FILE_NOT_CACHED);
78+
URI_MATCHER.addURI(AUTHORITY, Files.TBL_NAME + "/*", Code.FILE);
7479
URI_MATCHER.addURI(AUTHORITY, Files.TBL_NAME, Code.FILES);
7580
}
7681

@@ -120,9 +125,12 @@ public Cursor query(Uri uri, String[] projection, String selection, String[] sel
120125
case Code.TAGS:
121126
return db.query(Tags.TBL_NAME, merge(projection, "rowid as _id"),
122127
selection, selectionArgs, null, null, sortOrder);
123-
case Code.FILES:
124-
return db.query(Files.TBL_NAME, projection, Files.URL + "=?",
125-
new String[]{uri.getLastPathSegment()}, null, null, null);
128+
case Code.FILE:
129+
return db.query(Files.TBL_NAME, projection,
130+
Files.URL + "=?", new String[]{uri.getLastPathSegment()}, null, null, null);
131+
case Code.FILE_NOT_CACHED:
132+
return db.query(Files.TBL_NAME, new String[]{"rowid as _id", Files.URL},
133+
Files.FILENAME + " IS NULL", null, null, null, null);
126134
case Code.AUTHORITY: return null;
127135
default:
128136
throw new UnsupportedOperationException("Unsupported Uri " + uri);
@@ -152,7 +160,7 @@ protected long insert(final SQLiteDatabase db, final int uriCode, final ContentV
152160
case Code.ENTRIES_TAGS:
153161
return db.insertWithOnConflict(EntriesTags.TBL_NAME, null, values, CONFLICT_IGNORE);
154162
case Code.FILES:
155-
return db.replace(Files.TBL_NAME, null, values);
163+
return db.insertWithOnConflict(Files.TBL_NAME, null, values, CONFLICT_IGNORE);
156164
case UriMatcher.NO_MATCH:
157165
throw new UnsupportedOperationException("Unmatched Uri");
158166
default:
@@ -198,14 +206,54 @@ public int update(final Uri uri, final ContentValues values,
198206
return db.update(Feeds.TBL_NAME, values, selection, selectionArgs);
199207
case Code.CATEGORIES:
200208
return db.update(Categories.TBL_NAME, values, selection, selectionArgs);
201-
case Code.FILES:
209+
case Code.FILE:
202210
return db.update(Files.TBL_NAME, values, Files.URL + "=?",
203211
new String[]{uri.getLastPathSegment()});
204212
default:
205213
throw new UnsupportedOperationException("Unsupported Uri " + uri);
206214
}
207215
}
208216

217+
@Override
218+
public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
219+
Cursor c = getCursorForFile(uri);
220+
int count = (c != null) ? c.getCount() : 0;
221+
if (count != 1) {
222+
// If there is not exactly one result, throw an appropriate
223+
// exception.
224+
if (c != null) {
225+
c.close();
226+
}
227+
if (count == 0) {
228+
throw new FileNotFoundException("No entry for " + uri);
229+
}
230+
throw new FileNotFoundException("Multiple items at " + uri);
231+
}
232+
233+
c.moveToFirst();
234+
int i = c.getColumnIndex("_data");
235+
String path = (i >= 0 ? c.getString(i) : null);
236+
c.close();
237+
if (path == null) {
238+
throw new FileNotFoundException("Column _data not found.");
239+
}
240+
return ParcelFileDescriptor.open(new File(path), parseMode(mode));
241+
}
242+
243+
protected Cursor getCursorForFile(final Uri uri) {
244+
final Cursor c;
245+
switch (URI_MATCHER.match(uri)) {
246+
case Code.FILE:
247+
String cacheDir = getContext().getExternalCacheDir().getAbsolutePath();
248+
c = query(uri, new String[]{"('" + cacheDir + "/file-' || rowid) as _data"},
249+
null, null, null);
250+
break;
251+
default:
252+
throw new UnsupportedOperationException("Unsupported Uri " + uri);
253+
}
254+
return c;
255+
}
256+
209257
/**
210258
* With notification
211259
* {@inheritDoc}
@@ -256,6 +304,39 @@ public boolean onCreate() {
256304
return true;
257305
}
258306

307+
/**
308+
* Converts a string representing a file mode, such as "rw", into a bitmask.
309+
* <p>
310+
*
311+
* @param mode The string representation of the file mode.
312+
* @return A bitmask representing the given file mode.
313+
* @throws IllegalArgumentException if the given string does not match a known file mode.
314+
*/
315+
public static int parseMode(String mode) {
316+
final int modeBits;
317+
if ("r".equals(mode)) {
318+
modeBits = ParcelFileDescriptor.MODE_READ_ONLY;
319+
} else if ("w".equals(mode) || "wt".equals(mode)) {
320+
modeBits = ParcelFileDescriptor.MODE_WRITE_ONLY
321+
| ParcelFileDescriptor.MODE_CREATE
322+
| ParcelFileDescriptor.MODE_TRUNCATE;
323+
} else if ("wa".equals(mode)) {
324+
modeBits = ParcelFileDescriptor.MODE_WRITE_ONLY
325+
| ParcelFileDescriptor.MODE_CREATE
326+
| ParcelFileDescriptor.MODE_APPEND;
327+
} else if ("rw".equals(mode)) {
328+
modeBits = ParcelFileDescriptor.MODE_READ_WRITE
329+
| ParcelFileDescriptor.MODE_CREATE;
330+
} else if ("rwt".equals(mode)) {
331+
modeBits = ParcelFileDescriptor.MODE_READ_WRITE
332+
| ParcelFileDescriptor.MODE_CREATE
333+
| ParcelFileDescriptor.MODE_TRUNCATE;
334+
} else {
335+
throw new IllegalArgumentException("Bad mode '" + mode + "'");
336+
}
337+
return modeBits;
338+
}
339+
259340
private DatabaseHelper mHelper;
260341

261342
private WeakReference<ContentResolver> mResolver;
@@ -292,7 +373,10 @@ public void onDowngrade(final SQLiteDatabase db, final int oldVersion, final int
292373
}
293374

294375

295-
public DatabaseHelper(final Context context) { super(context, DB_NAME, null, VERSION); }
376+
public DatabaseHelper(final Context context) {
377+
super(context, context.getExternalFilesDir(null).getAbsolutePath() + '/' + DB_NAME,
378+
null, VERSION);
379+
}
296380

297381
private static final String DB_NAME = "feedly_cache.db";
298382

@@ -309,6 +393,6 @@ private interface Code {
309393
static final int FEEDS_CATEGORIES = 300, ENTRIES_TAGS = 301;
310394
static final int TAGS = 400, TAG = 401;
311395
static final int ENTRIES = 500, ENTRY = 501, ENTRIES_BY_TAG = 502, ENTRIES_BY_CATEGORY = 503;
312-
static final int FILES = 600;
396+
static final int FILES = 600, FILE = 601, FILE_NOT_CACHED = 602;
313397
}
314398
}

feedly-andrss/src/main/java/org/github/bademux/feedly/service/FeedlyBroadcastReceiver.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,16 +53,16 @@ public void onReceive(final Context context, final Intent intent) {
5353
String uri = c.getString(c.getColumnIndex(DownloadManager.COLUMN_URI));
5454
String filename = c.getString(c.getColumnIndex(DownloadManager.COLUMN_LOCAL_FILENAME));
5555
String mime = c.getString(c.getColumnIndex(DownloadManager.COLUMN_MEDIA_TYPE));
56-
context.startService(createIntent(context, uri, filename, mime));
56+
context.startService(createIntentDlComplete(context, uri, filename, mime));
5757
}
5858
}
5959
} else {
6060
new FeedlyServiceManager(context).process(intent);
6161
}
6262
}
6363

64-
private static Intent createIntent(final Context context,
65-
final String url, final String filename, final String mime) {
64+
private static Intent createIntentDlComplete(final Context context, final String url,
65+
final String filename, final String mime) {
6666
Intent intent = new Intent(FeedlyCacheService.ACTION_DOWNLOAD_COMPLETED, null,
6767
context, FeedlyCacheService.class);
6868
intent.putExtra(FeedlyCacheService.EXTRA_URL, url);

feedly-andrss/src/main/java/org/github/bademux/feedly/service/FeedlyCacheService.java

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -89,15 +89,18 @@ private void handleIntent(final Intent intent, final ContentResolver contentReso
8989
if (result != null) {
9090
processEntries(contentResolver, result.items());
9191
}
92-
case ACTION_DOWNLOAD:
93-
String where = Files.CREATED + ">= datetime('now') AND" + Files.FILENAME + " IS NULL";
94-
Cursor c = contentResolver.query(Files.CONTENT_URI, null, where, null, null);
92+
case ACTION_DOWNLOAD: //Get all not cached files
93+
Uri notcachedUri = Files.CONTENT_URI.buildUpon().appendPath("notcached").build();
94+
Cursor c = contentResolver.query(notcachedUri, null, null, null, null);
9595
if (c.moveToFirst()) {
9696
DownloadManager dm = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
97-
Uri cacheDir = Uri.fromFile(getCacheDir());
9897
do {
99-
Uri url = Uri.parse(c.getString(c.getColumnIndex(Files.URL)));
100-
dm.enqueue(new Request(url).setDestinationUri(cacheDir).setVisibleInDownloadsUi(false)
98+
long fileId = c.getLong(c.getColumnIndex(Files.ID));
99+
Uri uri = Uri.parse(c.getString(c.getColumnIndex(Files.URL)));
100+
Uri destinationUri = Uri.fromFile(getExternalCacheDir()).buildUpon()
101+
.appendPath("file-" + fileId).build();
102+
dm.enqueue(new Request(uri).setDestinationUri(destinationUri)
103+
.setVisibleInDownloadsUi(false)
101104
.setNotificationVisibility(Request.VISIBILITY_HIDDEN));
102105
} while (c.moveToNext());
103106
}
@@ -107,8 +110,8 @@ private void handleIntent(final Intent intent, final ContentResolver contentReso
107110
ContentValues values = new ContentValues(2);
108111
values.put(Files.FILENAME, intent.getStringExtra(FeedlyCacheService.EXTRA_FILENAME));
109112
values.put(Files.MIME, intent.getStringExtra(FeedlyCacheService.EXTRA_MIME));
110-
Uri uri = Files.CONTENT_URI.buildUpon().appendPath(url).build();
111-
contentResolver.update(uri, values, null, null);
113+
Uri updateUri = Files.CONTENT_URI.buildUpon().appendPath(url).build();
114+
contentResolver.update(updateUri, values, null, null);
112115
break;
113116
default:
114117
Log.d(TAG, "unknown action" + action);

feedly-api-android/src/main/java/org/github/bademux/feedly/api/provider/FeedlyContract.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -196,12 +196,12 @@ protected interface EntriesColumns {
196196
public static final String ORIGIN_STREAMID = "origin_streamid";
197197
public static final String ORIGIN_TITLE = "origin_title";
198198
public static final String VISUAL_URL = "visual_url";
199-
public static final String ENCLOSURE_MIMES = "ENCLOSURE_MIMES";
199+
public static final String ENCLOSURE_MIMES = "enclosure_mimes";
200200
}
201201

202-
203202
protected interface FileStats {
204203

204+
public static final String ID = "_id";
205205
public static final String URL = "url";
206206
public static final String MIME = "mime";
207207
public static final String FILENAME = "filename";

feedly-api-android/src/main/java/org/github/bademux/feedly/api/util/db/FeedlyDbUtils.java

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949

5050
import static android.content.ContentProviderOperation.Builder;
5151
import static android.content.ContentProviderOperation.newInsert;
52+
import static android.webkit.URLUtil.isNetworkUrl;
5253
import static org.github.bademux.feedly.api.provider.FeedlyContract.Categories;
5354
import static org.github.bademux.feedly.api.provider.FeedlyContract.Entries;
5455
import static org.github.bademux.feedly.api.provider.FeedlyContract.EntriesByCategory;
@@ -248,7 +249,10 @@ public static ContentValues convert(final Entry entry) {
248249
}
249250
Entry.Visual visual = entry.getVisual();
250251
if (visual != null) {
251-
values.put(Entries.VISUAL_URL, visual.getSource());
252+
String src = visual.getSource();
253+
if (!Entry.File.EMPTY_SOURCE.equals(src)) {
254+
values.put(Entries.VISUAL_URL, src);
255+
}
252256
}
253257
List<Entry.Enclosure> enclosures = entry.getEnclosure();
254258
if (enclosures != null && !enclosures.isEmpty()) {
@@ -283,7 +287,7 @@ public static ContentValues convert(final Entry.File file) {
283287
values.put(Files.URL, file.getSource());
284288
String mime = file.getMime();
285289
if (mime != null) {
286-
values.put(Files.MIME, file.getMime());
290+
values.put(Files.MIME, mime);
287291
}
288292
return values;
289293
}
@@ -348,14 +352,16 @@ public static void processEntries(final ContentResolver contentResolver,
348352
}
349353

350354
Entry.Visual visual = entry.getVisual();
351-
if (visual != null) {
355+
if (visual != null && isNetworkUrl(visual.getSource())) {
352356
files.add(convert(visual));
353357
}
354358

355359
List<Entry.Enclosure> enclosures = entry.getEnclosure();
356360
if (enclosures != null) {
357361
for (Entry.Enclosure enclosure : enclosures) {
358-
files.add(convert(enclosure));
362+
if (isNetworkUrl(enclosure.getSource())) {
363+
files.add(convert(enclosure));
364+
}
359365
}
360366
}
361367
}
@@ -602,7 +608,7 @@ public static final String[] merge(final String[] strings1, final String... stri
602608
private FeedlyDbUtils() {}
603609

604610

605-
public static class FileFeedFavicon implements Entry.File {
611+
static class FileFeedFavicon implements Entry.File {
606612

607613
public Feed getFeed() { return feed; }
608614

0 commit comments

Comments
 (0)