| Index: chrome/android/java/src/org/chromium/chrome/browser/pageinfo/WebsiteSettingsPopup.java
|
| diff --git a/chrome/android/java/src/org/chromium/chrome/browser/pageinfo/WebsiteSettingsPopup.java b/chrome/android/java/src/org/chromium/chrome/browser/pageinfo/WebsiteSettingsPopup.java
|
| deleted file mode 100644
|
| index 7685ecdb4b3fdd11d35c6461e3d9d99e0ea69637..0000000000000000000000000000000000000000
|
| --- a/chrome/android/java/src/org/chromium/chrome/browser/pageinfo/WebsiteSettingsPopup.java
|
| +++ /dev/null
|
| @@ -1,980 +0,0 @@
|
| -// Copyright 2013 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -package org.chromium.chrome.browser.pageinfo;
|
| -
|
| -import android.animation.Animator;
|
| -import android.animation.AnimatorListenerAdapter;
|
| -import android.animation.AnimatorSet;
|
| -import android.animation.ObjectAnimator;
|
| -import android.app.Activity;
|
| -import android.app.Dialog;
|
| -import android.content.ActivityNotFoundException;
|
| -import android.content.ClipData;
|
| -import android.content.ClipboardManager;
|
| -import android.content.Context;
|
| -import android.content.DialogInterface;
|
| -import android.content.Intent;
|
| -import android.content.pm.PackageManager;
|
| -import android.graphics.Color;
|
| -import android.graphics.drawable.ColorDrawable;
|
| -import android.net.Uri;
|
| -import android.os.Bundle;
|
| -import android.provider.Settings;
|
| -import android.support.annotation.IntDef;
|
| -import android.support.v7.widget.AppCompatTextView;
|
| -import android.text.Layout;
|
| -import android.text.Spannable;
|
| -import android.text.SpannableString;
|
| -import android.text.SpannableStringBuilder;
|
| -import android.text.TextUtils;
|
| -import android.text.style.ForegroundColorSpan;
|
| -import android.text.style.StyleSpan;
|
| -import android.util.AttributeSet;
|
| -import android.view.Gravity;
|
| -import android.view.LayoutInflater;
|
| -import android.view.View;
|
| -import android.view.View.OnClickListener;
|
| -import android.view.View.OnLongClickListener;
|
| -import android.view.ViewGroup;
|
| -import android.view.Window;
|
| -import android.widget.Button;
|
| -import android.widget.ImageView;
|
| -import android.widget.LinearLayout;
|
| -import android.widget.ScrollView;
|
| -import android.widget.TextView;
|
| -
|
| -import org.chromium.base.ApiCompatibilityUtils;
|
| -import org.chromium.base.annotations.CalledByNative;
|
| -import org.chromium.base.metrics.RecordHistogram;
|
| -import org.chromium.base.metrics.RecordUserAction;
|
| -import org.chromium.chrome.R;
|
| -import org.chromium.chrome.browser.ContentSettingsType;
|
| -import org.chromium.chrome.browser.UrlConstants;
|
| -import org.chromium.chrome.browser.instantapps.InstantAppsHandler;
|
| -import org.chromium.chrome.browser.offlinepages.OfflinePageItem;
|
| -import org.chromium.chrome.browser.offlinepages.OfflinePageUtils;
|
| -import org.chromium.chrome.browser.omnibox.OmniboxUrlEmphasizer;
|
| -import org.chromium.chrome.browser.preferences.PrefServiceBridge;
|
| -import org.chromium.chrome.browser.preferences.Preferences;
|
| -import org.chromium.chrome.browser.preferences.PreferencesLauncher;
|
| -import org.chromium.chrome.browser.preferences.website.ContentSetting;
|
| -import org.chromium.chrome.browser.preferences.website.ContentSettingsResources;
|
| -import org.chromium.chrome.browser.preferences.website.SingleWebsitePreferences;
|
| -import org.chromium.chrome.browser.preferences.website.WebsitePreferenceBridge;
|
| -import org.chromium.chrome.browser.profiles.Profile;
|
| -import org.chromium.chrome.browser.ssl.SecurityStateModel;
|
| -import org.chromium.chrome.browser.tab.Tab;
|
| -import org.chromium.chrome.browser.util.UrlUtilities;
|
| -import org.chromium.components.location.LocationUtils;
|
| -import org.chromium.content_public.browser.WebContents;
|
| -import org.chromium.content_public.browser.WebContentsObserver;
|
| -import org.chromium.ui.base.DeviceFormFactor;
|
| -import org.chromium.ui.base.WindowAndroid;
|
| -import org.chromium.ui.base.WindowAndroid.PermissionCallback;
|
| -import org.chromium.ui.interpolators.BakedBezierInterpolator;
|
| -import org.chromium.ui.widget.Toast;
|
| -
|
| -import java.lang.annotation.Retention;
|
| -import java.lang.annotation.RetentionPolicy;
|
| -import java.net.URI;
|
| -import java.net.URISyntaxException;
|
| -import java.text.DateFormat;
|
| -import java.util.ArrayList;
|
| -import java.util.Date;
|
| -import java.util.List;
|
| -
|
| -/**
|
| - * Java side of Android implementation of the website settings UI.
|
| - * TODO(sashab): Rename this, and all its resources, to PageInfo* and page_info_* instead of
|
| - * WebsiteSettings* and website_settings_*. Do this on the C++ side as well.
|
| - */
|
| -public class WebsiteSettingsPopup implements OnClickListener {
|
| - @Retention(RetentionPolicy.SOURCE)
|
| - @IntDef({OPENED_FROM_MENU, OPENED_FROM_TOOLBAR})
|
| - private @interface OpenedFromSource {}
|
| -
|
| - public static final int OPENED_FROM_MENU = 1;
|
| - public static final int OPENED_FROM_TOOLBAR = 2;
|
| -
|
| - /**
|
| - * An entry in the settings dropdown for a given permission. There are two options for each
|
| - * permission: Allow and Block.
|
| - */
|
| - private static final class PageInfoPermissionEntry {
|
| - public final String name;
|
| - public final int type;
|
| - public final ContentSetting setting;
|
| -
|
| - PageInfoPermissionEntry(String name, int type, ContentSetting setting) {
|
| - this.name = name;
|
| - this.type = type;
|
| - this.setting = setting;
|
| - }
|
| -
|
| - @Override
|
| - public String toString() {
|
| - return name;
|
| - }
|
| - }
|
| -
|
| - /**
|
| - * A TextView which truncates and displays a URL such that the origin is always visible.
|
| - * The URL can be expanded by clicking on the it.
|
| - */
|
| - public static class ElidedUrlTextView extends AppCompatTextView {
|
| - // The number of lines to display when the URL is truncated. This number
|
| - // should still allow the origin to be displayed. NULL before
|
| - // setUrlAfterLayout() is called.
|
| - private Integer mTruncatedUrlLinesToDisplay;
|
| -
|
| - // The number of lines to display when the URL is expanded. This should be enough to display
|
| - // at most two lines of the fragment if there is one in the URL.
|
| - private Integer mFullLinesToDisplay;
|
| -
|
| - // If true, the text view will show the truncated text. If false, it
|
| - // will show the full, expanded text.
|
| - private boolean mIsShowingTruncatedText = true;
|
| -
|
| - // The profile to use when getting the end index for the origin.
|
| - private Profile mProfile;
|
| -
|
| - // The maximum number of lines currently shown in the view
|
| - private int mCurrentMaxLines = Integer.MAX_VALUE;
|
| -
|
| - /** Constructor for inflating from XML. */
|
| - public ElidedUrlTextView(Context context, AttributeSet attrs) {
|
| - super(context, attrs);
|
| - }
|
| -
|
| - @Override
|
| - public void setMaxLines(int maxlines) {
|
| - super.setMaxLines(maxlines);
|
| - mCurrentMaxLines = maxlines;
|
| - }
|
| -
|
| - /**
|
| - * Find the number of lines of text which must be shown in order to display the character at
|
| - * a given index.
|
| - */
|
| - private int getLineForIndex(int index) {
|
| - Layout layout = getLayout();
|
| - int endLine = 0;
|
| - while (endLine < layout.getLineCount() && layout.getLineEnd(endLine) < index) {
|
| - endLine++;
|
| - }
|
| - // Since endLine is an index, add 1 to get the number of lines.
|
| - return endLine + 1;
|
| - }
|
| -
|
| - @Override
|
| - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
| - setMaxLines(Integer.MAX_VALUE);
|
| - super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
| - assert mProfile != null : "setProfile() must be called before layout.";
|
| - String urlText = getText().toString();
|
| -
|
| - // Lay out the URL in a StaticLayout that is the same size as our final
|
| - // container.
|
| - int originEndIndex = OmniboxUrlEmphasizer.getOriginEndIndex(urlText, mProfile);
|
| -
|
| - // Find the range of lines containing the origin.
|
| - int originEndLine = getLineForIndex(originEndIndex);
|
| -
|
| - // Display an extra line so we don't accidentally hide the origin with
|
| - // ellipses
|
| - mTruncatedUrlLinesToDisplay = originEndLine + 1;
|
| -
|
| - // Find the line where the fragment starts. Since # is a reserved character, it is safe
|
| - // to just search for the first # to appear in the url.
|
| - int fragmentStartIndex = urlText.indexOf('#');
|
| - if (fragmentStartIndex == -1) fragmentStartIndex = urlText.length();
|
| -
|
| - int fragmentStartLine = getLineForIndex(fragmentStartIndex);
|
| - mFullLinesToDisplay = fragmentStartLine + 1;
|
| -
|
| - // If there is no origin (according to OmniboxUrlEmphasizer), make sure the fragment is
|
| - // still hidden correctly.
|
| - if (mFullLinesToDisplay < mTruncatedUrlLinesToDisplay) {
|
| - mTruncatedUrlLinesToDisplay = mFullLinesToDisplay;
|
| - }
|
| -
|
| - if (updateMaxLines()) super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
| - }
|
| -
|
| - /**
|
| - * Sets the profile to use when calculating the end index of the origin.
|
| - * Must be called before layout.
|
| - *
|
| - * @param profile The profile to use when coloring the URL.
|
| - */
|
| - public void setProfile(Profile profile) {
|
| - mProfile = profile;
|
| - }
|
| -
|
| - /**
|
| - * Toggles truncating/expanding the URL text. If the URL text is not
|
| - * truncated, has no effect.
|
| - */
|
| - public void toggleTruncation() {
|
| - mIsShowingTruncatedText = !mIsShowingTruncatedText;
|
| - updateMaxLines();
|
| - }
|
| -
|
| - private boolean updateMaxLines() {
|
| - int maxLines = mFullLinesToDisplay;
|
| - if (mIsShowingTruncatedText) maxLines = mTruncatedUrlLinesToDisplay;
|
| - if (maxLines != mCurrentMaxLines) {
|
| - setMaxLines(maxLines);
|
| - return true;
|
| - }
|
| - return false;
|
| - }
|
| - }
|
| -
|
| - // Delay enter to allow the triggering button to animate before we cover it.
|
| - private static final int ENTER_START_DELAY = 100;
|
| - private static final int FADE_DURATION = 200;
|
| - private static final int FADE_IN_BASE_DELAY = 150;
|
| - private static final int FADE_IN_DELAY_OFFSET = 20;
|
| - private static final int CLOSE_CLEANUP_DELAY = 10;
|
| -
|
| - private static final int MAX_TABLET_DIALOG_WIDTH_DP = 400;
|
| -
|
| - private final Context mContext;
|
| - private final WindowAndroid mWindowAndroid;
|
| - private final Tab mTab;
|
| -
|
| - // A pointer to the C++ object for this UI.
|
| - private long mNativeWebsiteSettingsPopup;
|
| -
|
| - // The outer container, filled with the layout from website_settings.xml.
|
| - private final LinearLayout mContainer;
|
| -
|
| - // UI elements in the dialog.
|
| - private final ElidedUrlTextView mUrlTitle;
|
| - private final TextView mConnectionSummary;
|
| - private final TextView mConnectionMessage;
|
| - private final LinearLayout mPermissionsList;
|
| - private final Button mInstantAppButton;
|
| - private final Button mSiteSettingsButton;
|
| - private final Button mOpenOnlineButton;
|
| -
|
| - // The dialog the container is placed in.
|
| - private final Dialog mDialog;
|
| -
|
| - // Animation which is currently running, if there is one.
|
| - private AnimatorSet mCurrentAnimation;
|
| -
|
| - private boolean mDismissWithoutAnimation;
|
| -
|
| - // The full URL from the URL bar, which is copied to the user's clipboard when they select 'Copy
|
| - // URL'.
|
| - private String mFullUrl;
|
| -
|
| - // A parsed version of mFullUrl. Is null if the URL is invalid/cannot be
|
| - // parsed.
|
| - private URI mParsedUrl;
|
| -
|
| - // Whether or not this page is an internal chrome page (e.g. the
|
| - // chrome://settings page).
|
| - private boolean mIsInternalPage;
|
| -
|
| - // The security level of the page (a valid ConnectionSecurityLevel).
|
| - private int mSecurityLevel;
|
| -
|
| - // Permissions available to be displayed in mPermissionsList.
|
| - private List<PageInfoPermissionEntry> mDisplayedPermissions;
|
| -
|
| - // Creation date of an offline copy, if web contents contains an offline page.
|
| - private String mOfflinePageCreationDate;
|
| -
|
| - // The name of the content publisher, if any.
|
| - private String mContentPublisher;
|
| -
|
| - // The intent associated with the instant app for this URL (or null if one does not exist).
|
| - private Intent mInstantAppIntent;
|
| -
|
| - /**
|
| - * Creates the WebsiteSettingsPopup, but does not display it. Also initializes the corresponding
|
| - * C++ object and saves a pointer to it.
|
| - * @param activity Activity which is used for showing a popup.
|
| - * @param tab Tab for which the pop up is shown.
|
| - * @param offlinePageCreationDate Date when the offline page was created.
|
| - * @param publisher The name of the content publisher, if any.
|
| - */
|
| - private WebsiteSettingsPopup(Activity activity, Tab tab, String offlinePageCreationDate,
|
| - String publisher) {
|
| - mContext = activity;
|
| - mTab = tab;
|
| - if (offlinePageCreationDate != null) {
|
| - mOfflinePageCreationDate = offlinePageCreationDate;
|
| - }
|
| - mWindowAndroid = mTab.getWebContents().getTopLevelNativeWindow();
|
| - mContentPublisher = publisher;
|
| -
|
| - // Find the container and all it's important subviews.
|
| - mContainer = (LinearLayout) LayoutInflater.from(mContext).inflate(
|
| - R.layout.website_settings, null);
|
| - mContainer.setVisibility(View.INVISIBLE);
|
| - mContainer.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
|
| - @Override
|
| - public void onLayoutChange(
|
| - View v, int l, int t, int r, int b, int ol, int ot, int or, int ob) {
|
| - // Trigger the entrance animations once the main container has been laid out and has
|
| - // a height.
|
| - mContainer.removeOnLayoutChangeListener(this);
|
| - mContainer.setVisibility(View.VISIBLE);
|
| - createAllAnimations(true).start();
|
| - }
|
| - });
|
| -
|
| - mUrlTitle = (ElidedUrlTextView) mContainer.findViewById(R.id.website_settings_url);
|
| - mUrlTitle.setProfile(mTab.getProfile());
|
| - mUrlTitle.setOnClickListener(this);
|
| - // Long press the url text to copy it to the clipboard.
|
| - mUrlTitle.setOnLongClickListener(new OnLongClickListener() {
|
| - @Override
|
| - public boolean onLongClick(View v) {
|
| - ClipboardManager clipboard = (ClipboardManager) mContext
|
| - .getSystemService(Context.CLIPBOARD_SERVICE);
|
| - ClipData clip = ClipData.newPlainText("url", mFullUrl);
|
| - clipboard.setPrimaryClip(clip);
|
| - Toast.makeText(mContext, R.string.url_copied, Toast.LENGTH_SHORT).show();
|
| - return true;
|
| - }
|
| - });
|
| -
|
| - mConnectionSummary = (TextView) mContainer
|
| - .findViewById(R.id.website_settings_connection_summary);
|
| - mConnectionMessage = (TextView) mContainer
|
| - .findViewById(R.id.website_settings_connection_message);
|
| - mPermissionsList = (LinearLayout) mContainer
|
| - .findViewById(R.id.website_settings_permissions_list);
|
| -
|
| - mInstantAppButton =
|
| - (Button) mContainer.findViewById(R.id.website_settings_instant_app_button);
|
| - mInstantAppButton.setOnClickListener(this);
|
| -
|
| - mSiteSettingsButton =
|
| - (Button) mContainer.findViewById(R.id.website_settings_site_settings_button);
|
| - mSiteSettingsButton.setOnClickListener(this);
|
| -
|
| - mOpenOnlineButton =
|
| - (Button) mContainer.findViewById(R.id.website_settings_open_online_button);
|
| - mOpenOnlineButton.setOnClickListener(this);
|
| -
|
| - mDisplayedPermissions = new ArrayList<PageInfoPermissionEntry>();
|
| -
|
| - // Hide the permissions list for sites with no permissions.
|
| - setVisibilityOfPermissionsList(false);
|
| -
|
| - // Work out the URL and connection message and status visibility.
|
| - mFullUrl = mTab.getWebContents().getVisibleUrl();
|
| - if (isShowingOfflinePage()) {
|
| - mFullUrl = OfflinePageUtils.stripSchemeFromOnlineUrl(mFullUrl);
|
| - }
|
| -
|
| - try {
|
| - mParsedUrl = new URI(mFullUrl);
|
| - mIsInternalPage = UrlUtilities.isInternalScheme(mParsedUrl);
|
| - } catch (URISyntaxException e) {
|
| - mParsedUrl = null;
|
| - mIsInternalPage = false;
|
| - }
|
| - mSecurityLevel = SecurityStateModel.getSecurityLevelForWebContents(mTab.getWebContents());
|
| -
|
| - SpannableStringBuilder urlBuilder = new SpannableStringBuilder(mFullUrl);
|
| - OmniboxUrlEmphasizer.emphasizeUrl(urlBuilder, mContext.getResources(), mTab.getProfile(),
|
| - mSecurityLevel, mIsInternalPage, true, true);
|
| - mUrlTitle.setText(urlBuilder);
|
| -
|
| - if (mParsedUrl == null || mParsedUrl.getScheme() == null
|
| - || !(mParsedUrl.getScheme().equals(UrlConstants.HTTP_SCHEME)
|
| - || mParsedUrl.getScheme().equals(UrlConstants.HTTPS_SCHEME))) {
|
| - mSiteSettingsButton.setVisibility(View.GONE);
|
| - }
|
| -
|
| - if (isShowingOfflinePage()) {
|
| - boolean isConnected = OfflinePageUtils.isConnected();
|
| - RecordHistogram.recordBooleanHistogram(
|
| - "OfflinePages.WebsiteSettings.OpenOnlineButtonVisible", isConnected);
|
| - if (!isConnected) mOpenOnlineButton.setVisibility(View.GONE);
|
| - } else {
|
| - mOpenOnlineButton.setVisibility(View.GONE);
|
| - }
|
| -
|
| - mInstantAppIntent = (mIsInternalPage || isShowingOfflinePage()) ? null
|
| - : InstantAppsHandler.getInstance().getInstantAppIntentForUrl(mFullUrl);
|
| - if (mInstantAppIntent == null) mInstantAppButton.setVisibility(View.GONE);
|
| -
|
| - // Create the dialog.
|
| - mDialog = new Dialog(mContext) {
|
| - private void superDismiss() {
|
| - super.dismiss();
|
| - }
|
| -
|
| - @Override
|
| - public void dismiss() {
|
| - if (DeviceFormFactor.isTablet(mContext) || mDismissWithoutAnimation) {
|
| - // Dismiss the dialog without any custom animations on tablet.
|
| - super.dismiss();
|
| - } else {
|
| - Animator animator = createAllAnimations(false);
|
| - animator.addListener(new AnimatorListenerAdapter() {
|
| - @Override
|
| - public void onAnimationEnd(Animator animation) {
|
| - // onAnimationEnd is called during the final frame of the animation.
|
| - // Delay the cleanup by a tiny amount to give this frame a chance to be
|
| - // displayed before we destroy the dialog.
|
| - mContainer.postDelayed(new Runnable() {
|
| - @Override
|
| - public void run() {
|
| - superDismiss();
|
| - }
|
| - }, CLOSE_CLEANUP_DELAY);
|
| - }
|
| - });
|
| - animator.start();
|
| - }
|
| - }
|
| - };
|
| - mDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
|
| - mDialog.setCanceledOnTouchOutside(true);
|
| -
|
| - // On smaller screens, place the dialog at the top of the screen, and remove its border.
|
| - if (!DeviceFormFactor.isTablet(mContext)) {
|
| - Window window = mDialog.getWindow();
|
| - window.setGravity(Gravity.TOP);
|
| - window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
|
| - }
|
| -
|
| - // This needs to come after other member initialization.
|
| - mNativeWebsiteSettingsPopup = nativeInit(this, mTab.getWebContents());
|
| - final WebContentsObserver webContentsObserver =
|
| - new WebContentsObserver(mTab.getWebContents()) {
|
| - @Override
|
| - public void navigationEntryCommitted() {
|
| - // If a navigation is committed (e.g. from in-page redirect), the data we're showing
|
| - // is stale so dismiss the dialog.
|
| - mDialog.dismiss();
|
| - }
|
| -
|
| - @Override
|
| - public void wasHidden() {
|
| - // The web contents were hidden (potentially by loading another URL via an intent),
|
| - // so dismiss the dialog).
|
| - mDialog.dismiss();
|
| - }
|
| -
|
| - @Override
|
| - public void destroy() {
|
| - super.destroy();
|
| - // Force the dialog to close immediately in case the destroy was from Chrome
|
| - // quitting.
|
| - mDismissWithoutAnimation = true;
|
| - mDialog.dismiss();
|
| - }
|
| - };
|
| - mDialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
|
| - @Override
|
| - public void onDismiss(DialogInterface dialog) {
|
| - assert mNativeWebsiteSettingsPopup != 0;
|
| - webContentsObserver.destroy();
|
| - nativeDestroy(mNativeWebsiteSettingsPopup);
|
| - mNativeWebsiteSettingsPopup = 0;
|
| - }
|
| - });
|
| -
|
| - showDialog();
|
| - }
|
| -
|
| - /**
|
| - * Sets the visibility of the permissions list, which contains padding and borders that should
|
| - * not be shown if a site has no permissions.
|
| - *
|
| - * @param isVisible Whether to show or hide the dialog area.
|
| - */
|
| - private void setVisibilityOfPermissionsList(boolean isVisible) {
|
| - int visibility = isVisible ? View.VISIBLE : View.GONE;
|
| - mPermissionsList.setVisibility(visibility);
|
| - }
|
| -
|
| - /**
|
| - * Finds the Image resource of the icon to use for the given permission.
|
| - *
|
| - * @param permission A valid ContentSettingsType that can be displayed in the PageInfo dialog to
|
| - * retrieve the image for.
|
| - * @return The resource ID of the icon to use for that permission.
|
| - */
|
| - private int getImageResourceForPermission(int permission) {
|
| - int icon = ContentSettingsResources.getIcon(permission);
|
| - assert icon != 0 : "Icon requested for invalid permission: " + permission;
|
| - return icon;
|
| - }
|
| -
|
| - /**
|
| - * Whether to show a 'Details' link to the connection info popup. The link is only shown for
|
| - * HTTPS connections.
|
| - */
|
| - private boolean isConnectionDetailsLinkVisible() {
|
| - return mContentPublisher == null && !isShowingOfflinePage() && mParsedUrl != null
|
| - && mParsedUrl.getScheme() != null
|
| - && mParsedUrl.getScheme().equals(UrlConstants.HTTPS_SCHEME);
|
| - }
|
| -
|
| - private boolean hasAndroidPermission(int contentSettingType) {
|
| - String[] androidPermissions =
|
| - PrefServiceBridge.getAndroidPermissionsForContentSetting(contentSettingType);
|
| - if (androidPermissions == null) return true;
|
| - for (int i = 0; i < androidPermissions.length; i++) {
|
| - if (!mWindowAndroid.hasPermission(androidPermissions[i])) {
|
| - return false;
|
| - }
|
| - }
|
| - return true;
|
| - }
|
| -
|
| - /**
|
| - * Adds a new row for the given permission.
|
| - *
|
| - * @param name The title of the permission to display to the user.
|
| - * @param type The ContentSettingsType of the permission.
|
| - * @param currentSettingValue The ContentSetting value of the currently selected setting.
|
| - */
|
| - @CalledByNative
|
| - private void addPermissionSection(String name, int type, int currentSettingValue) {
|
| - // We have at least one permission, so show the lower permissions area.
|
| - setVisibilityOfPermissionsList(true);
|
| - mDisplayedPermissions.add(new PageInfoPermissionEntry(name, type, ContentSetting
|
| - .fromInt(currentSettingValue)));
|
| - }
|
| -
|
| - /**
|
| - * Update the permissions view based on the contents of mDisplayedPermissions.
|
| - */
|
| - @CalledByNative
|
| - private void updatePermissionDisplay() {
|
| - mPermissionsList.removeAllViews();
|
| - for (PageInfoPermissionEntry permission : mDisplayedPermissions) {
|
| - addReadOnlyPermissionSection(permission);
|
| - }
|
| - }
|
| -
|
| - private void addReadOnlyPermissionSection(PageInfoPermissionEntry permission) {
|
| - View permissionRow = LayoutInflater.from(mContext).inflate(
|
| - R.layout.website_settings_permission_row, null);
|
| -
|
| - ImageView permissionIcon = (ImageView) permissionRow.findViewById(
|
| - R.id.website_settings_permission_icon);
|
| - permissionIcon.setImageResource(getImageResourceForPermission(permission.type));
|
| -
|
| - if (permission.setting == ContentSetting.ALLOW) {
|
| - int warningTextResource = 0;
|
| -
|
| - // If warningTextResource is non-zero, then the view must be tagged with either
|
| - // permission_intent_override or permission_type.
|
| - LocationUtils locationUtils = LocationUtils.getInstance();
|
| - if (permission.type == ContentSettingsType.CONTENT_SETTINGS_TYPE_GEOLOCATION
|
| - && !locationUtils.isSystemLocationSettingEnabled()) {
|
| - warningTextResource = R.string.page_info_android_location_blocked;
|
| - permissionRow.setTag(R.id.permission_intent_override,
|
| - locationUtils.getSystemLocationSettingsIntent());
|
| - } else if (!hasAndroidPermission(permission.type)) {
|
| - warningTextResource = R.string.page_info_android_permission_blocked;
|
| - permissionRow.setTag(R.id.permission_type,
|
| - PrefServiceBridge.getAndroidPermissionsForContentSetting(permission.type));
|
| - }
|
| -
|
| - if (warningTextResource != 0) {
|
| - TextView permissionUnavailable = (TextView) permissionRow.findViewById(
|
| - R.id.website_settings_permission_unavailable_message);
|
| - permissionUnavailable.setVisibility(View.VISIBLE);
|
| - permissionUnavailable.setText(warningTextResource);
|
| -
|
| - permissionIcon.setImageResource(R.drawable.exclamation_triangle);
|
| - permissionIcon.setColorFilter(ApiCompatibilityUtils.getColor(
|
| - mContext.getResources(), R.color.website_settings_popup_text_link));
|
| -
|
| - permissionRow.setOnClickListener(this);
|
| - }
|
| - }
|
| -
|
| - TextView permissionStatus = (TextView) permissionRow.findViewById(
|
| - R.id.website_settings_permission_status);
|
| - SpannableStringBuilder builder = new SpannableStringBuilder();
|
| - SpannableString nameString = new SpannableString(permission.name);
|
| - final StyleSpan boldSpan = new StyleSpan(android.graphics.Typeface.BOLD);
|
| - nameString.setSpan(boldSpan, 0, nameString.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
|
| -
|
| - builder.append(nameString);
|
| - builder.append(" – "); // en-dash.
|
| - String status_text = "";
|
| - switch (permission.setting) {
|
| - case ALLOW:
|
| - status_text = mContext.getString(R.string.page_info_permission_allowed);
|
| - break;
|
| - case BLOCK:
|
| - status_text = mContext.getString(R.string.page_info_permission_blocked);
|
| - break;
|
| - default:
|
| - assert false : "Invalid setting " + permission.setting + " for permission "
|
| - + permission.type;
|
| - }
|
| - if (permission.type == ContentSettingsType.CONTENT_SETTINGS_TYPE_GEOLOCATION
|
| - && WebsitePreferenceBridge.shouldUseDSEGeolocationSetting(mFullUrl, false)) {
|
| - status_text = statusTextForDSEPermission(permission);
|
| - }
|
| - builder.append(status_text);
|
| - permissionStatus.setText(builder);
|
| - mPermissionsList.addView(permissionRow);
|
| - }
|
| -
|
| - /**
|
| - * Update the permission string for the Default Search Engine.
|
| - */
|
| - private String statusTextForDSEPermission(PageInfoPermissionEntry permission) {
|
| - if (permission.setting == ContentSetting.ALLOW) {
|
| - return mContext.getString(R.string.page_info_dse_permission_allowed);
|
| - }
|
| -
|
| - return mContext.getString(R.string.page_info_dse_permission_blocked);
|
| - }
|
| -
|
| - /**
|
| - * Sets the connection security summary and detailed description strings. These strings may be
|
| - * overridden based on the state of the Android UI.
|
| - */
|
| - @CalledByNative
|
| - private void setSecurityDescription(String summary, String details) {
|
| - // Display the appropriate connection message.
|
| - SpannableStringBuilder messageBuilder = new SpannableStringBuilder();
|
| - if (mContentPublisher != null) {
|
| - messageBuilder.append(
|
| - mContext.getString(R.string.page_info_domain_hidden, mContentPublisher));
|
| - } else if (isShowingOfflinePage()) {
|
| - messageBuilder.append(String.format(
|
| - mContext.getString(R.string.page_info_connection_offline),
|
| - mOfflinePageCreationDate));
|
| - } else {
|
| - if (!TextUtils.equals(summary, details)) {
|
| - mConnectionSummary.setVisibility(View.VISIBLE);
|
| - mConnectionSummary.setText(summary);
|
| - }
|
| - messageBuilder.append(details);
|
| - }
|
| -
|
| - if (isConnectionDetailsLinkVisible()) {
|
| - messageBuilder.append(" ");
|
| - SpannableString detailsText = new SpannableString(
|
| - mContext.getString(R.string.page_info_details_link));
|
| - final ForegroundColorSpan blueSpan = new ForegroundColorSpan(
|
| - ApiCompatibilityUtils.getColor(mContext.getResources(),
|
| - R.color.website_settings_popup_text_link));
|
| - detailsText.setSpan(
|
| - blueSpan, 0, detailsText.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
|
| - messageBuilder.append(detailsText);
|
| - }
|
| - mConnectionMessage.setText(messageBuilder);
|
| - if (isConnectionDetailsLinkVisible()) mConnectionMessage.setOnClickListener(this);
|
| - }
|
| -
|
| - /**
|
| - * Displays the WebsiteSettingsPopup.
|
| - */
|
| - private void showDialog() {
|
| - if (!DeviceFormFactor.isTablet(mContext)) {
|
| - // On smaller screens, make the dialog fill the width of the screen.
|
| - ScrollView scrollView = new ScrollView(mContext);
|
| - scrollView.addView(mContainer);
|
| - mDialog.addContentView(scrollView, new LinearLayout.LayoutParams(
|
| - LinearLayout.LayoutParams.MATCH_PARENT,
|
| - LinearLayout.LayoutParams.MATCH_PARENT));
|
| -
|
| - // This must be called after addContentView, or it won't fully fill to the edge.
|
| - Window window = mDialog.getWindow();
|
| - window.setLayout(ViewGroup.LayoutParams.MATCH_PARENT,
|
| - ViewGroup.LayoutParams.WRAP_CONTENT);
|
| - } else {
|
| - // On larger screens, make the dialog centered in the screen and have a maximum width.
|
| - ScrollView scrollView = new ScrollView(mContext) {
|
| - @Override
|
| - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
| - final int maxDialogWidthInPx = (int) (MAX_TABLET_DIALOG_WIDTH_DP
|
| - * mContext.getResources().getDisplayMetrics().density);
|
| - if (MeasureSpec.getSize(widthMeasureSpec) > maxDialogWidthInPx) {
|
| - widthMeasureSpec = MeasureSpec.makeMeasureSpec(maxDialogWidthInPx,
|
| - MeasureSpec.EXACTLY);
|
| - }
|
| - super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
| - }
|
| - };
|
| -
|
| - scrollView.addView(mContainer);
|
| - mDialog.addContentView(scrollView, new LinearLayout.LayoutParams(
|
| - LinearLayout.LayoutParams.WRAP_CONTENT,
|
| - LinearLayout.LayoutParams.MATCH_PARENT));
|
| - }
|
| -
|
| - mDialog.show();
|
| - }
|
| -
|
| - /**
|
| - * Dismiss the popup, and then run a task after the animation has completed (if there is one).
|
| - */
|
| - private void runAfterDismiss(Runnable task) {
|
| - mDialog.dismiss();
|
| - if (DeviceFormFactor.isTablet(mContext)) {
|
| - task.run();
|
| - } else {
|
| - mContainer.postDelayed(task, FADE_DURATION + CLOSE_CLEANUP_DELAY);
|
| - }
|
| - }
|
| -
|
| - @Override
|
| - public void onClick(View view) {
|
| - if (view == mSiteSettingsButton) {
|
| - // Delay while the WebsiteSettingsPopup closes.
|
| - runAfterDismiss(new Runnable() {
|
| - @Override
|
| - public void run() {
|
| - recordAction(WebsiteSettingsAction.WEBSITE_SETTINGS_SITE_SETTINGS_OPENED);
|
| - Bundle fragmentArguments =
|
| - SingleWebsitePreferences.createFragmentArgsForSite(mFullUrl);
|
| - fragmentArguments.putParcelable(SingleWebsitePreferences.EXTRA_WEB_CONTENTS,
|
| - mTab.getWebContents());
|
| - Intent preferencesIntent = PreferencesLauncher.createIntentForSettingsPage(
|
| - mContext, SingleWebsitePreferences.class.getName());
|
| - preferencesIntent.putExtra(
|
| - Preferences.EXTRA_SHOW_FRAGMENT_ARGUMENTS, fragmentArguments);
|
| - mContext.startActivity(preferencesIntent);
|
| - }
|
| - });
|
| - } else if (view == mInstantAppButton) {
|
| - try {
|
| - mContext.startActivity(mInstantAppIntent);
|
| - RecordUserAction.record("Android.InstantApps.LaunchedFromWebsiteSettingsPopup");
|
| - } catch (ActivityNotFoundException e) {
|
| - mInstantAppButton.setEnabled(false);
|
| - }
|
| - } else if (view == mUrlTitle) {
|
| - // Expand/collapse the displayed URL title.
|
| - mUrlTitle.toggleTruncation();
|
| - } else if (view == mConnectionMessage) {
|
| - runAfterDismiss(new Runnable() {
|
| - @Override
|
| - public void run() {
|
| - if (!mTab.getWebContents().isDestroyed()) {
|
| - recordAction(
|
| - WebsiteSettingsAction.WEBSITE_SETTINGS_SECURITY_DETAILS_OPENED);
|
| - ConnectionInfoPopup.show(mContext, mTab.getWebContents());
|
| - }
|
| - }
|
| - });
|
| - } else if (view.getId() == R.id.website_settings_permission_row) {
|
| - final Object intentOverride = view.getTag(R.id.permission_intent_override);
|
| -
|
| - if (intentOverride == null && mWindowAndroid != null) {
|
| - // Try and immediately request missing Android permissions where possible.
|
| - final String[] permissionType = (String[]) view.getTag(R.id.permission_type);
|
| - for (int i = 0; i < permissionType.length; i++) {
|
| - if (!mWindowAndroid.canRequestPermission(permissionType[i])) continue;
|
| -
|
| - // If any permissions can be requested, attempt to request them all.
|
| - mWindowAndroid.requestPermissions(permissionType, new PermissionCallback() {
|
| - @Override
|
| - public void onRequestPermissionsResult(
|
| - String[] permissions, int[] grantResults) {
|
| - boolean allGranted = true;
|
| - for (int i = 0; i < grantResults.length; i++) {
|
| - if (grantResults[i] != PackageManager.PERMISSION_GRANTED) {
|
| - allGranted = false;
|
| - break;
|
| - }
|
| - }
|
| - if (allGranted) updatePermissionDisplay();
|
| - }
|
| - });
|
| - return;
|
| - }
|
| - }
|
| -
|
| - runAfterDismiss(new Runnable() {
|
| - @Override
|
| - public void run() {
|
| - Intent settingsIntent;
|
| - if (intentOverride != null) {
|
| - settingsIntent = (Intent) intentOverride;
|
| - } else {
|
| - settingsIntent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
|
| - settingsIntent.setData(Uri.parse("package:" + mContext.getPackageName()));
|
| - }
|
| - settingsIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
| - mContext.startActivity(settingsIntent);
|
| - }
|
| - });
|
| - } else if (view == mOpenOnlineButton) {
|
| - runAfterDismiss(new Runnable() {
|
| - @Override
|
| - public void run() {
|
| - // Attempt to reload to an online version of the viewed offline web page. This
|
| - // attempt might fail if the user is offline, in which case an offline copy will
|
| - // be reloaded.
|
| - RecordHistogram.recordBooleanHistogram(
|
| - "OfflinePages.WebsiteSettings.ConnectedWhenOpenOnlineButtonClicked",
|
| - OfflinePageUtils.isConnected());
|
| - OfflinePageUtils.reload(mTab);
|
| - }
|
| - });
|
| - }
|
| - }
|
| -
|
| - /**
|
| - * Create a list of all the views which we want to individually fade in.
|
| - */
|
| - private List<View> collectAnimatableViews() {
|
| - List<View> animatableViews = new ArrayList<View>();
|
| - animatableViews.add(mUrlTitle);
|
| - if (mConnectionSummary.getVisibility() == View.VISIBLE) {
|
| - animatableViews.add(mConnectionSummary);
|
| - }
|
| - animatableViews.add(mConnectionMessage);
|
| - animatableViews.add(mInstantAppButton);
|
| - for (int i = 0; i < mPermissionsList.getChildCount(); i++) {
|
| - animatableViews.add(mPermissionsList.getChildAt(i));
|
| - }
|
| - animatableViews.add(mSiteSettingsButton);
|
| -
|
| - return animatableViews;
|
| - }
|
| -
|
| - /**
|
| - * Create an animator to fade an individual dialog element.
|
| - */
|
| - private Animator createInnerFadeAnimator(final View view, int position, boolean isEnter) {
|
| - ObjectAnimator alphaAnim;
|
| -
|
| - if (isEnter) {
|
| - view.setAlpha(0f);
|
| - alphaAnim = ObjectAnimator.ofFloat(view, View.ALPHA, 1f);
|
| - alphaAnim.setStartDelay(FADE_IN_BASE_DELAY + FADE_IN_DELAY_OFFSET * position);
|
| - } else {
|
| - alphaAnim = ObjectAnimator.ofFloat(view, View.ALPHA, 0f);
|
| - }
|
| -
|
| - alphaAnim.setDuration(FADE_DURATION);
|
| - return alphaAnim;
|
| - }
|
| -
|
| - /**
|
| - * Create an animator to slide in the entire dialog from the top of the screen.
|
| - */
|
| - private Animator createDialogSlideAnimator(boolean isEnter) {
|
| - final float animHeight = -1f * mContainer.getHeight();
|
| - ObjectAnimator translateAnim;
|
| - if (isEnter) {
|
| - mContainer.setTranslationY(animHeight);
|
| - translateAnim = ObjectAnimator.ofFloat(mContainer, View.TRANSLATION_Y, 0f);
|
| - translateAnim.setInterpolator(BakedBezierInterpolator.FADE_IN_CURVE);
|
| - } else {
|
| - translateAnim = ObjectAnimator.ofFloat(mContainer, View.TRANSLATION_Y, animHeight);
|
| - translateAnim.setInterpolator(BakedBezierInterpolator.FADE_OUT_CURVE);
|
| - }
|
| - translateAnim.setDuration(FADE_DURATION);
|
| - return translateAnim;
|
| - }
|
| -
|
| - /**
|
| - * Create animations for showing/hiding the popup.
|
| - *
|
| - * Tablets use the default Dialog fade-in instead of sliding in manually.
|
| - */
|
| - private Animator createAllAnimations(boolean isEnter) {
|
| - AnimatorSet animation = new AnimatorSet();
|
| - AnimatorSet.Builder builder = null;
|
| - Animator startAnim;
|
| -
|
| - if (DeviceFormFactor.isTablet(mContext)) {
|
| - // The start time of the entire AnimatorSet is the start time of the first animation
|
| - // added to the Builder. We use a blank AnimatorSet on tablet as an easy way to
|
| - // co-ordinate this start time.
|
| - startAnim = new AnimatorSet();
|
| - } else {
|
| - startAnim = createDialogSlideAnimator(isEnter);
|
| - }
|
| -
|
| - if (isEnter) startAnim.setStartDelay(ENTER_START_DELAY);
|
| - builder = animation.play(startAnim);
|
| -
|
| - List<View> animatableViews = collectAnimatableViews();
|
| - for (int i = 0; i < animatableViews.size(); i++) {
|
| - View view = animatableViews.get(i);
|
| - Animator anim = createInnerFadeAnimator(view, i, isEnter);
|
| - builder.with(anim);
|
| - }
|
| -
|
| - animation.addListener(new AnimatorListenerAdapter() {
|
| - @Override
|
| - public void onAnimationEnd(Animator animation) {
|
| - mCurrentAnimation = null;
|
| - }
|
| - });
|
| - if (mCurrentAnimation != null) mCurrentAnimation.cancel();
|
| - mCurrentAnimation = animation;
|
| - return animation;
|
| - }
|
| -
|
| - private void recordAction(int action) {
|
| - if (mNativeWebsiteSettingsPopup != 0) {
|
| - nativeRecordWebsiteSettingsAction(mNativeWebsiteSettingsPopup, action);
|
| - }
|
| - }
|
| -
|
| - /**
|
| - * Whether website dialog is displayed for an offline page.
|
| - */
|
| - private boolean isShowingOfflinePage() {
|
| - return mOfflinePageCreationDate != null;
|
| - }
|
| -
|
| - /**
|
| - * Shows a WebsiteSettings dialog for the provided Tab. The popup adds itself to the view
|
| - * hierarchy which owns the reference while it's visible.
|
| - *
|
| - * @param activity Activity which is used for launching a dialog.
|
| - * @param tab The tab hosting the web contents for which to show Website information. This
|
| - * information is retrieved for the visible entry.
|
| - * @param contentPublisher The name of the publisher of the content.
|
| - * @param source Determines the source that triggered the popup.
|
| - */
|
| - public static void show(final Activity activity, final Tab tab, final String contentPublisher,
|
| - @OpenedFromSource int source) {
|
| - if (source == OPENED_FROM_MENU) {
|
| - RecordUserAction.record("MobileWebsiteSettingsOpenedFromMenu");
|
| - } else if (source == OPENED_FROM_TOOLBAR) {
|
| - RecordUserAction.record("MobileWebsiteSettingsOpenedFromToolbar");
|
| - } else {
|
| - assert false : "Invalid source passed";
|
| - }
|
| -
|
| - String offlinePageCreationDate = null;
|
| -
|
| - OfflinePageItem offlinePage = tab.getOfflinePage();
|
| - if (offlinePage != null) {
|
| - // Get formatted creation date of the offline page.
|
| - Date creationDate = new Date(offlinePage.getCreationTimeMs());
|
| - DateFormat df = DateFormat.getDateInstance(DateFormat.MEDIUM);
|
| - offlinePageCreationDate = df.format(creationDate);
|
| - }
|
| -
|
| - new WebsiteSettingsPopup(activity, tab, offlinePageCreationDate, contentPublisher);
|
| - }
|
| -
|
| - private static native long nativeInit(WebsiteSettingsPopup popup, WebContents webContents);
|
| -
|
| - private native void nativeDestroy(long nativeWebsiteSettingsPopupAndroid);
|
| -
|
| - private native void nativeRecordWebsiteSettingsAction(
|
| - long nativeWebsiteSettingsPopupAndroid, int action);
|
| -}
|
|
|