Migrate to AndroidX from the Android Support Library. https://redmine.stoutner.com...
[PrivacyBrowser.git] / app / src / main / java / com / stoutner / privacybrowser / activities / ViewSourceActivity.java
index 67898509f28856ec41ded9ada9e718242160156b..052750b88576c8f989c1ba69c27168d727e4eef7 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright © 2017-2018 Soren Stoutner <soren@stoutner.com>.
+ * Copyright © 2017-2019 Soren Stoutner <soren@stoutner.com>.
  *
  * This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
  *
@@ -29,11 +29,6 @@ import android.os.Build;
 import android.os.Bundle;
 import android.os.LocaleList;
 import android.preference.PreferenceManager;
-import android.support.v4.app.NavUtils;
-import android.support.v4.widget.SwipeRefreshLayout;
-import android.support.v7.app.ActionBar;
-import android.support.v7.app.AppCompatActivity;
-import android.support.v7.widget.Toolbar;
 import android.text.SpannableStringBuilder;
 import android.text.Spanned;
 import android.text.style.ForegroundColorSpan;
@@ -49,6 +44,12 @@ import android.widget.EditText;
 import android.widget.ProgressBar;
 import android.widget.TextView;
 
+import androidx.appcompat.app.ActionBar;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.appcompat.widget.Toolbar;  // The AndroidX toolbar must be used until the minimum API is >= 21.
+import androidx.core.app.NavUtils;
+import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
+
 import com.stoutner.privacybrowser.R;
 import com.stoutner.privacybrowser.dialogs.AboutViewSourceDialog;
 
@@ -93,19 +94,19 @@ public class ViewSourceActivity extends AppCompatActivity {
         // Set the content view.
         setContentView(R.layout.view_source_coordinatorlayout);
 
-        // `SupportActionBar` from `android.support.v7.app.ActionBar` must be used until the minimum API is >= 21.
-        Toolbar viewSourceAppBar = findViewById(R.id.view_source_toolbar);
-        setSupportActionBar(viewSourceAppBar);
+        // The AndroidX toolbar must be used until the minimum API is >= 21.
+        Toolbar toolbar = findViewById(R.id.view_source_toolbar);
+        setSupportActionBar(toolbar);
 
-        // Setup the app bar.
-        final ActionBar appBar = getSupportActionBar();
+        // Get a handle for the action bar.
+        final ActionBar actionBar = getSupportActionBar();
 
-        // Remove the incorrect warning in Android Studio that appBar might be null.
-        assert appBar != null;
+        // Remove the incorrect lint warning that the action bar might be null.
+        assert actionBar != null;
 
-        // Add the custom layout to the app bar.
-        appBar.setCustomView(R.layout.view_source_app_bar);
-        appBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM);
+        // Add the custom layout to the action bar.
+        actionBar.setCustomView(R.layout.view_source_app_bar);
+        actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM);
 
         // Get a handle for the url text box.
         EditText urlEditText = findViewById(R.id.url_edittext);
@@ -141,10 +142,11 @@ public class ViewSourceActivity extends AppCompatActivity {
                 // Hide the soft keyboard.
                 inputMethodManager.hideSoftInputFromWindow(urlEditText.getWindowToken(), 0);
 
+                // Move to the beginning of the string.
+                urlEditText.setSelection(0);
+
                 // Reapply the highlighting.
                 highlightUrlText();
-
-
             }
         });
 
@@ -158,8 +160,13 @@ public class ViewSourceActivity extends AppCompatActivity {
                 // Remove the focus from the URL box.
                 urlEditText.clearFocus();
 
-                // Get new source data for the current URL.
-                new GetSource(this).execute(urlEditText.getText().toString());
+                // Get the URL.
+                String url = urlEditText.getText().toString();
+
+                // Get new source data for the current URL if it beings with `http`.
+                if (url.startsWith("http")) {
+                    new GetSource(this).execute(url);
+                }
 
                 // Consume the key press.
                 return true;
@@ -171,7 +178,18 @@ public class ViewSourceActivity extends AppCompatActivity {
 
         // Implement swipe to refresh.
         SwipeRefreshLayout swipeRefreshLayout = findViewById(R.id.view_source_swiperefreshlayout);
-        swipeRefreshLayout.setOnRefreshListener(() -> new GetSource(this).execute(urlEditText.getText().toString()));
+        swipeRefreshLayout.setOnRefreshListener(() -> {
+            // Get the URL.
+            String url = urlEditText.getText().toString();
+
+            // Get new source data for the URL if it begins with `http`.
+            if (url.startsWith("http")) {
+                new GetSource(this).execute(url);
+            } else {
+                // Stop the refresh animation.
+                swipeRefreshLayout.setRefreshing(false);
+            }
+        });
 
         // Set the swipe to refresh color according to the theme.
         if (MainWebViewActivity.darkTheme) {
@@ -181,13 +199,15 @@ public class ViewSourceActivity extends AppCompatActivity {
             swipeRefreshLayout.setColorSchemeResources(R.color.blue_700);
         }
 
-        // Get the source using an AsyncTask.
-        new GetSource(this).execute(formattedUrlString);
+        // Get the source using an AsyncTask if the URL begins with `http`.
+        if (formattedUrlString.startsWith("http")) {
+            new GetSource(this).execute(formattedUrlString);
+        }
     }
 
     @Override
     public boolean onCreateOptionsMenu(Menu menu) {
-        // Inflate the menu; this adds items to the action bar if it is present.
+        // Inflate the menu.  This adds items to the action bar if it is present.
         getMenuInflater().inflate(R.menu.view_source_options_menu, menu);
 
         // Display the menu.
@@ -218,52 +238,61 @@ public class ViewSourceActivity extends AppCompatActivity {
         // Get the URL string.
         String urlString = urlEditText.getText().toString();
 
-        // Get the index of the `/` immediately after the domain name.
-        int endOfDomainName = urlString.indexOf("/", (urlString.indexOf("//") + 2));
+        // Highlight the URL according to the protocol.
+        if (urlString.startsWith("file://")) {  // This is a file URL.
+            // De-emphasize only the protocol.
+            urlEditText.getText().setSpan(initialGrayColorSpan, 0, 7, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+        } else if (urlString.startsWith("content://")) {
+            // De-emphasize only the protocol.
+            urlEditText.getText().setSpan(initialGrayColorSpan, 0, 10, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+        } else {  // This is a web URL.
+            // Get the index of the `/` immediately after the domain name.
+            int endOfDomainName = urlString.indexOf("/", (urlString.indexOf("//") + 2));
 
-        // Create a base URL string.
-        String baseUrl;
+            // Create a base URL string.
+            String baseUrl;
 
-        // Get the base URL.
-        if (endOfDomainName > 0) {  // There is at least one character after the base URL.
             // Get the base URL.
-            baseUrl = urlString.substring(0, endOfDomainName);
-        } else {  // There are no characters after the base URL.
-            // Set the base URL to be the entire URL string.
-            baseUrl = urlString;
-        }
+            if (endOfDomainName > 0) {  // There is at least one character after the base URL.
+                // Get the base URL.
+                baseUrl = urlString.substring(0, endOfDomainName);
+            } else {  // There are no characters after the base URL.
+                // Set the base URL to be the entire URL string.
+                baseUrl = urlString;
+            }
 
-        // Get the index of the last `.` in the domain.
-        int lastDotIndex = baseUrl.lastIndexOf(".");
+            // Get the index of the last `.` in the domain.
+            int lastDotIndex = baseUrl.lastIndexOf(".");
 
-        // Get the index of the penultimate `.` in the domain.
-        int penultimateDotIndex = baseUrl.lastIndexOf(".", lastDotIndex - 1);
+            // Get the index of the penultimate `.` in the domain.
+            int penultimateDotIndex = baseUrl.lastIndexOf(".", lastDotIndex - 1);
 
-        // Markup the beginning of the URL.
-        if (urlString.startsWith("http://")) {  // Highlight the protocol of connections that are not encrypted.
-            urlEditText.getText().setSpan(redColorSpan, 0, 7, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+            // Markup the beginning of the URL.
+            if (urlString.startsWith("http://")) {  // Highlight the protocol of connections that are not encrypted.
+                urlEditText.getText().setSpan(redColorSpan, 0, 7, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
 
-            // De-emphasize subdomains.
-            if (penultimateDotIndex > 0)  {  // There is more than one subdomain in the domain name.
-                urlEditText.getText().setSpan(initialGrayColorSpan, 7, penultimateDotIndex + 1, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
-            }
-        } else if (urlString.startsWith("https://")) {  // De-emphasize the protocol of connections that are encrypted.
-            if (penultimateDotIndex > 0) {  // There is more than one subdomain in the domain name.
-                // De-emphasize the protocol and the additional subdomains.
-                urlEditText.getText().setSpan(initialGrayColorSpan, 0, penultimateDotIndex + 1, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
-            } else {  // There is only one subdomain in the domain name.
-                // De-emphasize only the protocol.
-                urlEditText.getText().setSpan(initialGrayColorSpan, 0, 8, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+                // De-emphasize subdomains.
+                if (penultimateDotIndex > 0) {  // There is more than one subdomain in the domain name.
+                    urlEditText.getText().setSpan(initialGrayColorSpan, 7, penultimateDotIndex + 1, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+                }
+            } else if (urlString.startsWith("https://")) {  // De-emphasize the protocol of connections that are encrypted.
+                if (penultimateDotIndex > 0) {  // There is more than one subdomain in the domain name.
+                    // De-emphasize the protocol and the additional subdomains.
+                    urlEditText.getText().setSpan(initialGrayColorSpan, 0, penultimateDotIndex + 1, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+                } else {  // There is only one subdomain in the domain name.
+                    // De-emphasize only the protocol.
+                    urlEditText.getText().setSpan(initialGrayColorSpan, 0, 8, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+                }
             }
-        }
 
-        // De-emphasize the text after the domain name.
-        if (endOfDomainName > 0) {
-            urlEditText.getText().setSpan(finalGrayColorSpan, endOfDomainName, urlString.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+            // De-emphasize the text after the domain name.
+            if (endOfDomainName > 0) {
+                urlEditText.getText().setSpan(finalGrayColorSpan, endOfDomainName, urlString.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+            }
         }
     }
 
-    // `String` declares the parameters.  `Void` does not declare progress units.  `String[]` contains the results.
+    // `String` declares the parameters.  `Void` does not declare progress units.  `SpannableStringBuilder[]` contains the results.
     private static class GetSource extends AsyncTask<String, Void, SpannableStringBuilder[]> {
         // Create a weak reference to the calling activity.
         private WeakReference<Activity> activityWeakReference;
@@ -280,7 +309,7 @@ public class ViewSourceActivity extends AppCompatActivity {
             Activity viewSourceActivity = activityWeakReference.get();
 
             // Abort if the activity is gone.
-            if ((viewSourceActivity == null) || (viewSourceActivity.isFinishing())) {
+            if ((viewSourceActivity == null) || viewSourceActivity.isFinishing()) {
                 return;
             }
 
@@ -306,7 +335,7 @@ public class ViewSourceActivity extends AppCompatActivity {
             Activity activity = activityWeakReference.get();
 
             // Abort if the activity is gone.
-            if ((activity == null) || (activity.isFinishing())) {
+            if ((activity == null) || activity.isFinishing()) {
                 return new SpannableStringBuilder[] {requestHeadersBuilder, responseMessageBuilder, responseHeadersBuilder, responseBodyBuilder};
             }
 
@@ -635,11 +664,11 @@ public class ViewSourceActivity extends AppCompatActivity {
         // `onPostExecute()` operates on the UI thread.
         @Override
         protected void onPostExecute(SpannableStringBuilder[] viewSourceStringArray){
-            // Get a handle the activity.
+            // Get a handle for the activity.
             Activity activity = activityWeakReference.get();
 
             // Abort if the activity is gone.
-            if ((activity == null) || (activity.isFinishing())) {
+            if ((activity == null) || activity.isFinishing()) {
                 return;
             }
 
@@ -651,7 +680,7 @@ public class ViewSourceActivity extends AppCompatActivity {
             ProgressBar progressBar = activity.findViewById(R.id.progress_bar);
             SwipeRefreshLayout swipeRefreshLayout = activity.findViewById(R.id.view_source_swiperefreshlayout);
 
-            // Populate the text views.
+            // Populate the text views.  This can take a long time, and freeze the user interface, if the response body is particularly large.
             requestHeadersTextView.setText(viewSourceStringArray[0]);
             responseMessageTextView.setText(viewSourceStringArray[1]);
             responseHeadersTextView.setText(viewSourceStringArray[2]);