import android.webkit.HttpAuthHandler;
import android.webkit.SslErrorHandler;
import android.webkit.ValueCallback;
-import android.webkit.WebBackForwardList;
import android.webkit.WebChromeClient;
import android.webkit.WebResourceResponse;
import android.webkit.WebSettings;
import com.stoutner.privacybrowser.dialogs.EditBookmarkDialog;
import com.stoutner.privacybrowser.dialogs.EditBookmarkFolderDialog;
import com.stoutner.privacybrowser.dialogs.HttpAuthenticationDialog;
-import com.stoutner.privacybrowser.dialogs.PinnedMismatchDialog;
import com.stoutner.privacybrowser.dialogs.SslCertificateErrorDialog;
import com.stoutner.privacybrowser.dialogs.UrlHistoryDialog;
import com.stoutner.privacybrowser.dialogs.ViewSslCertificateDialog;
import java.util.Map;
import java.util.Set;
-// TODO. Store up reloads for tabs that are not visible.
// TODO. New tabs are white in dark mode.
// TODO. Hide the tabs in full screen mode.
// TODO. Find on page.
-// TODO. Use TabLayout.setScrollPosition to scroll to new tabs.
// AppCompatActivity from android.support.v7.app.AppCompatActivity must be used to have access to the SupportActionBar until the minimum API is >= 21.
public class MainWebViewActivity extends AppCompatActivity implements CreateBookmarkDialog.CreateBookmarkListener, CreateBookmarkFolderDialog.CreateBookmarkFolderListener,
DownloadFileDialog.DownloadFileListener, DownloadImageDialog.DownloadImageListener, DownloadLocationPermissionDialog.DownloadLocationPermissionDialogListener, EditBookmarkDialog.EditBookmarkListener,
- EditBookmarkFolderDialog.EditBookmarkFolderListener, NavigationView.OnNavigationItemSelectedListener, WebViewTabFragment.NewTabListener, PinnedMismatchDialog.PinnedMismatchListener,
- UrlHistoryDialog.UrlHistoryListener {
+ EditBookmarkFolderDialog.EditBookmarkFolderListener, NavigationView.OnNavigationItemSelectedListener, WebViewTabFragment.NewTabListener {
// `orbotStatus` is public static so it can be accessed from `OrbotProxyHelper`. It is also used in `onCreate()`, `onResume()`, and `applyProxyThroughOrbot()`.
public static String orbotStatus;
// Set the current WebView.
setCurrentWebView(position);
- // Select the corresponding tab if it does not match the currently selected page. This will happen if the page was scrolled via swiping in the view pager.
+ // Select the corresponding tab if it does not match the currently selected page. This will happen if the page was scrolled via swiping in the view pager or by creating a new tab.
if (tabLayout.getSelectedTabPosition() != position) {
- // Get a handle for the corresponding tab.
- TabLayout.Tab correspondingTab = tabLayout.getTabAt(position);
+ // Create a handler to select the tab.
+ Handler selectTabHandler = new Handler();
- // Assert that the corresponding tab is not null.
- assert correspondingTab != null;
+ // Create a runnable select the new tab.
+ Runnable selectTabRunnable = () -> {
+ // Get a handle for the tab.
+ TabLayout.Tab tab = tabLayout.getTabAt(position);
- // Select the corresponding tab.
- correspondingTab.select();
+ // Assert that the tab is not null.
+ assert tab != null;
+
+ // Select the tab.
+ tab.select();
+ };
+
+ // Select the tab layout after 100 milliseconds, which leaves enough time for a new tab to be created.
+ selectTabHandler.postDelayed(selectTabRunnable, 100);
}
}
break;
case R.id.history:
- // Get the `WebBackForwardList`.
- WebBackForwardList webBackForwardList = currentWebView.copyBackForwardList();
+ // Instantiate the URL history dialog.
+ DialogFragment urlHistoryDialogFragment = UrlHistoryDialog.loadBackForwardList(currentWebView.getWebViewFragmentId());
- // Show the URL history dialog and name this instance `R.string.history`.
- DialogFragment urlHistoryDialogFragment = UrlHistoryDialog.loadBackForwardList(this, webBackForwardList);
+ // Show the URL history dialog.
urlHistoryDialogFragment.show(getSupportFragmentManager(), getString(R.string.history));
break;
}
}
- @Override
- public void onPinnedMismatchBack() { // TODO. Move this logic to the dialog.
- if (currentWebView.canGoBack()) { // There is a back page in the history.
- // Reset the current domain name so that navigation works if third-party requests are blocked.
- currentWebView.resetCurrentDomainName();
-
- // Set navigating history so that the domain settings are applied when the new URL is loaded.
- currentWebView.setNavigatingHistory(true);
-
- // Go back.
- currentWebView.goBack();
- } else { // There are no pages to go back to.
- // Load a blank page
- loadUrl("");
- }
- }
-
- @Override
- public void onPinnedMismatchProceed() { // TODO. Move this logic to the dialog.
- // Do not check the pinned information for this domain again until the domain changes.
- currentWebView.setIgnorePinnedDomainInformation(true);
- }
-
- @Override
- public void onUrlHistoryEntrySelected(int moveBackOrForwardSteps) { // TODO. Move this logic to the dialog.
- // Reset the current domain name so that navigation works if third-party requests are blocked.
- currentWebView.resetCurrentDomainName();
-
- // Set navigating history so that the domain settings are applied when the new URL is loaded.
- currentWebView.setNavigatingHistory(true);
-
- // Load the history entry.
- currentWebView.goBackOrForward(moveBackOrForwardSteps);
- }
-
- @Override
- public void onClearHistory() { // TODO. Move this logic to the dialog.
- // Clear the history.
- currentWebView.clearHistory();
- }
-
// Override `onBackPressed` to handle the navigation drawer and and the WebView.
@Override
public void onBackPressed() {
// Go back.
currentWebView.goBack();
- } else { // There isn't anything to do in Privacy Browser.
- // Pass `onBackPressed()` to the system.
- super.onBackPressed();
+ } else { // There is nothing else to do.
+ // Load a blank website.
+ loadUrl("");
}
}
// `reloadWebsite` is used if returning from the Domains activity. Otherwise JavaScript might not function correctly if it is newly enabled.
@SuppressLint("SetJavaScriptEnabled")
- private boolean applyDomainSettings(NestedScrollWebView nestedScrollWebView, String url, boolean resetFavoriteIcon, boolean reloadWebsite) {
+ private boolean applyDomainSettings(NestedScrollWebView nestedScrollWebView, String url, boolean resetTab, boolean reloadWebsite) {
// Store a copy of the current user agent to track changes for the return boolean.
String initialUserAgent = nestedScrollWebView.getSettings().getUserAgentString();
nestedScrollWebView.clearPinnedIpAddresses();
// Reset the favorite icon if specified.
- if (resetFavoriteIcon) {
+ if (resetTab) {
// Initialize the favorite icon.
nestedScrollWebView.initializeFavoriteIcon();
+ // Get the current page position.
+ int currentPagePosition = webViewPagerAdapter.getPositionForId(nestedScrollWebView.getWebViewFragmentId());
+
// Get a handle for the tab layout.
TabLayout tabLayout = findViewById(R.id.tablayout);
- // Get the current tab.
- TabLayout.Tab currentTab = tabLayout.getTabAt(tabLayout.getSelectedTabPosition()); // TODO. We need to get the tab for this WebView, which might not be the current tab.
+ // Get the corresponding tab.
+ TabLayout.Tab tab = tabLayout.getTabAt(currentPagePosition);
- // Remove the warning below that the current tab might be null.
- assert currentTab != null;
+ // Remove the warning below that the tab might be null.
+ assert tab != null;
- // Get the current tab custom view.
- View currentTabCustomView = currentTab.getCustomView();
+ // Get the tab custom view.
+ View tabCustomView = tab.getCustomView();
- // Remove the warning below that the current tab custom view might be null.
- assert currentTabCustomView != null;
+ // Remove the warning below that the tab custom view might be null.
+ assert tabCustomView != null;
- // Get the current tab favorite icon image view.
- ImageView currentTabFavoriteIconImageView = currentTabCustomView.findViewById(R.id.favorite_icon_imageview);
+ // Get the tab views.
+ ImageView tabFavoriteIconImageView = tabCustomView.findViewById(R.id.favorite_icon_imageview);
+ TextView tabTitleTextView = tabCustomView.findViewById(R.id.title_textview);
// Set the default favorite icon as the favorite icon for this tab.
- currentTabFavoriteIconImageView.setImageBitmap(Bitmap.createScaledBitmap(nestedScrollWebView.getFavoriteOrDefaultIcon(), 64, 64, true));
+ tabFavoriteIconImageView.setImageBitmap(Bitmap.createScaledBitmap(nestedScrollWebView.getFavoriteOrDefaultIcon(), 64, 64, true));
+
+ // Set the loading title text.
+ tabTitleTextView.setText(R.string.loading);
}
// Initialize the database handler. The `0` specifies the database version, but that is ignored and set instead using a constant in `DomainsDatabaseHelper`.
assert newTab != null;
// Set a custom view on the new tab.
- newTab.setCustomView(R.layout.custom_tab_view);
+ newTab.setCustomView(R.layout.tab_custom_view);
// Add the new WebView page.
webViewPagerAdapter.addPage(newTabNumber, webViewPager);
}
};
- // Displaying of `mainWebView` after 500 milliseconds.
+ // Display the WebView after 500 milliseconds.
displayWebViewHandler.postDelayed(displayWebViewRunnable, 500);
});
}
public class PinnedMismatchDialog extends DialogFragment {
// Declare the class variables.
- private PinnedMismatchListener pinnedMismatchListener;
private NestedScrollWebView nestedScrollWebView;
private String currentSslIssuedToCName;
private String currentSslIssuedToOName;
private Date currentSslStartDate;
private Date currentSslEndDate;
- // The public interface is used to send information back to the parent activity.
- public interface PinnedMismatchListener {
- void onPinnedMismatchBack();
-
- void onPinnedMismatchProceed();
- }
-
- // Check to make sure that the parent activity implements the listener.
- public void onAttach(Context context) {
- // Run the default commands.
- super.onAttach(context);
-
- // Get a handle for `PinnedSslCertificateMismatchListener` from the launching context.
- pinnedMismatchListener = (PinnedMismatchListener) context;
- }
-
public static PinnedMismatchDialog displayDialog(long webViewFragmentId) {
// Create an arguments bundle.
Bundle argumentsBundle = new Bundle();
}
});
- // Setup the negative button.
+ // Setup the back button.
dialogBuilder.setNegativeButton(R.string.back, (DialogInterface dialog, int which) -> {
- // Call the `onSslMismatchBack` public interface to send the `WebView` back one page.
- pinnedMismatchListener.onPinnedMismatchBack();
+ if (nestedScrollWebView.canGoBack()) { // There is a back page in the history.
+ // Reset the current domain name so that navigation works if third-party requests are blocked.
+ nestedScrollWebView.resetCurrentDomainName();
+
+ // Set navigating history so that the domain settings are applied when the new URL is loaded.
+ nestedScrollWebView.setNavigatingHistory(true);
+
+ // Go back.
+ nestedScrollWebView.goBack();
+ } else { // There are no pages to go back to.
+ // Load a blank page
+ nestedScrollWebView.loadUrl("");
+ }
});
- // Setup the positive button.
+ // Setup the proceed button.
dialogBuilder.setPositiveButton(R.string.proceed, (DialogInterface dialog, int which) -> {
- // Call the `onSslMismatchProceed` public interface.
- pinnedMismatchListener.onPinnedMismatchProceed();
+ // Do not check the pinned information for this domain again until the domain changes.
+ nestedScrollWebView.setIgnorePinnedDomainInformation(true);
});
// Set the title.
import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.app.Dialog;
-import android.content.Context;
import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.preference.PreferenceManager;
-import android.util.Base64;
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;
import androidx.fragment.app.DialogFragment; // The AndroidX dialog fragment must be used or an error is produced on API <=22.
import com.stoutner.privacybrowser.R;
+import com.stoutner.privacybrowser.activities.MainWebViewActivity;
import com.stoutner.privacybrowser.adapters.HistoryArrayAdapter;
import com.stoutner.privacybrowser.definitions.History;
+import com.stoutner.privacybrowser.fragments.WebViewTabFragment;
+import com.stoutner.privacybrowser.views.NestedScrollWebView;
-import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
public class UrlHistoryDialog extends DialogFragment{
- // Declare the class variables.
- private final ArrayList<History> historyArrayList = new ArrayList<>();
- private int currentPageId;
+ public static UrlHistoryDialog loadBackForwardList(long webViewFragmentId) {
+ // Create an arguments bundle.
+ Bundle argumentsBundle = new Bundle();
- // Create a URL history listener.
- private UrlHistoryListener urlHistoryListener;
+ // Store the WebView fragment ID in the bundle.
+ argumentsBundle.putLong("webview_fragment_id", webViewFragmentId);
+ // Create a new instance of the URL history dialog.
+ UrlHistoryDialog urlHistoryDialog = new UrlHistoryDialog();
- // The public interface is used to send information back to the parent activity.
- public interface UrlHistoryListener {
- // Send back the number of steps to move forward or back.
- void onUrlHistoryEntrySelected(int moveBackOrForwardSteps);
+ // Add the arguments bundle to this instance.
+ urlHistoryDialog.setArguments(argumentsBundle);
- // Clear the history.
- void onClearHistory();
+ // Return the new URL history dialog.
+ return urlHistoryDialog;
}
@Override
- public void onAttach(Context context) {
- super.onAttach(context);
-
- // Check to make sure tha the parent activity implements the listener.
- try {
- urlHistoryListener = (UrlHistoryListener) context;
- } catch (ClassCastException exception) {
- throw new ClassCastException(context.toString() + " must implement UrlHistoryListener.");
- }
- }
+ @NonNull
+ // `@SuppressLing("InflateParams")` removes the warning about using `null` as the parent view group when inflating the `AlertDialog`.
+ @SuppressLint("InflateParams")
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ // Remove the incorrect lint warning that `getActivity()` might be null.
+ assert getActivity() != null;
+ // Get the activity's layout inflater.
+ LayoutInflater layoutInflater = getActivity().getLayoutInflater();
- public static UrlHistoryDialog loadBackForwardList(Context context, WebBackForwardList webBackForwardList) {
- // Create an arguments bundle.
- Bundle argumentsBundle = new Bundle();
+ // Get the arguments.
+ Bundle arguments = getArguments();
+
+ // Remove the incorrect lint error that arguments might be null.
+ assert arguments != null;
+
+ // Get the WebView fragment ID from the arguments.
+ long webViewFragmentId = arguments.getLong("webview_fragment_id");
+
+ // Get the current position of this WebView fragment.
+ int webViewPosition = MainWebViewActivity.webViewPagerAdapter.getPositionForId(webViewFragmentId);
+
+ // Get the WebView tab fragment.
+ WebViewTabFragment webViewTabFragment = MainWebViewActivity.webViewPagerAdapter.getPageFragment(webViewPosition);
+
+ // Get the fragment view.
+ View fragmentView = webViewTabFragment.getView();
+
+ // Remove the incorrect lint warning below that the fragment view might be null.
+ assert fragmentView != null;
+
+ // Get a handle for the current WebView.
+ NestedScrollWebView nestedScrollWebView = fragmentView.findViewById(R.id.nestedscroll_webview);
+
+ // Get the web back forward list from the WebView.
+ WebBackForwardList webBackForwardList = nestedScrollWebView.copyBackForwardList();
// Store the current page index.
int currentPageIndex = webBackForwardList.getCurrentIndex();
- // Setup the URL array list and the icon array list.
- ArrayList<String> urlArrayList = new ArrayList<>();
- ArrayList<String> iconBase64StringArrayList = new ArrayList<>();
+ // Remove the lint warning below that `getContext()` might be null.
+ assert getContext() != null;
// Get the default favorite icon drawable. `ContextCompat` must be used until the minimum API >= 21.
- Drawable defaultFavoriteIconDrawable = ContextCompat.getDrawable(context, R.drawable.world);
+ Drawable defaultFavoriteIconDrawable = ContextCompat.getDrawable(getContext(), R.drawable.world);
// Convert the default favorite icon drawable to a `BitmapDrawable`.
BitmapDrawable defaultFavoriteIconBitmapDrawable = (BitmapDrawable) defaultFavoriteIconDrawable;
// Remove the incorrect lint error that `getBitmap()` might be null.
assert defaultFavoriteIconBitmapDrawable != null;
- // Extract a `Bitmap` from the default favorite icon `BitmapDrawable`.
+ // Extract a bitmap from the default favorite icon bitmap drawable.
Bitmap defaultFavoriteIcon = defaultFavoriteIconBitmapDrawable.getBitmap();
- // Populate the URL array list and the icon array list from `webBackForwardList`.
- for (int i=0; i < webBackForwardList.getSize(); i++) {
- // Store the URL.
- urlArrayList.add(webBackForwardList.getItemAtIndex(i).getUrl());
+ // Create a history array list.
+ ArrayList<History> historyArrayList = new ArrayList<>();
- // Create a variable to store the icon bitmap.
- Bitmap iconBitmap;
+ // Populate the history array list, descending from `urlStringArrayList.size()` so that the newest entries are at the top. `-1` is needed because the history array list is zero-based.
+ for (int i=webBackForwardList.getSize() -1; i >= 0; i--) {
+ // Create a variable to store the favorite icon bitmap.
+ Bitmap favoriteIconBitmap;
- // Store the icon bitmap.
+ // Determine the favorite icon bitmap
if (webBackForwardList.getItemAtIndex(i).getFavicon() == null) {
- // If `webBackForwardList` does not have a favorite icon, use Privacy Browser's default world icon.
- iconBitmap = defaultFavoriteIcon;
- } else { // Get the icon from `webBackForwardList`.
- iconBitmap = webBackForwardList.getItemAtIndex(i).getFavicon();
+ // If the web back forward list does not have a favorite icon, use Privacy Browser's default world icon.
+ favoriteIconBitmap = defaultFavoriteIcon;
+ } else { // Use the icon from the web back forward list.
+ favoriteIconBitmap = webBackForwardList.getItemAtIndex(i).getFavicon();
}
- // Create a `ByteArrayOutputStream`.
- ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
-
- // Remove the incorrect lint error that `compress()` might be null;
- assert iconBitmap != null;
-
- // Convert the favorite icon `Bitmap` to a `ByteArrayOutputStream`. `100` is the compression quality, which is ignored by `PNG`.
- iconBitmap.compress(Bitmap.CompressFormat.PNG, 100, byteArrayOutputStream);
-
- // Convert the favorite icon `ByteArrayOutputStream` to a `byte[]`.
- byte[] byteArray = byteArrayOutputStream.toByteArray();
-
- // Encode the favorite icon `byte[]` as a Base64 `String`.
- String iconBase64String = Base64.encodeToString(byteArray, Base64.DEFAULT);
-
- // Store the favorite icon Base64 `String` in `iconBase64StringArrayList`.
- iconBase64StringArrayList.add(iconBase64String);
- }
-
- // Store the variables in the `Bundle`.
- argumentsBundle.putInt("Current_Page", currentPageIndex);
- argumentsBundle.putStringArrayList("URL_History", urlArrayList);
- argumentsBundle.putStringArrayList("Favorite_Icons", iconBase64StringArrayList);
-
- // Add the arguments bundle to this instance of `UrlHistoryDialog`.
- UrlHistoryDialog thisUrlHistoryDialog = new UrlHistoryDialog();
- thisUrlHistoryDialog.setArguments(argumentsBundle);
- return thisUrlHistoryDialog;
- }
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- // Remove the incorrect lint error that `getArguments()` might be null.
- assert getArguments() != null;
+ // Store the favorite icon and the URL in history entry.
+ History historyEntry = new History(favoriteIconBitmap, webBackForwardList.getItemAtIndex(i).getUrl());
- // Get the `ArrayLists` from the `Arguments`.
- ArrayList<String> urlStringArrayList = getArguments().getStringArrayList("URL_History");
- ArrayList<String> favoriteIconBase64StringArrayList = getArguments().getStringArrayList("Favorite_Icons");
-
- // Remove the lint warning below that the `ArrayLists` might be `null`.
- assert urlStringArrayList != null;
- assert favoriteIconBase64StringArrayList != null;
-
- // Populate `historyArrayList`. We go down from `urlStringArrayList.size()` so that the newest entries are at the top. `-1` is needed because `historyArrayList` is zero-based.
- for (int i=urlStringArrayList.size() -1; i >= 0; i--) {
- // Decode the favorite icon Base64 `String` to a `byte[]`.
- byte[] favoriteIconByteArray = Base64.decode(favoriteIconBase64StringArrayList.get(i), Base64.DEFAULT);
-
- // Convert the favorite icon `byte[]` to a `Bitmap`. `0` is the starting offset.
- Bitmap favoriteIconBitmap = BitmapFactory.decodeByteArray(favoriteIconByteArray, 0, favoriteIconByteArray.length);
-
- // Store the favorite icon and the URL in `historyEntry`.
- History historyEntry = new History(favoriteIconBitmap, urlStringArrayList.get(i));
-
- // Add this history entry to `historyArrayList`.
+ // Add this history entry to the history array list.
historyArrayList.add(historyEntry);
}
- // Get the original current page ID.
- int originalCurrentPageId = getArguments().getInt("Current_Page");
-
- // Subtract `originalCurrentPageId` from the array size because we reversed the order of the array so that the newest entries are at the top. `-1` is needed because the array is zero-based.
- currentPageId = urlStringArrayList.size() - 1 - originalCurrentPageId;
- }
-
- @Override
- @NonNull
- // `@SuppressLing("InflateParams")` removes the warning about using `null` as the parent view group when inflating the `AlertDialog`.
- @SuppressLint("InflateParams")
- public Dialog onCreateDialog(Bundle savedInstanceState) {
- // Remove the incorrect lint warning that `getActivity()` might be null.
- assert getActivity() != null;
-
- // Get the activity's layout inflater.
- LayoutInflater layoutInflater = getActivity().getLayoutInflater();
+ // Subtract the original current page ID from the array size because the order of the array is reversed so that the newest entries are at the top. `-1` is needed because the array is zero-based.
+ int currentPageId = webBackForwardList.getSize() - 1 - currentPageIndex;
// Use an alert dialog builder to create the alert dialog.
AlertDialog.Builder dialogBuilder;
// Set the view. The parent view is `null` because it will be assigned by `AlertDialog`.
dialogBuilder.setView(layoutInflater.inflate(R.layout.url_history_dialog, null));
- // Set an `onClick()` listener on the negative button.
+ // Setup the clear history button.
dialogBuilder.setNegativeButton(R.string.clear_history, (DialogInterface dialog, int which) -> {
// Clear the history.
- urlHistoryListener.onClearHistory();
+ nestedScrollWebView.clearHistory();
});
// Set an `onClick()` listener on the positive button.
//The alert dialog must be shown before the contents can be modified.
alertDialog.show();
- // Instantiate a `HistoryArrayAdapter`.
+ // Instantiate a history array adapter.
HistoryArrayAdapter historyArrayAdapter = new HistoryArrayAdapter(getContext(), historyArrayList, currentPageId);
// Get a handle for the list view.
// Only consume the click if it is not on the `currentPageId`.
if (itemId != currentPageId) {
- // Go forward or back to `itemId`.
- urlHistoryListener.onUrlHistoryEntrySelected(currentPageId - itemId);
+ // Reset the current domain name so that navigation works if third-party requests are blocked.
+ nestedScrollWebView.resetCurrentDomainName();
+
+ // Set navigating history so that the domain settings are applied when the new URL is loaded.
+ nestedScrollWebView.setNavigatingHistory(true);
+
+ // Load the history entry.
+ nestedScrollWebView.goBackOrForward(currentPageId - itemId);
- // Dismiss the `Dialog`.
+ // Dismiss the alert dialog.
alertDialog.dismiss();
}
});
- // `onCreateDialog` requires the return of an `AlertDialog`.
+ // Return the alert dialog.
return alertDialog;
}
}
\ No newline at end of file
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-
-<!--
- Copyright © 2015-2017,2019 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
- 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"
- android:layout_height="match_parent"
- android:layout_width="wrap_content"
- android:orientation="horizontal"
- tools:ignore="UseCompoundDrawables" >
-
- <ImageView
- android:id="@+id/favorite_icon_imageview"
- android:src="@drawable/world"
- android:layout_height="26dp"
- android:layout_width="26dp"
- android:layout_gravity="center_vertical"
- android:layout_marginEnd="5dp"
- android:contentDescription="@string/favorite_icon" />
-
- <TextView
- android:id="@+id/title_textview"
- android:layout_height="match_parent"
- android:layout_width="wrap_content"
- android:gravity="center_vertical"
- android:textSize="16sp"
- android:text="@string/new_tab"
- app:autoSizeTextType="uniform"
- android:maxWidth="150dp"
- android:maxLines="2"
- android:ellipsize="end" />
-</LinearLayout>
\ No newline at end of file
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:id="@+id/guide_coordinatorlayout"
xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:android.support.design="http://schemas.android.com/apk/res-auto"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:fitsSystemWindows="true" >
<!-- For some reason `tabIndicatorColor` does not pull from the style unless specified explicitly here. -->
<com.google.android.material.tabs.TabLayout
android:id="@+id/guide_tablayout"
- xmlns:android.support.design="http://schemas.android.com/apk/res-auto"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android.support.design:tabMode="scrollable"
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:android.support.design="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/root_framelayout"
android:layout_height="match_parent"
android:id="@+id/toolbar"
android:layout_height="wrap_content"
android:layout_width="match_parent"
- app:layout_scrollFlags="scroll|enterAlways|snap" />
+ android.support.design:layout_scrollFlags="scroll|enterAlways|snap" />
- <HorizontalScrollView
+ <LinearLayout
android:layout_height="wrap_content"
- android:layout_width="match_parent"
- app:layout_scrollFlags="scroll|enterAlways|snap" >
+ android:layout_width="wrap_content"
+ android:orientation="horizontal"
+ android.support.design:layout_scrollFlags="scroll|enterAlways|snap" >
+
+ <com.google.android.material.tabs.TabLayout
+ android:id="@+id/tablayout"
+ android:layout_height="wrap_content"
+ android:layout_width="0dp"
+ android:layout_weight="1"
+ android.support.design:tabIndicatorGravity="top"
+ android.support.design:tabMode="scrollable" />
- <LinearLayout
+ <ImageView
android:layout_height="wrap_content"
android:layout_width="wrap_content"
- android:orientation="horizontal" >
-
- <com.google.android.material.tabs.TabLayout
- android:id="@+id/tablayout"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- app:tabIndicatorGravity="top"
- app:tabMode="scrollable" />
-
- <!-- `style="?android:borderlessButtonStyle"` shows a visual indication when the image view is tapped. -->
- <ImageView
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:layout_gravity="center_vertical"
- android:src="@drawable/add_light"
- android:tint="?attr/addTabIconTintColor"
- android:onClick="addTab"
- android:contentDescription="@string/add_tab"
- style="?android:attr/borderlessButtonStyle" />
- </LinearLayout>
- </HorizontalScrollView>
+ android:layout_gravity="center_vertical"
+ android:paddingStart="10dp"
+ android:paddingEnd="10dp"
+ android:src="@drawable/add_light"
+ android:tint="?attr/addTabIconTintColor"
+ android:onClick="addTab"
+ android:contentDescription="@string/add_tab" />
+ </LinearLayout>
<!-- The find on page linear layout. It is initially `visibility="gone"`. -->
<LinearLayout
android:id="@+id/swiperefreshlayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
- app:layout_behavior="@string/appbar_scrolling_view_behavior" >
+ android.support.design:layout_behavior="@string/appbar_scrolling_view_behavior" >
<androidx.viewpager.widget.ViewPager
android:id="@+id/webviewpager"
android:layout_height="match_parent"
android:layout_width="wrap_content"
android:layout_gravity="start"
- app:headerLayout="@layout/navigation_header"
- app:menu="@menu/webview_navigation_menu"
- app:itemIconTint="?attr/navigationIconTintColor" />
+ android.support.design:headerLayout="@layout/navigation_header"
+ android.support.design:menu="@menu/webview_navigation_menu"
+ android.support.design:itemIconTint="?attr/navigationIconTintColor" />
<!-- Include the bookmarks drawer, which varies based on screen width. -->
<include layout="@layout/bookmarks_drawer" />
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ Copyright © 2015-2017,2019 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
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_height="match_parent"
+ android:layout_width="wrap_content"
+ android:orientation="horizontal"
+ tools:ignore="UseCompoundDrawables">
+
+ <ImageView
+ android:id="@+id/favorite_icon_imageview"
+ android:src="@drawable/world"
+ android:layout_height="26dp"
+ android:layout_width="26dp"
+ android:layout_gravity="center_vertical"
+ android:layout_marginEnd="5dp"
+ android:contentDescription="@string/favorite_icon" />
+
+ <TextView
+ android:id="@+id/title_textview"
+ android:layout_height="match_parent"
+ android:layout_width="120dp"
+ android:gravity="center_vertical"
+ android:text="@string/new_tab"
+ android:maxLines="2"
+ android:ellipsize="end" />
+</LinearLayout>
\ No newline at end of file
<item name="sortIcon">@drawable/sort_light</item>
<item name="actionBarPopupTheme">@style/PrivacyBrowserPopupsLight</item>
<item name="appBarTextTheme">@style/PrivacyBrowserAppBarWhiteText</item>
- <item name="tabLayoutTheme">@style/PrivacyBrowserTabLayoutLight</item>
<item name="popupsTheme">@style/PrivacyBrowserPopupsLight</item>
+ <item name="tabLayoutTheme">@style/PrivacyBrowserTabLayoutLight</item>
</style>
<!-- `colorPrimaryDark` is the color of the status bar. -->
<item name="moveToFolderIcon">@drawable/move_to_folder_dark</item>
<item name="saveIcon">@drawable/save_dark</item>
<item name="sortIcon">@drawable/sort_dark</item>
+ <item name="android:spinnerDropDownItemStyle">@style/PrivacyBrowserSpinnerDropDownItemStyleDark</item>
<item name="appBarTextTheme">@style/PrivacyBrowserAppBarDark</item>
- <item name="tabLayoutTheme">@style/PrivacyBrowserTabLayoutDark</item>
<item name="popupsTheme">@style/PrivacyBrowserPopupsDark</item>
- <item name="android:spinnerDropDownItemStyle">@style/PrivacyBrowserSpinnerDropDownItemStyleDark</item>
+ <item name="tabLayoutTheme">@style/PrivacyBrowserTabLayoutDark</item>
</style>
<style name="PrivacyBrowserSettingsDark" parent="Theme.AppCompat" >
<string name="open_with">Open with</string>
<string name="new_tab">New tab</string>
<string name="add_tab">Add tab</string>
+ <string name="loading">Loading…</string>
<!-- Save As. -->
<string name="save_as">Save As</string>
<item name="sortIcon">@drawable/sort_light</item>
<item name="actionBarPopupTheme">@style/PrivacyBrowserPopupsLight</item>
<item name="appBarTextTheme">@style/PrivacyBrowserAppBarWhiteText</item>
- <item name="tabLayoutTheme">@style/PrivacyBrowserTabLayoutLight</item>
<item name="popupsTheme">@style/PrivacyBrowserPopupsLight</item>
+ <item name="tabLayoutTheme">@style/PrivacyBrowserTabLayoutLight</item>
</style>
<!-- `colorPrimaryDark` is the color of the status bar. -->
<item name="moveToFolderIcon">@drawable/move_to_folder_dark</item>
<item name="saveIcon">@drawable/save_dark</item>
<item name="sortIcon">@drawable/sort_dark</item>
+ <item name="android:spinnerDropDownItemStyle">@style/PrivacyBrowserSpinnerDropDownItemStyleDark</item>
<item name="appBarTextTheme">@style/PrivacyBrowserAppBarDark</item>
- <item name="tabLayoutTheme">@style/PrivacyBrowserTabLayoutDark</item>
<item name="popupsTheme">@style/PrivacyBrowserPopupsDark</item>
- <item name="android:spinnerDropDownItemStyle">@style/PrivacyBrowserSpinnerDropDownItemStyleDark</item>
+ <item name="tabLayoutTheme">@style/PrivacyBrowserTabLayoutDark</item>
</style>
<style name="PrivacyBrowserSettingsDark" parent="Theme.AppCompat" >