<w>fontsize</w>
<w>framelayout</w>
<w>gerlach</w>
+ <w>imageview</w>
<w>intl</w>
<w>ipleak</w>
<w>isfolder</w>
// Inflate the menu.
getMenuInflater().inflate(R.menu.domains_options_menu, menu);
- // Show the `MenuItems`.
- menu.findItem(R.id.save_domain).setVisible(true);
- menu.findItem(R.id.delete_domain).setVisible(true);
-
// Success!
return true;
}
// `domainsDatabaseHelper` is used in `onCreate()`, `onOptionsItemSelected()`, `onAddDomain()`, and `updateDomainsRecyclerView()`.
private static DomainsDatabaseHelper domainsDatabaseHelper;
+ // `twoPaneMode` is used in `onCreate()` and `updateDomainsListView()`.
+ private boolean twoPaneMode;
+
// `domainsRecyclerView` is used in `onCreate()` and `updateDomainsListView()`.
private ListView domainsListView;
domainsDatabaseHelper = new DomainsDatabaseHelper(this, null, null, 0);
// Determine if we are in two pane mode. `domains_settings_linearlayout` is only populated if two panes are present.
- final boolean twoPaneMode = ((findViewById(R.id.domain_settings_scrollview)) != null);
+ twoPaneMode = ((findViewById(R.id.domain_settings_scrollview)) != null);
// Initialize `domainsListView`.
domainsListView = (ListView) findViewById(R.id.domains_listview);
// Display the Domain Settings.
if (twoPaneMode) { // Display a fragment in two paned mode.
- // Display the options `MenuItems`.
- saveMenuItem.setVisible(true);
- deleteMenuItem.setVisible(true);
+ // Enable the options `MenuItems`.
+ saveMenuItem.setEnabled(true);
+ deleteMenuItem.setEnabled(true);
// Store `databaseId` in `argumentsBundle`.
Bundle argumentsBundle = new Bundle();
addDomainDialog.show(getSupportFragmentManager(), getResources().getString(R.string.add_domain));
}
});
-
- // Load the `ListView`.
- updateDomainsListView();
}
@Override
getMenuInflater().inflate(R.menu.domains_options_menu, menu);
// Store the `MenuItems` for future use.
- saveMenuItem = menu.findItem(R.id.save_domain);
deleteMenuItem = menu.findItem(R.id.delete_domain);
+ saveMenuItem = menu.findItem(R.id.save_domain);
+
+ // Only display the options `MenuItems` in two pane mode.
+ deleteMenuItem.setVisible(twoPaneMode);
+ saveMenuItem.setVisible(twoPaneMode);
+
+ // Load the `ListView`. We have to do this from `onCreateOptionsMenu()` instead of `onCreate()` because `updateDomainsListView()` needs the `MenuItems` to be inflated.
+ updateDomainsListView();
// Success!
return true;
// Detach the domain settings fragment.
getSupportFragmentManager().beginTransaction().detach(getSupportFragmentManager().findFragmentById(R.id.domain_settings_scrollview)).commit();
- // Hide the options `MenuItems`.
- saveMenuItem.setVisible(false);
- deleteMenuItem.setVisible(false);
-
// Update the `ListView`.
updateDomainsListView();
break;
}
};
- // Update the `RecyclerView`.
+ // Update the `ListView`.
domainsListView.setAdapter(domainsCursorAdapter);
+
+ // Display the domain settings in the second pane if operating in two pane mode and the database contains at least one domain.
+ if (twoPaneMode && (domainsCursor.getCount() > 0)) {
+ // Select the first domain.
+ domainsListView.setItemChecked(0, true);
+
+ // Get the `databaseId` of the first item.
+ domainsCursor.moveToFirst();
+ databaseId = domainsCursor.getInt(domainsCursor.getColumnIndex(DomainsDatabaseHelper._ID));
+
+ // Store `databaseId` in `argumentsBundle`.
+ Bundle argumentsBundle = new Bundle();
+ argumentsBundle.putInt(DomainSettingsFragment.DATABASE_ID, databaseId);
+
+ // Add `argumentsBundle` to `domainSettingsFragment`.
+ DomainSettingsFragment domainSettingsFragment = new DomainSettingsFragment();
+ domainSettingsFragment.setArguments(argumentsBundle);
+
+ // Display `domainSettingsFragment`.
+ getSupportFragmentManager().beginTransaction().replace(R.id.domain_settings_scrollview, domainSettingsFragment).commit();
+
+ // Enable the options `MenuItems`.
+ deleteMenuItem.setEnabled(true);
+ deleteMenuItem.setIcon(R.drawable.delete);
+ saveMenuItem.setEnabled(true);
+ } else {
+ // Disable the options `MenuItems`.
+ deleteMenuItem.setEnabled(false);
+ deleteMenuItem.setIcon(R.drawable.delete_blue);
+ saveMenuItem.setEnabled(false);
+ }
}
}
\ No newline at end of file
// It is also used in `onCreate()` and `onCreateHomeScreenShortcutCreate()`.
public static Bitmap favoriteIcon;
- // `formattedUrlString` is public static so it can be accessed from `BookmarksActivity`.
+ // `formattedUrlString` is public static so it can be accessed from `BookmarksActivity`, `CreateBookmarkDialog`, and `AddDomainDialog`.
// It is also used in `onCreate()`, `onOptionsItemSelected()`, `onCreateHomeScreenShortcutCreate()`, and `loadUrlFromTextBox()`.
public static String formattedUrlString;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
+import android.net.Uri;
import android.os.Bundle;
// We have to use `AppCompatDialogFragment` instead of `DialogFragment` or an error is produced on API <= 22.
import android.support.annotation.NonNull;
import android.widget.EditText;
import com.stoutner.privacybrowser.R;
+import com.stoutner.privacybrowser.activities.MainWebViewActivity;
public class AddDomainDialog extends AppCompatDialogFragment {
// The public interface is used to send information back to the parent activity.
// Show the keyboard when the `AlertDialog` is displayed on the screen.
alertDialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
- // We need to show the `AlertDialog` before w3e can call `setOnKeyListener()` below.
+ // We need to show the `AlertDialog` before we can edit the contents.
alertDialog.show();
- // Allow the `enter` key on the keyboard to create the domain from `add_domain_edittext`.
+ // Get a handle for `domain_name_edittext`.
EditText addDomainEditText = (EditText) alertDialog.findViewById(R.id.domain_name_edittext);
+
+ // Get the current domain from `formattedUrlString`.
+ Uri currentUri = Uri.parse(MainWebViewActivity.formattedUrlString);
+ addDomainEditText.setText(currentUri.getHost());
+
+ // Allow the `enter` key on the keyboard to create the domain from `add_domain_edittext`.
addDomainEditText.setOnKeyListener(new View.OnKeyListener() {
public boolean onKey(View view, int keyCode, KeyEvent event) {
// If the event is a key-down on the `enter` key, select the `PositiveButton` `Add`.
import android.webkit.WebView;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
+import android.widget.CompoundButton;
import android.widget.EditText;
+import android.widget.ImageView;
import android.widget.Spinner;
import android.widget.Switch;
import android.widget.TextView;
databaseId = getArguments().getInt(DATABASE_ID);
}
+ // We have to use the deprecated `getDrawable()` until the minimum API >= 21.
+ @SuppressWarnings("deprecation")
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Inflate `domain_settings`. `false` does not attach it to the root `container`.
// Get handles for the views in the fragment.
EditText domainNameEditText = (EditText) domainSettingsView.findViewById(R.id.domain_settings_name_edittext);
Switch javaScriptEnabledSwitch = (Switch) domainSettingsView.findViewById(R.id.domain_settings_javascript_switch);
+ final ImageView javaScriptImageView = (ImageView) domainSettingsView.findViewById(R.id.domain_settings_javascript_imageview);
Switch firstPartyCookiesEnabledSwitch = (Switch) domainSettingsView.findViewById(R.id.domain_settings_first_party_cookies_switch);
+ final ImageView firstPartyCookiesImageView = (ImageView) domainSettingsView.findViewById(R.id.domain_settings_first_party_cookies_imageview);
Switch thirdPartyCookiesEnabledSwitch = (Switch) domainSettingsView.findViewById(R.id.domain_settings_third_party_cookies_switch);
+ final ImageView thirdPartyCookiesImageView = (ImageView) domainSettingsView.findViewById(R.id.domain_settings_third_party_cookies_imageview);
Switch domStorageEnabledSwitch = (Switch) domainSettingsView.findViewById(R.id.domain_settings_dom_storage_switch);
+ final ImageView domStorageImageView = (ImageView) domainSettingsView.findViewById(R.id.domain_settings_dom_storage_imageview);
Switch formDataEnabledSwitch = (Switch) domainSettingsView.findViewById(R.id.domain_settings_form_data_switch);
+ final ImageView formDataImageView = (ImageView) domainSettingsView.findViewById(R.id.domain_settings_form_data_imageview);
Spinner userAgentSpinner = (Spinner) domainSettingsView.findViewById(R.id.domain_settings_user_agent_spinner);
final TextView userAgentTextView = (TextView) domainSettingsView.findViewById(R.id.domain_settings_user_agent_textview);
final EditText customUserAgentEditText = (EditText) domainSettingsView.findViewById(R.id.domain_settings_custom_user_agent_edittext);
// Set the domain name from the the database cursor.
domainNameEditText.setText(domainNameString);
- // Set the status of the `Switches` from the database cursor.
- javaScriptEnabledSwitch.setChecked(javaScriptEnabledInt == 1);
- firstPartyCookiesEnabledSwitch.setChecked(firstPartyCookiesEnabledInt == 1);
- thirdPartyCookiesEnabledSwitch.setChecked(thirdPartyCookiesEnabledInt == 1);
- domStorageEnabledSwitch.setChecked(domStorageEnabledInt == 1);
- formDataEnabledSwitch.setChecked(formDataEnabledInt == 1);
+ // Set the JavaScript status.
+ if (javaScriptEnabledInt == 1) { // JavaScript is enabled.
+ javaScriptEnabledSwitch.setChecked(true);
+ javaScriptImageView.setImageDrawable(getResources().getDrawable(R.drawable.javascript_enabled));
+ } else { // JavaScript is disabled.
+ javaScriptEnabledSwitch.setChecked(false);
+ javaScriptImageView.setImageDrawable(getResources().getDrawable(R.drawable.privacy_mode));
+ }
+
+ // Set the first-party cookies status.
+ if (firstPartyCookiesEnabledInt == 1) { // First-party cookies are enabled.
+ firstPartyCookiesEnabledSwitch.setChecked(true);
+ firstPartyCookiesImageView.setEnabled(true);
+ } else { // First-party cookies are disabled.
+ firstPartyCookiesEnabledSwitch.setChecked(false);
+ firstPartyCookiesImageView.setEnabled(false);
+ }
+
+ // Set the third-party cookies status.
+ if (thirdPartyCookiesEnabledInt == 1) { // Third-party cookies are enabled.
+ thirdPartyCookiesEnabledSwitch.setChecked(true);
+ thirdPartyCookiesImageView.setEnabled(true);
+ } else { // Third-party cookies are disabled.
+ thirdPartyCookiesEnabledSwitch.setChecked(false);
+ thirdPartyCookiesImageView.setEnabled(false);
+ }
+
+ // Set the DOM storage status.
+ if (domStorageEnabledInt == 1) { // DOM storage is enabled.
+ domStorageEnabledSwitch.setChecked(true);
+ domStorageImageView.setEnabled(true);
+ } else { // Dom storage is disabled.
+ domStorageEnabledSwitch.setChecked(false);
+ domStorageImageView.setEnabled(false);
+ }
+
+ // Set the form data status.
+ if (formDataEnabledInt == 1) { // Form data is enabled.
+ formDataEnabledSwitch.setChecked(true);
+ formDataImageView.setEnabled(true);
+ } else { // Form data is disabled.
+ formDataEnabledSwitch.setChecked(false);
+ formDataImageView.setEnabled(false);
+ }
// We need to inflated a `WebView` to get the default user agent.
// `@SuppressLint("InflateParams")` removes the warning about using `null` as the `ViewGroup`, which in this case makes sense because we don't want to display `bare_webview` on the screen. `false` does not attach the view to the root.
int fontSizeArrayPosition = fontSizeEntryValuesArrayAdapter.getPosition(String.valueOf(fontSizeInt));
fontSizeSpinner.setSelection(fontSizeArrayPosition);
+ // Set the `javaScriptEnabledSwitch` `OnCheckedChangeListener()`.
+ javaScriptEnabledSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
+ @Override
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ // Update the icon.
+ if (isChecked) {
+ javaScriptImageView.setImageDrawable(getResources().getDrawable(R.drawable.javascript_enabled));
+ } else {
+ javaScriptImageView.setImageDrawable(getResources().getDrawable(R.drawable.privacy_mode));
+ }
+ }
+ });
+
+ // Set the `firstPartyCookiesEnabledSwitch` `OnCheckedChangeListener()`.
+ firstPartyCookiesEnabledSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
+ @Override
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ // Update the icon.
+ firstPartyCookiesImageView.setEnabled(isChecked);
+ }
+ });
+
+ // Set the `thirdPartyCookiesEnabledSwitch` `OnCheckedChangeListener()`.
+ thirdPartyCookiesEnabledSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
+ @Override
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ // Update the icon.
+ thirdPartyCookiesImageView.setEnabled(isChecked);
+ }
+ });
+
+ // Set the `domStorageEnabledSwitch` `OnCheckedChangeListener()`.
+ domStorageEnabledSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
+ @Override
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ // Update the icon.
+ domStorageImageView.setEnabled(isChecked);
+ }
+ });
+
+ // Set the `formDataEnabledSwitch` `OnCheckedChangeListener()`.
+ formDataEnabledSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
+ @Override
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ // Update the icon.
+ formDataImageView.setEnabled(isChecked);
+ }
+ });
+
// Set the `userAgentSpinner` `onItemClickListener()`.
userAgentSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
private static final int SCHEMA_VERSION = 1;
private static final String DOMAINS_DATABASE = "domains.db";
private static final String DOMAINS_TABLE = "domains";
- private static final String _ID = "_id";
+ public static final String _ID = "_id";
public static final String DOMAIN_NAME = "domainname";
public static final String ENABLE_JAVASCRIPT = "enablejavascript";
public static final String ENABLE_FIRST_PARTY_COOKIES = "enablefirstpartycookies";
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ Copyright 2017 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/>. -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item
+ android:state_enabled="false"
+ android:color="@color/gray_500" />
+ <item
+ android:state_enabled="true"
+ android:color="@color/red_a700" />
+</selector>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ Copyright 2017 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/>. -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item
+ android:state_enabled="false"
+ android:color="@color/gray_500" />
+ <item
+ android:state_enabled="true"
+ android:color="@color/yellow_900" />
+</selector>
\ No newline at end of file
--- /dev/null
+<!-- `delete_blue.xml` comes from the Android Material icon set, where it is called `ic_delete`. It is released under the Apache License 2.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" >
+
+ <!-- We have to use a hard coded color code until API >= 21. Then we can use `@color`. -->
+ <path
+ android:fillColor="#FF90CAF9"
+ 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>
\ No newline at end of file
<!-- `android:imeOptions="actionGo" sets the keyboard to have a `go` key instead of a `new line` key. `android:inputType="textUri"` disables spell check in the `EditText`. -->
<android.support.design.widget.TextInputEditText
android:id="@+id/domain_name_edittext"
- android:layout_height="wrap_content"
android:layout_width="match_parent"
+ android:layout_height="wrap_content"
android:hint="@string/domain_name"
android:imeOptions="actionGo"
- android:inputType="textUri" />
+ android:inputType="textUri"
+ android:selectAllOnFocus="true" />
</android.support.design.widget.TextInputLayout>
</LinearLayout>
\ No newline at end of file
android:orientation="horizontal" >
<ImageView
+ android:id="@+id/domain_settings_javascript_imageview"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_marginEnd="10dp"
android:orientation="horizontal" >
<ImageView
+ android:id="@+id/domain_settings_first_party_cookies_imageview"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_marginTop="1dp"
android:layout_marginEnd="10dp"
android:layout_gravity="center_vertical"
android:src="@drawable/cookies_enabled"
- android:tint="@color/blue_800"
+ android:tint="@color/domain_settings_icon_yellow_tint_selector"
tools:ignore="contentDescription" />
<Switch
android:orientation="horizontal" >
<ImageView
+ android:id="@+id/domain_settings_third_party_cookies_imageview"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_marginTop="1dp"
android:layout_marginEnd="10dp"
android:layout_gravity="center_vertical"
android:src="@drawable/cookies_enabled"
- android:tint="@color/blue_800"
+ android:tint="@color/domain_settings_icon_red_tint_selector"
tools:ignore="contentDescription" />
<Switch
android:orientation="horizontal" >
<ImageView
+ android:id="@+id/domain_settings_dom_storage_imageview"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_marginTop="1dp"
android:layout_marginEnd="10dp"
android:layout_gravity="center_vertical"
android:src="@drawable/dom_storage_enabled"
- android:tint="@color/blue_800"
+ android:tint="@color/domain_settings_icon_yellow_tint_selector"
tools:ignore="contentDescription" />
<Switch
android:orientation="horizontal">
<ImageView
+ android:id="@+id/domain_settings_form_data_imageview"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_marginTop="1dp"
android:layout_marginEnd="10dp"
android:layout_gravity="center_vertical"
android:src="@drawable/form_data_enabled"
- android:tint="@color/blue_800"
+ android:tint="@color/domain_settings_icon_yellow_tint_selector"
tools:ignore="contentDescription" />
<Switch
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
- <item
- android:id="@+id/save_domain"
- android:title="@string/save"
- android:orderInCategory="10"
- android:visible="false"
- app:showAsAction="ifRoom" />
-
<item
android:id="@+id/delete_domain"
android:title="@string/delete"
android:orderInCategory="10"
android:icon="@drawable/delete"
- android:visible="false"
app:showAsAction="ifRoom" />
+
+ <item
+ android:id="@+id/save_domain"
+ android:title="@string/save"
+ android:orderInCategory="20"
+ app:showAsAction="ifRoom" />
+
</menu>
\ No newline at end of file