From dff8b7116c12a739b8f1136e90d107897a6e61fd Mon Sep 17 00:00:00 2001 From: Soren Stoutner Date: Sat, 29 Oct 2016 23:54:05 -0700 Subject: [PATCH] Partial Find on Page implementation. Fix crash on SSLCertificateError for API <= 22. --- .../privacybrowser/MainWebViewActivity.java | 87 ++++++++++++++++--- .../privacybrowser/SslCertificateError.java | 6 +- .../main/res/layout/find_on_page_app_bar.xml | 75 +++++++++------- .../res/layout/main_coordinatorlayout.xml | 30 ++++--- .../main/res/menu/webview_options_menu.xml | 2 - 5 files changed, 138 insertions(+), 62 deletions(-) diff --git a/app/src/main/java/com/stoutner/privacybrowser/MainWebViewActivity.java b/app/src/main/java/com/stoutner/privacybrowser/MainWebViewActivity.java index 9bcc6e4b..15531141 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/MainWebViewActivity.java +++ b/app/src/main/java/com/stoutner/privacybrowser/MainWebViewActivity.java @@ -20,7 +20,6 @@ package com.stoutner.privacybrowser; import android.annotation.SuppressLint; -import android.app.Activity; import android.app.DialogFragment; import android.app.DownloadManager; import android.content.Context; @@ -68,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; @@ -82,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()` and `onOptionsItemSelected()`. + // 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`. @@ -155,7 +155,11 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation // `sslErrorHandler` is used in `onCreate()`, `onSslErrorCancel()`, and `onSslErrorProceed`. private SslErrorHandler sslErrorHandler; - private MenuItem toggleJavaScript; + // `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. @@ -164,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); @@ -179,8 +186,9 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation // 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 { @@ -197,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 @@ -280,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)); } }); @@ -444,7 +473,6 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation updatePrivacyIcons(false); // Get handles for the menu items. - toggleJavaScript = menu.findItem(R.id.toggleJavaScript); MenuItem toggleFirstPartyCookies = menu.findItem(R.id.toggleFirstPartyCookies); MenuItem toggleThirdPartyCookies = menu.findItem(R.id.toggleThirdPartyCookies); MenuItem toggleDomStorage = menu.findItem(R.id.toggleDomStorage); @@ -742,13 +770,29 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation mainWebView.getSettings().setTextZoom(200); return true; - /* case R.id.find_on_page: - appBar.setCustomView(R.layout.find_on_page_app_bar); - toggleJavaScript.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER); - appBar.invalidateOptionsMenu(); + // 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(); @@ -1075,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); } diff --git a/app/src/main/java/com/stoutner/privacybrowser/SslCertificateError.java b/app/src/main/java/com/stoutner/privacybrowser/SslCertificateError.java index c8f3945d..388a09bd 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/SslCertificateError.java +++ b/app/src/main/java/com/stoutner/privacybrowser/SslCertificateError.java @@ -22,12 +22,13 @@ package com.stoutner.privacybrowser; import android.annotation.SuppressLint; import android.app.AlertDialog; import android.app.Dialog; -import android.app.DialogFragment; import android.content.Context; import android.content.DialogInterface; import android.net.http.SslCertificate; import android.net.http.SslError; import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.v7.app.AppCompatDialogFragment; import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.style.ForegroundColorSpan; @@ -36,7 +37,7 @@ import android.widget.TextView; import java.util.Date; -public class SslCertificateError extends DialogFragment { +public class SslCertificateError extends AppCompatDialogFragment { private String primaryError; private String urlWithError; @@ -150,6 +151,7 @@ public class SslCertificateError extends DialogFragment { // `@SuppressLing("InflateParams")` removes the warning about using `null` as the parent view group when inflating the `AlertDialog`. @SuppressLint("InflateParams") @Override + @NonNull public Dialog onCreateDialog(Bundle savedInstanceState) { // Get the activity's layout inflater. LayoutInflater layoutInflater = getActivity().getLayoutInflater(); diff --git a/app/src/main/res/layout/find_on_page_app_bar.xml b/app/src/main/res/layout/find_on_page_app_bar.xml index 3cb0f995..56f0c1e7 100644 --- a/app/src/main/res/layout/find_on_page_app_bar.xml +++ b/app/src/main/res/layout/find_on_page_app_bar.xml @@ -18,47 +18,56 @@ You should have received a copy of the GNU General Public License along with Privacy Browser. If not, see . --> - + + android:layout_width="match_parent" + android:orientation="horizontal" + android:visibility="gone" > + + + + android:id="@+id/find_previous" + android:src="@drawable/previous" + android:layout_width="35dp" + android:layout_height="35dp" + android:layout_marginStart="4dp" + android:layout_marginEnd="4dp" + android:layout_gravity="center_vertical" + android:contentDescription="@string/previous" /> - - - - - - \ No newline at end of file + android:id="@+id/close_find" + android:src="@drawable/close" + android:layout_width="35dp" + android:layout_height="35dp" + android:layout_marginStart="4dp" + android:layout_marginEnd="8dp" + android:layout_gravity="center_vertical" + android:contentDescription="@string/close" + android:onClick="closeFindOnPage" /> + \ No newline at end of file diff --git a/app/src/main/res/layout/main_coordinatorlayout.xml b/app/src/main/res/layout/main_coordinatorlayout.xml index b0d9c1f2..4016d722 100644 --- a/app/src/main/res/layout/main_coordinatorlayout.xml +++ b/app/src/main/res/layout/main_coordinatorlayout.xml @@ -34,30 +34,38 @@ xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" tools:context="com.stoutner.privacybrowser.MainWebViewActivity" - android:layout_width="match_parent" android:layout_height="match_parent" + android:layout_width="match_parent" android:fitsSystemWindows="true" android:focusable="true" android:focusableInTouchMode="true" > + android:layout_width="match_parent" + android:orientation="vertical" > - + + android:layout_width="match_parent" > + + + + + @@ -68,16 +76,16 @@ The `FrameLayout` needs to be before the `NavigationView` or touches on the navigation drawer will not work after exiting full screen video using the back button.--> -