| Index: chrome/android/java/src/org/chromium/chrome/browser/page_info/WebsiteSettingsPopup.java | 
| diff --git a/chrome/android/java/src/org/chromium/chrome/browser/page_info/WebsiteSettingsPopup.java b/chrome/android/java/src/org/chromium/chrome/browser/page_info/WebsiteSettingsPopup.java | 
| deleted file mode 100644 | 
| index e82ad2145da3084374eb1c8207a7d68083a25a65..0000000000000000000000000000000000000000 | 
| --- a/chrome/android/java/src/org/chromium/chrome/browser/page_info/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.page_info; | 
| - | 
| -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); | 
| -} | 
|  |