7d5b63fda042f7577743acfb58cc74c183b36ff9
[PrivacyBrowser.git] / app / src / main / java / com / stoutner / privacybrowser / Webview.java
1 package com.stoutner.privacybrowser;
2
3 import android.annotation.SuppressLint;
4 import android.annotation.TargetApi;
5 import android.app.Activity;
6 import android.content.ClipData;
7 import android.content.ClipboardManager;
8 import android.content.Context;
9 import android.content.Intent;
10 import android.graphics.Bitmap;
11 import android.net.Uri;
12 import android.os.Bundle;
13 import android.support.v7.app.ActionBar;
14 import android.support.v7.app.AppCompatActivity;
15 import android.util.Patterns;
16 import android.view.KeyEvent;
17 import android.view.Menu;
18 import android.view.MenuItem;
19 import android.view.View;
20 import android.view.inputmethod.InputMethodManager;
21 import android.webkit.WebChromeClient;
22 import android.webkit.WebView;
23 import android.webkit.WebViewClient;
24 import android.widget.EditText;
25 import android.widget.ImageView;
26 import android.widget.ProgressBar;
27 import java.io.UnsupportedEncodingException;
28 import java.net.MalformedURLException;
29 import java.net.URL;
30 import java.net.URLEncoder;
31
32 public class Webview extends AppCompatActivity {
33
34     static String formattedUrlString;
35     static WebView mainWebView;
36     static ProgressBar progressBar;
37     static EditText urlTextBox;
38     static ImageView favoriteIcon;
39     static final String homepage = "https://www.duckduckgo.com/";
40
41     // Remove Android Studio's warning about the dangers of using SetJavaScriptEnabled.
42     @SuppressLint("SetJavaScriptEnabled")
43
44     @Override
45     protected void onCreate(Bundle savedInstanceState) {
46         super.onCreate(savedInstanceState);
47         setContentView(R.layout.activity_webview);
48
49         mainWebView = (WebView) findViewById(R.id.mainWebView);
50
51         final ActionBar actionBar = getSupportActionBar();
52         if (actionBar != null) {
53             // Remove the title from the action bar.
54             actionBar.setDisplayShowTitleEnabled(false);
55
56             // Add the custom app_bar layout, which shows the favoriteIcon, urlTextBar, and progressBar.
57             actionBar.setCustomView(R.layout.app_bar);
58             actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM);
59
60             // Initialize the variables for favoriteIcon, urlTextBox, and progressBar
61             favoriteIcon = (ImageView) actionBar.getCustomView().findViewById(R.id.favoriteIcon);
62             urlTextBox = (EditText) actionBar.getCustomView().findViewById(R.id.urlTextBox);
63             progressBar = (ProgressBar) actionBar.getCustomView().findViewById(R.id.progressBar);
64         }
65
66         mainWebView.setWebViewClient(new WebViewClient() {
67
68             // setWebViewClient makes this WebView the default handler for URLs inside the app, so that links are not kicked out to other apps.
69             // Save the URL to formattedUrlString and update urlTextBox before loading mainWebView.
70             @Override
71             public boolean shouldOverrideUrlLoading(WebView view, String url) {
72                 mainWebView.loadUrl(url);
73                 return true;
74             }
75
76             // Update the URL in urlTextBox when the page starts to load.
77             @Override
78             public void onPageStarted(WebView view, String url, Bitmap favicon) {
79                 urlTextBox.setText(url);
80             }
81
82             // Update formattedUrlString and urlTextBox.  It is necessary to do this after the page finishes loading because the final URL can change during load.
83             @Override
84             public void onPageFinished(WebView view, String url) {
85                 formattedUrlString = url;
86                 urlTextBox.setText(formattedUrlString);
87             }
88         });
89
90         mainWebView.setWebChromeClient(new WebChromeClient() {
91
92             // Update the progress bar when a page is loading.
93             @Override
94             public void onProgressChanged(WebView view, int progress) {
95                 progressBar.setProgress(progress);
96                 if (progress < 100) {
97                     progressBar.setVisibility(View.VISIBLE);
98                 } else {
99                     progressBar.setVisibility(View.GONE);
100                 }
101             }
102
103             // Set the favorite icon when it changes.
104             @Override
105             public void onReceivedIcon(WebView view, Bitmap icon) {
106                 favoriteIcon.setImageBitmap(Bitmap.createScaledBitmap(icon, 64, 64, true));
107             }
108         });
109
110         // Set the "go" button on the keyboard to load the URL.
111         urlTextBox.setOnKeyListener(new View.OnKeyListener() {
112             public boolean onKey(View v, int keyCode, KeyEvent event) {
113
114                 // If the event is a key-down event on the "enter" button, load the URL.
115                 if ((event.getAction() == KeyEvent.ACTION_DOWN) &&
116                         (keyCode == KeyEvent.KEYCODE_ENTER)) {
117                     // Load the URL into the mainWebView and consume the event.
118                     try {
119                         loadUrlFromTextBox(mainWebView);
120                     } catch (UnsupportedEncodingException e) {
121                         e.printStackTrace();
122                     }
123                     // If the enter key was pressed, consume the event.
124                     return true;
125                 }
126                 // If any other key was pressed, do not consume the event.
127                 return false;
128             }
129         });
130
131         // Allow pinch to zoom.
132         mainWebView.getSettings().setBuiltInZoomControls(true);
133
134         // Hide zoom controls.
135         mainWebView.getSettings().setDisplayZoomControls(false);
136
137         // Enable JavaScript.
138         mainWebView.getSettings().setJavaScriptEnabled(true);
139
140         // Enable DOM Storage.
141         mainWebView.getSettings().setDomStorageEnabled(true);
142
143         // Get the intent information that started the app.
144         final Intent intent = getIntent();
145
146         if (intent.getData() != null) {
147             // Get the intent data and convert it to a string.
148             final Uri intentUriData = intent.getData();
149             formattedUrlString = intentUriData.toString();
150         }
151
152         // If formattedUrlString is null assign the homepage to it.
153         if (formattedUrlString == null) {
154             formattedUrlString = homepage;
155         }
156
157         // Load the initial website.
158         mainWebView.loadUrl(formattedUrlString);
159     }
160
161     @Override
162     public boolean onCreateOptionsMenu(Menu menu) {
163         // Inflate the menu; this adds items to the action bar if it is present.
164         getMenuInflater().inflate(R.menu.menu_webview, menu);
165         return true;
166     }
167
168     // @TargetApi(11) turns off the errors regarding copy and paste, which are removied from view in menu_webview.xml for lower version of Android.
169     @Override
170     @TargetApi(11)
171     public boolean onOptionsItemSelected(MenuItem menuItem) {
172         int menuItemId = menuItem.getItemId();
173         ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
174
175         // Sets the commands that relate to the menu entries.
176         switch (menuItemId) {
177             case R.id.home:
178                 mainWebView.loadUrl(homepage);
179                 break;
180
181             case R.id.refresh:
182                 mainWebView.loadUrl(formattedUrlString);
183                 break;
184
185             case R.id.back:
186                 mainWebView.goBack();
187                 break;
188
189             case R.id.forward:
190                 mainWebView.goForward();
191                 break;
192
193             case R.id.copyURL:
194                 clipboard.setPrimaryClip(ClipData.newPlainText("URL", urlTextBox.getText()));
195                 break;
196
197             case R.id.pasteURL:
198                 ClipData.Item clipboardData = clipboard.getPrimaryClip().getItemAt(0);
199                 urlTextBox.setText(clipboardData.coerceToText(this));
200                 try {
201                     loadUrlFromTextBox(mainWebView);
202                 } catch (UnsupportedEncodingException e) {
203                     e.printStackTrace();
204                 }
205                 break;
206
207             case R.id.shareURL:
208                 Intent shareIntent = new Intent();
209                 shareIntent.setAction(Intent.ACTION_SEND);
210                 shareIntent.putExtra(Intent.EXTRA_TEXT, urlTextBox.getText().toString());
211                 shareIntent.setType("text/plain");
212                 startActivity(Intent.createChooser(shareIntent, "Share URL"));
213                 break;
214         }
215
216         return super.onOptionsItemSelected(menuItem);
217     }
218
219     // Override onBackPressed so that if mainWebView can go back it does when the system back button is pressed.
220     @Override
221     public void onBackPressed() {
222         if (mainWebView.canGoBack()) {
223             mainWebView.goBack();
224         } else {
225             super.onBackPressed();
226         }
227     }
228
229     public void loadUrlFromTextBox(View view) throws UnsupportedEncodingException {
230         // Get the text from urlTextInput and convert it to a string.
231         String unformattedUrlString = urlTextBox.getText().toString();
232         URL unformattedUrl = null;
233         Uri.Builder formattedUri = new Uri.Builder();
234
235         // Check to see if unformattedUrlString is a valid URL.  Otherwise, convert it into a Duck Duck Go search.
236         if (Patterns.WEB_URL.matcher(unformattedUrlString).matches()) {
237
238             // Add http:// at the beginning if it is missing.  Otherwise the app will segfault.
239             if (!unformattedUrlString.startsWith("http")) {
240                 unformattedUrlString = "http://" + unformattedUrlString;
241             }
242
243             // Convert unformattedUrlString to a URL, then to a URI, and then back to a string, which sanitizes the input and adds in any missing components.
244             try {
245                 unformattedUrl = new URL(unformattedUrlString);
246             } catch (MalformedURLException e) {
247                 e.printStackTrace();
248             }
249
250             // The ternary operator (? :) makes sure that a null pointer exception is not thrown, which would happen if .get was called on a null value.
251             final String scheme = unformattedUrl != null ? unformattedUrl.getProtocol() : null;
252             final String authority = unformattedUrl != null ? unformattedUrl.getAuthority() : null;
253             final String path = unformattedUrl != null ? unformattedUrl.getPath() : null;
254             final String query = unformattedUrl != null ? unformattedUrl.getQuery() : null;
255             final String fragment = unformattedUrl != null ? unformattedUrl.getRef() : null;
256
257             formattedUri.scheme(scheme).authority(authority).path(path).query(query).fragment(fragment);
258             formattedUrlString = formattedUri.build().toString();
259
260         } else {
261             // Sanitize the search input.
262             final String encodedUrlString = URLEncoder.encode(unformattedUrlString, "UTF-8");
263             formattedUrlString = "https://duckduckgo.com/?q=" + encodedUrlString;
264         }
265
266         mainWebView.loadUrl(formattedUrlString);
267
268         // Hides the keyboard so we can see the webpage.
269         InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Activity.INPUT_METHOD_SERVICE);
270         inputMethodManager.hideSoftInputFromWindow(mainWebView.getWindowToken(), 0);
271     }
272 }