1 // Copyright 2020 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 package org.chromium.components.page_info;
6 
7 import android.content.Context;
8 import android.graphics.drawable.Drawable;
9 import android.view.LayoutInflater;
10 import android.view.View;
11 import android.view.ViewGroup;
12 import android.view.animation.AccelerateInterpolator;
13 import android.view.animation.DecelerateInterpolator;
14 import android.widget.FrameLayout;
15 import android.widget.TextView;
16 
17 import org.chromium.ui.widget.ChromeImageButton;
18 
19 /**
20  * Represents the url, a sub page header and container for page info content.
21  */
22 public class PageInfoContainer extends FrameLayout {
23     public static final float sScale = 0.92f;
24     public static final int sOutDuration = 90;
25     public static final int sInDuration = 210;
26 
27     /**  Parameters to configure the view of page info subpage. */
28     public static class Params {
29         // Whether the URL title should be shown.
30         public boolean urlTitleShown;
31         // The URL to be shown at the top of the page.
32         public CharSequence url;
33         // The length of the URL's origin in number of characters.
34         public int urlOriginLength;
35         // The URL to show in truncated state.
36         public String truncatedUrl;
37         // If the page has preview UI shown.
38         public boolean previewUIShown;
39         // The icon used for preview UI.
40         public Drawable previewUIIcon;
41 
42         public Runnable urlTitleClickCallback;
43         public Runnable urlTitleLongClickCallback;
44         public Runnable backButtonClickCallback;
45     }
46     private PageInfoView.ElidedUrlTextView mExpandedUrlTitle;
47     private TextView mTruncatedUrlTitle;
48     private TextView mPreviewMessage;
49 
50     private final ViewGroup mWrapper;
51     private final ViewGroup mContent;
52     private View mCurrentView;
53 
54     private final View mSubpageHeader;
55     private final TextView mSubpageTitle;
56 
PageInfoContainer(Context context)57     public PageInfoContainer(Context context) {
58         super(context);
59         LayoutInflater.from(context).inflate(R.layout.page_info_container, this, true);
60         mWrapper = findViewById(R.id.page_info_wrapper);
61         mContent = findViewById(R.id.page_info_content);
62         mSubpageHeader = findViewById(R.id.page_info_subpage_header);
63         mSubpageTitle = findViewById(R.id.page_info_subpage_title);
64     }
65 
setParams(Params params)66     public void setParams(Params params) {
67         mExpandedUrlTitle = findViewById(R.id.page_info_url);
68         initializeUrlView(mExpandedUrlTitle, params);
69         mExpandedUrlTitle.setUrl(params.url, params.urlOriginLength);
70         // Adjust the mUrlTitle for displaying the non-truncated URL.
71         mExpandedUrlTitle.toggleTruncation();
72 
73         mTruncatedUrlTitle = findViewById(R.id.page_info_truncated_url);
74         // Use a separate view for truncated URL display.
75         initializeUrlView(mTruncatedUrlTitle, params);
76         mTruncatedUrlTitle = findViewById(R.id.page_info_truncated_url);
77         mTruncatedUrlTitle.setText(params.truncatedUrl);
78 
79         View urlWrapper = findViewById(R.id.page_info_url_wrapper);
80         urlWrapper.setVisibility(params.urlTitleShown ? VISIBLE : GONE);
81 
82         mPreviewMessage = findViewById(R.id.page_info_preview_message);
83         mPreviewMessage.setText(R.string.page_info_preview_message);
84         mPreviewMessage.setCompoundDrawablesRelative(params.previewUIIcon, null, null, null);
85 
86         View previewWrapper = findViewById(R.id.page_info_preview_message_wrapper);
87         previewWrapper.setVisibility(params.previewUIShown ? VISIBLE : GONE);
88 
89         ChromeImageButton backButton = findViewById(R.id.subpage_back_button);
90         backButton.setOnClickListener(v -> params.backButtonClickCallback.run());
91     }
92 
initializeUrlView(View view, Params params)93     private void initializeUrlView(View view, Params params) {
94         if (params.urlTitleClickCallback != null) {
95             view.setOnClickListener(v -> { params.urlTitleClickCallback.run(); });
96         }
97         if (params.urlTitleLongClickCallback != null) {
98             view.setOnLongClickListener(v -> {
99                 params.urlTitleLongClickCallback.run();
100                 return true;
101             });
102         }
103     }
104 
toggleUrlTruncation()105     public void toggleUrlTruncation() {
106         boolean showExpanded = mExpandedUrlTitle.getVisibility() != VISIBLE;
107         mExpandedUrlTitle.setVisibility(showExpanded ? VISIBLE : GONE);
108         mTruncatedUrlTitle.setVisibility(showExpanded ? GONE : VISIBLE);
109         announceForAccessibility(getResources().getString(
110                 showExpanded ? R.string.page_info_url_expanded : R.string.page_info_url_truncated));
111     }
112 
setFavicon(Drawable favicon)113     public void setFavicon(Drawable favicon) {
114         mTruncatedUrlTitle.setCompoundDrawablesRelative(favicon, null, null, null);
115     }
116 
showPage(View view, CharSequence subPageTitle, Runnable onPreviousPageRemoved)117     public void showPage(View view, CharSequence subPageTitle, Runnable onPreviousPageRemoved) {
118         if (mCurrentView == null) {
119             // Don't animate if there is no current view.
120             assert onPreviousPageRemoved == null;
121             replaceContentView(view, subPageTitle);
122             return;
123         }
124         // Create "fade-through" animation.
125         // TODO(crbug.com/1077766): Animate height change and set correct interpolator.
126         mWrapper.animate()
127                 .setDuration(sOutDuration)
128                 .alpha(0)
129                 .setInterpolator(new AccelerateInterpolator())
130                 .withEndAction(() -> {
131                     replaceContentView(view, subPageTitle);
132                     mWrapper.setScaleX(sScale);
133                     mWrapper.setScaleY(sScale);
134                     mWrapper.setAlpha(0);
135                     mWrapper.animate()
136                             .setDuration(sInDuration)
137                             .scaleX(1)
138                             .scaleY(1)
139                             .alpha(1)
140                             .setInterpolator(new DecelerateInterpolator())
141                             .withEndAction(onPreviousPageRemoved);
142                 });
143     }
144 
145     /**
146      * Replaces the current view with |view| and configures the subpage header.
147      */
replaceContentView(View view, CharSequence subPageTitle)148     private void replaceContentView(View view, CharSequence subPageTitle) {
149         mContent.removeAllViews();
150         mCurrentView = view;
151         mSubpageHeader.setVisibility(subPageTitle != null ? VISIBLE : GONE);
152         mSubpageTitle.setText(subPageTitle);
153         mContent.addView(view);
154         announceForAccessibility(subPageTitle != null
155                         ? subPageTitle
156                         : getResources().getString(R.string.accessibility_toolbar_btn_site_info));
157     }
158 }
159