Enable full screen video.
[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.app.DownloadManager;
7 import android.content.ClipData;
8 import android.content.ClipboardManager;
9 import android.content.Context;
10 import android.content.Intent;
11 import android.graphics.Bitmap;
12 import android.net.Uri;
13 import android.os.Build;
14 import android.os.Bundle;
15 import android.support.v7.app.ActionBar;
16 import android.support.v7.app.AppCompatActivity;
17 import android.util.Patterns;
18 import android.view.KeyEvent;
19 import android.view.Menu;
20 import android.view.MenuItem;
21 import android.view.View;
22 import android.view.inputmethod.InputMethodManager;
23 import android.webkit.DownloadListener;
24 import android.webkit.WebChromeClient;
25 import android.webkit.WebResourceError;
26 import android.webkit.WebResourceRequest;
27 import android.webkit.WebView;
28 import android.webkit.WebViewClient;
29 import android.widget.EditText;
30 import android.widget.FrameLayout;
31 import android.widget.ImageView;
32 import android.widget.ProgressBar;
33 import android.widget.RelativeLayout;
34 import android.widget.Toast;
35 import java.io.UnsupportedEncodingException;
36 import java.net.MalformedURLException;
37 import java.net.URL;
38 import java.net.URLEncoder;
39
40 public class Webview extends AppCompatActivity {
41
42     private String formattedUrlString;
43     private String homepage = "https://www.duckduckgo.com/";
44
45     // Remove Android Studio's warning about the dangers of using SetJavaScriptEnabled.
46     @SuppressLint("SetJavaScriptEnabled")
47
48     @Override
49     protected void onCreate(Bundle savedInstanceState) {
50         super.onCreate(savedInstanceState);
51         setContentView(R.layout.activity_webview);
52
53         final WebView mainWebView = (WebView) findViewById(R.id.mainWebView);
54         final FrameLayout fullScreenVideoFrameLayout = (FrameLayout) findViewById(R.id.fullScreenVideoFrameLayout);
55         final RelativeLayout rootRelativeLayout = (RelativeLayout) findViewById(R.id.rootRelativeLayout);
56         final Activity mainWebViewActivity = this;
57
58         final ActionBar actionBar = getSupportActionBar();
59         if (actionBar != null) {
60             // Remove the title from the action bar.
61             actionBar.setDisplayShowTitleEnabled(false);
62
63             // Add the custom app_bar layout, which shows the favoriteIcon, urlTextBar, and progressBar.
64             actionBar.setCustomView(R.layout.app_bar);
65             actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM);
66
67             // Set the "go" button on the keyboard to load the URL in urlTextBox.
68             EditText urlTextBox = (EditText) actionBar.getCustomView().findViewById(R.id.urlTextBox);
69             urlTextBox.setOnKeyListener(new View.OnKeyListener() {
70                 public boolean onKey(View v, int keyCode, KeyEvent event) {
71                     // If the event is a key-down event on the "enter" button, load the URL.
72                     if ((event.getAction() == KeyEvent.ACTION_DOWN) &&
73                             (keyCode == KeyEvent.KEYCODE_ENTER)) {
74                         // Load the URL into the mainWebView and consume the event.
75                         try {
76                             loadUrlFromTextBox();
77                         } catch (UnsupportedEncodingException e) {
78                             e.printStackTrace();
79                         }
80                         // If the enter key was pressed, consume the event.
81                         return true;
82                     }
83                     // If any other key was pressed, do not consume the event.
84                     return false;
85                 }
86             });
87         }
88
89         mainWebView.setWebViewClient(new WebViewClient() {
90             // shouldOverrideUrlLoading makes this WebView the default handler for URLs inside the app, so that links are not kicked out to other apps.
91             @Override
92             public boolean shouldOverrideUrlLoading(WebView view, String url) {
93                 mainWebView.loadUrl(url);
94                 return true;
95             }
96
97             public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
98                 Toast.makeText(mainWebViewActivity, "Error loading " + request + "   Error: " + error, Toast.LENGTH_LONG).show();
99             }
100
101             // Update the URL in urlTextBox when the page starts to load.
102             @Override
103             public void onPageStarted(WebView view, String url, Bitmap favicon) {
104                 if (actionBar != null) {
105                     EditText urlTextBox = (EditText) actionBar.getCustomView().findViewById(R.id.urlTextBox);
106                     urlTextBox.setText(url);
107                 }
108             }
109
110             // Update formattedUrlString and urlTextBox.  It is necessary to do this after the page finishes loading because the final URL can change during load.
111             @Override
112             public void onPageFinished(WebView view, String url) {
113                 formattedUrlString = url;
114
115                 if (actionBar != null) {
116                     EditText urlTextBox = (EditText) actionBar.getCustomView().findViewById(R.id.urlTextBox);
117                     urlTextBox.setText(formattedUrlString);
118                 }
119             }
120         });
121
122         mainWebView.setWebChromeClient(new WebChromeClient() {
123             // Update the progress bar when a page is loading.
124             @Override
125             public void onProgressChanged(WebView view, int progress) {
126                 // Make sure that actionBar is not null.
127                 if (actionBar != null) {
128                     ProgressBar progressBar = (ProgressBar) actionBar.getCustomView().findViewById(R.id.progressBar);
129                     progressBar.setProgress(progress);
130                     if (progress < 100) {
131                         progressBar.setVisibility(View.VISIBLE);
132                     } else {
133                         progressBar.setVisibility(View.GONE);
134                     }
135                 }
136             }
137
138             // Set the favorite icon when it changes.
139             @Override
140             public void onReceivedIcon(WebView view, Bitmap icon) {
141                 // Make sure that actionBar is not null.
142                 if (actionBar != null) {
143                     ImageView favoriteIcon = (ImageView) actionBar.getCustomView().findViewById(R.id.favoriteIcon);
144                     favoriteIcon.setImageBitmap(Bitmap.createScaledBitmap(icon, 64, 64, true));
145                 }
146             }
147
148             // Enter full screen video
149             @Override
150             public void onShowCustomView(View view, CustomViewCallback callback) {
151                 getSupportActionBar().hide();
152
153                 fullScreenVideoFrameLayout.addView(view);
154                 fullScreenVideoFrameLayout.setVisibility(View.VISIBLE);
155
156                 mainWebView.setVisibility(View.GONE);
157
158                 /* SYSTEM_UI_FLAG_HIDE_NAVIGATION hides the navigation bars on the bottom or right of the screen.
159                 ** SYSTEM_UI_FLAG_FULLSCREEN hides the status bar across the top of the screen.
160                 ** SYSTEM_UI_FLAG_IMMERSIVE_STICKY makes the navigation and status bars ghosted overlays and automatically rehides them.
161                 */
162
163                 // Set the one flag supported by API >= 14.
164                 if (Build.VERSION.SDK_INT >= 14) {
165                     view.setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
166                 }
167
168                 // Set the two flags that are supported by API >= 16.
169                 if (Build.VERSION.SDK_INT >= 16) {
170                     view.setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN);
171                 }
172
173                 // Set all three flags that are supported by API >= 19.
174                 if (Build.VERSION.SDK_INT >= 19) {
175                     view.setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
176                 }
177             }
178
179             // Exit full screen video
180             public void onHideCustomView() {
181                 getSupportActionBar().show();
182
183                 mainWebView.setVisibility(View.VISIBLE);
184
185                 fullScreenVideoFrameLayout.removeAllViews();
186                 fullScreenVideoFrameLayout.setVisibility(View.GONE);
187             }
188         });
189
190         mainWebView.setDownloadListener(new DownloadListener() {
191             // Launch the Android download manager when a link leads to a download.
192             @Override
193             public void onDownloadStart(String url, String userAgent, String contentDisposition, String mimetype, long contentLength) {
194                 DownloadManager downloadManager = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
195                 DownloadManager.Request requestUri = new DownloadManager.Request(Uri.parse(url));
196
197                 // Add the URL as the description for the download.
198                 requestUri.setDescription(url);
199
200                 // Show the download notification after the download is completed if the API is 11 or greater.
201                 if (Build.VERSION.SDK_INT >= 11) {
202                     requestUri.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
203                 }
204
205                 downloadManager.enqueue(requestUri);
206                 Toast.makeText(mainWebViewActivity, "Download started", Toast.LENGTH_SHORT).show();
207             }
208         });
209
210         // Allow pinch to zoom.
211         mainWebView.getSettings().setBuiltInZoomControls(true);
212
213         // Hide zoom controls if the API is 11 or greater.
214         if (Build.VERSION.SDK_INT >= 11) {
215             mainWebView.getSettings().setDisplayZoomControls(false);
216         }
217
218         // Enable JavaScript.
219         mainWebView.getSettings().setJavaScriptEnabled(true);
220
221         // Enable DOM Storage.
222         mainWebView.getSettings().setDomStorageEnabled(true);
223
224         // Get the intent information that started the app.
225         final Intent intent = getIntent();
226
227         if (intent.getData() != null) {
228             // Get the intent data and convert it to a string.
229             final Uri intentUriData = intent.getData();
230             formattedUrlString = intentUriData.toString();
231         }
232
233         // If formattedUrlString is null assign the homepage to it.
234         if (formattedUrlString == null) {
235             formattedUrlString = homepage;
236         }
237
238         // Load the initial website.
239         mainWebView.loadUrl(formattedUrlString);
240     }
241
242     @Override
243     public boolean onCreateOptionsMenu(Menu menu) {
244         // Inflate the menu; this adds items to the action bar if it is present.
245         getMenuInflater().inflate(R.menu.menu_webview, menu);
246         return true;
247     }
248
249     // @TargetApi(11) turns off the errors regarding copy and paste, which are removed from view in menu_webview.xml for lower version of Android.
250     @Override
251     @TargetApi(11)
252     public boolean onOptionsItemSelected(MenuItem menuItem) {
253         int menuItemId = menuItem.getItemId();
254         ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
255         ActionBar actionBar = getSupportActionBar();
256         final WebView mainWebView = (WebView) findViewById(R.id.mainWebView);
257
258         // Sets the commands that relate to the menu entries.
259         switch (menuItemId) {
260             case R.id.home:
261                 mainWebView.loadUrl(homepage);
262                 break;
263
264             case R.id.refresh:
265                 mainWebView.loadUrl(formattedUrlString);
266                 break;
267
268             case R.id.back:
269                 mainWebView.goBack();
270                 break;
271
272             case R.id.forward:
273                 mainWebView.goForward();
274                 break;
275
276             case R.id.copyURL:
277                 // Make sure that actionBar is not null.
278                 if (actionBar != null) {
279                     EditText urlTextBox = (EditText) actionBar.getCustomView().findViewById(R.id.urlTextBox);
280                     clipboard.setPrimaryClip(ClipData.newPlainText("URL", urlTextBox.getText()));
281                 }
282                 break;
283
284             case R.id.pasteURL:
285                 // Make sure that actionBar is not null.
286                 if (actionBar != null) {
287                     ClipData.Item clipboardData = clipboard.getPrimaryClip().getItemAt(0);
288                     EditText urlTextBox = (EditText) actionBar.getCustomView().findViewById(R.id.urlTextBox);
289                     urlTextBox.setText(clipboardData.coerceToText(this));
290                     try {
291                         loadUrlFromTextBox();
292                     } catch (UnsupportedEncodingException e) {
293                         e.printStackTrace();
294                     }
295                 }
296                 break;
297
298             case R.id.shareURL:
299                 // Make sure that actionBar is not null.
300                 if (actionBar != null) {
301                     EditText urlTextBox = (EditText) actionBar.getCustomView().findViewById(R.id.urlTextBox);
302                     Intent shareIntent = new Intent();
303                     shareIntent.setAction(Intent.ACTION_SEND);
304                     shareIntent.putExtra(Intent.EXTRA_TEXT, urlTextBox.getText().toString());
305                     shareIntent.setType("text/plain");
306                     startActivity(Intent.createChooser(shareIntent, "Share URL"));
307                 }
308                 break;
309
310             case R.id.downloads:
311                 // Launch the system Download Manager.
312                 Intent downloadManangerIntent = new Intent(DownloadManager.ACTION_VIEW_DOWNLOADS);
313
314                 // Launch as a new task so that Download Manager and Privacy Browser show as separate windows in the recent tasks list.
315                 downloadManangerIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
316
317                 startActivity(downloadManangerIntent);
318         }
319
320         return super.onOptionsItemSelected(menuItem);
321     }
322
323     // Override onBackPressed so that if mainWebView can go back it does when the system back button is pressed.
324     @Override
325     public void onBackPressed() {
326         final WebView mainWebView = (WebView) findViewById(R.id.mainWebView);
327
328         if (mainWebView.canGoBack()) {
329             mainWebView.goBack();
330         } else {
331             super.onBackPressed();
332         }
333     }
334
335     public void loadUrlFromTextBox() throws UnsupportedEncodingException {
336         // Make sure that actionBar is not null.
337         ActionBar actionBar = getSupportActionBar();
338         if (actionBar != null) {
339             final WebView mainWebView = (WebView) findViewById(R.id.mainWebView);
340             EditText urlTextBox = (EditText) actionBar.getCustomView().findViewById(R.id.urlTextBox);
341
342             // Get the text from urlTextInput and convert it to a string.
343             String unformattedUrlString = urlTextBox.getText().toString();
344             URL unformattedUrl = null;
345             Uri.Builder formattedUri = new Uri.Builder();
346
347             // Check to see if unformattedUrlString is a valid URL.  Otherwise, convert it into a Duck Duck Go search.
348             if (Patterns.WEB_URL.matcher(unformattedUrlString).matches()) {
349
350                 // Add http:// at the beginning if it is missing.  Otherwise the app will segfault.
351                 if (!unformattedUrlString.startsWith("http")) {
352                     unformattedUrlString = "http://" + unformattedUrlString;
353                 }
354
355                 // 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.
356                 try {
357                     unformattedUrl = new URL(unformattedUrlString);
358                 } catch (MalformedURLException e) {
359                     e.printStackTrace();
360                 }
361
362                 // The ternary operator (? :) makes sure that a null pointer exception is not thrown, which would happen if .get was called on a null value.
363                 final String scheme = unformattedUrl != null ? unformattedUrl.getProtocol() : null;
364                 final String authority = unformattedUrl != null ? unformattedUrl.getAuthority() : null;
365                 final String path = unformattedUrl != null ? unformattedUrl.getPath() : null;
366                 final String query = unformattedUrl != null ? unformattedUrl.getQuery() : null;
367                 final String fragment = unformattedUrl != null ? unformattedUrl.getRef() : null;
368
369                 formattedUri.scheme(scheme).authority(authority).path(path).query(query).fragment(fragment);
370                 formattedUrlString = formattedUri.build().toString();
371
372             } else {
373                 // Sanitize the search input and convert it to a DuckDuckGo search.
374                 final String encodedUrlString = URLEncoder.encode(unformattedUrlString, "UTF-8");
375                 formattedUrlString = "https://duckduckgo.com/?q=" + encodedUrlString;
376             }
377
378             mainWebView.loadUrl(formattedUrlString);
379
380             // Hides the keyboard so we can see the webpage.
381             InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Activity.INPUT_METHOD_SERVICE);
382             inputMethodManager.hideSoftInputFromWindow(mainWebView.getWindowToken(), 0);
383         }
384     }
385 }