package acr.browser.lightning.database.downloads; import android.app.Application; import android.content.ContentValues; import android.database.Cursor; import android.database.DatabaseUtils; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.annotation.WorkerThread; import com.anthonycr.bonsai.Completable; import com.anthonycr.bonsai.CompletableAction; import com.anthonycr.bonsai.CompletableSubscriber; import com.anthonycr.bonsai.Single; import com.anthonycr.bonsai.SingleAction; import com.anthonycr.bonsai.SingleSubscriber; import java.util.ArrayList; import java.util.List; import javax.inject.Inject; import javax.inject.Singleton; import acr.browser.lightning.R; /** * The disk backed download database. * See {@link DownloadsModel} for method * documentation. */ @Singleton public class DownloadsDatabase extends SQLiteOpenHelper implements DownloadsModel { private static final String TAG = "DownloadsDatabase"; // Database Version private static final int DATABASE_VERSION = 1; // Database Name private static final String DATABASE_NAME = "downloadManager"; // HistoryItems table name private static final String TABLE_DOWNLOADS = "download"; // HistoryItems Table Columns names private static final String KEY_ID = "id"; private static final String KEY_URL = "url"; private static final String KEY_TITLE = "title"; private static final String KEY_SIZE = "size"; @NonNull private final String DEFAULT_DOWNLOADS_TITLE; @Nullable private SQLiteDatabase mDatabase; @Inject public DownloadsDatabase(@NonNull Application application) { super(application, DATABASE_NAME, null, DATABASE_VERSION); DEFAULT_DOWNLOADS_TITLE = application.getString(R.string.untitled); } /** * Lazily initializes the database * field when called. * * @return a non null writable database. */ @WorkerThread @NonNull private synchronized SQLiteDatabase lazyDatabase() { if (mDatabase == null || !mDatabase.isOpen()) { mDatabase = getWritableDatabase(); } return mDatabase; } // Creating Tables @Override public void onCreate(@NonNull SQLiteDatabase db) { String CREATE_BOOKMARK_TABLE = "CREATE TABLE " + DatabaseUtils.sqlEscapeString(TABLE_DOWNLOADS) + '(' + DatabaseUtils.sqlEscapeString(KEY_ID) + " INTEGER PRIMARY KEY," + DatabaseUtils.sqlEscapeString(KEY_URL) + " TEXT," + DatabaseUtils.sqlEscapeString(KEY_TITLE) + " TEXT," + DatabaseUtils.sqlEscapeString(KEY_SIZE) + " TEXT" + ')'; db.execSQL(CREATE_BOOKMARK_TABLE); } // Upgrading database @Override public void onUpgrade(@NonNull SQLiteDatabase db, int oldVersion, int newVersion) { // Drop older table if it exists db.execSQL("DROP TABLE IF EXISTS " + DatabaseUtils.sqlEscapeString(TABLE_DOWNLOADS)); // Create tables again onCreate(db); } @NonNull private static ContentValues bindBookmarkToContentValues(@NonNull DownloadItem downloadItem) { ContentValues contentValues = new ContentValues(3); contentValues.put(KEY_TITLE, downloadItem.getTitle()); contentValues.put(KEY_URL, downloadItem.getUrl()); contentValues.put(KEY_SIZE, downloadItem.getContentSize()); return contentValues; } @NonNull private static DownloadItem bindCursorToDownloadItem(@NonNull Cursor cursor) { DownloadItem download = new DownloadItem(); download.setUrl(cursor.getString(cursor.getColumnIndex(KEY_URL))); download.setTitle(cursor.getString(cursor.getColumnIndex(KEY_TITLE))); download.setContentSize(cursor.getString(cursor.getColumnIndex(KEY_SIZE))); return download; } @NonNull private static List<DownloadItem> bindCursorToDownloadItemList(@NonNull Cursor cursor) { List<DownloadItem> downloads = new ArrayList<>(); while (cursor.moveToNext()) { downloads.add(bindCursorToDownloadItem(cursor)); } cursor.close(); return downloads; } @NonNull @Override public Single<DownloadItem> findDownloadForUrl(@NonNull final String url) { return Single.create(new SingleAction<DownloadItem>() { @Override public void onSubscribe(@NonNull SingleSubscriber<DownloadItem> subscriber) { Cursor cursor = lazyDatabase().query(TABLE_DOWNLOADS, null, KEY_URL + "=?", new String[]{url}, null, null, "1"); if (cursor.moveToFirst()) { subscriber.onItem(bindCursorToDownloadItem(cursor)); } else { subscriber.onItem(null); } cursor.close(); subscriber.onComplete(); } }); } @NonNull @Override public Single<Boolean> isDownload(@NonNull final String url) { return Single.create(new SingleAction<Boolean>() { @Override public void onSubscribe(@NonNull SingleSubscriber<Boolean> subscriber) { Cursor cursor = lazyDatabase().query(TABLE_DOWNLOADS, null, KEY_URL + "=?", new String[]{url}, null, null, null, "1"); subscriber.onItem(cursor.moveToFirst()); cursor.close(); subscriber.onComplete(); } }); } @NonNull @Override public Single<Boolean> addDownloadIfNotExists(@NonNull final DownloadItem item) { return Single.create(new SingleAction<Boolean>() { @Override public void onSubscribe(@NonNull SingleSubscriber<Boolean> subscriber) { Cursor cursor = lazyDatabase().query(TABLE_DOWNLOADS, null, KEY_URL + "=?", new String[]{item.getUrl()}, null, null, "1"); if (cursor.moveToFirst()) { cursor.close(); subscriber.onItem(false); subscriber.onComplete(); return; } cursor.close(); long id = lazyDatabase().insert(TABLE_DOWNLOADS, null, bindBookmarkToContentValues(item)); subscriber.onItem(id != -1); subscriber.onComplete(); } }); } @NonNull @Override public Completable addDownloadsList(@NonNull final List<DownloadItem> bookmarkItems) { return Completable.create(new CompletableAction() { @Override public void onSubscribe(@NonNull CompletableSubscriber subscriber) { lazyDatabase().beginTransaction(); for (DownloadItem item : bookmarkItems) { addDownloadIfNotExists(item).subscribe(); } lazyDatabase().setTransactionSuccessful(); lazyDatabase().endTransaction(); subscriber.onComplete(); } }); } @NonNull @Override public Single<Boolean> deleteDownload(@NonNull final String url) { return Single.create(new SingleAction<Boolean>() { @Override public void onSubscribe(@NonNull SingleSubscriber<Boolean> subscriber) { int rows = lazyDatabase().delete(TABLE_DOWNLOADS, KEY_URL + "=?", new String[]{url}); subscriber.onItem(rows > 0); subscriber.onComplete(); } }); } @NonNull @Override public Completable deleteAllDownloads() { return Completable.create(new CompletableAction() { @Override public void onSubscribe(@NonNull CompletableSubscriber subscriber) { lazyDatabase().delete(TABLE_DOWNLOADS, null, null); subscriber.onComplete(); } }); } @NonNull @Override public Single<List<DownloadItem>> getAllDownloads() { return Single.create(new SingleAction<List<DownloadItem>>() { @Override public void onSubscribe(@NonNull SingleSubscriber<List<DownloadItem>> subscriber) { Cursor cursor = lazyDatabase().query(TABLE_DOWNLOADS, null, null, null, null, null, null); subscriber.onItem(bindCursorToDownloadItemList(cursor)); subscriber.onComplete(); } }); } @Override public long count() { return DatabaseUtils.queryNumEntries(lazyDatabase(), TABLE_DOWNLOADS); } }