import android.annotation.SuppressLint;
import android.app.DialogFragment;
import android.app.DownloadManager;
+import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
import android.content.ClipData;
import android.content.ClipboardManager;
import com.stoutner.privacybrowser.BannerAd;
import com.stoutner.privacybrowser.BuildConfig;
import com.stoutner.privacybrowser.R;
-import com.stoutner.privacybrowser.dialogs.AddDomainDialog;
import com.stoutner.privacybrowser.dialogs.CreateBookmarkDialog;
import com.stoutner.privacybrowser.dialogs.CreateBookmarkFolderDialog;
import com.stoutner.privacybrowser.dialogs.CreateHomeScreenShortcutDialog;
import java.util.Set;
// AppCompatActivity from android.support.v7.app.AppCompatActivity must be used to have access to the SupportActionBar until the minimum API is >= 21.
-public class MainWebViewActivity extends AppCompatActivity implements AddDomainDialog.AddDomainListener, CreateBookmarkDialog.CreateBookmarkListener,
- CreateBookmarkFolderDialog.CreateBookmarkFolderListener, CreateHomeScreenShortcutDialog.CreateHomeScreenSchortcutListener, DownloadFileDialog.DownloadFileListener,
- DownloadImageDialog.DownloadImageListener, DownloadLocationPermissionDialog.DownloadLocationPermissionDialogListener, EditBookmarkDialog.EditBookmarkListener,
- EditBookmarkFolderDialog.EditBookmarkFolderListener, HttpAuthenticationDialog.HttpAuthenticationListener, NavigationView.OnNavigationItemSelectedListener,
- PinnedSslCertificateMismatchDialog.PinnedSslCertificateMismatchListener, SslCertificateErrorDialog.SslCertificateErrorListener, UrlHistoryDialog.UrlHistoryListener {
+public class MainWebViewActivity extends AppCompatActivity implements CreateBookmarkDialog.CreateBookmarkListener, CreateBookmarkFolderDialog.CreateBookmarkFolderListener,
+ CreateHomeScreenShortcutDialog.CreateHomeScreenSchortcutListener, DownloadFileDialog.DownloadFileListener, DownloadImageDialog.DownloadImageListener,
+ DownloadLocationPermissionDialog.DownloadLocationPermissionDialogListener, EditBookmarkDialog.EditBookmarkListener, EditBookmarkFolderDialog.EditBookmarkFolderListener,
+ HttpAuthenticationDialog.HttpAuthenticationListener, NavigationView.OnNavigationItemSelectedListener, PinnedSslCertificateMismatchDialog.PinnedSslCertificateMismatchListener,
+ SslCertificateErrorDialog.SslCertificateErrorListener, UrlHistoryDialog.UrlHistoryListener {
// `darkTheme` is public static so it can be accessed from `AboutActivity`, `GuideActivity`, `AddDomainDialog`, `SettingsActivity`, `DomainsActivity`, `DomainsListFragment`, `BookmarksActivity`,
// `BookmarksDatabaseViewActivity`, `CreateBookmarkDialog`, `CreateBookmarkFolderDialog`, `DownloadFileDialog`, `DownloadImageDialog`, `EditBookmarkDialog`, `EditBookmarkFolderDialog`,
// `privacyBrowserRuntime` is used in `onCreate()`, `onOptionsItemSelected()`, and `applyAppSettings()`.
private Runtime privacyBrowserRuntime;
+ // `proxyThroughOrbot` is used in `onRestart()` and `applyAppSettings()`.
+ boolean proxyThroughOrbot;
+
// `incognitoModeEnabled` is used in `onCreate()` and `applyAppSettings()`.
private boolean incognitoModeEnabled;
mainWebView.setWebViewClient(new WebViewClient() {
// `shouldOverrideUrlLoading` makes this `WebView` the default handler for URLs inside the app, so that links are not kicked out to other apps.
- // We have to use the deprecated `shouldOverrideUrlLoading` until API >= 24.
+ // The deprecated `shouldOverrideUrlLoading` must be used until API >= 24.
@SuppressWarnings("deprecation")
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
- if (url.startsWith("mailto:")) { // Load the email address in an external email program.
+ if (url.startsWith("http")) { // Load the URL in Privacy Browser.
+ // Apply the domain settings for the new URL.
+ applyDomainSettings(url, true);
+
+ // Returning false causes the current `WebView` to handle the URL and prevents it from adding redirects to the history list.
+ return false;
+ } else if (url.startsWith("mailto:")) { // Load the email address in an external email program.
// Use `ACTION_SENDTO` instead of `ACTION_SEND` so that only email programs are launched.
Intent emailIntent = new Intent(Intent.ACTION_SENDTO);
- // Parse the url and set it as the data for the `Intent`.
+ // Parse the url and set it as the data for the intent.
emailIntent.setData(Uri.parse(url));
- // `FLAG_ACTIVITY_NEW_TASK` opens the email program in a new task instead as part of Privacy Browser.
+ // Open the email program in a new task instead of as part of Privacy Browser.
emailIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// Make it so.
startActivity(emailIntent);
- // Returning `true` indicates the application is handling the URL.
+ // Returning true indicates Privacy Browser is handling the URL by creating an intent.
return true;
} else if (url.startsWith("tel:")) { // Load the phone number in the dialer.
- // `ACTION_DIAL` open the dialer and loads the phone number, but waits for the user to place the call.
+ // Open the dialer and load the phone number, but wait for the user to place the call.
Intent dialIntent = new Intent(Intent.ACTION_DIAL);
// Add the phone number to the intent.
dialIntent.setData(Uri.parse(url));
- // `FLAG_ACTIVITY_NEW_TASK` opens the dialer in a new task instead as part of Privacy Browser.
+ // Open the dialer in a new task instead of as part of Privacy Browser.
dialIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// Make it so.
startActivity(dialIntent);
- // Returning `true` indicates the application is handling the URL.
+ // Returning true indicates Privacy Browser is handling the URL by creating an intent.
return true;
- } else { // Load the URL in Privacy Browser.
- // Apply the domain settings for the new URL.
- applyDomainSettings(url, true);
+ } else { // Load a system chooser to select an app that can handle the URL.
+ // Open an app that can handle the URL.
+ Intent genericIntent = new Intent(Intent.ACTION_VIEW);
- // Returning `false` causes the current `WebView` to handle the URL and prevents it from adding redirects to the history list.
- return false;
+ // Add the URL to the intent.
+ genericIntent.setData(Uri.parse(url));
+
+ // List all apps that can handle the URL instead of just opening the first one.
+ genericIntent.addCategory(Intent.CATEGORY_BROWSABLE);
+
+ // Open the app in a new task instead of as part of Privacy Browser.
+ genericIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+ // Start the app or display a snackbar if no app is available to handle the URL.
+ try {
+ startActivity(genericIntent);
+ } catch (ActivityNotFoundException exception) {
+ Snackbar.make(mainWebView, getString(R.string.unrecognized_url) + " " + url, Snackbar.LENGTH_SHORT).show();
+ }
+
+ // Returning true indicates Privacy Browser is handling the URL by creating an intent.
+ return true;
}
}
// Manually delete cache folders.
try {
- // Delete the main `cache` folder.
+ // Delete the main cache directory.
privacyBrowserRuntime.exec("rm -rf " + privateDataDirectoryString + "/cache");
- // Delete the `app_webview` folder, which contains an additional `WebView` cache. See `https://code.google.com/p/android/issues/detail?id=233826&thanks=233826&ts=1486670530`.
- privacyBrowserRuntime.exec("rm -rf " + privateDataDirectoryString + "/app_webview");
+ // Delete the secondary `Service Worker` cache directory.
+ // A `String[]` must be used because the directory contains a space and `Runtime.exec` will not escape the string correctly otherwise.
+ privacyBrowserRuntime.exec(new String[] {"rm", "-rf", privateDataDirectoryString + "/app_webview/Service Worker/"});
} catch (IOException e) {
// Do nothing if an error is thrown.
}
// Run the default commands.
super.onRestart();
+ // Make sure Orbot is running if Privacy Browser is proxying through Orbot.
+ if (proxyThroughOrbot) {
+ // Request Orbot to start. If Orbot is already running no hard will be caused by this request.
+ Intent orbotIntent = new Intent("org.torproject.android.intent.action.START");
+
+ // Send the intent to the Orbot package.
+ orbotIntent.setPackage("org.torproject.android");
+
+ // Make it so.
+ sendBroadcast(orbotIntent);
+ }
+
// Apply the app settings if returning from the Settings activity..
if (reapplyAppSettingsOnRestart) {
// Apply the app settings.
// Make it so.
startActivity(domainsIntent);
} else { // Add a new domain.
- // Show the add domain `AlertDialog`.
- AppCompatDialogFragment addDomainDialog = new AddDomainDialog();
- addDomainDialog.show(getSupportFragmentManager(), getResources().getString(R.string.add_domain));
+ // Apply the new domain settings on returning to `MainWebViewActivity`.
+ reapplyDomainSettingsOnRestart = true;
+ currentDomainName = "";
+
+ // Get the current domain
+ Uri currentUri = Uri.parse(formattedUrlString);
+ String currentDomain = currentUri.getHost();
+
+ // Initialize the database handler. The `0` specifies the database version, but that is ignored and set instead using a constant in `DomainsDatabaseHelper`.
+ DomainsDatabaseHelper domainsDatabaseHelper = new DomainsDatabaseHelper(this, null, null, 0);
+
+ // Create the domain and store the database ID.
+ int newDomainDatabaseId = domainsDatabaseHelper.addDomain(currentDomain);
+
+ // Create an intent to launch the domains activity.
+ Intent domainsIntent = new Intent(this, DomainsActivity.class);
+
+ // Put extra information instructing the domains activity to directly load the new domain.
+ domainsIntent.putExtra("LoadDomain", newDomainDatabaseId);
+
+ // Make it so.
+ startActivity(domainsIntent);
}
return true;
try {
// Delete the main cache directory.
privacyBrowserRuntime.exec("rm -rf " + privateDataDirectoryString + "/cache");
+
// Delete the secondary `Service Worker` cache directory.
- // We have to use a `String[]` because the directory contains a space and `Runtime.exec` will not escape the string correctly otherwise.
+ // A `String[]` must be used because the directory contains a space and `Runtime.exec` will not escape the string correctly otherwise.
privacyBrowserRuntime.exec(new String[] {"rm", "-rf", privateDataDirectoryString + "/app_webview/Service Worker/"});
} catch (IOException e) {
// Do nothing if an error is thrown.
}
}
- @Override
- public void onAddDomain(AppCompatDialogFragment dialogFragment) {
- // Reapply the domain settings on returning to `MainWebViewActivity`.
- reapplyDomainSettingsOnRestart = true;
- currentDomainName = "";
-
- // Get the new domain name `String` from `dialogFragment`.
- EditText domainNameEditText = dialogFragment.getDialog().findViewById(R.id.domain_name_edittext);
- String domainNameString = domainNameEditText.getText().toString();
-
- // Initialize the database handler. `this` specifies the context. The two `nulls` do not specify the database name or a `CursorFactory`.
- // The `0` specifies the database version, but that is ignored and set instead using a constant in `DomainsDatabaseHelper`.
- DomainsDatabaseHelper domainsDatabaseHelper = new DomainsDatabaseHelper(this, null, null, 0);
-
- // Create the domain and store the database ID in `currentDomainDatabaseId`.
- int newDomainDatabaseId = domainsDatabaseHelper.addDomain(domainNameString);
-
- // Create an intent to launch the domains activity.
- Intent domainsIntent = new Intent(this, DomainsActivity.class);
-
- // Put extra information instructing the domains activity to directly load the current domain.
- domainsIntent.putExtra("LoadDomain", newDomainDatabaseId);
-
- // Make it so.
- startActivity(domainsIntent);
- }
-
@Override
public void onCreateBookmark(AppCompatDialogFragment dialogFragment) {
// Get the `EditTexts` from the `dialogFragment`.
String searchCustomURLString = sharedPreferences.getString("search_custom_url", "");
incognitoModeEnabled = sharedPreferences.getBoolean("incognito_mode", false);
boolean doNotTrackEnabled = sharedPreferences.getBoolean("do_not_track", false);
- boolean proxyThroughOrbot = sharedPreferences.getBoolean("proxy_through_orbot", false);
+ proxyThroughOrbot = sharedPreferences.getBoolean("proxy_through_orbot", false);
fullScreenBrowsingModeEnabled = sharedPreferences.getBoolean("full_screen_browsing_mode", false);
hideSystemBarsOnFullscreen = sharedPreferences.getBoolean("hide_system_bars", false);
translucentNavigationBarOnFullscreen = sharedPreferences.getBoolean("translucent_navigation_bar", true);