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