Commit 2fe83d2d authored by Ehimare Okoyomon's avatar Ehimare Okoyomon Committed by Commit Bot

[Android] Add a base controller and subpage template for page info v2

Create PageInfoSubpageController and PageInfoSubpage for control
of a specific section of the page info v2. Componentized the cookies
section as an example.
https://screenshot.googleplex.com/XnhMwuBkVzG.png

Bug: 1077766
Change-Id: I7bf71c62859bcae7b2f24bd9509947c003a51c06
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2209070
Commit-Queue: Ehimare Okoyomon <eokoyomon@chromium.org>
Reviewed-by: default avatarBalazs Engedy <engedy@chromium.org>
Reviewed-by: default avatarChristian Dullweber <dullweber@chromium.org>
Cr-Commit-Position: refs/heads/master@{#772697}
parent 69b0dc7d
...@@ -54,6 +54,7 @@ android_resources("java_resources") { ...@@ -54,6 +54,7 @@ android_resources("java_resources") {
"java/res/layout/page_info.xml", "java/res/layout/page_info.xml",
"java/res/layout/page_info_permission_row.xml", "java/res/layout/page_info_permission_row.xml",
"java/res/layout/page_info_row.xml", "java/res/layout/page_info_row.xml",
"java/res/layout/page_info_subpage.xml",
"java/res/layout/page_info_v2.xml", "java/res/layout/page_info_v2.xml",
"java/res/values/colors.xml", "java/res/values/colors.xml",
"java/res/values/dimens.xml", "java/res/values/dimens.xml",
...@@ -77,9 +78,12 @@ android_library("java") { ...@@ -77,9 +78,12 @@ android_library("java") {
"java/src/org/chromium/components/page_info/CookieControlsView.java", "java/src/org/chromium/components/page_info/CookieControlsView.java",
"java/src/org/chromium/components/page_info/PageInfoController.java", "java/src/org/chromium/components/page_info/PageInfoController.java",
"java/src/org/chromium/components/page_info/PageInfoControllerDelegate.java", "java/src/org/chromium/components/page_info/PageInfoControllerDelegate.java",
"java/src/org/chromium/components/page_info/PageInfoCookiesController.java",
"java/src/org/chromium/components/page_info/PageInfoDialog.java", "java/src/org/chromium/components/page_info/PageInfoDialog.java",
"java/src/org/chromium/components/page_info/PageInfoFeatureList.java", "java/src/org/chromium/components/page_info/PageInfoFeatureList.java",
"java/src/org/chromium/components/page_info/PageInfoRowView.java", "java/src/org/chromium/components/page_info/PageInfoRowView.java",
"java/src/org/chromium/components/page_info/PageInfoSubpage.java",
"java/src/org/chromium/components/page_info/PageInfoSubpageController.java",
"java/src/org/chromium/components/page_info/PageInfoView.java", "java/src/org/chromium/components/page_info/PageInfoView.java",
"java/src/org/chromium/components/page_info/PageInfoViewV2.java", "java/src/org/chromium/components/page_info/PageInfoViewV2.java",
"java/src/org/chromium/components/page_info/PermissionParamsListBuilder.java", "java/src/org/chromium/components/page_info/PermissionParamsListBuilder.java",
......
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2020 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.
-->
<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_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="8dp"
android:orientation="vertical"
android:background="@color/sheet_bg_color">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="12dp"
android:paddingEnd="@dimen/page_info_popup_padding_sides"
android:paddingStart="@dimen/page_info_popup_padding_sides" >
<view class="org.chromium.components.page_info.PageInfoView$ElidedUrlTextView"
android:id="@+id/subpage_url"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="end"
android:lineSpacingExtra="6dp"
android:paddingTop="16dp"
android:paddingBottom="16dp"
android:textAlignment="center"
android:textAppearance="@style/TextAppearance.TextLarge.Primary" />
<ImageView
android:id="@+id/subpage_back_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/subpage_url"
tools:ignore="ContentDescription"
android:layout_marginEnd="16dp"
android:layout_centerVertical="true"
android:layout_alignParentStart="true"
android:src="@drawable/ic_arrow_back_white_24dp"
app:tint="@color/default_icon_color" />
<TextView
android:id="@+id/subpage_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/subpage_url"
android:layout_toEndOf="@id/subpage_back_button"
android:gravity="center_vertical"
android:paddingBottom="12dp"
app:chromeDrawableTint="@color/default_icon_color"
android:textAppearance="@style/TextAppearance.TextLarge.Primary"/>
</RelativeLayout>
<!-- Programmatically add page specific inner view here -->
<FrameLayout
android:id="@+id/placeholder"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
...@@ -17,7 +17,10 @@ import android.text.SpannableStringBuilder; ...@@ -17,7 +17,10 @@ import android.text.SpannableStringBuilder;
import android.text.TextUtils; import android.text.TextUtils;
import android.text.style.ForegroundColorSpan; import android.text.style.ForegroundColorSpan;
import android.text.style.TextAppearanceSpan; import android.text.style.TextAppearanceSpan;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window; import android.view.Window;
import android.widget.FrameLayout;
import androidx.annotation.IntDef; import androidx.annotation.IntDef;
import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
...@@ -90,6 +93,12 @@ public class PageInfoController implements ModalDialogProperties.Controller, ...@@ -90,6 +93,12 @@ public class PageInfoController implements ModalDialogProperties.Controller,
// URL'. // URL'.
private String mFullUrl; private String mFullUrl;
// The URL to be shown at the top of the page info views.
private SpannableStringBuilder mDisplayUrlBuilder;
// The length of the URL's origin in number of characters.
private int mUrlOriginLength;
// Whether or not this page is an internal chrome page (e.g. the // Whether or not this page is an internal chrome page (e.g. the
// chrome://settings page). // chrome://settings page).
private boolean mIsInternalPage; private boolean mIsInternalPage;
...@@ -120,6 +129,15 @@ public class PageInfoController implements ModalDialogProperties.Controller, ...@@ -120,6 +129,15 @@ public class PageInfoController implements ModalDialogProperties.Controller,
// Delegate used by PermissionParamsListBuilder. // Delegate used by PermissionParamsListBuilder.
private final PermissionParamsListBuilderDelegate mPermissionParamsListBuilderDelegate; private final PermissionParamsListBuilderDelegate mPermissionParamsListBuilderDelegate;
// The specific subpage being shown at any time, if any.
private PageInfoSubpage mSubpage;
// The current page info subpage controller, if any.
private PageInfoSubpageController mSubpageController;
// The controller for the cookies functionality of the page info.
private PageInfoCookiesController mCookiesController;
/** /**
* Creates the PageInfoController, but does not display it. Also initializes the corresponding * Creates the PageInfoController, but does not display it. Also initializes the corresponding
* C++ object and saves a pointer to it. * C++ object and saves a pointer to it.
...@@ -179,27 +197,28 @@ public class PageInfoController implements ModalDialogProperties.Controller, ...@@ -179,27 +197,28 @@ public class PageInfoController implements ModalDialogProperties.Controller,
if (mDelegate.isShowingOfflinePage()) { if (mDelegate.isShowingOfflinePage()) {
displayUrl = UrlUtilities.stripScheme(mFullUrl); displayUrl = UrlUtilities.stripScheme(mFullUrl);
} }
SpannableStringBuilder displayUrlBuilder = new SpannableStringBuilder(displayUrl); mDisplayUrlBuilder = new SpannableStringBuilder(displayUrl);
AutocompleteSchemeClassifier autocompleteSchemeClassifier = AutocompleteSchemeClassifier autocompleteSchemeClassifier =
delegate.createAutocompleteSchemeClassifier(); delegate.createAutocompleteSchemeClassifier();
if (mSecurityLevel == ConnectionSecurityLevel.SECURE) { if (mSecurityLevel == ConnectionSecurityLevel.SECURE) {
OmniboxUrlEmphasizer.EmphasizeComponentsResponse emphasizeResponse = OmniboxUrlEmphasizer.EmphasizeComponentsResponse emphasizeResponse =
OmniboxUrlEmphasizer.parseForEmphasizeComponents( OmniboxUrlEmphasizer.parseForEmphasizeComponents(
displayUrlBuilder.toString(), autocompleteSchemeClassifier); mDisplayUrlBuilder.toString(), autocompleteSchemeClassifier);
if (emphasizeResponse.schemeLength > 0) { if (emphasizeResponse.schemeLength > 0) {
displayUrlBuilder.setSpan( mDisplayUrlBuilder.setSpan(
new TextAppearanceSpan(mContext, R.style.TextAppearance_RobotoMediumStyle), new TextAppearanceSpan(mContext, R.style.TextAppearance_RobotoMediumStyle),
0, emphasizeResponse.schemeLength, Spannable.SPAN_EXCLUSIVE_INCLUSIVE); 0, emphasizeResponse.schemeLength, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
} }
} }
boolean useDarkText = ColorUtils.useDarkColors(mContext); boolean useDarkText = ColorUtils.useDarkColors(mContext);
OmniboxUrlEmphasizer.emphasizeUrl(displayUrlBuilder, mContext.getResources(), OmniboxUrlEmphasizer.emphasizeUrl(mDisplayUrlBuilder, mContext.getResources(),
autocompleteSchemeClassifier, mSecurityLevel, mIsInternalPage, useDarkText, autocompleteSchemeClassifier, mSecurityLevel, mIsInternalPage, useDarkText,
/*emphasizeScheme=*/true); /*emphasizeScheme=*/true);
viewParams.url = displayUrlBuilder; viewParams.url = mDisplayUrlBuilder;
viewParams.urlOriginLength = OmniboxUrlEmphasizer.getOriginEndIndex( mUrlOriginLength = OmniboxUrlEmphasizer.getOriginEndIndex(
displayUrlBuilder.toString(), autocompleteSchemeClassifier); mDisplayUrlBuilder.toString(), autocompleteSchemeClassifier);
viewParams.urlOriginLength = mUrlOriginLength;
autocompleteSchemeClassifier.destroy(); autocompleteSchemeClassifier.destroy();
if (mDelegate.isSiteSettingsAvailable()) { if (mDelegate.isSiteSettingsAvailable()) {
...@@ -247,11 +266,8 @@ public class PageInfoController implements ModalDialogProperties.Controller, ...@@ -247,11 +266,8 @@ public class PageInfoController implements ModalDialogProperties.Controller,
mNativePageInfoController = PageInfoControllerJni.get().init(this, mWebContents); mNativePageInfoController = PageInfoControllerJni.get().init(this, mWebContents);
if (mIsV2Enabled) { if (mIsV2Enabled) {
PageInfoRowView.ViewParams cookieControlsParams = new PageInfoRowView.ViewParams(); mCookiesController =
cookieControlsParams.visible = viewParams.cookieControlsShown; new PageInfoCookiesController(this, (PageInfoViewV2) mView, viewParams);
cookieControlsParams.title =
mView.getContext().getResources().getString(R.string.cookies_title);
((PageInfoViewV2) mView).getCookiesRowView().setParams(cookieControlsParams);
} else { } else {
CookieControlsView.CookieControlsParams cookieControlsParams = CookieControlsView.CookieControlsParams cookieControlsParams =
new CookieControlsView.CookieControlsParams(); new CookieControlsView.CookieControlsParams();
...@@ -526,9 +542,7 @@ public class PageInfoController implements ModalDialogProperties.Controller, ...@@ -526,9 +542,7 @@ public class PageInfoController implements ModalDialogProperties.Controller,
@Override @Override
public void onBlockedCookiesCountChanged(int blockedCookies) { public void onBlockedCookiesCountChanged(int blockedCookies) {
if (mIsV2Enabled) { if (mIsV2Enabled) {
String subtitle = mContext.getResources().getQuantityString( mCookiesController.onBlockedCookiesCountChanged(blockedCookies);
R.plurals.cookie_controls_blocked_cookies, blockedCookies, blockedCookies);
((PageInfoViewV2) mView).getCookiesRowView().updateSubtitle(subtitle);
} else { } else {
mView.getCookieControlsView().setBlockedCookiesCount(blockedCookies); mView.getCookieControlsView().setBlockedCookiesCount(blockedCookies);
} }
...@@ -541,4 +555,54 @@ public class PageInfoController implements ModalDialogProperties.Controller, ...@@ -541,4 +555,54 @@ public class PageInfoController implements ModalDialogProperties.Controller,
void recordPageInfoAction( void recordPageInfoAction(
long nativePageInfoControllerAndroid, PageInfoController caller, int action); long nativePageInfoControllerAndroid, PageInfoController caller, int action);
} }
/**
* Launches a subpage with the specified params.
*/
void launchSubpage(PageInfoSubpageController controller) {
mSubpageController = controller;
PageInfoSubpage.Params subpageParams = new PageInfoSubpage.Params();
subpageParams.url = mDisplayUrlBuilder;
subpageParams.urlOriginLength = mUrlOriginLength;
subpageParams.subpageTitle = mSubpageController.getSubpageTitle();
mSubpage = new PageInfoSubpage(mContext, subpageParams);
mSubpage.setBackButtonOnClickListener(view -> exitSubpage());
View subview = mSubpageController.createViewForSubpage(mSubpage);
if (subview != null) {
((FrameLayout) mSubpage.findViewById(R.id.placeholder)).addView(subview);
}
replaceView(mView, mSubpage);
}
private ViewGroup getParent(View view) {
return (ViewGroup) view.getParent();
}
private void removeView(View view) {
ViewGroup parent = getParent(view);
if (parent != null) {
parent.removeView(view);
}
}
private void replaceView(View currentView, View newView) {
ViewGroup parent = getParent(currentView);
if (parent == null) {
return;
}
final int index = parent.indexOfChild(currentView);
removeView(currentView);
removeView(newView);
parent.addView(newView, index);
}
/**
* Switches back to the main page info view.
*/
private void exitSubpage() {
mSubpageController.willRemoveSubpage();
replaceView(mSubpage, mView);
mSubpage = null;
mSubpageController = null;
}
} }
// Copyright 2020 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.components.page_info;
import android.view.View;
import android.view.ViewGroup;
/**
* Class for controlling the page info cookies section.
*/
public class PageInfoCookiesController implements PageInfoSubpageController {
private PageInfoController mMainController;
private PageInfoViewV2 mView;
private String mTitle;
public PageInfoCookiesController(PageInfoController mainController, PageInfoViewV2 view,
PageInfoView.PageInfoViewParams setupParams) {
mMainController = mainController;
mView = view;
mTitle = mView.getContext().getResources().getString(R.string.cookies_title);
PageInfoRowView.ViewParams rowParams = new PageInfoRowView.ViewParams();
rowParams.visible = setupParams.cookieControlsShown;
rowParams.title = mTitle;
rowParams.clickCallback = this::launchSubpage;
mView.getCookiesRowView().setParams(rowParams);
}
private void launchSubpage() {
mMainController.launchSubpage(this);
}
@Override
public String getSubpageTitle() {
return mTitle;
}
@Override
public View createViewForSubpage(ViewGroup parent) {
// TODO(crbug.com/1077766): Create and set the cookie specific view.
return null;
}
@Override
public void willRemoveSubpage() {}
public void onBlockedCookiesCountChanged(int blockedCookies) {
String subtitle = mView.getContext().getResources().getQuantityString(
R.plurals.cookie_controls_blocked_cookies, blockedCookies, blockedCookies);
mView.getCookiesRowView().updateSubtitle(subtitle);
}
}
...@@ -49,6 +49,7 @@ public class PageInfoRowView extends RelativeLayout implements OnClickListener { ...@@ -49,6 +49,7 @@ public class PageInfoRowView extends RelativeLayout implements OnClickListener {
mTitle.setText(params.title); mTitle.setText(params.title);
updateSubtitle(params.subtitle); updateSubtitle(params.subtitle);
mClickCallback = params.clickCallback; mClickCallback = params.clickCallback;
setOnClickListener(this);
} }
public void updateSubtitle(String subtitle) { public void updateSubtitle(String subtitle) {
......
// Copyright 2020 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.components.page_info;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;
/**
* Represents a particular page info subpage.
*/
public class PageInfoSubpage extends FrameLayout {
/** Parameters to configure the view of page info subpage. */
public static class Params {
// The URL to be shown at the top of the page.
public CharSequence url;
// The length of the URL's origin in number of characters.
public int urlOriginLength;
// The name of the subpage to be displayed.
public String subpageTitle;
}
private PageInfoView.ElidedUrlTextView mUrlTitle;
private ImageView mBackButton;
private TextView mSubpageTitle;
public PageInfoSubpage(Context context, Params params) {
super(context);
LayoutInflater.from(context).inflate(R.layout.page_info_subpage, this, true);
// Set the url title.
mUrlTitle = findViewById(R.id.subpage_url);
mUrlTitle.setUrl(params.url, params.urlOriginLength);
// Set the back button.
mBackButton = findViewById(R.id.subpage_back_button);
// Set the page title.
mSubpageTitle = findViewById(R.id.subpage_title);
mSubpageTitle.setText(params.subpageTitle);
}
public void setBackButtonOnClickListener(View.OnClickListener listener) {
mBackButton.setOnClickListener(listener);
}
}
// Copyright 2020 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.components.page_info;
import android.view.View;
import android.view.ViewGroup;
/**
* Interface for a page info subpage controller.
*/
public interface PageInfoSubpageController {
/**
* Returns a title string for the page info subpage.
*/
String getSubpageTitle();
/**
* Returns a personalized subview to be used inside of the page info subpage.
*/
View createViewForSubpage(ViewGroup parent);
/**
* Called before the subpage closes in order to perform any necessary cleanup.
*/
void willRemoveSubpage();
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment