<w>appbarlayout</w>
<w>aren</w>
<w>bebdb</w>
+ <w>bookmarkname</w>
+ <w>bookmarkurl</w>
<w>buildapi</w>
<w>buildversion</w>
<w>chromeversion</w>
<w>commitdiff</w>
<w>coordinatorlayout</w>
+ <w>displayorder</w>
<w>eadd</w>
+ <w>edittext</w>
<w>exynos</w>
+ <w>favoriteicon</w>
<w>imbedded</w>
<w>imbedding</w>
<w>intl</w>
+ <w>isfolder</w>
<w>khtml</w>
<w>konqueror</w>
<w>linearlayout</w>
+ <w>listview</w>
<w>logins</w>
<w>mozilla</w>
<w>nojs</w>
<w>orbot</w>
<w>panopticlick</w>
+ <w>parentfolder</w>
<w>redmine</w>
<w>referer</w>
<w>relativelayout</w>
<w>tablayout</w>
<w>techrepublic</w>
<w>textview</w>
+ <w>uids</w>
<w>webkay</w>
<w>webkitversion</w>
<w>whatismyip</w>
</intent-filter>
</activity>
+
<!-- android:configChanges="orientation|screenSize" makes the activity not reload when the orientation changes.
android:persistableMode="persistNever" removes Privacy Browser from the recents screen on a device reboot. -->
<activity
- android:name=".GuideActivity"
- android:label="@string/privacy_browser_guide"
- android:theme="@style/PrivacyBrowser.TabActivity"
+ android:name=".BookmarksActivity"
+ android:label="@string/bookmarks"
+ android:theme="@style/PrivacyBrowser.SecondaryActivity"
android:parentActivityName=".MainWebViewActivity"
android:configChanges="orientation|screenSize"
android:persistableMode="persistNever" >
android:persistableMode="persistNever" >
</activity>
+ <!-- android:configChanges="orientation|screenSize" makes the activity not reload when the orientation changes.
+ android:persistableMode="persistNever" removes Privacy Browser from the recents screen on a device reboot. -->
+ <activity
+ android:name=".GuideActivity"
+ android:label="@string/privacy_browser_guide"
+ android:theme="@style/PrivacyBrowser.SecondaryActivity"
+ android:parentActivityName=".MainWebViewActivity"
+ android:configChanges="orientation|screenSize"
+ android:persistableMode="persistNever" >
+ </activity>
+
<!-- android:configChanges="orientation|screenSize" makes the activity not reload when the orientation changes.
android:persistableMode="persistNever" removes Privacy Browser from the recents screen on a device reboot. -->
<activity
android:name=".AboutActivity"
android:label="@string/about_privacy_browser"
- android:theme="@style/PrivacyBrowser.TabActivity"
+ android:theme="@style/PrivacyBrowser.SecondaryActivity"
android:parentActivityName=".MainWebViewActivity"
android:configChanges="orientation|screenSize"
android:persistableMode="persistNever" >
<p><img class="center" src="images/ic_arrow_forward.png" height="32" width="32"> ic_arrow_forward.</p>
-<p><img class="center" src="images/ic_file_download.png" height="32" width="32"> ic_file_download.</p>
+<p><img class="center" src="images/ic_bookmark_border.png" height="32" width="32"> ic_bookmark_border.</p>
-<p><img class="center" src="images/ic_import_contacts.png" height="32" width="32"> ic_import_contacts.</p>
+<p><img class="center" src="images/ic_file_download.png" height="32" width="32"> ic_file_download.</p>
<p><img class="center" src="images/ic_settings.png" height="32" width="32"> ic_settings.</p>
+<p><img class="center" src="images/ic_import_contacts.png" height="32" width="32"> ic_import_contacts.</p>
+
<p><img class="center" src="images/ic_info_outline.png" height="32" width="32"> ic_info_outline.</p>
<p><img class="center" src="images/ic_exit_to_app.png" height="32" width="32"> ic_exit_to_app.</p>
+<p><img class="center" src="images/ic_add.png" height="32" width="32"> ic_add.</p>
+
<hr/>
<h3>GNU General Public License</h3>
<ul>
<li><item>Removes all cookies</item>.</li>
<li><item>Removes all DOM storage</item>.</li>
+ <li><item>Removes all form data</item>.</li>
<li><item>Clears the cache, including disk files</item>.</li>
<li><item>Clears the back/forward history</item>.</li>
<li><item>Destroys the internal state of the WebView</item>.</li>
<p>Of course, the concept of running arbitrary programs from a website is potentially dangerous. So there are limitations placed on JavaScript
to keep it from doing things like installing viruses on the device. However, it turns out that these limitations are overly broad.
Below is a screenshot from <a href="http://webkay.robinlinus.com">webkay</a>, which is a website that demonstrates the type of information that
- JavaScript can produce about a device.</p>
+ JavaScript can produce about a device. <a href="http://www.browserleaks.com/">Browser Leaks</a> is another good resource.</p>
<p><img class="center" src="images/webkay.png" height="640" width="360"></p>
without informing the user they are doing so. Privacy Browser is designed to grant the user as much information and control over these tracking techniques as possible.</p>
-<h3>WebView Limitations</h3>
+<h3>Android's WebView Limitations</h3>
<p>Privacy Browser uses Android's built-in WebView to render websites. There are some limitations in the controls WebView exposes for managing privacy settings. For example,
- it isn't possible to enable some JavaScript commands while disabling others. It also isn't possible to control the
- <a href="https://blog.fastmail.com/2016/06/20/everything-you-could-ever-want-to-know-and-more-about-controlling-the-referer-header/">referer header</a>.
- Once Privacy Browser has matured to take full advantage of all the privacy options WebView does offer, some consideration might be made to imbedding a customized WebView
- or using a different rendering engine.</p>
+ it isn't possible to enable some JavaScript commands while disabling others. Once Privacy Browser has matured to take full advantage of all the privacy options WebView
+ does offer, some consideration might be made to imbedding a customized WebView or using a different rendering engine.</p>
</body>
</html>
\ No newline at end of file
<li><strong>Integrated ad blocker</strong>.</li>
</ul>
-<p>A full list of planned features and bug reports is available on <a href="https://redmine.stoutner.com/projects/privacy-browser/issues">redmine.stoutner.com</a>.</p>
+<p>A full list of planned features and bug reports is available at <a href="https://redmine.stoutner.com/projects/privacy-browser/issues">redmine.stoutner.com</a>.</p>
</body>
</html>
\ No newline at end of file
setContentView(R.layout.about_coordinatorlayout);
// We need to use the SupportActionBar from android.support.v7.app.ActionBar until the minimum API is >= 21.
- Toolbar supportAppBar = (Toolbar) findViewById(R.id.about_toolbar);
- setSupportActionBar(supportAppBar);
+ Toolbar aboutAppBar = (Toolbar) findViewById(R.id.about_toolbar);
+ setSupportActionBar(aboutAppBar);
// Display the home arrow on supportAppBar.
final ActionBar appBar = getSupportActionBar();
--- /dev/null
+/**
+ * Copyright 2016 Soren Stoutner <soren@stoutner.com>.
+ *
+ * This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
+ *
+ * Privacy Browser is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Privacy Browser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Privacy Browser. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package com.stoutner.privacybrowser;
+
+import android.app.Activity;
+import android.app.DialogFragment;
+import android.database.Cursor;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.os.Bundle;
+import android.support.design.widget.FloatingActionButton;
+import android.support.v4.app.NavUtils;
+import android.support.v7.app.ActionBar;
+import android.support.v7.app.AppCompatActivity;
+import android.support.v7.widget.Toolbar;
+import android.view.View;
+import android.widget.AdapterView;
+import android.widget.EditText;
+import android.widget.ImageView;
+import android.widget.ListView;
+import android.widget.SimpleCursorAdapter;
+
+import java.io.ByteArrayOutputStream;
+
+public class BookmarksActivity extends AppCompatActivity implements CreateBookmark.CreateBookmarkListener {
+ private BookmarksDatabaseHandler bookmarksDatabaseHandler;
+ private ListView bookmarksListView;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.bookmarks_coordinatorlayout);
+
+ // We need to use the SupportActionBar from android.support.v7.app.ActionBar until the minimum API is >= 21.
+ Toolbar bookmarksAppBar = (Toolbar) findViewById(R.id.bookmarks_toolbar);
+ setSupportActionBar(bookmarksAppBar);
+
+ // Display the home arrow on supportAppBar.
+ final ActionBar appBar = getSupportActionBar();
+ assert appBar != null;// This assert removes the incorrect warning in Android Studio on the following line that appBar might be null.
+ appBar.setDisplayHomeAsUpEnabled(true);
+
+ // Initialize the database handler and the ListView.
+ bookmarksDatabaseHandler = new BookmarksDatabaseHandler(this, null, null, 0);
+ bookmarksListView = (ListView) findViewById(R.id.bookmarks_listview);
+
+ // Display the bookmarks in the ListView.
+ updateBookmarksListView();
+
+ // Set a listener so that tapping a list item loads the URL. We need to store the activity in a variable so that we can return to the parent activity after loading the URL.
+ final Activity bookmarksActivity = this;
+ bookmarksListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
+ @Override
+ public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+ // Convert the id from long to int to match the format of the bookmarks database.
+ int databaseID = (int) id;
+
+ // Get the bookmark URL and assign it to formattedUrlString.
+ MainWebViewActivity.formattedUrlString = bookmarksDatabaseHandler.getBookmarkURL(databaseID);
+
+ // Load formattedUrlString and return to the main activity.
+ MainWebViewActivity.mainWebView.loadUrl(MainWebViewActivity.formattedUrlString);
+ NavUtils.navigateUpFromSameTask(bookmarksActivity);
+ }
+ });
+
+ // Set a FloatingActionButton for creating new bookmarks.
+ FloatingActionButton createBookmarkFAB = (FloatingActionButton) findViewById(R.id.create_bookmark_fab);
+ assert createBookmarkFAB != null;
+ createBookmarkFAB.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ // Show the CreateBookmark AlertDialog and name the instance "@string/create_bookmark".
+ DialogFragment createBookmarkDialog = new CreateBookmark();
+ createBookmarkDialog.show(getFragmentManager(), "@string/create_bookmark");
+ }
+ });
+ }
+
+ @Override
+ public void onCreateBookmarkCancel(DialogFragment createBookmarkDialogFragment) {
+ // Do nothing because the user selected "Cancel".
+ }
+
+ @Override
+ public void onCreateBookmarkCreate(DialogFragment createBookmarkDialogFragment) {
+ // Get the EditTexts from the DialogFragment and extract the strings.
+ EditText createBookmarkNameEditText = (EditText) createBookmarkDialogFragment.getDialog().findViewById(R.id.create_bookmark_name_edittext);
+ String bookmarkNameString = createBookmarkNameEditText.getText().toString();
+ EditText createBookmarkURLEditText = (EditText) createBookmarkDialogFragment.getDialog().findViewById(R.id.create_bookmark_url_edittext);
+ String bookmarkURLString = createBookmarkURLEditText.getText().toString();
+
+ // Convert the favoriteIcon Bitmap to a byte array.
+ ByteArrayOutputStream favoriteIconByteArrayOutputStream = new ByteArrayOutputStream();
+ MainWebViewActivity.favoriteIcon.compress(Bitmap.CompressFormat.PNG, 0, favoriteIconByteArrayOutputStream);
+ byte[] favoriteIconByteArray = favoriteIconByteArrayOutputStream.toByteArray();
+
+ // Create the bookmark.
+ bookmarksDatabaseHandler.createBookmark(bookmarkNameString, bookmarkURLString, favoriteIconByteArray);
+
+ // Refresh the ListView.
+ updateBookmarksListView();
+ }
+
+ private void updateBookmarksListView() {
+ // Get a Cursor with the current contents of the bookmarks database.
+ final Cursor bookmarksCursor = bookmarksDatabaseHandler.getBookmarksCursor();
+
+ // The last argument is 0 because no special behavior is required.
+ SimpleCursorAdapter bookmarksAdapter = new SimpleCursorAdapter(this,
+ R.layout.bookmarks_item_linearlayout,
+ bookmarksCursor,
+ new String[] { BookmarksDatabaseHandler.FAVORITEICON, BookmarksDatabaseHandler.BOOKMARK_NAME },
+ new int[] { R.id.bookmark_favorite_icon, R.id.bookmark_name },
+ 0);
+
+ // Override the handling of R.id.bookmark_favorite_icon to load an image instead of a string.
+ bookmarksAdapter.setViewBinder(new SimpleCursorAdapter.ViewBinder() {
+ public boolean setViewValue(View view, Cursor cursor, int columnIndex) {
+ if (view.getId() == R.id.bookmark_favorite_icon) {
+ // Get the byte array from the database.
+ byte[] favoriteIconByteArray = cursor.getBlob(columnIndex);
+
+ // Convert the byte array to a Bitmap beginning at the first byte and ending at the last.
+ Bitmap favoriteIconBitmap = BitmapFactory.decodeByteArray(favoriteIconByteArray, 0, favoriteIconByteArray.length);
+
+ // Set the favoriteIconBitmap.
+ ImageView bookmarkFavoriteIcon = (ImageView) view;
+ bookmarkFavoriteIcon.setImageBitmap(favoriteIconBitmap);
+ return true;
+ } else { // Process the rest of the bookmarksAdapter with default settings.
+ return false;
+ }
+ }
+ });
+
+ // Update the ListView.
+ bookmarksListView.setAdapter(bookmarksAdapter);
+ }
+}
\ No newline at end of file
--- /dev/null
+/**
+ * Copyright 2016 Soren Stoutner <soren@stoutner.com>.
+ *
+ * This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
+ *
+ * Privacy Browser is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Privacy Browser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Privacy Browser. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package com.stoutner.privacybrowser;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+
+public class BookmarksDatabaseHandler extends SQLiteOpenHelper {
+ private static final int SCHEMA_VERSION = 1;
+ private static final String BOOKMARKS_DATABASE = "bookmarks.db";
+ private static final String BOOKMARKS_TABLE = "bookmarks";
+
+ public static final String ID = "_id";
+ public static final String DISPLAYORDER = "displayorder";
+ public static final String BOOKMARK_NAME = "bookmarkname";
+ public static final String BOOKMARK_URL = "bookmarkurl";
+ public static final String PARENTFOLDER = "parentfolder";
+ public static final String ISFOLDER = "isfolder";
+ public static final String FAVORITEICON = "favoriteicon";
+
+ public BookmarksDatabaseHandler(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
+ super(context, BOOKMARKS_DATABASE, factory, SCHEMA_VERSION);
+ }
+
+ @Override
+ public void onCreate(SQLiteDatabase bookmarksDatabase) {
+ // Create the database if it doesn't exist.
+ String CREATE_BOOKMARKS_TABLE = "CREATE TABLE " + BOOKMARKS_TABLE + " (" +
+ ID + " integer primary key, " +
+ DISPLAYORDER + " integer, " +
+ BOOKMARK_NAME + " text, " +
+ BOOKMARK_URL + " text, " +
+ PARENTFOLDER + " text, " +
+ ISFOLDER + " boolean, " +
+ FAVORITEICON + " blob);";
+
+ bookmarksDatabase.execSQL(CREATE_BOOKMARKS_TABLE);
+ }
+
+ @Override
+ public void onUpgrade(SQLiteDatabase bookmarksDatabase, int oldVersion, int newVersion) {
+ // Code for upgrading the database will be added here when the schema version > 1.
+ }
+
+ public void createBookmark(String bookmarkName, String bookmarkURL, byte[] favoriteIcon) {
+ ContentValues bookmarkContentValues = new ContentValues();
+
+ // ID is created automatically.
+ bookmarkContentValues.put(BOOKMARK_NAME, bookmarkName);
+ bookmarkContentValues.put(BOOKMARK_URL, bookmarkURL);
+ bookmarkContentValues.put(PARENTFOLDER, "");
+ bookmarkContentValues.put(ISFOLDER, false);
+ bookmarkContentValues.put(FAVORITEICON, favoriteIcon);
+
+ // Get a writable database handle.
+ SQLiteDatabase bookmarksDatabase = this.getWritableDatabase();
+
+ // The second argument is "null", which makes it so that completely null rows cannot be created. Not a problem in our case.
+ bookmarksDatabase.insert(BOOKMARKS_TABLE, null, bookmarkContentValues);
+
+ // Close the database handle.
+ bookmarksDatabase.close();
+ }
+
+ public Cursor getBookmarksCursor() {
+ // Get a readable database handle.
+ SQLiteDatabase bookmarksDatabase = this.getReadableDatabase();
+
+ // Get everything in the BOOKMARKS_TABLE.
+ String GET_ALL_BOOKMARKS = "Select * FROM " + BOOKMARKS_TABLE;
+
+ // Return the results as a Cursor. The second argument is "null" because there are no selectionArgs.
+ // We can't close the Cursor because we need to use it in the parent activity.
+ return bookmarksDatabase.rawQuery(GET_ALL_BOOKMARKS, null);
+ }
+
+ public String getBookmarkURL(int databaseID) {
+ // Get a readable database handle.
+ SQLiteDatabase bookmarksDatabase = this.getReadableDatabase();
+
+ // Get the row for the selected databaseID.
+ String GET_BOOKMARK_URL = "Select * FROM " + BOOKMARKS_TABLE +
+ " WHERE " + ID + " = " + databaseID;
+
+ // Save the results as Cursor and move it to the first (only) row. The second argument is "null" because there are no selectionArgs.
+ Cursor bookmarksCursor = bookmarksDatabase.rawQuery(GET_BOOKMARK_URL, null);
+ bookmarksCursor.moveToFirst();
+
+ // Get the int that identifies the "BOOKMARK_URL" column and save the string as bookmarkURL.
+ int urlColumnInt = bookmarksCursor.getColumnIndex(BOOKMARK_URL);
+ String bookmarkURLString = bookmarksCursor.getString(urlColumnInt);
+
+ // Close the Cursor and the database handle.
+ bookmarksCursor.close();
+ bookmarksDatabase.close();
+
+ // Return the bookmarkURLString.
+ return bookmarkURLString;
+ }
+}
--- /dev/null
+/**
+ * Copyright 2016 Soren Stoutner <soren@stoutner.com>.
+ *
+ * This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
+ *
+ * Privacy Browser is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Privacy Browser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Privacy Browser. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package com.stoutner.privacybrowser;
+
+import android.app.Activity;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.content.DialogInterface;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+// If we don't use android.support.v7.app.AlertDialog instead of android.app.AlertDialog then the dialog will be covered by the keyboard.
+import android.support.v7.app.AlertDialog;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.WindowManager;
+import android.widget.EditText;
+
+public class CreateBookmark extends DialogFragment {
+ // The public interface is used to send information back to the parent activity.
+ public interface CreateBookmarkListener {
+ void onCreateBookmarkCancel(DialogFragment createBookmarkDialogFragment);
+
+ void onCreateBookmarkCreate(DialogFragment createBookmarkDialogFragment);
+ }
+
+ // createBookmarkListener is used in onAttach() and onCreateDialog()
+ private CreateBookmarkListener createBookmarkListener;
+
+ // Check to make sure the parent activity implements the listener.
+ public void onAttach(Activity parentActivity) {
+ super.onAttach(parentActivity);
+ try {
+ createBookmarkListener = (CreateBookmarkListener) parentActivity;
+ } catch(ClassCastException exception) {
+ throw new ClassCastException(parentActivity.toString() + " must implement CreateBookmarkListener.");
+ }
+ }
+
+ // onCreateDialog requires @NonNull.
+ @Override
+ @NonNull
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ // Create a drawable version of the favorite icon.
+ Drawable favoriteIconDrawable = new BitmapDrawable(getResources(), MainWebViewActivity.favoriteIcon);
+
+ // Get the activity's layout inflater.
+ LayoutInflater customDialogInflater = getActivity().getLayoutInflater();
+
+ // Use AlertDialog.Builder to create the AlertDialog. The style formats the color of the button text.
+ AlertDialog.Builder createBookmarkDialogBuilder = new AlertDialog.Builder(getActivity(), R.style.PrivacyBrowser_AlertDialog);
+ createBookmarkDialogBuilder.setTitle(R.string.create_bookmark);
+ createBookmarkDialogBuilder.setIcon(favoriteIconDrawable);
+ // The parent view is "null" because it will be assigned by AlertDialog.
+ createBookmarkDialogBuilder.setView(customDialogInflater.inflate(R.layout.create_bookmark_dialog, null));
+
+ // Set an onClick listener on the negative button.
+ createBookmarkDialogBuilder.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ createBookmarkListener.onCreateBookmarkCancel(CreateBookmark.this);
+ }
+ });
+
+ // Set an onClick listener on the positive button.
+ createBookmarkDialogBuilder.setPositiveButton(R.string.create, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ createBookmarkListener.onCreateBookmarkCreate(CreateBookmark.this);
+ }
+ });
+
+
+ // Create an AlertDialog from the AlertDialog.Builder.
+ final AlertDialog createBookmarkDialog = createBookmarkDialogBuilder.create();
+
+ // Show the keyboard when the Dialog is displayed on the screen.
+ createBookmarkDialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
+
+ // We need to show the AlertDialog before we can call setOnKeyListener() below.
+ createBookmarkDialog.show();
+
+ // Allow the "enter" key on the keyboard to create the bookmark from "create_bookmark_name_edittext".
+ EditText createBookmarkNameEditText = (EditText) createBookmarkDialog.findViewById(R.id.create_bookmark_name_edittext);
+ assert createBookmarkNameEditText != null; // Remove the warning below that createBookmarkNameEditText might be null.
+ createBookmarkNameEditText.setOnKeyListener(new View.OnKeyListener() {
+ public boolean onKey(View v, int keyCode, KeyEvent event) {
+ // If the event is a key-down on the "enter" button, select the PositiveButton "Create".
+ if ((event.getAction() == KeyEvent.ACTION_DOWN) && (keyCode == KeyEvent.KEYCODE_ENTER)) {
+ // Trigger the createBookmarkListener.
+ createBookmarkListener.onCreateBookmarkCreate(CreateBookmark.this);
+
+ // Manually dismiss the AlertDialog.
+ createBookmarkDialog.dismiss();
+
+ // Consume the event.
+ return true;
+ } else { // If any other key was pressed, do not consume the event.
+ return false;
+ }
+ }
+ });
+
+ // Set the formattedUrlString as the initial text of "create_bookmark_url_edittext".
+ EditText createBookmarkUrlEditText = (EditText) createBookmarkDialog.findViewById(R.id.create_bookmark_url_edittext);
+ assert createBookmarkUrlEditText != null;// Remove the warning below that createBookmarkUrlEditText might be null.
+ createBookmarkUrlEditText.setText(MainWebViewActivity.formattedUrlString);
+
+ // Allow the "enter" key on the keyboard to create the bookmark from "create_bookmark_url_edittext".
+ createBookmarkUrlEditText.setOnKeyListener(new View.OnKeyListener() {
+ public boolean onKey(View v, int keyCode, KeyEvent event) {
+ // If the event is a key-down on the "enter" button, select the PositiveButton "Create".
+ if ((event.getAction() == KeyEvent.ACTION_DOWN) && (keyCode == KeyEvent.KEYCODE_ENTER)) {
+ // Trigger the create listener.
+ createBookmarkListener.onCreateBookmarkCreate(CreateBookmark.this);
+
+ // Manually dismiss the AlertDialog.
+ createBookmarkDialog.dismiss();
+
+ // Consume the event.
+ return true;
+ } else { // If any other key was pressed, do not consume the event.
+ return false;
+ }
+ }
+ });
+
+ // onCreateDialog requires the return of an AlertDialog
+ return createBookmarkDialog;
+ }
+}
\ No newline at end of file
/**
- * Copyright 2015 Soren Stoutner <soren@stoutner.com>.
+ * Copyright 2015-2016 Soren Stoutner <soren@stoutner.com>.
*
* This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
*
import android.app.Activity;
import android.app.Dialog;
+import android.app.DialogFragment;
import android.content.DialogInterface;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.support.annotation.NonNull;
-import android.support.v4.app.DialogFragment;
+// If we don't use android.support.v7.app.AlertDialog instead of android.app.AlertDialog then the dialog will be covered by the keyboard.
import android.support.v7.app.AlertDialog;
-import android.support.v7.app.AppCompatDialogFragment;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;
import android.widget.EditText;
-public class CreateHomeScreenShortcut extends AppCompatDialogFragment {
- // The public interface is used to send information back to the activity that called CreateHomeScreenShortcut.
+public class CreateHomeScreenShortcut extends DialogFragment {
+ // The public interface is used to send information back to the parent activity.
public interface CreateHomeScreenSchortcutListener {
- void onCreateHomeScreenShortcutCancel(DialogFragment dialog);
+ void onCreateHomeScreenShortcutCancel(DialogFragment dialogFragment);
- void onCreateHomeScreenShortcutCreate(DialogFragment dialog);
+ void onCreateHomeScreenShortcutCreate(DialogFragment dialogFragment);
}
- private CreateHomeScreenSchortcutListener buttonListener;
+ //createHomeScreenShortcutListener is used in onAttach and and onCreateDialog.
+ private CreateHomeScreenSchortcutListener createHomeScreenShortcutListener;
- // Check to make sure that the activity that called CreateHomeScreenShortcut implements both listeners.
- public void onAttach(Activity activity) {
- super.onAttach(activity);
+ // Check to make sure that the parent activity implements the listener.
+ public void onAttach(Activity parentActivity) {
+ super.onAttach(parentActivity);
try {
- buttonListener = (CreateHomeScreenSchortcutListener) activity;
- } catch (ClassCastException e) {
- throw new ClassCastException(activity.toString() + " must implement CreateHomeScreenShortcutListener.");
+ createHomeScreenShortcutListener = (CreateHomeScreenSchortcutListener) parentActivity;
+ } catch(ClassCastException exception) {
+ throw new ClassCastException(parentActivity.toString() + " must implement CreateHomeScreenShortcutListener.");
}
}
// Create a drawable version of the favorite icon.
Drawable favoriteIconDrawable = new BitmapDrawable(getResources(), MainWebViewActivity.favoriteIcon);
- // Use AlertDialog.Builder to create the AlertDialog
- AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(getActivity());
+ // Get the activity's layout inflater.
LayoutInflater customDialogInflater = getActivity().getLayoutInflater();
- alertDialogBuilder.setTitle(R.string.shortcut_name);
- alertDialogBuilder.setIcon(favoriteIconDrawable);
- alertDialogBuilder.setView(customDialogInflater.inflate(R.layout.create_home_screen_shortcut_dialog, null));
- alertDialogBuilder.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
+
+ // Use AlertDialog.Builder to create the AlertDialog. The style formats the color of the button text.
+ AlertDialog.Builder createHomeScreenShorcutDialogBuilder = new AlertDialog.Builder(getActivity(), R.style.PrivacyBrowser_AlertDialog);
+ createHomeScreenShorcutDialogBuilder.setTitle(R.string.create_shortcut);
+ createHomeScreenShorcutDialogBuilder.setIcon(favoriteIconDrawable);
+ // The parent view is "null" because it will be assigned by AlertDialog.
+ createHomeScreenShorcutDialogBuilder.setView(customDialogInflater.inflate(R.layout.create_home_screen_shortcut_dialog, null));
+
+ // Set an onClick listener on the negative button.
+ createHomeScreenShorcutDialogBuilder.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
- buttonListener.onCreateHomeScreenShortcutCancel(CreateHomeScreenShortcut.this);
+ createHomeScreenShortcutListener.onCreateHomeScreenShortcutCancel(CreateHomeScreenShortcut.this);
}
});
- alertDialogBuilder.setPositiveButton(R.string.create, new DialogInterface.OnClickListener() {
+
+ // Set an onClick listener on the positive button.
+ createHomeScreenShorcutDialogBuilder.setPositiveButton(R.string.create, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
- buttonListener.onCreateHomeScreenShortcutCreate(CreateHomeScreenShortcut.this);
+ createHomeScreenShortcutListener.onCreateHomeScreenShortcutCreate(CreateHomeScreenShortcut.this);
}
});
- // Assign the alertDialogBuilder to an AlertDialog.
- final AlertDialog alertDialog = alertDialogBuilder.create();
- // Show the keyboard when the dialog is displayed on the screen.
- alertDialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
+ // Create an AlertDialog from the AlertDialogBuilder.
+ final AlertDialog createHomeScreenShortcutAlertDialog = createHomeScreenShorcutDialogBuilder.create();
- // We need to show alertDialog before we can setOnKeyListener below.
- alertDialog.show();
+ // Show the keyboard when the Dialog is displayed on the screen.
+ createHomeScreenShortcutAlertDialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
- EditText shortcutNameEditText = (EditText) alertDialog.findViewById(R.id.shortcutNameEditText);
+ // We need to show the AlertDialog before we can call setOnKeyListener() below.
+ createHomeScreenShortcutAlertDialog.show();
// Allow the "enter" key on the keyboard to create the shortcut.
+ EditText shortcutNameEditText = (EditText) createHomeScreenShortcutAlertDialog.findViewById(R.id.shortcut_name_edittext);
+ assert shortcutNameEditText != null; // Remove the warning below that shortcutNameEditText might be null.
shortcutNameEditText.setOnKeyListener(new View.OnKeyListener() {
public boolean onKey(View v, int keyCode, KeyEvent event) {
- // If the event is a key-down event on the "enter" button, select the PositiveButton "Create".
+ // If the event is a key-down on the "enter" button, select the PositiveButton "Create".
if ((event.getAction() == KeyEvent.ACTION_DOWN) && (keyCode == KeyEvent.KEYCODE_ENTER)) {
// Trigger the create listener.
- buttonListener.onCreateHomeScreenShortcutCreate(CreateHomeScreenShortcut.this);
+ createHomeScreenShortcutListener.onCreateHomeScreenShortcutCreate(CreateHomeScreenShortcut.this);
- // Manually dismiss alertDialog.
- alertDialog.dismiss();
+ // Manually dismiss the AlertDialog.
+ createHomeScreenShortcutAlertDialog.dismiss();
// Consume the event.
return true;
- } else {
- // If any other key was pressed, do not consume the event.
+ } else { // If any other key was pressed, do not consume the event.
return false;
}
}
});
// onCreateDialog requires the return of an AlertDialog.
- return alertDialog;
+ return createHomeScreenShortcutAlertDialog;
}
}
\ No newline at end of file
setContentView(R.layout.guide_coordinatorlayout);
// We need to use the SupportActionBar from android.support.v7.app.ActionBar until the minimum API is >= 21.
- Toolbar supportAppBar = (Toolbar) findViewById(R.id.guide_toolbar);
- setSupportActionBar(supportAppBar);
+ Toolbar guideAppBar = (Toolbar) findViewById(R.id.guide_toolbar);
+ setSupportActionBar(guideAppBar);
// Display the home arrow on supportAppBar.
final ActionBar appBar = getSupportActionBar();
import android.annotation.SuppressLint;
import android.app.Activity;
+import android.app.DialogFragment;
import android.app.DownloadManager;
import android.content.Intent;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.support.design.widget.NavigationView;
import android.support.design.widget.Snackbar;
-import android.support.v4.app.DialogFragment;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.app.ActionBar;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.AppCompatActivity;
-import android.support.v7.app.AppCompatDialogFragment;
import android.support.v7.widget.Toolbar;
import android.util.Patterns;
import android.view.KeyEvent;
// We need to use AppCompatActivity from android.support.v7.app.AppCompatActivity to have access to the SupportActionBar until the minimum API is >= 21.
public class MainWebViewActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener, CreateHomeScreenShortcut.CreateHomeScreenSchortcutListener {
- // favoriteIcon is public static so it can be accessed from CreateHomeScreenShortcut.
+ // favoriteIcon is public static so it can be accessed from CreateHomeScreenShortcut and BookmarksActivity.
+ // It is also used in onCreate() and onCreateHomeScreenShortcutCreate().
public static Bitmap favoriteIcon;
- // mainWebView is public static so it can be accessed from SettingsFragment. It is also used in onCreate(), onOptionsItemSelected(), onNavigationItemSelected(), and loadUrlFromTextBox().
+
+ // mainWebView is public static so it can be accessed from SettingsFragment.
+ // It is also used in onCreate(), onOptionsItemSelected(), onNavigationItemSelected(), and loadUrlFromTextBox().
public static WebView mainWebView;
+ // formattedUrlString is public static so it can be accessed from BookmarksActivity.
+ // It is also used in onCreate(), onOptionsItemSelected(), onCreateHomeScreenShortcutCreate(), and loadUrlFromTextBox().
+ public static String formattedUrlString;
+
// mainMenu is public static so it can be accessed from SettingsFragment. It is also used in onCreateOptionsMenu() and onOptionsItemSelected().
public static Menu mainMenu;
+
// cookieManager is public static so it can be accessed from SettingsFragment. It is also used in onCreate(), onOptionsItemSelected(), and onNavigationItemSelected().
public static CookieManager cookieManager;
- // javaScriptEnabled is public static so it can be accessed from SettingsFragment. It is also used in onCreate(), onCreateOptionsMenu(), onOptionsItemSelected(), and loadUrlFromTextBox().
+
+ // javaScriptEnabled is public static so it can be accessed from SettingsFragment.
+ // It is also used in onCreate(), onCreateOptionsMenu(), onOptionsItemSelected(), and loadUrlFromTextBox().
public static boolean javaScriptEnabled;
- // firstPartyCookiesEnabled is public static so it can be accessed from SettingsFragment. It is also used in onCreate(), onCreateOptionsMenu(), onPrepareOptionsMenu(), and onOptionsItemSelected().
+
+ // firstPartyCookiesEnabled is public static so it can be accessed from SettingsFragment.
+ // It is also used in onCreate(), onCreateOptionsMenu(), onPrepareOptionsMenu(), and onOptionsItemSelected().
public static boolean firstPartyCookiesEnabled;
+
// thirdPartyCookiesEnabled is used in onCreate(), onCreateOptionsMenu(), onPrepareOptionsMenu(), and onOptionsItemSelected().
public static boolean thirdPartyCookiesEnabled;
+
// domStorageEnabled is public static so it can be accessed from SettingsFragment. It is also used in onCreate(), onCreateOptionsMenu(), and onOptionsItemSelected().
public static boolean domStorageEnabled;
+
// saveFormDataEnabled is public static so it can be accessed from SettingsFragment. It is also used in onCreate(), onCreateOptionsMenu(), and onOptionsItemSelected().
public static boolean saveFormDataEnabled;
+
// javaScriptDisabledSearchURL is public static so it can be accessed from SettingsFragment. It is also used in onCreate() and loadURLFromTextBox().
public static String javaScriptDisabledSearchURL;
+
// javaScriptEnabledSearchURL is public static so it can be accessed from SettingsFragment. It is also used in onCreate() and loadURLFromTextBox().
public static String javaScriptEnabledSearchURL;
+
// homepage is public static so it can be accessed from SettingsFragment. It is also used in onCreate() and onOptionsItemSelected().
public static String homepage;
+
// swipeToRefresh is public static so it can be accessed from SettingsFragment. It is also used in onCreate().
public static SwipeRefreshLayout swipeToRefresh;
+
// swipeToRefreshEnabled is public static so it can be accessed from SettingsFragment. It is also used in onCreate().
public static boolean swipeToRefreshEnabled;
+
+
// drawerToggle is used in onCreate(), onPostCreate(), onConfigurationChanged(), onNewIntent(), and onNavigationItemSelected().
private ActionBarDrawerToggle drawerToggle;
+
// drawerLayout is used in onCreate(), onNewIntent(), and onBackPressed().
private DrawerLayout drawerLayout;
- // formattedUrlString is used in onCreate(), onOptionsItemSelected(), onCreateHomeScreenShortcutCreate(), and loadUrlFromTextBox().
- private String formattedUrlString;
+
// privacyIcon is used in onCreateOptionsMenu() and updatePrivacyIcon().
private MenuItem privacyIcon;
+
// urlTextBox is used in onCreate(), onOptionsItemSelected(), and loadUrlFromTextBox().
private EditText urlTextBox;
+
// adView is used in onCreate() and onConfigurationChanged().
private View adView;
return true;
case R.id.addToHomescreen:
- // Show the CreateHomeScreenShortcut AlertDialog and name this instance createShortcut.
- AppCompatDialogFragment shortcutDialog = new CreateHomeScreenShortcut();
- shortcutDialog.show(getSupportFragmentManager(), "createShortcut");
+ // Show the CreateHomeScreenShortcut AlertDialog and name this instance "@string/create_shortcut".
+ DialogFragment createHomeScreenShortcutDialogFragment = new CreateHomeScreenShortcut();
+ createHomeScreenShortcutDialogFragment.show(getFragmentManager(), "@string/create_shortcut");
//Everything else will be handled by CreateHomeScreenShortcut and the associated listeners below.
return true;
}
break;
+ case R.id.bookmarks:
+ // Launch BookmarksActivity.
+ Intent bookmarksIntent = new Intent(this, BookmarksActivity.class);
+ startActivity(bookmarksIntent);
+ break;
+
case R.id.downloads:
// Launch the system Download Manager.
Intent downloadManagerIntent = new Intent(DownloadManager.ACTION_VIEW_DOWNLOADS);
startActivity(downloadManagerIntent);
break;
- case R.id.guide:
- // Launch GuideActivity.
- Intent guideIntent = new Intent(this, GuideActivity.class);
- startActivity(guideIntent);
- break;
-
case R.id.settings:
// Launch SettingsActivity.
Intent settingsIntent = new Intent(this, SettingsActivity.class);
startActivity(settingsIntent);
break;
+ case R.id.guide:
+ // Launch GuideActivity.
+ Intent guideIntent = new Intent(this, GuideActivity.class);
+ startActivity(guideIntent);
+ break;
+
case R.id.about:
// Launch AboutActivity.
Intent aboutIntent = new Intent(this, AboutActivity.class);
WebStorage domStorage = WebStorage.getInstance();
domStorage.deleteAllData();
+ // Clear form data.
+ WebViewDatabase formData = WebViewDatabase.getInstance(this);
+ formData.clearFormData();
+
// Clear cache. The argument of "true" includes disk files.
mainWebView.clearCache(true);
}
@Override
- public void onCreateHomeScreenShortcutCancel(DialogFragment dialog) {
+ public void onCreateHomeScreenShortcutCancel(DialogFragment dialogFragment) {
// Do nothing because the user selected "Cancel".
}
@Override
- public void onCreateHomeScreenShortcutCreate(DialogFragment dialog) {
+ public void onCreateHomeScreenShortcutCreate(DialogFragment dialogFragment) {
// Get shortcutNameEditText from the alert dialog.
- EditText shortcutNameEditText = (EditText) dialog.getDialog().findViewById(R.id.shortcutNameEditText);
+ EditText shortcutNameEditText = (EditText) dialogFragment.getDialog().findViewById(R.id.shortcut_name_edittext);
// Create the bookmark shortcut based on formattedUrlString.
Intent bookmarkShortcut = new Intent();
customUserAgent.setSummary(sharedPreferences.getString("custom_user_agent", "PrivacyBrowser/1.0"));
// Update mainWebView's user agent. The default is "PrivacyBrowser/1.0".
- MainWebViewActivity.mainWebView.getSettings().setUserAgentString(sharedPreferences.getString("user_agent", "PrivacyBrowser/1.0"));
+ MainWebViewActivity.mainWebView.getSettings().setUserAgentString(sharedPreferences.getString("custom_user_agent", "PrivacyBrowser/1.0"));
break;
case "javascript_disabled_search":
--- /dev/null
+<!-- add.xml comes from the Android Material icon set, where it is called ic_add.
+ It is released under the CC-BY license <https://creativecommons.org/licenses/by/4.0/>. -->
+
+<vector
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="24dp"
+ android:width="24dp"
+ android:viewportHeight="24.0"
+ android:viewportWidth="24.0" >
+
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
+</vector>
--- /dev/null
+<!-- bookmarks.xml comes from the Android Material icon set, where it is called ic_bookmark_border.
+ It is released under the CC-BY license <https://creativecommons.org/licenses/by/4.0/>. -->
+
+<vector
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="24dp"
+ android:width="24dp"
+ android:viewportHeight="24.0"
+ android:viewportWidth="24.0" >
+
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M17,3L7,3c-1.1,0 -1.99,0.9 -1.99,2L5,21l7,-3 7,3L19,5c0,-1.1 -0.9,-2 -2,-2zM17,18l-5,-2.18L7,18L7,5h10v13z"/>
+</vector>
<!-- the LinearLayout with orientation="vertical" moves the ViewPager below the AppBarLayout. -->
<LinearLayout
- android:layout_width="match_parent"
android:layout_height="match_parent"
+ android:layout_width="match_parent"
android:orientation="vertical" >
<!-- We need to set android:background="@color/blue" here or any space to the right of the TabLayout on large devices will be white. -->
<!-- android:theme="@style/PrivacyBrowser.DarkAppBar" makes the text and icons in the AppBar white. -->
<android.support.v7.widget.Toolbar
android:id="@+id/about_toolbar"
- android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:layout_width="match_parent"
android:background="@color/blue"
android:theme="@style/PrivacyBrowser.DarkAppBar"
app:popupTheme="@style/PrivacyBrowser.PopupOverlay" />
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ Copyright 2016 Soren Stoutner <soren@stoutner.com>.
+
+ This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
+
+ Privacy Browser is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Privacy Browser is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Privacy Browser. If not, see <http://www.gnu.org/licenses/>. -->
+
+<!-- android:fitsSystemWindows="true" moves the AppBar below the status bar.
+ When it is specified the theme should include <item name="android:windowTranslucentStatus">true</item>
+ to make the status bar a transparent, darkened overlay. -->
+<android.support.design.widget.CoordinatorLayout
+ android:id="@+id/bookmarks_coordinatorlayout"
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_height="match_parent"
+ android:layout_width="match_parent"
+ android:fitsSystemWindows="true" >
+
+ <!-- the LinearLayout with orientation="vertical" moves the content below the AppBarLayout. -->
+ <LinearLayout
+ android:layout_height="match_parent"
+ android:layout_width="match_parent"
+ android:orientation="vertical" >
+
+ <android.support.design.widget.AppBarLayout
+ android:id="@+id/bookmarks_appbarlayout"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:theme="@style/PrivacyBrowser.AppBarOverlay" >
+
+ <!-- android:theme="@style/PrivacyBrowser.DarkAppBar" makes the text and icons in the AppBar white. -->
+ <android.support.v7.widget.Toolbar
+ android:id="@+id/bookmarks_toolbar"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:background="@color/blue"
+ android:theme="@style/PrivacyBrowser.DarkAppBar"
+ app:popupTheme="@style/PrivacyBrowser.PopupOverlay" />
+ </android.support.design.widget.AppBarLayout>
+
+ <ListView
+ android:id="@+id/bookmarks_listview"
+ android:layout_height="match_parent"
+ android:layout_width="match_parent" />
+ </LinearLayout>
+
+ <android.support.design.widget.FloatingActionButton
+ android:id="@+id/create_bookmark_fab"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:layout_gravity="bottom|end"
+ android:layout_margin="16dp"
+ android:src="@drawable/add" />
+</android.support.design.widget.CoordinatorLayout>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ Copyright 2016 Soren Stoutner <soren@stoutner.com>.
+
+ This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
+
+ Privacy Browser is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Privacy Browser is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Privacy Browser. If not, see <http://www.gnu.org/licenses/>. -->
+
+<LinearLayout
+ android:id="@+id/bookmarks_item_linearlayout"
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:orientation="horizontal"
+ xmlns:tools="http://schemas.android.com/tools">
+
+ <ImageView
+ android:id="@+id/bookmark_favorite_icon"
+ android:layout_height="30dp"
+ android:layout_width="30dp"
+ android:layout_gravity="center_vertical"
+ android:layout_marginStart="10dp"
+ tools:ignore="ContentDescription" />
+
+ <TextView
+ android:id="@+id/bookmark_name"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textColor="@color/black"
+ android:textSize="22sp"
+ android:layout_margin="10dp"
+ android:singleLine="true" />
+</LinearLayout>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ Copyright 2016 Soren Stoutner <soren@stoutner.com>.
+
+ This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
+
+ Privacy Browser is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Privacy Browser is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Privacy Browser. If not, see <http://www.gnu.org/licenses/>. -->
+
+<LinearLayout
+ android:id="@+id/create_bookmark_dialog_linearlayout"
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent" >
+
+ <!-- android:imeOptions="actionGo" sets the keyboard to have a "go" key instead of a "new line" key.
+ android:imeOptions=flagNoExtractUi" doesn't cover up the entire UI when typing in landscape orientation.
+ android:inputType="textUri" disables spell check in the EditText.
+ android:singleLine="true" is not needed in a Dialog.-->
+ <EditText
+ android:id="@+id/create_bookmark_name_edittext"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:layout_marginTop="16dp"
+ android:layout_marginLeft="4dp"
+ android:layout_marginRight="4dp"
+ android:layout_marginBottom="4dp"
+ android:hint="@string/bookmark_name"
+ android:imeOptions="actionGo|flagNoExtractUi"
+ android:inputType="textUri" />
+
+ <EditText
+ android:id="@+id/create_bookmark_url_edittext"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:layout_marginTop="4dp"
+ android:layout_marginLeft="4dp"
+ android:layout_marginRight="4dp"
+ android:layout_marginBottom="16dp"
+ android:hint="@string/bookmark_url"
+ android:imeOptions="actionGo|flagNoExtractUi"
+ android:inputType="textUri" />
+
+</LinearLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright 2015 Soren Stoutner <soren@stoutner.com>.
+ Copyright 2015-2016 Soren Stoutner <soren@stoutner.com>.
This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
along with Privacy Browser. If not, see <http://www.gnu.org/licenses/>. -->
<RelativeLayout
- android:id="@+id/createHomeScreenShortcutDialogRelativeLayout"
+ android:id="@+id/create_home_screen_shortcut_dialog_relativelayout"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
- <!-- android:imeOptions="actionGo" sets the keyboard to have a "go" key instead of a "new line" key. -->
- <!-- android:imeOptions=flagNoExtractUi" doesn't cover up the entire UI when typing in landscape orientation. -->
- <!-- android:inputType="textUri" disables spell check in the EditText. -->
+ <!-- android:imeOptions="actionGo" sets the keyboard to have a "go" key instead of a "new line" key.
+ android:imeOptions=flagNoExtractUi" doesn't cover up the entire UI when typing in landscape orientation.
+ android:inputType="textUri" disables spell check in the EditText.
+ android:singleLine="true" is not needed in a Dialog.-->
<EditText
- android:id="@+id/shortcutNameEditText"
+ android:id="@+id/shortcut_name_edittext"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:layout_marginLeft="4dp"
android:layout_marginRight="4dp"
android:layout_marginBottom="16dp"
+ android:hint="@string/shortcut_name"
android:imeOptions="actionGo|flagNoExtractUi"
android:inputType="textUri" />
<group
android:id="@+id/navigationGroup1" >
<item
- android:id="@+id/downloads"
- android:title="@string/downloads"
- android:icon="@drawable/downloads"
+ android:id="@+id/bookmarks"
+ android:title="@string/bookmarks"
+ android:icon="@drawable/bookmarks"
android:orderInCategory="40" />
<item
- android:id="@+id/guide"
- android:title="@string/guide"
- android:icon="@drawable/guide"
+ android:id="@+id/downloads"
+ android:title="@string/downloads"
+ android:icon="@drawable/downloads"
android:orderInCategory="50" />
+ </group>
+ <group
+ android:id="@+id/navigationGroup2" >
<item
android:id="@+id/settings"
android:title="@string/settings"
android:icon="@drawable/settings"
android:orderInCategory="60" />
+ <item
+ android:id="@+id/guide"
+ android:title="@string/guide"
+ android:icon="@drawable/guide"
+ android:orderInCategory="70" />
+
<item
android:id="@+id/about"
android:title="@string/about"
android:icon="@drawable/about"
- android:orderInCategory="70" />
+ android:orderInCategory="80" />
</group>
<!-- If a group has an id, a line is drawn above it in the navigation view. -->
<group
- android:id="@+id/navigationGroup2" >
+ android:id="@+id/navigationGroup3" >
<item
android:id="@+id/clearAndExit"
android:title="@string/clear_and_exit"
android:icon="@drawable/exit"
- android:orderInCategory="80" />
+ android:orderInCategory="90" />
</group>
</menu>
\ No newline at end of file
<!-- android:windowTranslucentStatus requires API >= 19. It makes the system status bar transparent.
When it is specified the root layout should include android:fitsSystemWindows="true".
colorPrimaryDark goes behind the status bar, which is then darkened by the overlay. -->
- <style name="PrivacyBrowser.TabActivity">
+ <style name="PrivacyBrowser.SecondaryActivity">
<item name="android:windowTranslucentStatus">true</item>
<item name="colorPrimaryDark">@color/blue</item>
</style>
<string name="home">Home</string>
<string name="back">Back</string>
<string name="forward">Forward</string>
+ <string name="bookmarks">Bookmarks</string>
<string name="downloads">Downloads</string>
- <string name="guide">Guide</string>
<string name="settings">Settings</string>
+ <string name="guide">Guide</string>
<string name="about">About</string>
<string name="clear_and_exit">Clear and Exit</string>
<string name="refresh">Refresh</string>
<!-- Create Home Screen Shortcut Alert Dialog. -->
+ <string name="create_shortcut">Create shortcut</string>
<string name="shortcut_name">Shortcut name</string>
<string name="cancel">Cancel</string>
<string name="create">Create</string>
+ <!-- Bookmarks. -->
+ <string name="create_bookmark">Create bookmark</string>
+ <string name="bookmark_name">Bookmark name</string>
+ <string name="bookmark_url">Bookmark URL</string>
+
<!-- Guide. -->
<string name="privacy_browser_guide">Privacy Browser Guide</string>
<string name="overview">Overview</string>
<style name="PrivacyBrowser.MainWebView" />
- <style name="PrivacyBrowser.TabActivity" />
+ <style name="PrivacyBrowser.SecondaryActivity" />
<!-- colorPrimaryDark is the color of the status bar. -->
<style name="PrivacyBrowser.Settings" parent="Theme.AppCompat.Light.DarkActionBar">
<style name="PrivacyBrowser.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />
+ <style name="PrivacyBrowser.AlertDialog" parent="Theme.AppCompat.Light.Dialog.Alert">
+ <item name="colorAccent">@color/blue</item>
+ </style>
+
</resources>
\ No newline at end of file