commit
be1548e9a8
@ -14,6 +14,7 @@ import acr.browser.lightning.constant.HistoryPage;
|
|||||||
import acr.browser.lightning.constant.StartPage;
|
import acr.browser.lightning.constant.StartPage;
|
||||||
import acr.browser.lightning.database.history.HistoryDatabase;
|
import acr.browser.lightning.database.history.HistoryDatabase;
|
||||||
import acr.browser.lightning.dialog.LightningDialogBuilder;
|
import acr.browser.lightning.dialog.LightningDialogBuilder;
|
||||||
|
import acr.browser.lightning.download.DownloadHandler;
|
||||||
import acr.browser.lightning.download.LightningDownloadListener;
|
import acr.browser.lightning.download.LightningDownloadListener;
|
||||||
import acr.browser.lightning.fragment.BookmarkSettingsFragment;
|
import acr.browser.lightning.fragment.BookmarkSettingsFragment;
|
||||||
import acr.browser.lightning.fragment.BookmarksFragment;
|
import acr.browser.lightning.fragment.BookmarksFragment;
|
||||||
@ -80,6 +81,8 @@ public interface AppComponent {
|
|||||||
|
|
||||||
void inject(LightningChromeClient chromeClient);
|
void inject(LightningChromeClient chromeClient);
|
||||||
|
|
||||||
|
void inject(DownloadHandler downloadHandler);
|
||||||
|
|
||||||
HistoryDatabase historyDatabase();
|
HistoryDatabase historyDatabase();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,7 @@ import acr.browser.lightning.database.downloads.DownloadsDatabase;
|
|||||||
import acr.browser.lightning.database.downloads.DownloadsModel;
|
import acr.browser.lightning.database.downloads.DownloadsModel;
|
||||||
import acr.browser.lightning.database.history.HistoryDatabase;
|
import acr.browser.lightning.database.history.HistoryDatabase;
|
||||||
import acr.browser.lightning.database.history.HistoryModel;
|
import acr.browser.lightning.database.history.HistoryModel;
|
||||||
|
import acr.browser.lightning.download.DownloadHandler;
|
||||||
import dagger.Module;
|
import dagger.Module;
|
||||||
import dagger.Provides;
|
import dagger.Provides;
|
||||||
|
|
||||||
@ -56,6 +57,13 @@ public class AppModule {
|
|||||||
return new HistoryDatabase(mApp);
|
return new HistoryDatabase(mApp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
public DownloadHandler provideDownloadHandler() {
|
||||||
|
return new DownloadHandler();
|
||||||
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
|
@ -8,9 +8,7 @@ import android.support.annotation.NonNull;
|
|||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.support.v7.app.AlertDialog;
|
import android.support.v7.app.AlertDialog;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.Log;
|
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.webkit.URLUtil;
|
|
||||||
import android.widget.ArrayAdapter;
|
import android.widget.ArrayAdapter;
|
||||||
import android.widget.AutoCompleteTextView;
|
import android.widget.AutoCompleteTextView;
|
||||||
import android.widget.EditText;
|
import android.widget.EditText;
|
||||||
@ -31,13 +29,12 @@ import acr.browser.lightning.constant.Constants;
|
|||||||
import acr.browser.lightning.controller.UIController;
|
import acr.browser.lightning.controller.UIController;
|
||||||
import acr.browser.lightning.database.HistoryItem;
|
import acr.browser.lightning.database.HistoryItem;
|
||||||
import acr.browser.lightning.database.bookmark.BookmarkModel;
|
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.downloads.DownloadsModel;
|
||||||
import acr.browser.lightning.database.history.HistoryModel;
|
import acr.browser.lightning.database.history.HistoryModel;
|
||||||
|
import acr.browser.lightning.download.DownloadHandler;
|
||||||
import acr.browser.lightning.preference.PreferenceManager;
|
import acr.browser.lightning.preference.PreferenceManager;
|
||||||
import acr.browser.lightning.utils.IntentUtils;
|
import acr.browser.lightning.utils.IntentUtils;
|
||||||
import acr.browser.lightning.utils.Preconditions;
|
import acr.browser.lightning.utils.Preconditions;
|
||||||
import acr.browser.lightning.utils.Utils;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO Rename this class it doesn't build dialogs only for bookmarks
|
* TODO Rename this class it doesn't build dialogs only for bookmarks
|
||||||
@ -57,6 +54,7 @@ public class LightningDialogBuilder {
|
|||||||
@Inject DownloadsModel mDownloadsModel;
|
@Inject DownloadsModel mDownloadsModel;
|
||||||
@Inject HistoryModel mHistoryModel;
|
@Inject HistoryModel mHistoryModel;
|
||||||
@Inject PreferenceManager mPreferenceManager;
|
@Inject PreferenceManager mPreferenceManager;
|
||||||
|
@Inject DownloadHandler mDownloadHandler;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public LightningDialogBuilder() {
|
public LightningDialogBuilder() {
|
||||||
@ -385,16 +383,7 @@ public class LightningDialogBuilder {
|
|||||||
new BrowserDialog.Item(R.string.dialog_download_image) {
|
new BrowserDialog.Item(R.string.dialog_download_image) {
|
||||||
@Override
|
@Override
|
||||||
public void onClick() {
|
public void onClick() {
|
||||||
Utils.downloadFile(activity, mPreferenceManager, url, userAgent, "attachment");
|
mDownloadHandler.onDownloadStart(activity, mPreferenceManager, url, userAgent, "attachment", null, "");
|
||||||
|
|
||||||
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");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -23,16 +23,26 @@ import android.webkit.CookieManager;
|
|||||||
import android.webkit.MimeTypeMap;
|
import android.webkit.MimeTypeMap;
|
||||||
import android.webkit.URLUtil;
|
import android.webkit.URLUtil;
|
||||||
|
|
||||||
|
import com.anthonycr.bonsai.SingleOnSubscribe;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import acr.browser.lightning.BuildConfig;
|
import acr.browser.lightning.BuildConfig;
|
||||||
import acr.browser.lightning.R;
|
import acr.browser.lightning.R;
|
||||||
|
import acr.browser.lightning.activity.BrowserActivity;
|
||||||
import acr.browser.lightning.activity.MainActivity;
|
import acr.browser.lightning.activity.MainActivity;
|
||||||
|
import acr.browser.lightning.app.BrowserApp;
|
||||||
import acr.browser.lightning.constant.Constants;
|
import acr.browser.lightning.constant.Constants;
|
||||||
|
import acr.browser.lightning.database.downloads.DownloadItem;
|
||||||
|
import acr.browser.lightning.database.downloads.DownloadsModel;
|
||||||
import acr.browser.lightning.dialog.BrowserDialog;
|
import acr.browser.lightning.dialog.BrowserDialog;
|
||||||
import acr.browser.lightning.preference.PreferenceManager;
|
import acr.browser.lightning.preference.PreferenceManager;
|
||||||
|
import acr.browser.lightning.utils.FileUtils;
|
||||||
import acr.browser.lightning.utils.Utils;
|
import acr.browser.lightning.utils.Utils;
|
||||||
|
import acr.browser.lightning.view.LightningView;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle download requests
|
* Handle download requests
|
||||||
@ -43,9 +53,11 @@ public class DownloadHandler {
|
|||||||
|
|
||||||
private static final String COOKIE_REQUEST_HEADER = "Cookie";
|
private static final String COOKIE_REQUEST_HEADER = "Cookie";
|
||||||
|
|
||||||
public static final String DEFAULT_DOWNLOAD_PATH =
|
@Inject DownloadsModel downloadsModel;
|
||||||
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
|
|
||||||
.getPath();
|
public DownloadHandler() {
|
||||||
|
BrowserApp.getAppComponent().inject(this);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notify the host application a download should be done, or that the data
|
* Notify the host application a download should be done, or that the data
|
||||||
@ -56,9 +68,10 @@ public class DownloadHandler {
|
|||||||
* @param userAgent User agent of the downloading application.
|
* @param userAgent User agent of the downloading application.
|
||||||
* @param contentDisposition Content-disposition http header, if present.
|
* @param contentDisposition Content-disposition http header, if present.
|
||||||
* @param mimetype The mimetype of the content reported by the server
|
* @param mimetype The mimetype of the content reported by the server
|
||||||
|
* @param contentSize The size of the content
|
||||||
*/
|
*/
|
||||||
public static void onDownloadStart(@NonNull Activity context, @NonNull PreferenceManager manager, String url, String userAgent,
|
public void onDownloadStart(@NonNull Activity context, @NonNull PreferenceManager manager, String url, String userAgent,
|
||||||
@Nullable String contentDisposition, String mimetype) {
|
@Nullable String contentDisposition, String mimetype, String contentSize) {
|
||||||
|
|
||||||
Log.d(TAG, "DOWNLOAD: Trying to download from URL: " + url);
|
Log.d(TAG, "DOWNLOAD: Trying to download from URL: " + url);
|
||||||
Log.d(TAG, "DOWNLOAD: Content disposition: " + contentDisposition);
|
Log.d(TAG, "DOWNLOAD: Content disposition: " + contentDisposition);
|
||||||
@ -68,7 +81,7 @@ public class DownloadHandler {
|
|||||||
// if we're dealing wih A/V content that's not explicitly marked
|
// if we're dealing wih A/V content that's not explicitly marked
|
||||||
// for download, check if it's streamable.
|
// for download, check if it's streamable.
|
||||||
if (contentDisposition == null
|
if (contentDisposition == null
|
||||||
|| !contentDisposition.regionMatches(true, 0, "attachment", 0, 10)) {
|
|| !contentDisposition.regionMatches(true, 0, "attachment", 0, 10)) {
|
||||||
// query the package manager to see if there's a registered handler
|
// query the package manager to see if there's a registered handler
|
||||||
// that matches.
|
// that matches.
|
||||||
Intent intent = new Intent(Intent.ACTION_VIEW);
|
Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||||
@ -80,12 +93,12 @@ public class DownloadHandler {
|
|||||||
intent.setSelector(null);
|
intent.setSelector(null);
|
||||||
}
|
}
|
||||||
ResolveInfo info = context.getPackageManager().resolveActivity(intent,
|
ResolveInfo info = context.getPackageManager().resolveActivity(intent,
|
||||||
PackageManager.MATCH_DEFAULT_ONLY);
|
PackageManager.MATCH_DEFAULT_ONLY);
|
||||||
if (info != null) {
|
if (info != null) {
|
||||||
// If we resolved to ourselves, we don't want to attempt to
|
// If we resolved to ourselves, we don't want to attempt to
|
||||||
// load the url only to try and download it again.
|
// load the url only to try and download it again.
|
||||||
if (BuildConfig.APPLICATION_ID.equals(info.activityInfo.packageName)
|
if (BuildConfig.APPLICATION_ID.equals(info.activityInfo.packageName)
|
||||||
|| MainActivity.class.getName().equals(info.activityInfo.name)) {
|
|| MainActivity.class.getName().equals(info.activityInfo.name)) {
|
||||||
// someone (other than us) knows how to handle this mime
|
// someone (other than us) knows how to handle this mime
|
||||||
// type with this scheme, don't download.
|
// type with this scheme, don't download.
|
||||||
try {
|
try {
|
||||||
@ -98,7 +111,7 @@ public class DownloadHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onDownloadStartNoStream(context, manager, url, userAgent, contentDisposition, mimetype);
|
onDownloadStartNoStream(context, manager, url, userAgent, contentDisposition, mimetype, contentSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is to work around the fact that java.net.URI throws Exceptions
|
// This is to work around the fact that java.net.URI throws Exceptions
|
||||||
@ -141,11 +154,12 @@ public class DownloadHandler {
|
|||||||
* @param userAgent User agent of the downloading application.
|
* @param userAgent User agent of the downloading application.
|
||||||
* @param contentDisposition Content-disposition http header, if present.
|
* @param contentDisposition Content-disposition http header, if present.
|
||||||
* @param mimetype The mimetype of the content reported by the server
|
* @param mimetype The mimetype of the content reported by the server
|
||||||
|
* @param contentSize The size of the content
|
||||||
*/
|
*/
|
||||||
/* package */
|
/* package */
|
||||||
private static void onDownloadStartNoStream(@NonNull final Activity context, @NonNull PreferenceManager preferences,
|
private void onDownloadStartNoStream(@NonNull final Activity context, @NonNull PreferenceManager preferences,
|
||||||
String url, String userAgent,
|
String url, String userAgent,
|
||||||
String contentDisposition, @Nullable String mimetype) {
|
String contentDisposition, @Nullable String mimetype, String contentSize) {
|
||||||
final String filename = URLUtil.guessFileName(url, contentDisposition, mimetype);
|
final String filename = URLUtil.guessFileName(url, contentDisposition, mimetype);
|
||||||
|
|
||||||
// Check to see if we have an SDCard
|
// Check to see if we have an SDCard
|
||||||
@ -164,8 +178,8 @@ public class DownloadHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Dialog dialog = new AlertDialog.Builder(context).setTitle(title)
|
Dialog dialog = new AlertDialog.Builder(context).setTitle(title)
|
||||||
.setIcon(android.R.drawable.ic_dialog_alert).setMessage(msg)
|
.setIcon(android.R.drawable.ic_dialog_alert).setMessage(msg)
|
||||||
.setPositiveButton(R.string.action_ok, null).show();
|
.setPositiveButton(R.string.action_ok, null).show();
|
||||||
BrowserDialog.setDialogSize(context, dialog);
|
BrowserDialog.setDialogSize(context, dialog);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -198,16 +212,8 @@ public class DownloadHandler {
|
|||||||
// or, should it be set to one of several Environment.DIRECTORY* dirs
|
// or, should it be set to one of several Environment.DIRECTORY* dirs
|
||||||
// depending on mimetype?
|
// depending on mimetype?
|
||||||
String location = preferences.getDownloadDirectory();
|
String location = preferences.getDownloadDirectory();
|
||||||
Uri downloadFolder;
|
location = FileUtils.addNecessarySlashes(location);
|
||||||
location = addNecessarySlashes(location);
|
Uri downloadFolder = Uri.parse(location);
|
||||||
downloadFolder = Uri.parse(location);
|
|
||||||
|
|
||||||
File dir = new File(downloadFolder.getPath());
|
|
||||||
if (!dir.isDirectory() && !dir.mkdirs()) {
|
|
||||||
// Cannot make the directory
|
|
||||||
Utils.showSnackbar(context, R.string.problem_location_download);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isWriteAccessAvailable(downloadFolder)) {
|
if (!isWriteAccessAvailable(downloadFolder)) {
|
||||||
Utils.showSnackbar(context, R.string.problem_location_download);
|
Utils.showSnackbar(context, R.string.problem_location_download);
|
||||||
@ -240,7 +246,7 @@ public class DownloadHandler {
|
|||||||
} else {
|
} else {
|
||||||
Log.d(TAG, "Valid mimetype, attempting to download");
|
Log.d(TAG, "Valid mimetype, attempting to download");
|
||||||
final DownloadManager manager = (DownloadManager) context
|
final DownloadManager manager = (DownloadManager) context
|
||||||
.getSystemService(Context.DOWNLOAD_SERVICE);
|
.getSystemService(Context.DOWNLOAD_SERVICE);
|
||||||
try {
|
try {
|
||||||
manager.enqueue(request);
|
manager.enqueue(request);
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
@ -254,80 +260,30 @@ public class DownloadHandler {
|
|||||||
}
|
}
|
||||||
Utils.showSnackbar(context, context.getString(R.string.download_pending) + ' ' + filename);
|
Utils.showSnackbar(context, context.getString(R.string.download_pending) + ' ' + filename);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private static final String sFileName = "test";
|
// save download in database
|
||||||
private static final String sFileExtension = ".txt";
|
BrowserActivity browserActivity = (BrowserActivity) context;
|
||||||
|
LightningView view = browserActivity.getTabModel().getCurrentTab();
|
||||||
|
|
||||||
/**
|
if (view != null && !view.isIncognito()) {
|
||||||
* Determine whether there is write access in the given directory. Returns false if a
|
downloadsModel.addDownloadIfNotExists(new DownloadItem(url, filename, contentSize))
|
||||||
* file cannot be created in the directory or if the directory does not exist.
|
.subscribe(new SingleOnSubscribe<Boolean>() {
|
||||||
*
|
@Override
|
||||||
* @param directory the directory to check for write access
|
public void onItem(@Nullable Boolean item) {
|
||||||
* @return returns true if the directory can be written to or is in a directory that can
|
if (item != null && !item)
|
||||||
* be written to. false if there is no write access.
|
Log.i(TAG, "error saving download to database");
|
||||||
*/
|
}
|
||||||
public static boolean isWriteAccessAvailable(@Nullable String directory) {
|
});
|
||||||
if (directory == null || directory.isEmpty()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
String dir = addNecessarySlashes(directory);
|
|
||||||
dir = getFirstRealParentDirectory(dir);
|
|
||||||
File file = new File(dir + sFileName + sFileExtension);
|
|
||||||
for (int n = 0; n < 100; n++) {
|
|
||||||
if (!file.exists()) {
|
|
||||||
try {
|
|
||||||
if (file.createNewFile()) {
|
|
||||||
//noinspection ResultOfMethodCallIgnored
|
|
||||||
file.delete();
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
} catch (IOException ignored) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
file = new File(dir + sFileName + '-' + n + sFileExtension);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return file.canWrite();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the first parent directory of a directory that exists. This is useful
|
|
||||||
* for subdirectories that do not exist but their parents do.
|
|
||||||
*
|
|
||||||
* @param directory the directory to find the first existent parent
|
|
||||||
* @return the first existent parent
|
|
||||||
*/
|
|
||||||
@Nullable
|
|
||||||
private static String getFirstRealParentDirectory(@Nullable String directory) {
|
|
||||||
while (true) {
|
|
||||||
if (directory == null || directory.isEmpty()) {
|
|
||||||
return "/";
|
|
||||||
}
|
|
||||||
directory = addNecessarySlashes(directory);
|
|
||||||
File file = new File(directory);
|
|
||||||
if (!file.isDirectory()) {
|
|
||||||
int indexSlash = directory.lastIndexOf('/');
|
|
||||||
if (indexSlash > 0) {
|
|
||||||
String parent = directory.substring(0, indexSlash);
|
|
||||||
int previousIndex = parent.lastIndexOf('/');
|
|
||||||
if (previousIndex > 0) {
|
|
||||||
directory = parent.substring(0, previousIndex);
|
|
||||||
} else {
|
|
||||||
return "/";
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return "/";
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return directory;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isWriteAccessAvailable(@NonNull Uri fileUri) {
|
private static boolean isWriteAccessAvailable(@NonNull Uri fileUri) {
|
||||||
File file = new File(fileUri.getPath());
|
File file = new File(fileUri.getPath());
|
||||||
|
|
||||||
|
if (!file.isDirectory() && !file.mkdirs()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (file.createNewFile()) {
|
if (file.createNewFile()) {
|
||||||
//noinspection ResultOfMethodCallIgnored
|
//noinspection ResultOfMethodCallIgnored
|
||||||
@ -338,19 +294,4 @@ public class DownloadHandler {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public static String addNecessarySlashes(@Nullable String originalPath) {
|
|
||||||
if (originalPath == null || originalPath.length() == 0) {
|
|
||||||
return "/";
|
|
||||||
}
|
|
||||||
if (originalPath.charAt(originalPath.length() - 1) != '/') {
|
|
||||||
originalPath = originalPath + '/';
|
|
||||||
}
|
|
||||||
if (originalPath.charAt(0) != '/') {
|
|
||||||
originalPath = '/' + originalPath;
|
|
||||||
}
|
|
||||||
return originalPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
@ -7,7 +7,6 @@ import android.Manifest;
|
|||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.Dialog;
|
import android.app.Dialog;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.support.annotation.Nullable;
|
|
||||||
import android.support.v7.app.AlertDialog;
|
import android.support.v7.app.AlertDialog;
|
||||||
import android.text.format.Formatter;
|
import android.text.format.Formatter;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
@ -16,12 +15,10 @@ import android.webkit.URLUtil;
|
|||||||
|
|
||||||
import acr.browser.lightning.R;
|
import acr.browser.lightning.R;
|
||||||
import acr.browser.lightning.app.BrowserApp;
|
import acr.browser.lightning.app.BrowserApp;
|
||||||
import acr.browser.lightning.database.downloads.DownloadItem;
|
|
||||||
import acr.browser.lightning.database.downloads.DownloadsModel;
|
import acr.browser.lightning.database.downloads.DownloadsModel;
|
||||||
import acr.browser.lightning.dialog.BrowserDialog;
|
import acr.browser.lightning.dialog.BrowserDialog;
|
||||||
import acr.browser.lightning.preference.PreferenceManager;
|
import acr.browser.lightning.preference.PreferenceManager;
|
||||||
|
|
||||||
import com.anthonycr.bonsai.SingleOnSubscribe;
|
|
||||||
import com.anthonycr.grant.PermissionsManager;
|
import com.anthonycr.grant.PermissionsManager;
|
||||||
import com.anthonycr.grant.PermissionsResultAction;
|
import com.anthonycr.grant.PermissionsResultAction;
|
||||||
|
|
||||||
@ -34,7 +31,7 @@ public class LightningDownloadListener implements DownloadListener {
|
|||||||
private final Activity mActivity;
|
private final Activity mActivity;
|
||||||
|
|
||||||
@Inject PreferenceManager mPreferenceManager;
|
@Inject PreferenceManager mPreferenceManager;
|
||||||
|
@Inject DownloadHandler mDownloadHandler;
|
||||||
@Inject DownloadsModel downloadsModel;
|
@Inject DownloadsModel downloadsModel;
|
||||||
|
|
||||||
public LightningDownloadListener(Activity context) {
|
public LightningDownloadListener(Activity context) {
|
||||||
@ -64,17 +61,7 @@ public class LightningDownloadListener implements DownloadListener {
|
|||||||
public void onClick(DialogInterface dialog, int which) {
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
switch (which) {
|
switch (which) {
|
||||||
case DialogInterface.BUTTON_POSITIVE:
|
case DialogInterface.BUTTON_POSITIVE:
|
||||||
DownloadHandler.onDownloadStart(mActivity, mPreferenceManager, url, userAgent,
|
mDownloadHandler.onDownloadStart(mActivity, mPreferenceManager, url, userAgent, "attachment", null, "");
|
||||||
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;
|
break;
|
||||||
case DialogInterface.BUTTON_NEGATIVE:
|
case DialogInterface.BUTTON_NEGATIVE:
|
||||||
break;
|
break;
|
||||||
|
@ -25,7 +25,7 @@ import acr.browser.lightning.BuildConfig;
|
|||||||
import acr.browser.lightning.R;
|
import acr.browser.lightning.R;
|
||||||
import acr.browser.lightning.constant.Constants;
|
import acr.browser.lightning.constant.Constants;
|
||||||
import acr.browser.lightning.dialog.BrowserDialog;
|
import acr.browser.lightning.dialog.BrowserDialog;
|
||||||
import acr.browser.lightning.download.DownloadHandler;
|
import acr.browser.lightning.utils.FileUtils;
|
||||||
import acr.browser.lightning.utils.ProxyUtils;
|
import acr.browser.lightning.utils.ProxyUtils;
|
||||||
import acr.browser.lightning.utils.ThemeUtils;
|
import acr.browser.lightning.utils.ThemeUtils;
|
||||||
import acr.browser.lightning.utils.Utils;
|
import acr.browser.lightning.utils.Utils;
|
||||||
@ -459,8 +459,8 @@ public class GeneralSettingsFragment extends LightningPreferenceFragment impleme
|
|||||||
public void onClick(DialogInterface dialog, int which) {
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
switch (which) {
|
switch (which) {
|
||||||
case 0:
|
case 0:
|
||||||
mPreferenceManager.setDownloadDirectory(DownloadHandler.DEFAULT_DOWNLOAD_PATH);
|
mPreferenceManager.setDownloadDirectory(FileUtils.DEFAULT_DOWNLOAD_PATH);
|
||||||
downloadloc.setSummary(DownloadHandler.DEFAULT_DOWNLOAD_PATH);
|
downloadloc.setSummary(FileUtils.DEFAULT_DOWNLOAD_PATH);
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
downPicker();
|
downPicker();
|
||||||
@ -539,7 +539,7 @@ public class GeneralSettingsFragment extends LightningPreferenceFragment impleme
|
|||||||
@Override
|
@Override
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
String text = getDownload.getText().toString();
|
String text = getDownload.getText().toString();
|
||||||
text = DownloadHandler.addNecessarySlashes(text);
|
text = FileUtils.addNecessarySlashes(text);
|
||||||
mPreferenceManager.setDownloadDirectory(text);
|
mPreferenceManager.setDownloadDirectory(text);
|
||||||
downloadloc.setSummary(text);
|
downloadloc.setSummary(text);
|
||||||
}
|
}
|
||||||
@ -667,7 +667,7 @@ public class GeneralSettingsFragment extends LightningPreferenceFragment impleme
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void afterTextChanged(@NonNull Editable s) {
|
public void afterTextChanged(@NonNull Editable s) {
|
||||||
if (!DownloadHandler.isWriteAccessAvailable(s.toString())) {
|
if (!FileUtils.isWriteAccessAvailable(s.toString())) {
|
||||||
this.getDownload.setTextColor(this.errorColor);
|
this.getDownload.setTextColor(this.errorColor);
|
||||||
} else {
|
} else {
|
||||||
this.getDownload.setTextColor(this.regularColor);
|
this.getDownload.setTextColor(this.regularColor);
|
||||||
|
@ -9,7 +9,7 @@ import javax.inject.Inject;
|
|||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
import acr.browser.lightning.constant.Constants;
|
import acr.browser.lightning.constant.Constants;
|
||||||
import acr.browser.lightning.download.DownloadHandler;
|
import acr.browser.lightning.utils.FileUtils;
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
public class PreferenceManager {
|
public class PreferenceManager {
|
||||||
@ -150,7 +150,7 @@ public class PreferenceManager {
|
|||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public String getDownloadDirectory() {
|
public String getDownloadDirectory() {
|
||||||
return mPrefs.getString(Name.DOWNLOAD_DIRECTORY, DownloadHandler.DEFAULT_DOWNLOAD_PATH);
|
return mPrefs.getString(Name.DOWNLOAD_DIRECTORY, FileUtils.DEFAULT_DOWNLOAD_PATH);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getFlashSupport() {
|
public int getFlashSupport() {
|
||||||
|
@ -28,6 +28,9 @@ public class FileUtils {
|
|||||||
|
|
||||||
private static final String TAG = "FileUtils";
|
private static final String TAG = "FileUtils";
|
||||||
|
|
||||||
|
public static final String DEFAULT_DOWNLOAD_PATH =
|
||||||
|
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getPath();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Writes a bundle to persistent storage in the files directory
|
* Writes a bundle to persistent storage in the files directory
|
||||||
* using the specified file name. This method is a blocking
|
* using the specified file name. This method is a blocking
|
||||||
@ -160,4 +163,87 @@ public class FileUtils {
|
|||||||
return megaBytes * 1024 * 1024;
|
return megaBytes * 1024 * 1024;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether there is write access in the given directory. Returns false if a
|
||||||
|
* file cannot be created in the directory or if the directory does not exist.
|
||||||
|
*
|
||||||
|
* @param directory the directory to check for write access
|
||||||
|
* @return returns true if the directory can be written to or is in a directory that can
|
||||||
|
* be written to. false if there is no write access.
|
||||||
|
*/
|
||||||
|
public static boolean isWriteAccessAvailable(@Nullable String directory) {
|
||||||
|
if (directory == null || directory.isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final String sFileName = "test";
|
||||||
|
final String sFileExtension = ".txt";
|
||||||
|
String dir = addNecessarySlashes(directory);
|
||||||
|
dir = getFirstRealParentDirectory(dir);
|
||||||
|
File file = new File(dir + sFileName + sFileExtension);
|
||||||
|
for (int n = 0; n < 100; n++) {
|
||||||
|
if (!file.exists()) {
|
||||||
|
try {
|
||||||
|
if (file.createNewFile()) {
|
||||||
|
//noinspection ResultOfMethodCallIgnored
|
||||||
|
file.delete();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} catch (IOException ignored) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
file = new File(dir + sFileName + '-' + n + sFileExtension);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return file.canWrite();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the first parent directory of a directory that exists. This is useful
|
||||||
|
* for subdirectories that do not exist but their parents do.
|
||||||
|
*
|
||||||
|
* @param directory the directory to find the first existent parent
|
||||||
|
* @return the first existent parent
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
private static String getFirstRealParentDirectory(@Nullable String directory) {
|
||||||
|
while (true) {
|
||||||
|
if (directory == null || directory.isEmpty()) {
|
||||||
|
return "/";
|
||||||
|
}
|
||||||
|
directory = addNecessarySlashes(directory);
|
||||||
|
File file = new File(directory);
|
||||||
|
if (!file.isDirectory()) {
|
||||||
|
int indexSlash = directory.lastIndexOf('/');
|
||||||
|
if (indexSlash > 0) {
|
||||||
|
String parent = directory.substring(0, indexSlash);
|
||||||
|
int previousIndex = parent.lastIndexOf('/');
|
||||||
|
if (previousIndex > 0) {
|
||||||
|
directory = parent.substring(0, previousIndex);
|
||||||
|
} else {
|
||||||
|
return "/";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return "/";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return directory;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public static String addNecessarySlashes(@Nullable String originalPath) {
|
||||||
|
if (originalPath == null || originalPath.length() == 0) {
|
||||||
|
return "/";
|
||||||
|
}
|
||||||
|
if (originalPath.charAt(originalPath.length() - 1) != '/') {
|
||||||
|
originalPath = originalPath + '/';
|
||||||
|
}
|
||||||
|
if (originalPath.charAt(0) != '/') {
|
||||||
|
originalPath = '/' + originalPath;
|
||||||
|
}
|
||||||
|
return originalPath;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
*/
|
*/
|
||||||
package acr.browser.lightning.utils;
|
package acr.browser.lightning.utils;
|
||||||
|
|
||||||
import android.Manifest;
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
@ -33,12 +32,8 @@ import android.text.TextUtils;
|
|||||||
import android.util.DisplayMetrics;
|
import android.util.DisplayMetrics;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.webkit.URLUtil;
|
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import com.anthonycr.grant.PermissionsManager;
|
|
||||||
import com.anthonycr.grant.PermissionsResultAction;
|
|
||||||
|
|
||||||
import java.io.Closeable;
|
import java.io.Closeable;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -52,8 +47,6 @@ import acr.browser.lightning.activity.MainActivity;
|
|||||||
import acr.browser.lightning.constant.Constants;
|
import acr.browser.lightning.constant.Constants;
|
||||||
import acr.browser.lightning.database.HistoryItem;
|
import acr.browser.lightning.database.HistoryItem;
|
||||||
import acr.browser.lightning.dialog.BrowserDialog;
|
import acr.browser.lightning.dialog.BrowserDialog;
|
||||||
import acr.browser.lightning.download.DownloadHandler;
|
|
||||||
import acr.browser.lightning.preference.PreferenceManager;
|
|
||||||
|
|
||||||
public final class Utils {
|
public final class Utils {
|
||||||
|
|
||||||
@ -63,35 +56,6 @@ public final class Utils {
|
|||||||
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
|
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Downloads a file from the specified URL. Handles permissions
|
|
||||||
* requests, and creates all the necessary dialogs that must be
|
|
||||||
* showed to the user.
|
|
||||||
*
|
|
||||||
* @param activity activity needed to created dialogs.
|
|
||||||
* @param url url to download from.
|
|
||||||
* @param userAgent the user agent of the browser.
|
|
||||||
* @param contentDisposition the content description of the file.
|
|
||||||
*/
|
|
||||||
public static void downloadFile(@NonNull final Activity activity, @NonNull final PreferenceManager manager, final String url,
|
|
||||||
final String userAgent, final String contentDisposition) {
|
|
||||||
PermissionsManager.getInstance().requestPermissionsIfNecessaryForResult(activity, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE,
|
|
||||||
Manifest.permission.WRITE_EXTERNAL_STORAGE}, new PermissionsResultAction() {
|
|
||||||
@Override
|
|
||||||
public void onGranted() {
|
|
||||||
String fileName = URLUtil.guessFileName(url, null, null);
|
|
||||||
DownloadHandler.onDownloadStart(activity, manager, url, userAgent, contentDisposition, null);
|
|
||||||
Log.i(TAG, "Downloading: " + fileName);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDenied(String permission) {
|
|
||||||
// TODO Show Message
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new intent that can launch the email
|
* Creates a new intent that can launch the email
|
||||||
* app with a subject, address, body, and cc. It
|
* app with a subject, address, body, and cc. It
|
||||||
|
@ -366,8 +366,7 @@ public class LightningWebClient extends WebViewClient {
|
|||||||
String newMimeType = MimeTypeMap.getSingleton()
|
String newMimeType = MimeTypeMap.getSingleton()
|
||||||
.getMimeTypeFromExtension(Utils.guessFileExtension(file.toString()));
|
.getMimeTypeFromExtension(Utils.guessFileExtension(file.toString()));
|
||||||
|
|
||||||
Intent intent = new Intent();
|
Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||||
intent.setAction(Intent.ACTION_VIEW);
|
|
||||||
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||||
Uri contentUri = FileProvider.getUriForFile(mActivity, BuildConfig.APPLICATION_ID + ".fileprovider", file);
|
Uri contentUri = FileProvider.getUriForFile(mActivity, BuildConfig.APPLICATION_ID + ".fileprovider", file);
|
||||||
intent.setDataAndType(contentUri, newMimeType);
|
intent.setDataAndType(contentUri, newMimeType);
|
||||||
@ -377,8 +376,10 @@ public class LightningWebClient extends WebViewClient {
|
|||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
System.out.println("LightningWebClient: cannot open downloaded file");
|
System.out.println("LightningWebClient: cannot open downloaded file");
|
||||||
}
|
}
|
||||||
return true;
|
} else {
|
||||||
|
Utils.showSnackbar(mActivity, R.string.message_open_download_fail);
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -160,7 +160,7 @@
|
|||||||
<string name="export_bookmarks">Exportiere Datensicherung</string>
|
<string name="export_bookmarks">Exportiere Datensicherung</string>
|
||||||
<string name="import_backup">Importiere Lesezeichen aus Datensicherung</string>
|
<string name="import_backup">Importiere Lesezeichen aus Datensicherung</string>
|
||||||
<string name="bookmark_export_path">Lesezeichen exportiert nach</string>
|
<string name="bookmark_export_path">Lesezeichen exportiert nach</string>
|
||||||
<string name="bookmark_settings">Lesezeichen Einstellungen</string>
|
<string name="bookmark_settings">Lesezeichen</string>
|
||||||
<string name="import_bookmark_error">Lesezeichen konnten nicht importiert werden</string>
|
<string name="import_bookmark_error">Lesezeichen konnten nicht importiert werden</string>
|
||||||
<string name="title_chooser">Wähle Datei aus</string>
|
<string name="title_chooser">Wähle Datei aus</string>
|
||||||
<string name="settings_general">Allgemein</string>
|
<string name="settings_general">Allgemein</string>
|
||||||
@ -246,4 +246,5 @@
|
|||||||
<string name="host">Host:</string>
|
<string name="host">Host:</string>
|
||||||
<string name="hosts_source">Quelle für Werbeblocker</string>
|
<string name="hosts_source">Quelle für Werbeblocker</string>
|
||||||
<string name="settings_display">Anzeige</string>
|
<string name="settings_display">Anzeige</string>
|
||||||
|
<string name="message_open_download_fail">Diese Datei existiert nicht mehr</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -229,6 +229,7 @@
|
|||||||
<string name="action_delete_all_bookmarks">Delete all bookmarks</string>
|
<string name="action_delete_all_bookmarks">Delete all bookmarks</string>
|
||||||
<string name="flash_not_supported">Flash Player is not supported by your system</string>
|
<string name="flash_not_supported">Flash Player is not supported by your system</string>
|
||||||
<string name="upsell_plus_version">Upgrade to Lightning Plus to block ads</string>
|
<string name="upsell_plus_version">Upgrade to Lightning Plus to block ads</string>
|
||||||
|
<string name="message_open_download_fail">This file doesn\'t exist anymore</string>
|
||||||
|
|
||||||
<string name="faq">FAQ</string>
|
<string name="faq">FAQ</string>
|
||||||
<string name="faq_description">Frequently asked questions</string>
|
<string name="faq_description">Frequently asked questions</string>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user