<p><img class="center" src="images/ic_add.png" height="32" width="32"> ic_add.</p>
+<p><img class="center" src="images/ic_delete.png" height="32" width="32"> ic_download.</p>
<hr/>
<h3>GNU General Public License</h3>
<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>Deletes the current URL</item>.</li>
<li><item>Destroys the internal state of the WebView</item>.</li>
<li><item>Closes Privacy Browser</item>. For Android Lollipop and newer (version >= 5.0 or API >= 21), Privacy Browser is also removed from the recent app list.</li>
</ul>
import android.app.Activity;
import android.app.DialogFragment;
+import android.content.Context;
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.design.widget.Snackbar;
import android.support.v4.app.NavUtils;
+import android.support.v4.widget.CursorAdapter;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
+import android.view.ActionMode;
+import android.view.Menu;
+import android.view.MenuItem;
import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AbsListView;
import android.widget.AdapterView;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.ListView;
-import android.widget.SimpleCursorAdapter;
+import android.widget.TextView;
import java.io.ByteArrayOutputStream;
private BookmarksDatabaseHandler bookmarksDatabaseHandler;
private ListView bookmarksListView;
+ // deleteBookmarkMenuItem is used in onCreate() and onPrepareOptionsMenu().
+ private MenuItem deleteBookmarkMenuItem;
+
@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);
+ final Toolbar bookmarksAppBar = (Toolbar) findViewById(R.id.bookmarks_toolbar);
setSupportActionBar(bookmarksAppBar);
// Display the home arrow on supportAppBar.
}
});
+ // registerForContextMenu(bookmarksListView);
+
+ bookmarksListView.setMultiChoiceModeListener(new AbsListView.MultiChoiceModeListener() {
+ @Override
+ public void onItemCheckedStateChanged(ActionMode mode, int position, long id, boolean checked) {
+ String numberSelectedString;
+ long[] selectedItemsLongArray = bookmarksListView.getCheckedItemIds();
+
+ numberSelectedString = selectedItemsLongArray.length + " " + getString(R.string.selected);
+
+ mode.setSubtitle(numberSelectedString);
+ }
+
+ @Override
+ public boolean onCreateActionMode(ActionMode mode, Menu menu) {
+ // Inflate the menu for the contextual app bar.
+ getMenuInflater().inflate(R.menu.bookmarks_context_menu, menu);
+
+ mode.setTitle(R.string.bookmarks);
+
+ return true;
+ }
+
+ @Override
+ public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
+ return false;
+ }
+
+ @Override
+ public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
+ int menuItemId = item.getItemId();
+
+ switch (menuItemId) {
+ case R.id.delete_bookmark:
+ // Get an array of the selected rows.
+ final long[] selectedItemsLongArray = bookmarksListView.getCheckedItemIds();
+
+ String snackbarMessage;
+
+ // Determine how many items are in the array and prepare an appropriate Snackbar message.
+ if (selectedItemsLongArray.length == 1) {
+ snackbarMessage = getString(R.string.one_bookmark_deleted);
+ } else {
+ snackbarMessage = selectedItemsLongArray.length + " " + getString(R.string.bookmarks_deleted);
+ }
+
+ updateBookmarksListViewExcept(selectedItemsLongArray);
+
+ // Show a SnackBar.
+ Snackbar.make(findViewById(R.id.bookmarks_coordinatorlayout), snackbarMessage, Snackbar.LENGTH_LONG)
+ .setAction(R.string.undo, new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ // Do nothing because everything will be handled by `onDismissed()` below.
+ }
+ })
+ .setCallback(new Snackbar.Callback() {
+ @Override
+ public void onDismissed(Snackbar snackbar, int event) {
+ switch (event) {
+ // The user pushed the "Undo" button.
+ case Snackbar.Callback.DISMISS_EVENT_ACTION:
+ // Refresh the ListView to show the rows again.
+ updateBookmarksListView();
+
+ break;
+
+ // The Snackbar was dismissed without the "Undo" button being pushed.
+ default:
+ // Delete each selected row.
+ for (long databaseIdLong : selectedItemsLongArray) {
+ // Convert `databaseIdLong` to an int.
+ int databaseIdInt = (int) databaseIdLong;
+
+ // Delete the database row.
+ bookmarksDatabaseHandler.deleteBookmark(databaseIdInt);
+ }
+ break;
+ }
+ }
+ })
+ .show();
+
+ // Close the contextual app bar.
+ mode.finish();
+ }
+ return true;
+ }
+
+ @Override
+ public void onDestroyActionMode(ActionMode mode) {
+
+ }
+ });
+
// Set a FloatingActionButton for creating new bookmarks.
FloatingActionButton createBookmarkFAB = (FloatingActionButton) findViewById(R.id.create_bookmark_fab);
assert createBookmarkFAB != null;
});
}
+ /*
+ @Override
+ public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
+ super.onCreateContextMenu(menu, v, menuInfo);
+ getMenuInflater().inflate(R.menu.bookmarks_context_menu, menu);
+ } */
+
+ /*@Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ getMenuInflater().inflate(R.menu.menu_bookmarks_options, menu);
+
+ return true;
+ }
+
+ @Override
+ public boolean onPrepareOptionsMenu(Menu menu) {
+ // Disable the delete icon.
+ deleteBookmarkMenuItem = menu.findItem(R.id.delete_bookmark);
+ deleteBookmarkMenuItem.setVisible(false);
+
+ // Run all the other default commands.
+ super.onPrepareOptionsMenu(menu);
+
+ // `return true` displays the menu;
+ return true;
+ }*/
+
@Override
public void onCreateBookmarkCancel(DialogFragment createBookmarkDialogFragment) {
// Do nothing because the user selected "Cancel".
// 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;
- }
+ // Setup bookmarksCursorAdapter with `this` context. The `false` disables autoRequery.
+ CursorAdapter bookmarksCursorAdapter = new CursorAdapter(this, bookmarksCursor, false) {
+ @Override
+ public View newView(Context context, Cursor cursor, ViewGroup parent) {
+ // Inflate the individual item layout. `false` does not attach it to the root.
+ return getLayoutInflater().inflate(R.layout.bookmarks_item_linearlayout, parent, false);
}
- });
+
+ @Override
+ public void bindView(View view, Context context, Cursor cursor) {
+ // Get the favorite icon byte array from the cursor.
+ byte[] favoriteIconByteArray = cursor.getBlob(cursor.getColumnIndex(BookmarksDatabaseHandler.FAVORITEICON));
+
+ // 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);
+
+ // Display the bitmap in `bookmarkFavoriteIcon`.
+ ImageView bookmarkFavoriteIcon = (ImageView) view.findViewById(R.id.bookmark_favorite_icon);
+ bookmarkFavoriteIcon.setImageBitmap(favoriteIconBitmap);
+
+
+ // Get the bookmark name from the cursor and display it in `bookmarkNameTextView`.
+ String bookmarkNameString = cursor.getString(cursor.getColumnIndex(BookmarksDatabaseHandler.BOOKMARK_NAME));
+ TextView bookmarkNameTextView = (TextView) view.findViewById(R.id.bookmark_name);
+ assert bookmarkNameTextView != null; // This assert removes the warning that bookmarkNameTextView might be null.
+ bookmarkNameTextView.setText(bookmarkNameString);
+ }
+ };
+
+ // Update the ListView.
+ bookmarksListView.setAdapter(bookmarksCursorAdapter);
+ }
+
+ private void updateBookmarksListViewExcept(long[] exceptIdLongArray) {
+ // Get a Cursor with the current contents of the bookmarks database except for the specified database IDs.
+ final Cursor bookmarksCursor = bookmarksDatabaseHandler.getBookmarksCursorExcept(exceptIdLongArray);
+
+ // Setup bookmarksCursorAdapter with `this` context. The `false` disables autoRequery.
+ CursorAdapter bookmarksCursorAdapter = new CursorAdapter(this, bookmarksCursor, false) {
+ @Override
+ public View newView(Context context, Cursor cursor, ViewGroup parent) {
+ // Inflate the individual item layout. `false` does not attach it to the root.
+ return getLayoutInflater().inflate(R.layout.bookmarks_item_linearlayout, parent, false);
+ }
+
+ @Override
+ public void bindView(View view, Context context, Cursor cursor) {
+ // Get the favorite icon byte array from the cursor.
+ byte[] favoriteIconByteArray = cursor.getBlob(cursor.getColumnIndex(BookmarksDatabaseHandler.FAVORITEICON));
+
+ // 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);
+
+ // Display the bitmap in `bookmarkFavoriteIcon`.
+ ImageView bookmarkFavoriteIcon = (ImageView) view.findViewById(R.id.bookmark_favorite_icon);
+ bookmarkFavoriteIcon.setImageBitmap(favoriteIconBitmap);
+
+
+ // Get the bookmark name from the cursor and display it in `bookmarkNameTextView`.
+ String bookmarkNameString = cursor.getString(cursor.getColumnIndex(BookmarksDatabaseHandler.BOOKMARK_NAME));
+ TextView bookmarkNameTextView = (TextView) view.findViewById(R.id.bookmark_name);
+ assert bookmarkNameTextView != null; // This assert removes the warning that bookmarkNameTextView might be null.
+ bookmarkNameTextView.setText(bookmarkNameString);
+ }
+ };
// Update the ListView.
- bookmarksListView.setAdapter(bookmarksAdapter);
+ bookmarksListView.setAdapter(bookmarksCursorAdapter);
}
}
\ No newline at end of file
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 _ID = "_id";
public static final String DISPLAYORDER = "displayorder";
public static final String BOOKMARK_NAME = "bookmarkname";
public static final String BOOKMARK_URL = "bookmarkurl";
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, " +
+ _ID + " integer primary key, " +
DISPLAYORDER + " integer, " +
BOOKMARK_NAME + " text, " +
BOOKMARK_URL + " text, " +
SQLiteDatabase bookmarksDatabase = this.getReadableDatabase();
// Get everything in the BOOKMARKS_TABLE.
- String GET_ALL_BOOKMARKS = "Select * FROM " + BOOKMARKS_TABLE;
+ final String GET_ALL_BOOKMARKS = "Select * FROM " + BOOKMARKS_TABLE;
- // Return the results as a Cursor. The second argument is "null" because there are no selectionArgs.
+ // 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) {
+ public Cursor getBookmarksCursorExcept(long[] exceptIdLongArray) {
// 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;
+ // Prepare a string that contains the comma-separated list of IDs not to get.
+ String doNotGetIdsString = "";
+ // Extract the array to `doNotGetIdsString`.
+ for (long databaseIdLong : exceptIdLongArray) {
+ // If this is the first number, only add the number.
+ if (doNotGetIdsString.isEmpty()) {
+ doNotGetIdsString = String.valueOf(databaseIdLong);
+ } else { // If there already is a number in the string, place a `,` before the number.
+ doNotGetIdsString = doNotGetIdsString + "," + databaseIdLong;
+ }
+ }
+
+ // Prepare the SQL statement to select all items except those with the specified IDs.
+ final String GET_All_BOOKMARKS_EXCEPT_SPECIFIED = "Select * FROM " + BOOKMARKS_TABLE +
+ " WHERE " + _ID + " NOT IN (" + doNotGetIdsString + ")";
+
+ // 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_EXCEPT_SPECIFIED, null);
+ }
+
+ public String getBookmarkURL(int databaseId) {
+ // Get a readable database handle.
+ SQLiteDatabase bookmarksDatabase = this.getReadableDatabase();
+
+ // Prepare the SQL statement to get the row for the selected databaseId.
+ final 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);
// Return the bookmarkURLString.
return bookmarkURLString;
}
-}
+
+ public void deleteBookmark(int databaseId) {
+ // Get a writable database handle.
+ SQLiteDatabase bookmarksDatabase = this.getWritableDatabase();
+
+ // Deletes the row with the given databaseId. The last argument is null because we don't need additional parameters.
+ bookmarksDatabase.delete(BOOKMARKS_TABLE, _ID + " = " + databaseId, null);
+
+ // Close the database handle.
+ bookmarksDatabase.close();
+ }
+}
\ No newline at end of file
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
- getMenuInflater().inflate(R.menu.menu_options, menu);
+ getMenuInflater().inflate(R.menu.webview_options_menu, menu);
// Set mainMenu so it can be used by onOptionsItemSelected.
mainMenu = menu;
// Run all the other default commands.
super.onPrepareOptionsMenu(menu);
- // return true displays the menu.
+ // `return true` displays the menu.
return true;
}
// Clear the back/forward history.
mainWebView.clearHistory();
+ formattedUrlString = null;
+
// Destroy the internal state of the webview.
mainWebView.destroy();
--- /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/>. -->
+
+<!-- This selector changes the background of activated items in the bookmarks list view. -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item
+ android:state_activated="true"
+ android:drawable="@color/light_blue" />
+</selector>
\ No newline at end of file
--- /dev/null
+<!-- delete.xml comes from the Android Material icon set, where it is called ic_delete.
+ 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="M6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2V7H6v12zM19,4h-3.5l-1,-1h-5l-1,1H5v2h14V4z"/>
+</vector>
app:popupTheme="@style/PrivacyBrowser.PopupOverlay" />
</android.support.design.widget.AppBarLayout>
+ <!-- android:choiceMode="multipleChoiceModal" allows the contextual action menu to select more than one item at a time.
+ android:dividerHeight must be specified with android:divider or the height will be 0dp.
+ In our case we want the height to be 0dp. -->
<ListView
android:id="@+id/bookmarks_listview"
android:layout_height="match_parent"
- android:layout_width="match_parent" />
+ android:layout_width="match_parent"
+ android:choiceMode="multipleChoiceModal"
+ android:divider="@color/white"
+ android:dividerHeight="0dp" />
</LinearLayout>
<android.support.design.widget.FloatingActionButton
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:orientation="horizontal"
+ android:background="@drawable/bookmarks_list_selector"
xmlns:tools="http://schemas.android.com/tools">
<ImageView
android:layout_height="match_parent"
android:layout_gravity="start"
app:headerLayout="@layout/navigation_header"
- app:menu="@menu/menu_navigation"/>
+ app:menu="@menu/webview_navigation_menu"/>
<!-- fullScreenVideoFrameLayout is used to display full screen videos. It is initially android:visibility="gone" to hide it from view. -->
<FrameLayout
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ Copyright 2015-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/>. -->
+
+<menu
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto">
+
+ <item
+ android:id="@+id/delete_bookmark"
+ android:title="@string/delete"
+ android:orderInCategory="10"
+ android:icon="@drawable/delete"
+ app:showAsAction="ifRoom" />
+</menu>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ Copyright 2015-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/>. -->
+
+<menu
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto">
+
+ <item
+ android:id="@+id/delete_bookmark1"
+ android:title="@string/delete"
+ android:orderInCategory="10"
+ android:icon="@drawable/delete"
+ app:showAsAction="ifRoom" />
+</menu>
\ 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/>. -->
-
-<menu
- xmlns:android="http://schemas.android.com/apk/res/android">
- <item
- android:id="@+id/home"
- android:title="@string/home"
- android:icon="@drawable/home"
- android:orderInCategory="10" />
-
- <item
- android:id="@+id/back"
- android:title="@string/back"
- android:icon="@drawable/back"
- android:orderInCategory="20" />
-
- <item
- android:id="@+id/forward"
- android:title="@string/forward"
- android:icon="@drawable/forward"
- android:orderInCategory="30" />
-
- <!-- If a group has an id, a line is drawn above it in the navigation view. -->
- <group
- android:id="@+id/navigationGroup1" >
- <item
- android:id="@+id/bookmarks"
- android:title="@string/bookmarks"
- android:icon="@drawable/bookmarks"
- android:orderInCategory="40" />
-
- <item
- 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="80" />
- </group>
-
- <!-- If a group has an id, a line is drawn above it in the navigation view. -->
- <group
- android:id="@+id/navigationGroup3" >
- <item
- android:id="@+id/clearAndExit"
- android:title="@string/clear_and_exit"
- android:icon="@drawable/exit"
- android:orderInCategory="90" />
- </group>
-</menu>
\ No newline at end of file
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-
-<!--
- Copyright 2015-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/>. -->
-
-<menu
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- xmlns:tools="http://schemas.android.com/tools"
- tools:context=".MainWebViewActivity">
-
- <item
- android:id="@+id/toggleJavaScript"
- android:title="@string/javascript"
- android:orderInCategory="10"
- app:showAsAction="always" />
-
- <item
- android:id="@+id/toggleFirstPartyCookies"
- android:title="@string/first_party_cookies"
- android:orderInCategory="20"
- android:checkable="true"
- app:showAsAction="never" />
-
- <item
- android:id="@+id/toggleThirdPartyCookies"
- android:title="@string/third_party_cookies"
- android:orderInCategory="30"
- android:checkable="true"
- app:showAsAction="never" />
-
- <item
- android:id="@+id/toggleDomStorage"
- android:title="@string/dom_storage"
- android:orderInCategory="40"
- android:checkable="true"
- app:showAsAction="never" />
-
- <item
- android:id="@+id/toggleSaveFormData"
- android:title="@string/form_data"
- android:orderInCategory="50"
- android:checkable="true"
- app:showAsAction="never" />
-
- <item
- android:id="@+id/clearCookies"
- android:title="@string/clear_cookies"
- android:orderInCategory="60"
- app:showAsAction="never" />
-
- <item
- android:id="@+id/clearDomStorage"
- android:title="@string/clear_dom_storage"
- android:orderInCategory="70"
- app:showAsAction="never" />
-
- <item
- android:id="@+id/clearFormData"
- android:title="@string/clear_form_data"
- android:orderInCategory="80"
- app:showAsAction="never" />
-
- <item
- android:id="@+id/share"
- android:title="@string/share"
- android:orderInCategory="90"
- app:showAsAction="never" />
-
- <item
- android:id="@+id/addToHomescreen"
- android:title="@string/add_to_home_screen"
- android:orderInCategory="100"
- app:showAsAction="never" />
-
- <item
- android:id="@+id/refresh"
- android:title="@string/refresh"
- android:orderInCategory="110"
- app:showAsAction="never" />
-</menu>
--- /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/>. -->
+
+<menu
+ xmlns:android="http://schemas.android.com/apk/res/android">
+ <item
+ android:id="@+id/home"
+ android:title="@string/home"
+ android:icon="@drawable/home"
+ android:orderInCategory="10" />
+
+ <item
+ android:id="@+id/back"
+ android:title="@string/back"
+ android:icon="@drawable/back"
+ android:orderInCategory="20" />
+
+ <item
+ android:id="@+id/forward"
+ android:title="@string/forward"
+ android:icon="@drawable/forward"
+ android:orderInCategory="30" />
+
+ <!-- If a group has an id, a line is drawn above it in the navigation view. -->
+ <group
+ android:id="@+id/navigationGroup1" >
+ <item
+ android:id="@+id/bookmarks"
+ android:title="@string/bookmarks"
+ android:icon="@drawable/bookmarks"
+ android:orderInCategory="40" />
+
+ <item
+ 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="80" />
+ </group>
+
+ <!-- If a group has an id, a line is drawn above it in the navigation view. -->
+ <group
+ android:id="@+id/navigationGroup3" >
+ <item
+ android:id="@+id/clearAndExit"
+ android:title="@string/clear_and_exit"
+ android:icon="@drawable/exit"
+ android:orderInCategory="90" />
+ </group>
+</menu>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ Copyright 2015-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/>. -->
+
+<menu
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ tools:context=".MainWebViewActivity">
+
+ <item
+ android:id="@+id/toggleJavaScript"
+ android:title="@string/javascript"
+ android:orderInCategory="10"
+ app:showAsAction="always" />
+
+ <item
+ android:id="@+id/toggleFirstPartyCookies"
+ android:title="@string/first_party_cookies"
+ android:orderInCategory="20"
+ android:checkable="true"
+ app:showAsAction="never" />
+
+ <item
+ android:id="@+id/toggleThirdPartyCookies"
+ android:title="@string/third_party_cookies"
+ android:orderInCategory="30"
+ android:checkable="true"
+ app:showAsAction="never" />
+
+ <item
+ android:id="@+id/toggleDomStorage"
+ android:title="@string/dom_storage"
+ android:orderInCategory="40"
+ android:checkable="true"
+ app:showAsAction="never" />
+
+ <item
+ android:id="@+id/toggleSaveFormData"
+ android:title="@string/form_data"
+ android:orderInCategory="50"
+ android:checkable="true"
+ app:showAsAction="never" />
+
+ <item
+ android:id="@+id/clearCookies"
+ android:title="@string/clear_cookies"
+ android:orderInCategory="60"
+ app:showAsAction="never" />
+
+ <item
+ android:id="@+id/clearDomStorage"
+ android:title="@string/clear_dom_storage"
+ android:orderInCategory="70"
+ app:showAsAction="never" />
+
+ <item
+ android:id="@+id/clearFormData"
+ android:title="@string/clear_form_data"
+ android:orderInCategory="80"
+ app:showAsAction="never" />
+
+ <item
+ android:id="@+id/share"
+ android:title="@string/share"
+ android:orderInCategory="90"
+ app:showAsAction="never" />
+
+ <item
+ android:id="@+id/addToHomescreen"
+ android:title="@string/add_to_home_screen"
+ android:orderInCategory="100"
+ app:showAsAction="never" />
+
+ <item
+ android:id="@+id/refresh"
+ android:title="@string/refresh"
+ android:orderInCategory="110"
+ app:showAsAction="never" />
+</menu>
+++ /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/>. -->
-
-<resources>
- <!-- android:windowTranslucentStatus requires API >= 19. It makes the system status bar transparent.
- When it is specified the root layout should include android:fitsSystemWindows="true". -->
- <style name="PrivacyBrowser.MainWebView">
- <item name="android:windowTranslucentStatus">true</item>
- </style>
-
- <!-- 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.SecondaryActivity">
- <item name="android:windowTranslucentStatus">true</item>
- <item name="colorPrimaryDark">@color/blue</item>
- </style>
-</resources>
\ No newline at end of file
<!-- Custom App Bar. -->
<string name="favorite_icon">Favorite Icon</string>
- <!-- Navigation Drawer. -->
+ <!-- Main WebView Navigation Drawer. -->
<string name="navigation_drawer">Navigation Drawer</string>
<string name="navigation">Navigation</string>
<string name="home">Home</string>
<string name="about">About</string>
<string name="clear_and_exit">Clear and Exit</string>
- <!-- Options Menu. -->
+ <!-- Main WebView Options Menu. -->
<string name="javascript">JavaScript</string>
<string name="first_party_cookies">First-Party Cookies</string>
<string name="third_party_cookies">Third-Party Cookies</string>
<string name="bookmark_name">Bookmark name</string>
<string name="bookmark_url">Bookmark URL</string>
+ <!-- Bookmarks Contextual App Bar. -->
+ <string name="selected">Selected</string>
+ <string name="delete">Delete</string>
+ <string name="one_bookmark_deleted">1 Bookmark Deleted</string>
+ <string name="bookmarks_deleted">Bookmarks Deleted</string>
+ <string name="undo">Undo</string>
+
<!-- Guide. -->
<string name="privacy_browser_guide">Privacy Browser Guide</string>
<string name="overview">Overview</string>
along with Privacy Browser. If not, see <http://www.gnu.org/licenses/>. -->
<resources>
-
+ <!-- `android:windowTranslucentStatus` makes the system status bar transparent.
+ When it is specified the root layout should include android:fitsSystemWindows="true". -->
<style name="PrivacyBrowser" parent="Theme.AppCompat.Light.NoActionBar">
+ <item name="android:windowTranslucentStatus">true</item>
<item name="colorAccent">@color/blue</item>
</style>
<style name="PrivacyBrowser.MainWebView" />
- <style name="PrivacyBrowser.SecondaryActivity" />
+ <!-- `android:windowTranslucentStatus` 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.
+ `windowActionModeOverlay` makes the contextual app bar cover the support app bar.
+ `actionModeStyle` sets the style of the contextual app bar. -->
+ <style name="PrivacyBrowser.SecondaryActivity">
+ <item name="android:windowTranslucentStatus">true</item>
+ <item name="colorPrimaryDark">@color/blue</item>
+ <item name="windowActionModeOverlay">true</item>
+ <item name="android:actionModeBackground">@color/blue</item>
+ </style>
- <!-- colorPrimaryDark is the color of the status bar. -->
+ <!-- `colorPrimaryDark` is the color of the status bar. -->
<style name="PrivacyBrowser.Settings" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="colorPrimary">@color/blue</item>
<item name="colorPrimaryDark">@color/dark_blue</item>
<item name="colorAccent">@color/blue</item>
</style>
- <!-- ThemeOverlay.AppCompat.Dark.ActionBar" makes the text and the icons in the AppBar white. -->
+ <!-- `ThemeOverlay.AppCompat.Dark.ActionBar` makes the text and the icons in the AppBar white.-->
<style name="PrivacyBrowser.DarkAppBar" parent="ThemeOverlay.AppCompat.Dark.ActionBar" />
<style name="PrivacyBrowser.AppBarOverlay" parent="ThemeOverlay.AppCompat.ActionBar" />
<style name="PrivacyBrowser.AlertDialog" parent="Theme.AppCompat.Light.Dialog.Alert">
<item name="colorAccent">@color/blue</item>
</style>
-
</resources>
\ No newline at end of file