X-Git-Url: https://gitweb.stoutner.com/?a=blobdiff_plain;f=app%2Fsrc%2Fmain%2Fjava%2Fcom%2Fstoutner%2Fprivacybrowser%2FMainWebViewActivity.java;h=15531141913b6263aecaf14b805e8f3f33424e79;hb=dff8b7116c12a739b8f1136e90d107897a6e61fd;hp=104522b600f0b9f467e539d27dc6a69d29d84bce;hpb=0abf9642763f1af98af73b2fc3cc44752a342db3;p=PrivacyBrowserAndroid.git diff --git a/app/src/main/java/com/stoutner/privacybrowser/MainWebViewActivity.java b/app/src/main/java/com/stoutner/privacybrowser/MainWebViewActivity.java index 104522b6..15531141 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/MainWebViewActivity.java +++ b/app/src/main/java/com/stoutner/privacybrowser/MainWebViewActivity.java @@ -20,9 +20,9 @@ package com.stoutner.privacybrowser; import android.annotation.SuppressLint; -import android.app.Activity; import android.app.DialogFragment; import android.app.DownloadManager; +import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.content.res.Configuration; @@ -35,6 +35,8 @@ import android.net.http.SslError; import android.os.Build; import android.os.Bundle; import android.preference.PreferenceManager; +import android.print.PrintDocumentAdapter; +import android.print.PrintManager; import android.support.annotation.NonNull; import android.support.design.widget.NavigationView; import android.support.design.widget.Snackbar; @@ -46,6 +48,7 @@ import android.support.v4.widget.SwipeRefreshLayout; import android.support.v7.app.ActionBar; import android.support.v7.app.ActionBarDrawerToggle; import android.support.v7.app.AppCompatActivity; +import android.support.v7.app.AppCompatDialogFragment; import android.support.v7.widget.Toolbar; import android.util.Patterns; import android.view.KeyEvent; @@ -64,6 +67,7 @@ import android.webkit.WebViewDatabase; import android.widget.EditText; import android.widget.FrameLayout; import android.widget.ImageView; +import android.widget.LinearLayout; import android.widget.ProgressBar; import java.io.UnsupportedEncodingException; @@ -78,7 +82,7 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation SslCertificateError.SslCertificateErrorListener, DownloadFile.DownloadFileListener { // `appBar` is public static so it can be accessed from `OrbotProxyHelper`. - // It is also used in `onCreate()`. + // It is also used in `onCreate()`, `onOptionsItemSelected()`, and `closeFindOnPage()`. public static ActionBar appBar; // `favoriteIcon` is public static so it can be accessed from `CreateHomeScreenShortcut`, `BookmarksActivity`, `CreateBookmark`, `CreateBookmarkFolder`, and `EditBookmark`. @@ -151,6 +155,12 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation // `sslErrorHandler` is used in `onCreate()`, `onSslErrorCancel()`, and `onSslErrorProceed`. private SslErrorHandler sslErrorHandler; + // `findOnPageEditText` is used in `onCreate()`, `onOptionsItemSelected()`, and `closeFindOnPage()`. + private EditText findOnPageEditText; + + // `inputMethodManager` is used in `onOptionsItemSelected()`, `loadUrlFromTextBox()`, and `closeFindOnPage()`. + private InputMethodManager inputMethodManager; + @Override // Remove Android Studio's warning about the dangers of using SetJavaScriptEnabled. The whole premise of Privacy Browser is built around an understanding of these dangers. @SuppressLint("SetJavaScriptEnabled") @@ -158,6 +168,9 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation super.onCreate(savedInstanceState); setContentView(R.layout.main_coordinatorlayout); + // Get a handle for `inputMethodManager`. + inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); + // We need to use the SupportActionBar from android.support.v7.app.ActionBar until the minimum API is >= 21. Toolbar supportAppBar = (Toolbar) findViewById(R.id.appBar); setSupportActionBar(supportAppBar); @@ -166,15 +179,16 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation // This is needed to get rid of the Android Studio warning that appBar might be null. assert appBar != null; - // Add the custom url_bar layout, which shows the favoriteIcon, urlTextBar, and progressBar. - appBar.setCustomView(R.layout.url_bar); + // Add the custom url_app_bar layout, which shows the favoriteIcon, urlTextBar, and progressBar. + appBar.setCustomView(R.layout.url_app_bar); appBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM); // Set the "go" button on the keyboard to load the URL in urlTextBox. urlTextBox = (EditText) appBar.getCustomView().findViewById(R.id.urlTextBox); urlTextBox.setOnKeyListener(new View.OnKeyListener() { + @Override public boolean onKey(View v, int keyCode, KeyEvent event) { - // If the event is a key-down event on the "enter" button, load the URL. + // If the event is a key-down event on the `enter` button, load the URL. if ((event.getAction() == KeyEvent.ACTION_DOWN) && (keyCode == KeyEvent.KEYCODE_ENTER)) { // Load the URL into the mainWebView and consume the event. try { @@ -191,6 +205,27 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation } }); + // Get a handle for `find_on_page_edittext`. + findOnPageEditText = (EditText) findViewById(R.id.find_on_page_edittext); + + // Set the `go` button on the keyboard to search for the phrase in `find_on_page_edittext` + findOnPageEditText.setOnKeyListener(new View.OnKeyListener() { + @Override + public boolean onKey(View v, int keyCode, KeyEvent event) { + // If the event is a key-down event on the `enter` button, search for the phrase. + if ((event.getAction() == KeyEvent.ACTION_DOWN) && (keyCode == KeyEvent.KEYCODE_ENTER)) { + // Search for the phrase. + mainWebView.findAllAsync(findOnPageEditText.getText().toString()); + + // Consume the event. + return true; + } else { + // Do not consume the event. + return false; + } + } + }); + final FrameLayout fullScreenVideoFrameLayout = (FrameLayout) findViewById(R.id.fullScreenVideoFrameLayout); // Implement swipe to refresh @@ -274,8 +309,8 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation sslErrorHandler = handler; // Display the SSL error `AlertDialog`. - DialogFragment sslCertificateErrorDialogFragment = SslCertificateError.displayDialog(error); - sslCertificateErrorDialogFragment.show(getFragmentManager(), getResources().getString(R.string.ssl_certificate_error)); + AppCompatDialogFragment sslCertificateErrorDialogFragment = SslCertificateError.displayDialog(error); + sslCertificateErrorDialogFragment.show(getSupportFragmentManager(), getResources().getString(R.string.ssl_certificate_error)); } }); @@ -349,8 +384,8 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation @Override public void onDownloadStart(String url, String userAgent, String contentDisposition, String mimetype, long contentLength) { // Show the `DownloadFile` `AlertDialog` and name this instance `@string/download`. - DialogFragment downloadFileDialogFragment = DownloadFile.fromUrl(url, contentDisposition, contentLength); - downloadFileDialogFragment.show(getFragmentManager(), getResources().getString(R.string.download)); + AppCompatDialogFragment downloadFileDialogFragment = DownloadFile.fromUrl(url, contentDisposition, contentLength); + downloadFileDialogFragment.show(getSupportFragmentManager(), getResources().getString(R.string.download)); } }); @@ -434,8 +469,8 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation // Set mainMenu so it can be used by `onOptionsItemSelected()` and `updatePrivacyIcons`. mainMenu = menu; - // Set the initial status of the privacy icons. - updatePrivacyIcons(); + // Set the initial status of the privacy icons. `false` does not call `invalidateOptionsMenu` as the last step. + updatePrivacyIcons(false); // Get handles for the menu items. MenuItem toggleFirstPartyCookies = menu.findItem(R.id.toggleFirstPartyCookies); @@ -573,8 +608,8 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation // Apply the new JavaScript status. mainWebView.getSettings().setJavaScriptEnabled(javaScriptEnabled); - // Update the privacy icon. - updatePrivacyIcons(); + // Update the privacy icon. `true` runs `invalidateOptionsMenu` as the last step. + updatePrivacyIcons(true); // Display a `Snackbar`. if (javaScriptEnabled) { // JavaScrip is enabled. @@ -599,8 +634,8 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation // Apply the new cookie status. cookieManager.setAcceptCookie(firstPartyCookiesEnabled); - // Update the privacy icon. - updatePrivacyIcons(); + // Update the privacy icon. `true` runs `invalidateOptionsMenu` as the last step. + updatePrivacyIcons(true); // Display a `Snackbar`. if (firstPartyCookiesEnabled) { // First-party cookies are enabled. @@ -648,6 +683,9 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation // Apply the new DOM Storage status. mainWebView.getSettings().setDomStorageEnabled(domStorageEnabled); + // Update the privacy icon. `true` runs `invalidateOptionsMenu` as the last step. + updatePrivacyIcons(true); + // Display a `Snackbar`. if (domStorageEnabled) { Snackbar.make(findViewById(R.id.mainWebView), R.string.dom_storage_enabled, Snackbar.LENGTH_SHORT).show(); @@ -676,6 +714,9 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation Snackbar.make(findViewById(R.id.mainWebView), R.string.form_data_disabled, Snackbar.LENGTH_SHORT).show(); } + // Update the privacy icon. `true` runs `invalidateOptionsMenu` as the last step. + updatePrivacyIcons(true); + // Reload the WebView. mainWebView.reload(); return true; @@ -729,6 +770,30 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation mainWebView.getSettings().setTextZoom(200); return true; + case R.id.find_on_page: + // Hide the URL app bar. + Toolbar appBarToolbar = (Toolbar) findViewById(R.id.appBar); + appBarToolbar.setVisibility(View.GONE); + + // Show the Find on Page `RelativeLayout`. + LinearLayout findOnPageLinearLayout = (LinearLayout) findViewById(R.id.find_on_page_linearlayout); + findOnPageLinearLayout.setVisibility(View.VISIBLE); + + // Display the keyboard. We have to wait 200 ms before running the command to work around a bug in Android. + findOnPageEditText.postDelayed(new Runnable() + { + @Override + public void run() + { + // Set the focus on `findOnPageEditText`. + findOnPageEditText.requestFocus(); + + // Display the keyboard. + inputMethodManager.showSoftInput(findOnPageEditText, 0); + } + }, 200); + return true; + case R.id.share: Intent shareIntent = new Intent(); shareIntent.setAction(Intent.ACTION_SEND); @@ -739,12 +804,23 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation case R.id.addToHomescreen: // Show the `CreateHomeScreenShortcut` `AlertDialog` and name this instance `@string/create_shortcut`. - DialogFragment createHomeScreenShortcutDialogFragment = new CreateHomeScreenShortcut(); - createHomeScreenShortcutDialogFragment.show(getFragmentManager(), getResources().getString(R.string.create_shortcut)); + AppCompatDialogFragment createHomeScreenShortcutDialogFragment = new CreateHomeScreenShortcut(); + createHomeScreenShortcutDialogFragment.show(getSupportFragmentManager(), getResources().getString(R.string.create_shortcut)); //Everything else will be handled by `CreateHomeScreenShortcut` and the associated listener below. return true; + case R.id.print: + // Get a `PrintManager` instance. + PrintManager printManager = (PrintManager) getSystemService(Context.PRINT_SERVICE); + + // Convert `mainWebView` to `printDocumentAdapter`. + PrintDocumentAdapter printDocumentAdapter = mainWebView.createPrintDocumentAdapter(); + + // Print the document. The print attributes are `null`. + printManager.print(getResources().getString(R.string.privacy_browser_web_page), printDocumentAdapter, null); + return true; + case R.id.refresh: mainWebView.reload(); return true; @@ -846,12 +922,15 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation // Destroy the internal state of the webview. mainWebView.destroy(); - // Close Privacy Browser. finishAndRemoveTask also removes Privacy Browser from the recent app list. + // Close Privacy Browser. `finishAndRemoveTask` also removes Privacy Browser from the recent app list. if (Build.VERSION.SDK_INT >= 21) { finishAndRemoveTask(); } else { finish(); } + + // Remove the terminated program from RAM. The status code is `0`. + System.exit(0); break; default: @@ -882,11 +961,11 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation adView = findViewById(R.id.adView); // `invalidateOptionsMenu` should recalculate the number of action buttons from the menu to display on the app bar, but it doesn't because of the this bug: https://code.google.com/p/android/issues/detail?id=20493#c8 - invalidateOptionsMenu(); + // ActivityCompat.invalidateOptionsMenu(this); } @Override - public void onCreateHomeScreenShortcut(DialogFragment dialogFragment) { + public void onCreateHomeScreenShortcut(AppCompatDialogFragment dialogFragment) { // Get shortcutNameEditText from the alert dialog. EditText shortcutNameEditText = (EditText) dialogFragment.getDialog().findViewById(R.id.shortcut_name_edittext); @@ -905,7 +984,7 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation } @Override - public void onDownloadFile(DialogFragment dialogFragment, String downloadUrl) { + public void onDownloadFile(AppCompatDialogFragment dialogFragment, String downloadUrl) { DownloadManager downloadManager = (DownloadManager) getSystemService(DOWNLOAD_SERVICE); DownloadManager.Request downloadRequest = new DownloadManager.Request(Uri.parse(downloadUrl)); @@ -913,9 +992,12 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation EditText downloadFileNameEditText = (EditText) dialogFragment.getDialog().findViewById(R.id.download_file_name); String fileName = downloadFileNameEditText.getText().toString(); - // Set the download save in the the `DIRECTORY_DOWNLOADS`using `fileName`. // Once we have `WRITE_EXTERNAL_STORAGE` permissions we can use `setDestinationInExternalPublicDir`. - downloadRequest.setDestinationInExternalFilesDir(this, "/", fileName); + if (Build.VERSION.SDK_INT >= 23) { // If API >= 23, set the download save in the the `DIRECTORY_DOWNLOADS` using `fileName`. + downloadRequest.setDestinationInExternalFilesDir(this, "/", fileName); + } else { // Only set the title using `fileName`. + downloadRequest.setTitle(fileName); + } // Allow `MediaScanner` to index the download if it is a media file. downloadRequest.allowScanningByMediaScanner(); @@ -988,8 +1070,8 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation // Apply the settings from shared preferences, which might have been changed in `SettingsActivity`. applySettings(); - // Update the privacy icons. - updatePrivacyIcons(); + // Update the privacy icon. `true` runs `invalidateOptionsMenu` as the last step. + updatePrivacyIcons(true); } @@ -1037,8 +1119,23 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation mainWebView.loadUrl(formattedUrlString, customHeaders); - // Hides the keyboard so we can see the webpage. - InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Activity.INPUT_METHOD_SERVICE); + // Hides the keyboard so we can see the webpage. `0` indicates no additional flags. + inputMethodManager.hideSoftInputFromWindow(mainWebView.getWindowToken(), 0); + } + + public void closeFindOnPage(View view) { + // Delete the contents of `find_on_page_edittext`. + findOnPageEditText.setText(null); + + // Hide the Find on Page `RelativeLayout`. + LinearLayout findOnPageLinearLayout = (LinearLayout) findViewById(R.id.find_on_page_linearlayout); + findOnPageLinearLayout.setVisibility(View.GONE); + + // Show the URL app bar. + Toolbar appBarToolbar = (Toolbar) findViewById(R.id.appBar); + appBarToolbar.setVisibility(View.VISIBLE); + + // Hides the keyboard so we can see the webpage. `0` indicates no additional flags. inputMethodManager.hideSoftInputFromWindow(mainWebView.getWindowToken(), 0); } @@ -1133,7 +1230,7 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation } } - private void updatePrivacyIcons() { + private void updatePrivacyIcons(boolean runInvalidateOptionsMenu) { // Get handles for the icons. MenuItem privacyIcon = mainMenu.findItem(R.id.toggleJavaScript); MenuItem firstPartyCookiesIcon = mainMenu.findItem(R.id.toggleFirstPartyCookies); @@ -1159,7 +1256,7 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation // Update `domStorageIcon`. if (javaScriptEnabled && domStorageEnabled) { // Both JavaScript and DOM storage are enabled. domStorageIcon.setIcon(R.drawable.dom_storage_enabled); - } else if (javaScriptEnabled){ // JavaScript is enabled but DOM storage is disabled. + } else if (javaScriptEnabled) { // JavaScript is enabled but DOM storage is disabled. domStorageIcon.setIcon(R.drawable.dom_storage_disabled); } else { // JavaScript is disabled, so DOM storage is ghosted. domStorageIcon.setIcon(R.drawable.dom_storage_ghosted); @@ -1172,8 +1269,9 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation formDataIcon.setIcon(R.drawable.form_data_disabled); } - // `invalidateOptionsMenu` calls `onPrepareOptionsMenu()` and redraws the icons in the `AppBar`. - // `this` references the current activity. - ActivityCompat.invalidateOptionsMenu(this); + // `invalidateOptionsMenu` calls `onPrepareOptionsMenu()` and redraws the icons in the `AppBar`. `this` references the current activity. + if (runInvalidateOptionsMenu) { + ActivityCompat.invalidateOptionsMenu(this); + } } }