1 package com.stoutner.privacybrowser;
3 import android.Manifest;
4 import android.annotation.SuppressLint;
5 import android.annotation.TargetApi;
6 import android.app.Activity;
7 import android.app.DownloadManager;
8 import android.content.ClipData;
9 import android.content.ClipboardManager;
10 import android.content.Context;
11 import android.content.Intent;
12 import android.content.pm.PackageManager;
13 import android.graphics.Bitmap;
14 import android.net.Uri;
15 import android.os.Build;
16 import android.os.Bundle;
17 import android.os.Environment;
18 import android.support.v4.app.ActivityCompat;
19 import android.support.v4.content.ContextCompat;
20 import android.support.v7.app.ActionBar;
21 import android.support.v7.app.AppCompatActivity;
22 import android.util.Patterns;
23 import android.view.KeyEvent;
24 import android.view.Menu;
25 import android.view.MenuItem;
26 import android.view.View;
27 import android.view.inputmethod.InputMethodManager;
28 import android.webkit.DownloadListener;
29 import android.webkit.WebChromeClient;
30 import android.webkit.WebResourceError;
31 import android.webkit.WebResourceRequest;
32 import android.webkit.WebView;
33 import android.webkit.WebViewClient;
34 import android.widget.EditText;
35 import android.widget.ImageView;
36 import android.widget.ProgressBar;
37 import android.widget.Toast;
40 import java.io.UnsupportedEncodingException;
41 import java.net.MalformedURLException;
43 import java.net.URLEncoder;
45 public class Webview extends AppCompatActivity {
47 private String formattedUrlString;
48 private String homepage = "https://www.duckduckgo.com/";
50 // Remove Android Studio's warning about the dangers of using SetJavaScriptEnabled.
51 @SuppressLint("SetJavaScriptEnabled")
54 protected void onCreate(Bundle savedInstanceState) {
55 super.onCreate(savedInstanceState);
56 setContentView(R.layout.activity_webview);
58 final WebView mainWebView = (WebView) findViewById(R.id.mainWebView);
59 final Activity mainWebViewActivity = this;
61 final ActionBar actionBar = getSupportActionBar();
62 if (actionBar != null) {
63 // Remove the title from the action bar.
64 actionBar.setDisplayShowTitleEnabled(false);
66 // Add the custom app_bar layout, which shows the favoriteIcon, urlTextBar, and progressBar.
67 actionBar.setCustomView(R.layout.app_bar);
68 actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM);
70 // Set the "go" button on the keyboard to load the URL in urlTextBox.
71 EditText urlTextBox = (EditText) actionBar.getCustomView().findViewById(R.id.urlTextBox);
72 urlTextBox.setOnKeyListener(new View.OnKeyListener() {
73 public boolean onKey(View v, int keyCode, KeyEvent event) {
74 // If the event is a key-down event on the "enter" button, load the URL.
75 if ((event.getAction() == KeyEvent.ACTION_DOWN) &&
76 (keyCode == KeyEvent.KEYCODE_ENTER)) {
77 // Load the URL into the mainWebView and consume the event.
80 } catch (UnsupportedEncodingException e) {
83 // If the enter key was pressed, consume the event.
86 // If any other key was pressed, do not consume the event.
92 mainWebView.setWebViewClient(new WebViewClient() {
93 // shouldOverrideUrlLoading makes this WebView the default handler for URLs inside the app, so that links are not kicked out to other apps.
95 public boolean shouldOverrideUrlLoading(WebView view, String url) {
96 mainWebView.loadUrl(url);
100 public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
101 Toast.makeText(mainWebViewActivity, "Error loading " + request + " Error: " + error, Toast.LENGTH_LONG).show();
104 // Update the URL in urlTextBox when the page starts to load.
106 public void onPageStarted(WebView view, String url, Bitmap favicon) {
107 if (actionBar != null) {
108 EditText urlTextBox = (EditText) actionBar.getCustomView().findViewById(R.id.urlTextBox);
109 urlTextBox.setText(url);
113 // Update formattedUrlString and urlTextBox. It is necessary to do this after the page finishes loading because the final URL can change during load.
115 public void onPageFinished(WebView view, String url) {
116 formattedUrlString = url;
118 if (actionBar != null) {
119 EditText urlTextBox = (EditText) actionBar.getCustomView().findViewById(R.id.urlTextBox);
120 urlTextBox.setText(formattedUrlString);
125 mainWebView.setWebChromeClient(new WebChromeClient() {
126 // Update the progress bar when a page is loading.
128 public void onProgressChanged(WebView view, int progress) {
129 // Make sure that actionBar is not null.
130 if (actionBar != null) {
131 ProgressBar progressBar = (ProgressBar) actionBar.getCustomView().findViewById(R.id.progressBar);
132 progressBar.setProgress(progress);
133 if (progress < 100) {
134 progressBar.setVisibility(View.VISIBLE);
136 progressBar.setVisibility(View.GONE);
141 // Set the favorite icon when it changes.
143 public void onReceivedIcon(WebView view, Bitmap icon) {
144 // Make sure that actionBar is not null.
145 if (actionBar != null) {
146 ImageView favoriteIcon = (ImageView) actionBar.getCustomView().findViewById(R.id.favoriteIcon);
147 favoriteIcon.setImageBitmap(Bitmap.createScaledBitmap(icon, 64, 64, true));
152 mainWebView.setDownloadListener(new DownloadListener() {
153 // Launch the Android download manager when a link leads to a download.
155 public void onDownloadStart(String url, String userAgent, String contentDisposition, String mimetype, long contentLength) {
156 DownloadManager downloadManager = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
157 DownloadManager.Request requestUri = new DownloadManager.Request(Uri.parse(url));
159 // Add the URL as the description for the download.
160 requestUri.setDescription(url);
162 // Show the download notification after the download is completed if the API is 11 or greater.
163 if (Build.VERSION.SDK_INT >= 11) {
164 requestUri.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
167 downloadManager.enqueue(requestUri);
168 Toast.makeText(mainWebViewActivity, "Download started", Toast.LENGTH_SHORT).show();
172 // Allow pinch to zoom.
173 mainWebView.getSettings().setBuiltInZoomControls(true);
175 // Hide zoom controls if the API is 11 or greater.
176 if (Build.VERSION.SDK_INT >= 11) {
177 mainWebView.getSettings().setDisplayZoomControls(false);
180 // Enable JavaScript.
181 mainWebView.getSettings().setJavaScriptEnabled(true);
183 // Enable DOM Storage.
184 mainWebView.getSettings().setDomStorageEnabled(true);
186 // Get the intent information that started the app.
187 final Intent intent = getIntent();
189 if (intent.getData() != null) {
190 // Get the intent data and convert it to a string.
191 final Uri intentUriData = intent.getData();
192 formattedUrlString = intentUriData.toString();
195 // If formattedUrlString is null assign the homepage to it.
196 if (formattedUrlString == null) {
197 formattedUrlString = homepage;
200 // Load the initial website.
201 mainWebView.loadUrl(formattedUrlString);
205 public boolean onCreateOptionsMenu(Menu menu) {
206 // Inflate the menu; this adds items to the action bar if it is present.
207 getMenuInflater().inflate(R.menu.menu_webview, menu);
211 // @TargetApi(11) turns off the errors regarding copy and paste, which are removed from view in menu_webview.xml for lower version of Android.
214 public boolean onOptionsItemSelected(MenuItem menuItem) {
215 int menuItemId = menuItem.getItemId();
216 ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
217 ActionBar actionBar = getSupportActionBar();
218 final WebView mainWebView = (WebView) findViewById(R.id.mainWebView);
220 // Sets the commands that relate to the menu entries.
221 switch (menuItemId) {
223 mainWebView.loadUrl(homepage);
227 mainWebView.loadUrl(formattedUrlString);
231 mainWebView.goBack();
235 mainWebView.goForward();
239 // Make sure that actionBar is not null.
240 if (actionBar != null) {
241 EditText urlTextBox = (EditText) actionBar.getCustomView().findViewById(R.id.urlTextBox);
242 clipboard.setPrimaryClip(ClipData.newPlainText("URL", urlTextBox.getText()));
247 // Make sure that actionBar is not null.
248 if (actionBar != null) {
249 ClipData.Item clipboardData = clipboard.getPrimaryClip().getItemAt(0);
250 EditText urlTextBox = (EditText) actionBar.getCustomView().findViewById(R.id.urlTextBox);
251 urlTextBox.setText(clipboardData.coerceToText(this));
253 loadUrlFromTextBox();
254 } catch (UnsupportedEncodingException e) {
261 // Make sure that actionBar is not null.
262 if (actionBar != null) {
263 EditText urlTextBox = (EditText) actionBar.getCustomView().findViewById(R.id.urlTextBox);
264 Intent shareIntent = new Intent();
265 shareIntent.setAction(Intent.ACTION_SEND);
266 shareIntent.putExtra(Intent.EXTRA_TEXT, urlTextBox.getText().toString());
267 shareIntent.setType("text/plain");
268 startActivity(Intent.createChooser(shareIntent, "Share URL"));
273 // Launch the system Download Manager.
274 Intent downloadManangerIntent = new Intent(DownloadManager.ACTION_VIEW_DOWNLOADS);
276 // Launch as a new task so that Download Manager and Privacy Browser show as separate windows in the recent tasks list.
277 downloadManangerIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
279 startActivity(downloadManangerIntent);
282 return super.onOptionsItemSelected(menuItem);
285 // Override onBackPressed so that if mainWebView can go back it does when the system back button is pressed.
287 public void onBackPressed() {
288 final WebView mainWebView = (WebView) findViewById(R.id.mainWebView);
290 if (mainWebView.canGoBack()) {
291 mainWebView.goBack();
293 super.onBackPressed();
297 public void loadUrlFromTextBox() throws UnsupportedEncodingException {
298 // Make sure that actionBar is not null.
299 ActionBar actionBar = getSupportActionBar();
300 if (actionBar != null) {
301 final WebView mainWebView = (WebView) findViewById(R.id.mainWebView);
302 EditText urlTextBox = (EditText) actionBar.getCustomView().findViewById(R.id.urlTextBox);
304 // Get the text from urlTextInput and convert it to a string.
305 String unformattedUrlString = urlTextBox.getText().toString();
306 URL unformattedUrl = null;
307 Uri.Builder formattedUri = new Uri.Builder();
309 // Check to see if unformattedUrlString is a valid URL. Otherwise, convert it into a Duck Duck Go search.
310 if (Patterns.WEB_URL.matcher(unformattedUrlString).matches()) {
312 // Add http:// at the beginning if it is missing. Otherwise the app will segfault.
313 if (!unformattedUrlString.startsWith("http")) {
314 unformattedUrlString = "http://" + unformattedUrlString;
317 // 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.
319 unformattedUrl = new URL(unformattedUrlString);
320 } catch (MalformedURLException e) {
324 // The ternary operator (? :) makes sure that a null pointer exception is not thrown, which would happen if .get was called on a null value.
325 final String scheme = unformattedUrl != null ? unformattedUrl.getProtocol() : null;
326 final String authority = unformattedUrl != null ? unformattedUrl.getAuthority() : null;
327 final String path = unformattedUrl != null ? unformattedUrl.getPath() : null;
328 final String query = unformattedUrl != null ? unformattedUrl.getQuery() : null;
329 final String fragment = unformattedUrl != null ? unformattedUrl.getRef() : null;
331 formattedUri.scheme(scheme).authority(authority).path(path).query(query).fragment(fragment);
332 formattedUrlString = formattedUri.build().toString();
335 // Sanitize the search input and convert it to a DuckDuckGo search.
336 final String encodedUrlString = URLEncoder.encode(unformattedUrlString, "UTF-8");
337 formattedUrlString = "https://duckduckgo.com/?q=" + encodedUrlString;
340 mainWebView.loadUrl(formattedUrlString);
342 // Hides the keyboard so we can see the webpage.
343 InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Activity.INPUT_METHOD_SERVICE);
344 inputMethodManager.hideSoftInputFromWindow(mainWebView.getWindowToken(), 0);