commit
88c796f65d
@ -157,6 +157,16 @@
|
||||
<category android:name="android.intent.category.DEFAULT"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<provider
|
||||
android:name="android.support.v4.content.FileProvider"
|
||||
android:authorities="${applicationId}.fileprovider"
|
||||
android:grantUriPermissions="true"
|
||||
android:exported="false">
|
||||
<meta-data
|
||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||
android:resource="@xml/filepaths" />
|
||||
</provider>
|
||||
</application>
|
||||
|
||||
</manifest>
|
@ -97,6 +97,7 @@ import acr.browser.lightning.browser.BrowserView;
|
||||
import acr.browser.lightning.browser.TabsView;
|
||||
import acr.browser.lightning.constant.BookmarkPage;
|
||||
import acr.browser.lightning.constant.Constants;
|
||||
import acr.browser.lightning.constant.DownloadsPage;
|
||||
import acr.browser.lightning.constant.HistoryPage;
|
||||
import acr.browser.lightning.controller.UIController;
|
||||
import acr.browser.lightning.database.HistoryItem;
|
||||
@ -800,6 +801,9 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
|
||||
case R.id.action_history:
|
||||
openHistory();
|
||||
return true;
|
||||
case R.id.action_downloads:
|
||||
openDownloads();
|
||||
return true;
|
||||
case R.id.action_add_bookmark:
|
||||
if (currentUrl != null && !UrlUtils.isSpecialUrl(currentUrl)) {
|
||||
addBookmark(currentView.getTitle(), currentUrl);
|
||||
@ -1598,6 +1602,22 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
|
||||
});
|
||||
}
|
||||
|
||||
private void openDownloads() {
|
||||
new DownloadsPage().getDownloadsPage()
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(Schedulers.main())
|
||||
.subscribe(new SingleOnSubscribe<String>() {
|
||||
@Override
|
||||
public void onItem(@Nullable String item) {
|
||||
Preconditions.checkNonNull(item);
|
||||
LightningView view = mTabsManager.getCurrentTab();
|
||||
if (view != null) {
|
||||
view.loadUrl(item);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private View getBookmarkDrawer() {
|
||||
return mSwapBookmarksAndTabs ? mDrawerLeft : mDrawerRight;
|
||||
}
|
||||
@ -2110,6 +2130,18 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleDownloadDeleted() {
|
||||
final LightningView currentTab = mTabsManager.getCurrentTab();
|
||||
if (currentTab != null && currentTab.getUrl().startsWith(Constants.FILE)
|
||||
&& currentTab.getUrl().endsWith(DownloadsPage.FILENAME)) {
|
||||
currentTab.loadDownloadspage();
|
||||
}
|
||||
if (currentTab != null) {
|
||||
mBookmarksView.handleUpdatedUrl(currentTab.getUrl());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleBookmarkDeleted(@NonNull HistoryItem item) {
|
||||
mBookmarksView.handleBookmarkDeleted(item);
|
||||
|
@ -33,6 +33,7 @@ import acr.browser.lightning.R;
|
||||
import acr.browser.lightning.app.BrowserApp;
|
||||
import acr.browser.lightning.constant.BookmarkPage;
|
||||
import acr.browser.lightning.constant.Constants;
|
||||
import acr.browser.lightning.constant.DownloadsPage;
|
||||
import acr.browser.lightning.constant.HistoryPage;
|
||||
import acr.browser.lightning.constant.StartPage;
|
||||
import acr.browser.lightning.dialog.BrowserDialog;
|
||||
@ -171,6 +172,17 @@ public class TabsManager {
|
||||
tab.loadUrl(item);
|
||||
}
|
||||
});
|
||||
} else if (UrlUtils.isDownloadsUrl(url)) {
|
||||
new DownloadsPage().getDownloadsPage()
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(Schedulers.main())
|
||||
.subscribe(new SingleOnSubscribe<String>() {
|
||||
@Override
|
||||
public void onItem(@Nullable String item) {
|
||||
Preconditions.checkNonNull(item);
|
||||
tab.loadUrl(item);
|
||||
}
|
||||
});
|
||||
} else if (UrlUtils.isStartPageUrl(url)) {
|
||||
new StartPage().getHomepage()
|
||||
.subscribeOn(Schedulers.io())
|
||||
|
@ -9,6 +9,7 @@ import acr.browser.lightning.activity.ThemableBrowserActivity;
|
||||
import acr.browser.lightning.activity.ThemableSettingsActivity;
|
||||
import acr.browser.lightning.browser.BrowserPresenter;
|
||||
import acr.browser.lightning.constant.BookmarkPage;
|
||||
import acr.browser.lightning.constant.DownloadsPage;
|
||||
import acr.browser.lightning.constant.HistoryPage;
|
||||
import acr.browser.lightning.constant.StartPage;
|
||||
import acr.browser.lightning.database.history.HistoryDatabase;
|
||||
@ -67,6 +68,8 @@ public interface AppComponent {
|
||||
|
||||
void inject(BookmarkPage bookmarkPage);
|
||||
|
||||
void inject(DownloadsPage downloadsPage);
|
||||
|
||||
void inject(BrowserPresenter presenter);
|
||||
|
||||
void inject(TabsManager manager);
|
||||
|
@ -10,6 +10,8 @@ import javax.inject.Singleton;
|
||||
|
||||
import acr.browser.lightning.database.bookmark.BookmarkDatabase;
|
||||
import acr.browser.lightning.database.bookmark.BookmarkModel;
|
||||
import acr.browser.lightning.database.downloads.DownloadsDatabase;
|
||||
import acr.browser.lightning.database.downloads.DownloadsModel;
|
||||
import dagger.Module;
|
||||
import dagger.Provides;
|
||||
|
||||
@ -38,6 +40,13 @@ public class AppModule {
|
||||
return new BookmarkDatabase(mApp);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Provides
|
||||
@Singleton
|
||||
public DownloadsModel provideDownloadsMode() {
|
||||
return new DownloadsDatabase(mApp);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Provides
|
||||
@Singleton
|
||||
|
@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Copyright 2014 A.C.R. Development
|
||||
*/
|
||||
package acr.browser.lightning.constant;
|
||||
|
||||
import android.app.Application;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import com.anthonycr.bonsai.Single;
|
||||
import com.anthonycr.bonsai.SingleAction;
|
||||
import com.anthonycr.bonsai.SingleOnSubscribe;
|
||||
import com.anthonycr.bonsai.SingleSubscriber;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import acr.browser.lightning.R;
|
||||
import acr.browser.lightning.app.BrowserApp;
|
||||
import acr.browser.lightning.database.downloads.DownloadItem;
|
||||
import acr.browser.lightning.database.downloads.DownloadsModel;
|
||||
import acr.browser.lightning.preference.PreferenceManager;
|
||||
import acr.browser.lightning.utils.Preconditions;
|
||||
import acr.browser.lightning.utils.Utils;
|
||||
|
||||
public final class DownloadsPage {
|
||||
|
||||
/**
|
||||
* The download page standard suffix
|
||||
*/
|
||||
public static final String FILENAME = "downloads.html";
|
||||
|
||||
private static final String HEADING_1 = "<!DOCTYPE html><html xmlns=http://www.w3.org/1999/xhtml>\n" +
|
||||
"<head>\n" +
|
||||
"<meta content=en-us http-equiv=Content-Language />\n" +
|
||||
"<meta content='text/html; charset=utf-8' http-equiv=Content-Type />\n" +
|
||||
"<meta name=viewport content='width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no'>\n" +
|
||||
"<title>";
|
||||
|
||||
private static final String HEADING_2 = "</title>" +
|
||||
"</head>" +
|
||||
"<style>body{background:#f5f5f5;}.box{vertical-align:middle;position:relative; display: block; margin: 10px;padding:10px; background-color:#fff;box-shadow: 0px 2px 4px rgba( 0, 0, 0, 0.25 );font-family: Arial;color: #444;font-size: 12px;-moz-border-radius: 2px;-webkit-border-radius: 2px;border-radius: 2px;}.box a { width: 100%; height: 100%; position: absolute; left: 0; top: 0;}.black {color: black;font-size: 15px;font-family: Arial; white-space: nowrap; overflow: hidden;margin:auto; text-overflow: ellipsis; -o-text-overflow: ellipsis; -ms-text-overflow: ellipsis;}.font {color: gray;font-size: 10px;font-family: Arial; white-space: nowrap; overflow: hidden;margin:auto; text-overflow: ellipsis; -o-text-overflow: ellipsis; -ms-text-overflow: ellipsis;}</style>" +
|
||||
"<body><div id='content'>";
|
||||
|
||||
private static final String PART1 = "<div class=box><a href='";
|
||||
|
||||
private static final String PART2 = "'></a><p class='black'>";
|
||||
|
||||
private static final String PART3 = "</p><p class='font'>";
|
||||
|
||||
private static final String PART4 = "</p></div>";
|
||||
|
||||
private static final String END = "</div></body></html>";
|
||||
|
||||
private File mFilesDir;
|
||||
|
||||
@Inject Application mApp;
|
||||
@Inject PreferenceManager mPreferenceManager;
|
||||
@Inject DownloadsModel mManager;
|
||||
|
||||
@NonNull private final String mTitle;
|
||||
|
||||
public DownloadsPage() {
|
||||
BrowserApp.getAppComponent().inject(this);
|
||||
mTitle = mApp.getString(R.string.action_downloads);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public Single<String> getDownloadsPage() {
|
||||
return Single.create(new SingleAction<String>() {
|
||||
@Override
|
||||
public void onSubscribe(@NonNull SingleSubscriber<String> subscriber) {
|
||||
mFilesDir = mApp.getFilesDir();
|
||||
|
||||
buildDownloadsPage();
|
||||
|
||||
File downloadsWebPage = new File(mFilesDir, FILENAME);
|
||||
|
||||
subscriber.onItem(Constants.FILE + downloadsWebPage);
|
||||
subscriber.onComplete();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void buildDownloadsPage() {
|
||||
mManager.getAllDownloads()
|
||||
.subscribe(new SingleOnSubscribe<List<DownloadItem>>() {
|
||||
@Override
|
||||
public void onItem(@Nullable List<DownloadItem> list) {
|
||||
Preconditions.checkNonNull(list);
|
||||
String directory = mPreferenceManager.getDownloadDirectory();
|
||||
|
||||
final StringBuilder downloadsBuilder = new StringBuilder(HEADING_1 + mTitle + HEADING_2);
|
||||
|
||||
for (int n = 0, size = list.size(); n < size; n++) {
|
||||
final DownloadItem item = list.get(n);
|
||||
downloadsBuilder.append(PART1);
|
||||
downloadsBuilder.append("file://");
|
||||
downloadsBuilder.append(directory);
|
||||
downloadsBuilder.append("/");
|
||||
downloadsBuilder.append(item.getTitle());
|
||||
downloadsBuilder.append(PART2);
|
||||
downloadsBuilder.append(item.getTitle());
|
||||
|
||||
if (!item.getContentSize().isEmpty()) {
|
||||
downloadsBuilder.append(" [");
|
||||
downloadsBuilder.append(item.getContentSize());
|
||||
downloadsBuilder.append("]");
|
||||
}
|
||||
|
||||
downloadsBuilder.append(PART3);
|
||||
downloadsBuilder.append(item.getUrl());
|
||||
downloadsBuilder.append(PART4);
|
||||
}
|
||||
downloadsBuilder.append(END);
|
||||
FileWriter bookWriter = null;
|
||||
try {
|
||||
//noinspection IOResourceOpenedButNotSafelyClosed
|
||||
bookWriter = new FileWriter(new File(mFilesDir, FILENAME), false);
|
||||
bookWriter.write(downloadsBuilder.toString());
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
Utils.close(bookWriter);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@ -37,17 +37,25 @@ public class HistoryPage {
|
||||
|
||||
public static final String FILENAME = "history.html";
|
||||
|
||||
private static final String HEADING_1 = "<!DOCTYPE html><html xmlns=\"http://www.w3.org/1999/xhtml\"><head><meta content=\"en-us\" http-equiv=\"Content-Language\" /><meta content=\"text/html; charset=utf-8\" http-equiv=\"Content-Type\" /><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no\"><title>";
|
||||
private static final String HEADING_1 = "<!DOCTYPE html><html xmlns=http://www.w3.org/1999/xhtml>\n" +
|
||||
"<head>\n" +
|
||||
"<meta content=en-us http-equiv=Content-Language />\n" +
|
||||
"<meta content='text/html; charset=utf-8' http-equiv=Content-Type />\n" +
|
||||
"<meta name=viewport content='width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no'>\n" +
|
||||
"<title>";
|
||||
|
||||
private static final String HEADING_2 = "</title></head><style>body { background: #f5f5f5;}.box { vertical-align:middle;position:relative; display: block; margin: 10px;padding-left:10px;padding-right:10px;padding-top:5px;padding-bottom:5px; background-color:#fff;box-shadow: 0px 2px 3px rgba( 0, 0, 0, 0.25 );font-family: Arial;color: #444;font-size: 12px;-moz-border-radius: 2px;-webkit-border-radius: 2px;border-radius: 2px;}.box a { width: 100%; height: 100%; position: absolute; left: 0; top: 0;}.black {color: black;font-size: 15px;font-family: Arial; white-space: nowrap; overflow: hidden;margin:auto; text-overflow: ellipsis; -o-text-overflow: ellipsis; -ms-text-overflow: ellipsis;}.font {color: gray;font-size: 10px;font-family: Arial; white-space: nowrap; overflow: hidden;margin:auto; text-overflow: ellipsis; -o-text-overflow: ellipsis; -ms-text-overflow: ellipsis;}</style><body><div id=\"content\">";
|
||||
private static final String HEADING_2 = "</title>" +
|
||||
"</head>" +
|
||||
"<style>body{background:#f5f5f5;}.box{vertical-align:middle;position:relative; display: block; margin: 10px;padding:10px; background-color:#fff;box-shadow: 0px 2px 4px rgba( 0, 0, 0, 0.25 );font-family: Arial;color: #444;font-size: 12px;-moz-border-radius: 2px;-webkit-border-radius: 2px;border-radius: 2px;}.box a { width: 100%; height: 100%; position: absolute; left: 0; top: 0;}.black {color: black;font-size: 15px;font-family: Arial; white-space: nowrap; overflow: hidden;margin:auto; text-overflow: ellipsis; -o-text-overflow: ellipsis; -ms-text-overflow: ellipsis;}.font {color: gray;font-size: 10px;font-family: Arial; white-space: nowrap; overflow: hidden;margin:auto; text-overflow: ellipsis; -o-text-overflow: ellipsis; -ms-text-overflow: ellipsis;}</style>" +
|
||||
"<body><div id='content'>";
|
||||
|
||||
private static final String PART1 = "<div class=\"box\"><a href=\"";
|
||||
private static final String PART1 = "<div class=box><a href='";
|
||||
|
||||
private static final String PART2 = "\"></a><p class=\"black\">";
|
||||
private static final String PART2 = "'></a><p class='black'>";
|
||||
|
||||
private static final String PART3 = "</p><p class=\"font\">";
|
||||
private static final String PART3 = "</p><p class='font'>";
|
||||
|
||||
private static final String PART4 = "</p></div></div>";
|
||||
private static final String PART4 = "</p></div>";
|
||||
|
||||
private static final String END = "</div></body></html>";
|
||||
|
||||
|
@ -86,6 +86,8 @@ public interface UIController {
|
||||
|
||||
void handleBookmarksChange();
|
||||
|
||||
void handleDownloadDeleted();
|
||||
|
||||
void handleBookmarkDeleted(@NonNull HistoryItem item);
|
||||
|
||||
void handleNewTab(@NonNull LightningDialogBuilder.NewTab newTabType, @NonNull String url);
|
||||
|
@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright 2014 A.C.R. Development
|
||||
*/
|
||||
package acr.browser.lightning.database.downloads;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import acr.browser.lightning.utils.Preconditions;
|
||||
|
||||
public class DownloadItem implements Comparable<DownloadItem> {
|
||||
|
||||
// private variables
|
||||
@NonNull
|
||||
private String mUrl = "";
|
||||
|
||||
@NonNull
|
||||
private String mTitle = "";
|
||||
|
||||
@NonNull
|
||||
private String mContentSize = "";
|
||||
|
||||
public DownloadItem() {}
|
||||
|
||||
public DownloadItem(@NonNull String url, @NonNull String title, @NonNull String size) {
|
||||
Preconditions.checkNonNull(url);
|
||||
Preconditions.checkNonNull(title);
|
||||
Preconditions.checkNonNull(size);
|
||||
this.mUrl = url;
|
||||
this.mTitle = title;
|
||||
this.mContentSize = size;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public String getUrl() {
|
||||
return this.mUrl;
|
||||
}
|
||||
|
||||
public void setUrl(@Nullable String url) {
|
||||
this.mUrl = (url == null) ? "" : url;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public String getTitle() {
|
||||
return this.mTitle;
|
||||
}
|
||||
|
||||
public void setTitle(@Nullable String title) {
|
||||
this.mTitle = (title == null) ? "" : title;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public String getContentSize() {
|
||||
return this.mContentSize;
|
||||
}
|
||||
|
||||
public void setContentSize(@Nullable String size) {
|
||||
this.mContentSize = (size == null) ? "" : size;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String toString() {
|
||||
return mTitle;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(@NonNull DownloadItem another) {
|
||||
int compare = this.mTitle.compareTo(another.mTitle);
|
||||
if (compare == 0) {
|
||||
return this.mUrl.compareTo(another.mUrl);
|
||||
}
|
||||
return compare;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object object) {
|
||||
|
||||
if (this == object) return true;
|
||||
if (object == null) return false;
|
||||
if (!(object instanceof DownloadItem)) return false;
|
||||
|
||||
DownloadItem that = (DownloadItem) object;
|
||||
|
||||
return this.mTitle.equals(that.mTitle) && this.mUrl.equals(that.mUrl)
|
||||
&& this.mContentSize.equals(that.mContentSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
|
||||
int result = mUrl.hashCode();
|
||||
result = 31 * result + mTitle.hashCode();
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
@ -0,0 +1,261 @@
|
||||
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 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);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,97 @@
|
||||
package acr.browser.lightning.database.downloads;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.WorkerThread;
|
||||
|
||||
import com.anthonycr.bonsai.Completable;
|
||||
import com.anthonycr.bonsai.Single;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* The interface that should be used to
|
||||
* communicate with the download database.
|
||||
* <p>
|
||||
* Created by df1e on 29/5/17.
|
||||
*/
|
||||
public interface DownloadsModel {
|
||||
|
||||
/**
|
||||
* Determines if a URL is associated with a download.
|
||||
*
|
||||
* @param url the URL to check.
|
||||
* @return an observable that will emit true if
|
||||
* the URL is a download, false otherwise.
|
||||
*/
|
||||
@NonNull
|
||||
Single<Boolean> isDownload(@NonNull String url);
|
||||
|
||||
/**
|
||||
* Gets the download associated with the URL.
|
||||
*
|
||||
* @param url the URL to look for.
|
||||
* @return an observable that will emit either
|
||||
* the download associated with the URL or null.
|
||||
*/
|
||||
@NonNull
|
||||
Single<DownloadItem> findDownloadForUrl(@NonNull String url);
|
||||
|
||||
/**
|
||||
* Adds a download if one does not already exist with
|
||||
* the same URL.
|
||||
*
|
||||
* @param item the download to add.
|
||||
* @return an observable that emits true if the download
|
||||
* was added, false otherwise.
|
||||
*/
|
||||
@NonNull
|
||||
Single<Boolean> addDownloadIfNotExists(@NonNull DownloadItem item);
|
||||
|
||||
/**
|
||||
* Adds a list of downloads to the database.
|
||||
*
|
||||
* @param downloadItems the downloads to add.
|
||||
* @return an observable that emits a complete event
|
||||
* when all the downloads have been added.
|
||||
*/
|
||||
@NonNull
|
||||
Completable addDownloadsList(@NonNull List<DownloadItem> downloadItems);
|
||||
|
||||
/**
|
||||
* Deletes a download from the database.
|
||||
*
|
||||
* @param url the download url to delete.
|
||||
* @return an observable that emits true when
|
||||
* the download is deleted, false otherwise.
|
||||
*/
|
||||
@NonNull
|
||||
Single<Boolean> deleteDownload(@NonNull String url);
|
||||
|
||||
/**
|
||||
* Deletes all downloads in the database.
|
||||
*
|
||||
* @return an observable that emits a completion
|
||||
* event when all downloads have been deleted.
|
||||
*/
|
||||
@NonNull
|
||||
Completable deleteAllDownloads();
|
||||
|
||||
/**
|
||||
* Emits a list of all downloads
|
||||
*
|
||||
* @return an observable that emits a list
|
||||
* of all downloads.
|
||||
*/
|
||||
@NonNull
|
||||
Single<List<DownloadItem>> getAllDownloads();
|
||||
|
||||
/**
|
||||
* A synchronous call to the model
|
||||
* that returns the number of downloads.
|
||||
* Should be called from a background thread.
|
||||
*
|
||||
* @return the number of downloads in the database.
|
||||
*/
|
||||
@WorkerThread
|
||||
long count();
|
||||
}
|
@ -8,12 +8,15 @@ import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.webkit.URLUtil;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.AutoCompleteTextView;
|
||||
import android.widget.EditText;
|
||||
|
||||
import com.anthonycr.bonsai.CompletableOnSubscribe;
|
||||
import com.anthonycr.bonsai.CompletableSubscriber;
|
||||
import com.anthonycr.bonsai.Schedulers;
|
||||
import com.anthonycr.bonsai.SingleOnSubscribe;
|
||||
|
||||
@ -29,6 +32,8 @@ import acr.browser.lightning.constant.Constants;
|
||||
import acr.browser.lightning.controller.UIController;
|
||||
import acr.browser.lightning.database.HistoryItem;
|
||||
import acr.browser.lightning.database.bookmark.BookmarkModel;
|
||||
import acr.browser.lightning.database.downloads.DownloadItem;
|
||||
import acr.browser.lightning.database.downloads.DownloadsModel;
|
||||
import acr.browser.lightning.database.history.HistoryModel;
|
||||
import acr.browser.lightning.preference.PreferenceManager;
|
||||
import acr.browser.lightning.utils.IntentUtils;
|
||||
@ -41,6 +46,7 @@ import acr.browser.lightning.utils.Utils;
|
||||
* Created by Stefano Pacifici on 02/09/15, based on Anthony C. Restaino's code.
|
||||
*/
|
||||
public class LightningDialogBuilder {
|
||||
public static final String TAG = "LightningDialogBuilder";
|
||||
|
||||
public enum NewTab {
|
||||
FOREGROUND,
|
||||
@ -49,6 +55,7 @@ public class LightningDialogBuilder {
|
||||
}
|
||||
|
||||
@Inject BookmarkModel mBookmarkManager;
|
||||
@Inject DownloadsModel mDownloadsModel;
|
||||
@Inject PreferenceManager mPreferenceManager;
|
||||
|
||||
@Inject
|
||||
@ -152,6 +159,33 @@ public class LightningDialogBuilder {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the appropriated dialog for the long pressed link.
|
||||
*
|
||||
* @param activity used to show the dialog
|
||||
* @param url the long pressed url
|
||||
*/
|
||||
public void showLongPressedDialogForDownloadUrl(@NonNull final Activity activity,
|
||||
@NonNull final UIController uiController,
|
||||
@NonNull final String url) {
|
||||
|
||||
BrowserDialog.show(activity, R.string.action_downloads,
|
||||
new BrowserDialog.Item(R.string.dialog_delete_all_downloads) {
|
||||
@Override
|
||||
public void onClick() {
|
||||
mDownloadsModel.deleteAllDownloads()
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(Schedulers.main())
|
||||
.subscribe(new CompletableOnSubscribe() {
|
||||
@Override
|
||||
public void onComplete() {
|
||||
uiController.handleDownloadDeleted();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void showEditBookmarkDialog(@NonNull final Activity activity,
|
||||
@NonNull final UIController uiController,
|
||||
@NonNull final HistoryItem item) {
|
||||
@ -352,6 +386,15 @@ public class LightningDialogBuilder {
|
||||
@Override
|
||||
public void onClick() {
|
||||
Utils.downloadFile(activity, mPreferenceManager, url, userAgent, "attachment");
|
||||
|
||||
mDownloadsModel.addDownloadIfNotExists(new DownloadItem(url, URLUtil.guessFileName(url, null, null), ""))
|
||||
.subscribe(new SingleOnSubscribe<Boolean>() {
|
||||
@Override
|
||||
public void onItem(@Nullable Boolean item) {
|
||||
if (item != null && !item)
|
||||
Log.i(TAG, "error saving download to database");
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -47,15 +47,6 @@ public class DownloadHandler {
|
||||
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
|
||||
.getPath();
|
||||
|
||||
@Nullable
|
||||
static String guessFileExtension(@NonNull String filename) {
|
||||
int lastIndex = filename.lastIndexOf('.') + 1;
|
||||
if (lastIndex > 0 && filename.length() > lastIndex) {
|
||||
return filename.substring(lastIndex, filename.length());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify the host application a download should be done, or that the data
|
||||
* should be streamed if a streaming viewer is available.
|
||||
@ -222,7 +213,7 @@ public class DownloadHandler {
|
||||
Utils.showSnackbar(context, R.string.problem_location_download);
|
||||
return;
|
||||
}
|
||||
String newMimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(guessFileExtension(filename));
|
||||
String newMimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(Utils.guessFileExtension(filename));
|
||||
Log.d(TAG, "New mimetype: " + newMimeType);
|
||||
request.setMimeType(newMimeType);
|
||||
request.setDestinationUri(Uri.parse(Constants.FILE + location + filename));
|
||||
|
@ -93,7 +93,7 @@ class FetchUrlMimeType extends Thread {
|
||||
if (mimeType.equalsIgnoreCase("text/plain")
|
||||
|| mimeType.equalsIgnoreCase("application/octet-stream")) {
|
||||
String newMimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(
|
||||
DownloadHandler.guessFileExtension(mUri));
|
||||
Utils.guessFileExtension(mUri));
|
||||
if (newMimeType != null) {
|
||||
mRequest.setMimeType(newMimeType);
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import android.Manifest;
|
||||
import android.app.Activity;
|
||||
import android.app.Dialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.text.format.Formatter;
|
||||
import android.util.Log;
|
||||
@ -15,9 +16,12 @@ import android.webkit.URLUtil;
|
||||
|
||||
import acr.browser.lightning.R;
|
||||
import acr.browser.lightning.app.BrowserApp;
|
||||
import acr.browser.lightning.database.downloads.DownloadItem;
|
||||
import acr.browser.lightning.database.downloads.DownloadsModel;
|
||||
import acr.browser.lightning.dialog.BrowserDialog;
|
||||
import acr.browser.lightning.preference.PreferenceManager;
|
||||
|
||||
import com.anthonycr.bonsai.SingleOnSubscribe;
|
||||
import com.anthonycr.grant.PermissionsManager;
|
||||
import com.anthonycr.grant.PermissionsResultAction;
|
||||
|
||||
@ -31,6 +35,8 @@ public class LightningDownloadListener implements DownloadListener {
|
||||
|
||||
@Inject PreferenceManager mPreferenceManager;
|
||||
|
||||
@Inject DownloadsModel downloadsModel;
|
||||
|
||||
public LightningDownloadListener(Activity context) {
|
||||
BrowserApp.getAppComponent().inject(this);
|
||||
mActivity = context;
|
||||
@ -44,7 +50,15 @@ public class LightningDownloadListener implements DownloadListener {
|
||||
new PermissionsResultAction() {
|
||||
@Override
|
||||
public void onGranted() {
|
||||
String fileName = URLUtil.guessFileName(url, contentDisposition, mimetype);
|
||||
final String fileName = URLUtil.guessFileName(url, contentDisposition, mimetype);
|
||||
final String downloadSize;
|
||||
|
||||
if (contentLength > 0) {
|
||||
downloadSize = Formatter.formatFileSize(mActivity, contentLength);
|
||||
} else {
|
||||
downloadSize = mActivity.getString(R.string.unknown_size);
|
||||
}
|
||||
|
||||
DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
@ -52,6 +66,15 @@ public class LightningDownloadListener implements DownloadListener {
|
||||
case DialogInterface.BUTTON_POSITIVE:
|
||||
DownloadHandler.onDownloadStart(mActivity, mPreferenceManager, url, userAgent,
|
||||
contentDisposition, mimetype);
|
||||
|
||||
downloadsModel.addDownloadIfNotExists(new DownloadItem(url, fileName, downloadSize))
|
||||
.subscribe(new SingleOnSubscribe<Boolean>() {
|
||||
@Override
|
||||
public void onItem(@Nullable Boolean item) {
|
||||
if (item != null && !item)
|
||||
Log.i(TAG, "error saving download to database");
|
||||
}
|
||||
});
|
||||
break;
|
||||
case DialogInterface.BUTTON_NEGATIVE:
|
||||
break;
|
||||
@ -60,12 +83,6 @@ public class LightningDownloadListener implements DownloadListener {
|
||||
};
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(mActivity); // dialog
|
||||
String downloadSize;
|
||||
if (contentLength > 0) {
|
||||
downloadSize = Formatter.formatFileSize(mActivity, contentLength);
|
||||
} else {
|
||||
downloadSize = mActivity.getString(R.string.unknown_size);
|
||||
}
|
||||
String message = mActivity.getString(R.string.dialog_download, downloadSize);
|
||||
Dialog dialog = builder.setTitle(fileName)
|
||||
.setMessage(message)
|
||||
|
@ -25,6 +25,7 @@ import java.util.regex.Pattern;
|
||||
|
||||
import acr.browser.lightning.constant.BookmarkPage;
|
||||
import acr.browser.lightning.constant.Constants;
|
||||
import acr.browser.lightning.constant.DownloadsPage;
|
||||
import acr.browser.lightning.constant.HistoryPage;
|
||||
import acr.browser.lightning.constant.StartPage;
|
||||
|
||||
@ -91,6 +92,7 @@ public class UrlUtils {
|
||||
public static boolean isSpecialUrl(@Nullable String url) {
|
||||
return url != null && url.startsWith(Constants.FILE) &&
|
||||
(url.endsWith(BookmarkPage.FILENAME) ||
|
||||
url.endsWith(DownloadsPage.FILENAME) ||
|
||||
url.endsWith(HistoryPage.FILENAME) ||
|
||||
url.endsWith(StartPage.FILENAME));
|
||||
}
|
||||
@ -105,6 +107,16 @@ public class UrlUtils {
|
||||
return url != null && url.startsWith(Constants.FILE) && url.endsWith(BookmarkPage.FILENAME);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the url is a url for the bookmark page.
|
||||
*
|
||||
* @param url the url to check, may be null.
|
||||
* @return true if the url is a bookmark url, false otherwise.
|
||||
*/
|
||||
public static boolean isDownloadsUrl(@Nullable String url) {
|
||||
return url != null && url.startsWith(Constants.FILE) && url.endsWith(DownloadsPage.FILENAME);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the url is a url for the history page.
|
||||
*
|
||||
|
@ -456,4 +456,13 @@ public final class Utils {
|
||||
return inSampleSize;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static String guessFileExtension(@NonNull String filename) {
|
||||
int lastIndex = filename.lastIndexOf('.') + 1;
|
||||
if (lastIndex > 0 && filename.length() > lastIndex) {
|
||||
return filename.substring(lastIndex, filename.length());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -47,6 +47,7 @@ import javax.inject.Inject;
|
||||
import acr.browser.lightning.app.BrowserApp;
|
||||
import acr.browser.lightning.constant.BookmarkPage;
|
||||
import acr.browser.lightning.constant.Constants;
|
||||
import acr.browser.lightning.constant.DownloadsPage;
|
||||
import acr.browser.lightning.constant.HistoryPage;
|
||||
import acr.browser.lightning.constant.StartPage;
|
||||
import acr.browser.lightning.controller.UIController;
|
||||
@ -242,6 +243,24 @@ public class LightningView {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* This method gets the bookmark page URL from the {@link BookmarkPage}
|
||||
* class asynchronously and loads the URL in the WebView on the
|
||||
* UI thread. It also caches the default folder icon locally.
|
||||
*/
|
||||
public void loadDownloadspage() {
|
||||
new DownloadsPage().getDownloadsPage()
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(Schedulers.main())
|
||||
.subscribe(new SingleOnSubscribe<String>() {
|
||||
@Override
|
||||
public void onItem(@Nullable String item) {
|
||||
Preconditions.checkNonNull(item);
|
||||
loadUrl(item);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the preference driven settings of the WebView. This method
|
||||
* must be called whenever the preferences are changed within SharedPreferences.
|
||||
@ -984,6 +1003,13 @@ public class LightningView {
|
||||
final String newUrl = result.getExtra();
|
||||
mBookmarksDialogBuilder.showLongPressedDialogForBookmarkUrl(mActivity, mUIController, newUrl);
|
||||
}
|
||||
} else if (currentUrl.endsWith(DownloadsPage.FILENAME)) {
|
||||
if (url != null) {
|
||||
mBookmarksDialogBuilder.showLongPressedDialogForDownloadUrl(mActivity, mUIController, url);
|
||||
} else if (result != null && result.getExtra() != null) {
|
||||
final String newUrl = result.getExtra();
|
||||
mBookmarksDialogBuilder.showLongPressedDialogForDownloadUrl(mActivity, mUIController, newUrl);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (url != null) {
|
||||
|
@ -8,16 +8,19 @@ import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Bitmap;
|
||||
import android.net.MailTo;
|
||||
import android.net.Uri;
|
||||
import android.net.http.SslError;
|
||||
import android.os.Build;
|
||||
import android.os.Message;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.content.FileProvider;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.webkit.HttpAuthHandler;
|
||||
import android.webkit.MimeTypeMap;
|
||||
import android.webkit.SslErrorHandler;
|
||||
import android.webkit.ValueCallback;
|
||||
import android.webkit.WebResourceRequest;
|
||||
@ -28,6 +31,7 @@ import android.widget.EditText;
|
||||
import android.widget.TextView;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@ -35,6 +39,7 @@ import java.util.Map;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import acr.browser.lightning.BuildConfig;
|
||||
import acr.browser.lightning.R;
|
||||
import acr.browser.lightning.app.BrowserApp;
|
||||
import acr.browser.lightning.constant.Constants;
|
||||
@ -354,6 +359,26 @@ public class LightningWebClient extends WebViewClient {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} else if (url.startsWith(Constants.FILE)) {
|
||||
File file = new File(url.replace(Constants.FILE, ""));
|
||||
|
||||
if (file.exists()) {
|
||||
String newMimeType = MimeTypeMap.getSingleton()
|
||||
.getMimeTypeFromExtension(Utils.guessFileExtension(file.toString()));
|
||||
|
||||
Intent intent = new Intent();
|
||||
intent.setAction(Intent.ACTION_VIEW);
|
||||
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||
Uri contentUri = FileProvider.getUriForFile(mActivity, BuildConfig.APPLICATION_ID + ".fileprovider", file);
|
||||
intent.setDataAndType(contentUri, newMimeType);
|
||||
|
||||
try {
|
||||
mActivity.startActivity(intent);
|
||||
} catch (Exception e) {
|
||||
System.out.println("LightningWebClient: cannot open downloaded file");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -47,6 +47,9 @@
|
||||
<item
|
||||
android:id="@+id/action_history"
|
||||
android:title="@string/action_history"/>
|
||||
<item
|
||||
android:id="@+id/action_downloads"
|
||||
android:title="@string/action_downloads"/>
|
||||
<item
|
||||
android:id="@+id/action_find"
|
||||
android:title="@string/action_find"/>
|
||||
|
@ -47,6 +47,9 @@
|
||||
<item
|
||||
android:id="@+id/action_history"
|
||||
android:title="@string/action_history"/>
|
||||
<item
|
||||
android:id="@+id/action_downloads"
|
||||
android:title="@string/action_downloads"/>
|
||||
<item
|
||||
android:id="@+id/action_find"
|
||||
android:title="@string/action_find"/>
|
||||
|
@ -29,6 +29,9 @@
|
||||
<item
|
||||
android:id="@+id/action_history"
|
||||
android:title="@string/action_history"/>
|
||||
<item
|
||||
android:id="@+id/action_downloads"
|
||||
android:title="@string/action_downloads"/>
|
||||
<item
|
||||
android:id="@+id/action_find"
|
||||
android:title="@string/action_find"/>
|
||||
|
@ -6,6 +6,7 @@
|
||||
<string name="action_share">Share</string>
|
||||
<string name="action_history">History</string>
|
||||
<string name="action_bookmarks">Bookmarks</string>
|
||||
<string name="action_downloads">Downloads</string>
|
||||
<string name="action_add_bookmark">Add bookmark</string>
|
||||
<string name="action_copy">Copy link</string>
|
||||
<string name="action_forward">Forward</string>
|
||||
@ -245,4 +246,6 @@
|
||||
<string name="dialog_rename_folder">Rename folder</string>
|
||||
<string name="dialog_remove_folder">Remove folder</string>
|
||||
<string name="dialog_title_close_browser">Close browser</string>
|
||||
<string name="dialog_delete_download">Delete download</string>
|
||||
<string name="dialog_delete_all_downloads">Delete all downloads</string>
|
||||
</resources>
|
||||
|
5
app/src/main/res/xml/filepaths.xml
Normal file
5
app/src/main/res/xml/filepaths.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<paths>
|
||||
<external-path name="share" path="/" />
|
||||
<external-path name="external_files" path="."/>
|
||||
</paths>
|
Loading…
x
Reference in New Issue
Block a user