Browse Source

Preliminary fix for permissions, fixed a new crash, formatted some code

master
Anthony Restaino 9 years ago
parent
commit
99e4773e45
  1. 32
      app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java
  2. 2
      app/src/main/java/acr/browser/lightning/activity/SettingsActivity.java
  3. 41
      app/src/main/java/acr/browser/lightning/activity/TabsManager.java
  4. 13
      app/src/main/java/acr/browser/lightning/download/FetchUrlMimeType.java
  5. 68
      app/src/main/java/acr/browser/lightning/download/LightningDownloadListener.java
  6. 41
      app/src/main/java/acr/browser/lightning/fragment/BookmarkSettingsFragment.java
  7. 86
      app/src/main/java/acr/browser/lightning/utils/PermissionsManager.java
  8. 21
      app/src/main/java/acr/browser/lightning/utils/Utils.java
  9. 68
      app/src/main/java/acr/browser/lightning/view/LightningChromeClient.java
  10. 8
      app/src/main/java/acr/browser/lightning/view/LightningView.java

32
app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java

@ -11,14 +11,12 @@ import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.app.Activity; import android.app.Activity;
import android.content.ClipData; import android.content.ClipData;
import android.content.ClipboardManager; import android.content.ClipboardManager;
import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.content.IntentFilter; import android.content.IntentFilter;
import android.database.sqlite.SQLiteException; import android.database.sqlite.SQLiteException;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color; import android.graphics.Color;
import android.graphics.PorterDuff; import android.graphics.PorterDuff;
import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.ColorDrawable;
@ -45,7 +43,6 @@ import android.support.v7.graphics.drawable.DrawerArrowDrawable;
import android.support.v7.widget.Toolbar; import android.support.v7.widget.Toolbar;
import android.util.Log; import android.util.Log;
import android.view.KeyEvent; import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.Menu; import android.view.Menu;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.MotionEvent; import android.view.MotionEvent;
@ -77,7 +74,6 @@ import android.widget.EditText;
import android.widget.FrameLayout; import android.widget.FrameLayout;
import android.widget.ImageButton; import android.widget.ImageButton;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout; import android.widget.RelativeLayout;
import android.widget.TextView; import android.widget.TextView;
import android.widget.TextView.OnEditorActionListener; import android.widget.TextView.OnEditorActionListener;
@ -88,8 +84,6 @@ import com.squareup.otto.Subscribe;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.inject.Inject; import javax.inject.Inject;
@ -109,7 +103,6 @@ import acr.browser.lightning.dialog.LightningDialogBuilder;
import acr.browser.lightning.fragment.BookmarksFragment; import acr.browser.lightning.fragment.BookmarksFragment;
import acr.browser.lightning.fragment.TabsFragment; import acr.browser.lightning.fragment.TabsFragment;
import acr.browser.lightning.object.SearchAdapter; import acr.browser.lightning.object.SearchAdapter;
import acr.browser.lightning.preference.PreferenceManager;
import acr.browser.lightning.receiver.NetworkReceiver; import acr.browser.lightning.receiver.NetworkReceiver;
import acr.browser.lightning.utils.PermissionsManager; import acr.browser.lightning.utils.PermissionsManager;
import acr.browser.lightning.utils.ProxyUtils; import acr.browser.lightning.utils.ProxyUtils;
@ -822,7 +815,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
* displays the WebView contained in the LightningView Also handles the * displays the WebView contained in the LightningView Also handles the
* removal of previous views * removal of previous views
* *
* @param position the poition of the tab to display * @param position the poition of the tab to display
*/ */
private synchronized void showTab(final int position) { private synchronized void showTab(final int position) {
final LightningView currentView = tabsManager.getCurrentTab(); final LightningView currentView = tabsManager.getCurrentTab();
@ -1733,7 +1726,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
mToolbarLayout.setTranslationY(0); mToolbarLayout.setTranslationY(0);
if (view != null) { if (view != null) {
view.setTranslationY(height); view.setTranslationY(height);
} }
} }
final LightningView currentTab = tabsManager.getCurrentTab(); final LightningView currentTab = tabsManager.getCurrentTab();
if (currentTab == null) if (currentTab == null)
@ -1755,9 +1748,9 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
show.setInterpolator(new DecelerateInterpolator()); show.setInterpolator(new DecelerateInterpolator());
if (view != null) { if (view != null) {
view.startAnimation(show); view.startAnimation(show);
}
} }
} }
}
} }
/** /**
@ -1848,6 +1841,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
} }
// TODO Check if all the calls are relative to TabsFragement // TODO Check if all the calls are relative to TabsFragement
/** /**
* A utility method that creates a FrameLayout button with the given ID and * A utility method that creates a FrameLayout button with the given ID and
* sets the image of the button to the given image ID. The OnClick and OnLongClick * sets the image of the button to the given image ID. The OnClick and OnLongClick
@ -1880,7 +1874,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
boolean isConnected = isConnected(context); boolean isConnected = isConnected(context);
Log.d(Constants.TAG, "Network Connected: " + String.valueOf(isConnected)); Log.d(Constants.TAG, "Network Connected: " + String.valueOf(isConnected));
tabsManager.notifyConnectioneStatus(isConnected); tabsManager.notifyConnectioneStatus(isConnected);
} }
}; };
/** /**
@ -1894,7 +1888,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
*/ */
@Override @Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
PermissionsManager.getInstance().notifyPermissionsChange(permissions); PermissionsManager.getInstance().notifyPermissionsChange(permissions, grantResults);
super.onRequestPermissionsResult(requestCode, permissions, grantResults); super.onRequestPermissionsResult(requestCode, permissions, grantResults);
} }
@ -2037,7 +2031,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
*/ */
@Subscribe @Subscribe
public void showCloseDialog(final TabEvents.ShowCloseDialog event) { public void showCloseDialog(final TabEvents.ShowCloseDialog event) {
BrowserActivity.this.showCloseDialog(event.position); BrowserActivity.this.showCloseDialog(event.position);
} }
/** /**
@ -2098,13 +2092,13 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
*/ */
@Subscribe @Subscribe
public void newTabLongPress(final TabEvents.NewTabLongPress event) { public void newTabLongPress(final TabEvents.NewTabLongPress event) {
String url = mPreferences.getSavedUrl(); String url = mPreferences.getSavedUrl();
if (url != null) { if (url != null) {
BrowserActivity.this.newTab(url, true); BrowserActivity.this.newTab(url, true);
Utils.showSnackbar(BrowserActivity.this, R.string.deleted_tab); Utils.showSnackbar(BrowserActivity.this, R.string.deleted_tab);
} }
mPreferences.setSavedUrl(null); mPreferences.setSavedUrl(null);
} }
@Subscribe @Subscribe

2
app/src/main/java/acr/browser/lightning/activity/SettingsActivity.java

@ -61,7 +61,7 @@ public class SettingsActivity extends ThemableSettingsActivity {
@Override @Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
PermissionsManager.getInstance().notifyPermissionsChange(permissions); PermissionsManager.getInstance().notifyPermissionsChange(permissions, grantResults);
super.onRequestPermissionsResult(requestCode, permissions, grantResults); super.onRequestPermissionsResult(requestCode, permissions, grantResults);
} }
} }

41
app/src/main/java/acr/browser/lightning/activity/TabsManager.java

@ -1,6 +1,5 @@
package acr.browser.lightning.activity; package acr.browser.lightning.activity;
import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.webkit.WebView; import android.webkit.WebView;
@ -11,7 +10,6 @@ import java.util.List;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
import acr.browser.lightning.controller.BrowserController;
import acr.browser.lightning.preference.PreferenceManager; import acr.browser.lightning.preference.PreferenceManager;
import acr.browser.lightning.utils.Utils; import acr.browser.lightning.utils.Utils;
import acr.browser.lightning.view.LightningView; import acr.browser.lightning.view.LightningView;
@ -57,7 +55,7 @@ public class TabsManager {
* Return a clone of the current tabs list. The list will not be updated, the user has to fetch * Return a clone of the current tabs list. The list will not be updated, the user has to fetch
* a new copy when notified. * a new copy when notified.
* *
* @return a copy of the current tabs list * @return a copy of the current tabs list
*/ */
public List<LightningView> getTabsList() { public List<LightningView> getTabsList() {
return new ArrayList<>(mWebViewList); return new ArrayList<>(mWebViewList);
@ -67,8 +65,8 @@ public class TabsManager {
* Return the tab at the given position in tabs list, or null if position is not in tabs list * Return the tab at the given position in tabs list, or null if position is not in tabs list
* range. * range.
* *
* @param position the index in tabs list * @param position the index in tabs list
* @return the corespondent {@link LightningView}, or null if the index is invalid * @return the corespondent {@link LightningView}, or null if the index is invalid
*/ */
@Nullable @Nullable
public LightningView getTabAtPosition(final int position) { public LightningView getTabAtPosition(final int position) {
@ -83,7 +81,7 @@ public class TabsManager {
* Try to low memory pressure * Try to low memory pressure
*/ */
public void freeMemory() { public void freeMemory() {
for (LightningView tab: mWebViewList) { for (LightningView tab : mWebViewList) {
tab.freeMemory(); tab.freeMemory();
} }
} }
@ -92,7 +90,7 @@ public class TabsManager {
* Shutdown the manager * Shutdown the manager
*/ */
public synchronized void shutdown() { public synchronized void shutdown() {
for (LightningView tab: mWebViewList) { for (LightningView tab : mWebViewList) {
tab.onDestroy(); tab.onDestroy();
} }
mWebViewList.clear(); mWebViewList.clear();
@ -104,7 +102,7 @@ public class TabsManager {
* @param context * @param context
*/ */
public synchronized void resume(final Context context) { public synchronized void resume(final Context context) {
for (LightningView tab: mWebViewList) { for (LightningView tab : mWebViewList) {
tab.initializePreferences(null, context); tab.initializePreferences(null, context);
} }
} }
@ -115,15 +113,16 @@ public class TabsManager {
* @param isConnected * @param isConnected
*/ */
public synchronized void notifyConnectioneStatus(final boolean isConnected) { public synchronized void notifyConnectioneStatus(final boolean isConnected) {
for (LightningView tab: mWebViewList) { for (LightningView tab : mWebViewList) {
final WebView webView = tab.getWebView(); final WebView webView = tab.getWebView();
if (webView != null) { if (webView != null) {
webView.setNetworkAvailable(isConnected); webView.setNetworkAvailable(isConnected);
} }
} }
} }
/** /**
* @return The number of currently opened tabs * @return The number of currently opened tabs
*/ */
public int size() { public int size() {
return mWebViewList.size(); return mWebViewList.size();
@ -149,8 +148,8 @@ public class TabsManager {
/** /**
* Remove a tab and return its reference or null if the position is not in tabs range * Remove a tab and return its reference or null if the position is not in tabs range
* *
* @param position The position of the tab to remove * @param position The position of the tab to remove
* @return The removed tab reference or null * @return The removed tab reference or null
*/ */
@Nullable @Nullable
public synchronized LightningView deleteTab(final int position) { public synchronized LightningView deleteTab(final int position) {
@ -163,22 +162,23 @@ public class TabsManager {
} }
/** /**
* Return the position of the given tab * Return the position of the given tab.
* @param tab *
* @return * @param tab the tab to look for
* @return the position of the tab or -1 if the tab is not in the list
*/ */
public int positionOf(final LightningView tab) { public int positionOf(final LightningView tab) {
return mWebViewList.indexOf(tab); return mWebViewList.indexOf(tab);
} }
/** /**
* @return A string representation of the currently opened tabs * @return A string representation of the currently opened tabs
*/ */
public String tabsString() { public String tabsString() {
final StringBuilder builder = new StringBuilder(); final StringBuilder builder = new StringBuilder();
for (LightningView tab: mWebViewList) { for (LightningView tab : mWebViewList) {
final String url = tab.getUrl(); final String url = tab.getUrl();
if (url != null && !url.isEmpty()) { if (!url.isEmpty()) {
builder.append(url).append("|$|SEPARATOR|$|"); builder.append(url).append("|$|SEPARATOR|$|");
} }
} }
@ -187,6 +187,7 @@ public class TabsManager {
/** /**
* Return the {@link WebView} associated to the current tab, or null if there is no current tab * Return the {@link WebView} associated to the current tab, or null if there is no current tab
*
* @return a {@link WebView} or null * @return a {@link WebView} or null
*/ */
@Nullable @Nullable
@ -196,8 +197,10 @@ public class TabsManager {
/** /**
* TODO We should remove also this, but probably not * TODO We should remove also this, but probably not
*
* @return * @return
*/ */
@Nullable
public LightningView getCurrentTab() { public LightningView getCurrentTab() {
return mCurrentTab; return mCurrentTab;
} }
@ -207,7 +210,7 @@ public class TabsManager {
* call {@link TabsManager#getCurrentTab()} return the same reference returned by this method if * call {@link TabsManager#getCurrentTab()} return the same reference returned by this method if
* position is valid. * position is valid.
* *
* @return the selected tab or null if position is out of tabs range * @return the selected tab or null if position is out of tabs range
*/ */
@Nullable @Nullable
public LightningView switchToTab(final int position) { public LightningView switchToTab(final int position) {

13
app/src/main/java/acr/browser/lightning/download/FetchUrlMimeType.java

@ -6,6 +6,8 @@ package acr.browser.lightning.download;
import android.app.DownloadManager; import android.app.DownloadManager;
import android.content.Context; import android.content.Context;
import android.os.Environment; import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
import android.webkit.MimeTypeMap; import android.webkit.MimeTypeMap;
import android.webkit.URLUtil; import android.webkit.URLUtil;
@ -53,7 +55,7 @@ class FetchUrlMimeType extends Thread {
public void run() { public void run() {
// User agent is likely to be null, though the AndroidHttpClient // User agent is likely to be null, though the AndroidHttpClient
// seems ok with that. // seems ok with that.
final Bus evenBus = BrowserApp.getAppComponent().getBus(); final Bus eventBus = BrowserApp.getAppComponent().getBus();
String mimeType = null; String mimeType = null;
String contentDisposition = null; String contentDisposition = null;
HttpURLConnection connection = null; HttpURLConnection connection = null;
@ -108,6 +110,13 @@ class FetchUrlMimeType extends Thread {
DownloadManager manager = (DownloadManager) mContext DownloadManager manager = (DownloadManager) mContext
.getSystemService(Context.DOWNLOAD_SERVICE); .getSystemService(Context.DOWNLOAD_SERVICE);
manager.enqueue(mRequest); manager.enqueue(mRequest);
evenBus.post(new BrowserEvents.ShowSnackBarMessage(mContext.getString(R.string.download_pending) + ' ' + filename)); Handler handler = new Handler(Looper.getMainLooper());
final String file = filename;
handler.post(new Runnable() {
@Override
public void run() {
eventBus.post(new BrowserEvents.ShowSnackBarMessage(mContext.getString(R.string.download_pending) + ' ' + file));
}
});
} }
} }

68
app/src/main/java/acr/browser/lightning/download/LightningDownloadListener.java

@ -3,7 +3,8 @@
*/ */
package acr.browser.lightning.download; package acr.browser.lightning.download;
import android.content.Context; import android.Manifest;
import android.app.Activity;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.support.v7.app.AlertDialog; import android.support.v7.app.AlertDialog;
import android.util.Log; import android.util.Log;
@ -16,40 +17,51 @@ import acr.browser.lightning.utils.PermissionsManager;
public class LightningDownloadListener implements DownloadListener { public class LightningDownloadListener implements DownloadListener {
private final Context mContext; private final Activity mActivity;
public LightningDownloadListener(Context context) { public LightningDownloadListener(Activity context) {
mContext = context; mActivity = context;
} }
//TODO implement permissions for downloading
@Override @Override
public void onDownloadStart(final String url, final String userAgent, public void onDownloadStart(final String url, final String userAgent,
final String contentDisposition, final String mimetype, long contentLength) { final String contentDisposition, final String mimetype, long contentLength) {
String fileName = URLUtil.guessFileName(url, contentDisposition, mimetype); PermissionsManager.getInstance().requestPermissionsIfNecessary(mActivity, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE,
DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() { Manifest.permission.WRITE_EXTERNAL_STORAGE}, new PermissionsManager.PermissionResult() {
@Override @Override
public void onClick(DialogInterface dialog, int which) { public void onGranted() {
switch (which) { String fileName = URLUtil.guessFileName(url, contentDisposition, mimetype);
case DialogInterface.BUTTON_POSITIVE: DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() {
DownloadHandler.onDownloadStart(mContext, url, userAgent, @Override
contentDisposition, mimetype); public void onClick(DialogInterface dialog, int which) {
break; switch (which) {
case DialogInterface.BUTTON_POSITIVE:
case DialogInterface.BUTTON_NEGATIVE: DownloadHandler.onDownloadStart(mActivity, url, userAgent,
break; contentDisposition, mimetype);
} break;
case DialogInterface.BUTTON_NEGATIVE:
break;
}
}
};
AlertDialog.Builder builder = new AlertDialog.Builder(mActivity); // dialog
builder.setTitle(fileName)
.setMessage(mActivity.getResources().getString(R.string.dialog_download))
.setPositiveButton(mActivity.getResources().getString(R.string.action_download),
dialogClickListener)
.setNegativeButton(mActivity.getResources().getString(R.string.action_cancel),
dialogClickListener).show();
Log.i(Constants.TAG, "Downloading" + fileName);
}
@Override
public void onDenied(String permission) {
//TODO show message
} }
}; });
AlertDialog.Builder builder = new AlertDialog.Builder(mContext); // dialog
builder.setTitle(fileName)
.setMessage(mContext.getResources().getString(R.string.dialog_download))
.setPositiveButton(mContext.getResources().getString(R.string.action_download),
dialogClickListener)
.setNegativeButton(mContext.getResources().getString(R.string.action_cancel),
dialogClickListener).show();
Log.i(Constants.TAG, "Downloading" + fileName);
} }
} }

41
app/src/main/java/acr/browser/lightning/fragment/BookmarkSettingsFragment.java

@ -88,7 +88,7 @@ public class BookmarkSettingsFragment extends PreferenceFragment implements Pref
PermissionsManager permissionsManager = PermissionsManager.getInstance(); PermissionsManager permissionsManager = PermissionsManager.getInstance();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
permissionsManager.requestPermissionsIfNecessary(getActivity(), REQUIRED_PERMISSIONS); permissionsManager.requestPermissionsIfNecessary(getActivity(), REQUIRED_PERMISSIONS, null);
} }
} }
@ -124,15 +124,40 @@ public class BookmarkSettingsFragment extends PreferenceFragment implements Pref
public boolean onPreferenceClick(Preference preference) { public boolean onPreferenceClick(Preference preference) {
switch (preference.getKey()) { switch (preference.getKey()) {
case SETTINGS_EXPORT: case SETTINGS_EXPORT:
if (PermissionsManager.checkPermissions(getActivity(), REQUIRED_PERMISSIONS)) { // if (PermissionsManager.checkPermissions(getActivity(), REQUIRED_PERMISSIONS)) {
mBookmarkManager.exportBookmarks(getActivity()); // mBookmarkManager.exportBookmarks(getActivity());
} // }
PermissionsManager.getInstance().requestPermissionsIfNecessary(getActivity(), REQUIRED_PERMISSIONS,
new PermissionsManager.PermissionResult() {
@Override
public void onGranted() {
mBookmarkManager.exportBookmarks(getActivity());
}
@Override
public void onDenied(String permission) {
//TODO Show message
}
});
return true; return true;
case SETTINGS_IMPORT: case SETTINGS_IMPORT:
if (PermissionsManager.checkPermissions(getActivity(), REQUIRED_PERMISSIONS)) { // if (PermissionsManager.checkPermissions(getActivity(), REQUIRED_PERMISSIONS)) {
loadFileList(null); // loadFileList(null);
createDialog(); // createDialog();
} // }
PermissionsManager.getInstance().requestPermissionsIfNecessary(getActivity(), REQUIRED_PERMISSIONS,
new PermissionsManager.PermissionResult() {
@Override
public void onGranted() {
loadFileList(null);
createDialog();
}
@Override
public void onDenied(String permission) {
//TODO Show message
}
});
return true; return true;
case SETTINGS_IMPORT_BROWSER: case SETTINGS_IMPORT_BROWSER:
new ImportBookmarksTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); new ImportBookmarksTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);

86
app/src/main/java/acr/browser/lightning/utils/PermissionsManager.java

@ -4,8 +4,11 @@ import android.app.Activity;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.os.Build; import android.os.Build;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.ActivityCompat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
@ -13,10 +16,11 @@ import java.util.Set;
/** /**
* Copyright 8/22/2015 Anthony Restaino * Copyright 8/22/2015 Anthony Restaino
*/ */
public class PermissionsManager { public final class PermissionsManager {
private static PermissionsManager mInstance; private static PermissionsManager mInstance;
private final Set<String> mPendingRequests = new HashSet<>(); private final Set<String> mPendingRequests = new HashSet<>();
private final List<PermissionResult> mPendingActions = new ArrayList<>();
public static PermissionsManager getInstance() { public static PermissionsManager getInstance() {
if (mInstance == null) { if (mInstance == null) {
@ -25,34 +29,47 @@ public class PermissionsManager {
return mInstance; return mInstance;
} }
public void requestPermissionsIfNecessary(Activity activity, @NonNull String[] permissions) { private void addPendingAction(@NonNull String[] permissions, @Nullable PermissionResult result) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M || activity == null) { if (result == null) {
return;
}
result.addPermissions(permissions);
mPendingActions.add(result);
}
public void requestPermissionsIfNecessary(@Nullable Activity activity, @NonNull String[] permissions, @Nullable PermissionResult result) {
if (activity == null) {
return;
}
addPendingAction(permissions, result);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
for (String perm : permissions) {
if (result != null) {
result.onResult(perm, PackageManager.PERMISSION_GRANTED);
}
}
return; return;
} }
List<String> permList = new ArrayList<>(); List<String> permList = new ArrayList<>();
for (String perm : permissions) { for (String perm : permissions) {
if (activity.checkSelfPermission(perm) != PackageManager.PERMISSION_GRANTED if (ActivityCompat.checkSelfPermission(activity, perm) != PackageManager.PERMISSION_GRANTED) {
&& !mPendingRequests.contains(perm)) { if (!mPendingRequests.contains(perm)) {
permList.add(perm); permList.add(perm);
}
} else {
if (result != null) {
result.onResult(perm, PackageManager.PERMISSION_GRANTED);
}
} }
} }
if (!permList.isEmpty()) { if (!permList.isEmpty()) {
String[] permsToRequest = permList.toArray(new String[permList.size()]); String[] permsToRequest = permList.toArray(new String[permList.size()]);
mPendingRequests.addAll(permList); mPendingRequests.addAll(permList);
activity.requestPermissions(permsToRequest, 1); ActivityCompat.requestPermissions(activity, permsToRequest, 1);
} }
} }
public static boolean checkPermission(Activity activity, @NonNull String permission) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
return true;
} else if (activity == null) {
return false;
}
return activity.checkSelfPermission(permission) == PackageManager.PERMISSION_GRANTED;
}
public static boolean checkPermissions(Activity activity, @NonNull String[] permissions) { public static boolean checkPermissions(Activity activity, @NonNull String[] permissions) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
return true; return true;
@ -66,9 +83,40 @@ public class PermissionsManager {
return permissionsNecessary; return permissionsNecessary;
} }
public void notifyPermissionsChange(String[] permissions) { public void notifyPermissionsChange(@NonNull String[] permissions, @NonNull int[] results) {
for (String perm : permissions) { int size = permissions.length;
mPendingRequests.remove(perm); if (results.length < size) {
size = results.length;
}
for (int n = 0; n < size; n++) {
for (PermissionResult result : mPendingActions) {
result.onResult(permissions[n], results[n]);
mPendingRequests.remove(permissions[n]);
}
}
}
public static abstract class PermissionResult {
private Set<String> mPermissions = new HashSet<>();
public abstract void onGranted();
public abstract void onDenied(String permission);
public void onResult(String permission, int result) {
if (result == PackageManager.PERMISSION_GRANTED) {
mPermissions.remove(permission);
if (mPermissions.isEmpty()) {
onGranted();
}
} else {
onDenied(permission);
}
}
public void addPermissions(@NonNull String[] perms) {
Collections.addAll(mPermissions, perms);
} }
} }

21
app/src/main/java/acr/browser/lightning/utils/Utils.java

@ -3,6 +3,7 @@
*/ */
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;
@ -44,10 +45,22 @@ public final class Utils {
public static void downloadFile(final Activity activity, final String url, public static void downloadFile(final Activity activity, final String url,
final String userAgent, final String contentDisposition) { final String userAgent, final String contentDisposition) {
String fileName = URLUtil.guessFileName(url, null, null); PermissionsManager.getInstance().requestPermissionsIfNecessary(activity, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE,
DownloadHandler.onDownloadStart(activity, url, userAgent, contentDisposition, null Manifest.permission.WRITE_EXTERNAL_STORAGE}, new PermissionsManager.PermissionResult() {
); @Override
Log.i(Constants.TAG, "Downloading" + fileName); public void onGranted() {
String fileName = URLUtil.guessFileName(url, null, null);
DownloadHandler.onDownloadStart(activity, url, userAgent, contentDisposition, null
);
Log.i(Constants.TAG, "Downloading" + fileName);
}
@Override
public void onDenied(String permission) {
// TODO Show Message
}
});
} }
public static Intent newEmailIntent(String address, String subject, public static Intent newEmailIntent(String address, String subject,

68
app/src/main/java/acr/browser/lightning/view/LightningChromeClient.java

@ -61,12 +61,14 @@ class LightningChromeClient extends WebChromeClient {
if (icon == null) if (icon == null)
return; return;
mLightningView.mTitle.setFavicon(icon); mLightningView.mTitle.setFavicon(icon);
eventBus.post(new BrowserEvents.TabsChanged()); ; eventBus.post(new BrowserEvents.TabsChanged());
;
cacheFavicon(view.getUrl(), icon); cacheFavicon(view.getUrl(), icon);
} }
/** /**
* Naive caching of the favicon according to the domain name of the URL * Naive caching of the favicon according to the domain name of the URL
*
* @param icon the icon to cache * @param icon the icon to cache
*/ */
private void cacheFavicon(final String url, final Bitmap icon) { private void cacheFavicon(final String url, final Bitmap icon) {
@ -112,35 +114,43 @@ class LightningChromeClient extends WebChromeClient {
@Override @Override
public void onGeolocationPermissionsShowPrompt(final String origin, public void onGeolocationPermissionsShowPrompt(final String origin,
final GeolocationPermissions.Callback callback) { final GeolocationPermissions.Callback callback) {
PermissionsManager.getInstance().requestPermissionsIfNecessary(mActivity, PERMISSIONS); PermissionsManager.getInstance().requestPermissionsIfNecessary(mActivity, PERMISSIONS, new PermissionsManager.PermissionResult() {
final boolean remember = true; @Override
AlertDialog.Builder builder = new AlertDialog.Builder(mActivity); public void onGranted() {
builder.setTitle(mActivity.getString(R.string.location)); final boolean remember = true;
String org; AlertDialog.Builder builder = new AlertDialog.Builder(mActivity);
if (origin.length() > 50) { builder.setTitle(mActivity.getString(R.string.location));
org = origin.subSequence(0, 50) + "..."; String org;
} else { if (origin.length() > 50) {
org = origin; org = origin.subSequence(0, 50) + "...";
} } else {
builder.setMessage(org + mActivity.getString(R.string.message_location)) org = origin;
.setCancelable(true) }
.setPositiveButton(mActivity.getString(R.string.action_allow), builder.setMessage(org + mActivity.getString(R.string.message_location))
new DialogInterface.OnClickListener() { .setCancelable(true)
@Override .setPositiveButton(mActivity.getString(R.string.action_allow),
public void onClick(DialogInterface dialog, int id) { new DialogInterface.OnClickListener() {
callback.invoke(origin, true, remember); @Override
} public void onClick(DialogInterface dialog, int id) {
}) callback.invoke(origin, true, remember);
.setNegativeButton(mActivity.getString(R.string.action_dont_allow), }
new DialogInterface.OnClickListener() { })
@Override .setNegativeButton(mActivity.getString(R.string.action_dont_allow),
public void onClick(DialogInterface dialog, int id) { new DialogInterface.OnClickListener() {
callback.invoke(origin, false, remember); @Override
} public void onClick(DialogInterface dialog, int id) {
}); callback.invoke(origin, false, remember);
AlertDialog alert = builder.create(); }
alert.show(); });
AlertDialog alert = builder.create();
alert.show();
}
@Override
public void onDenied(String permission) {
//TODO show message and/or turn off setting
}
});
} }
@Override @Override

8
app/src/main/java/acr/browser/lightning/view/LightningView.java

@ -39,6 +39,7 @@ import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import javax.inject.Inject; import javax.inject.Inject;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -198,9 +199,6 @@ public class LightningView {
if (!mIsIncognitoTab) { if (!mIsIncognitoTab) {
settings.setGeolocationEnabled(mPreferences.getLocationEnabled()); settings.setGeolocationEnabled(mPreferences.getLocationEnabled());
if (mPreferences.getLocationEnabled() && !PermissionsManager.checkPermissions(mActivity, PERMISSIONS)) {
mPermissionsManager.requestPermissionsIfNecessary(mActivity, PERMISSIONS);
}
} else { } else {
settings.setGeolocationEnabled(false); settings.setGeolocationEnabled(false);
} }
@ -527,6 +525,7 @@ public class LightningView {
/** /**
* Naive caching of the favicon according to the domain name of the URL * Naive caching of the favicon according to the domain name of the URL
*
* @param icon the icon to cache * @param icon the icon to cache
*/ */
private void cacheFavicon(final Bitmap icon) { private void cacheFavicon(final Bitmap icon) {
@ -591,6 +590,7 @@ public class LightningView {
public boolean getInvertePage() { public boolean getInvertePage() {
return mInvertPage; return mInvertPage;
} }
/** /**
* handles a long click on the page, parameter String url * handles a long click on the page, parameter String url
* is the url that should have been obtained from the WebView touch node * is the url that should have been obtained from the WebView touch node
@ -741,7 +741,7 @@ public class LightningView {
msg.setTarget(webViewHandler); msg.setTarget(webViewHandler);
mWebView.requestFocusNodeHref(msg); mWebView.requestFocusNodeHref(msg);
} }
} }
} }
/** /**

Loading…
Cancel
Save