Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(52)

Side by Side Diff: chrome/android/java_staging/src/org/chromium/chrome/browser/dom_distiller/ReaderModeManager.java

Issue 1141283003: Upstream oodles of Chrome for Android code into Chromium. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: final patch? Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2015 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.chrome.browser.dom_distiller;
6
7 import android.app.Activity;
8 import android.content.Context;
9 import android.text.TextUtils;
10
11 import com.google.android.apps.chrome.R;
12
13 import org.chromium.base.CommandLine;
14 import org.chromium.base.ObserverList;
15 import org.chromium.base.metrics.RecordHistogram;
16 import org.chromium.chrome.browser.ApplicationSwitches;
17 import org.chromium.chrome.browser.ChromeSwitches;
18 import org.chromium.chrome.browser.ChromeVersionInfo;
19 import org.chromium.chrome.browser.CompositorChromeActivity;
20 import org.chromium.chrome.browser.EmptyTabObserver;
21 import org.chromium.chrome.browser.Tab;
22 import org.chromium.chrome.browser.contextualsearch.ContextualSearchManager;
23 import org.chromium.chrome.browser.contextualsearch.ContextualSearchObserver;
24 import org.chromium.chrome.browser.dom_distiller.ReaderModePanel.ReaderModePanel Host;
25 import org.chromium.chrome.browser.gsa.GSAContextDisplaySelection;
26 import org.chromium.chrome.browser.tab.ChromeTab;
27 import org.chromium.components.dom_distiller.content.DistillablePageUtils;
28 import org.chromium.components.dom_distiller.core.DomDistillerUrlUtils;
29 import org.chromium.content_public.browser.WebContents;
30 import org.chromium.content_public.browser.WebContentsObserver;
31 import org.chromium.ui.base.DeviceFormFactor;
32
33 /**
34 * Manages UI effects for reader mode including hiding and showing the
35 * reader mode and reader mode preferences toolbar icon and hiding the
36 * top controls when a reader mode page has finished loading.
37 */
38 public class ReaderModeManager extends EmptyTabObserver
39 implements ContextualSearchObserver, ReaderModePanelHost {
40
41 /**
42 * Observer for changes to the current status of reader mode.
43 */
44 public static interface ReaderModeManagerObserver {
45 /**
46 * Triggered on changes to the reader mode status for the owning tab.
47 *
48 * @param readerModeStatus The current status of reader mode.
49 * @see ReaderModeManager#POSSIBLE
50 * @see ReaderModeManager#NOT_POSSIBLE
51 * @see ReaderModeManager#STARTED
52 */
53 void onReaderModeStatusChanged(int readerModeStatus);
54 }
55
56 /**
57 * POSSIBLE means reader mode can be entered.
58 */
59 public static final int POSSIBLE = 0;
60 /**
61 * NOT_POSSIBLE means reader mode cannot be entered.
62 */
63 public static final int NOT_POSSIBLE = 1;
64 /**
65 * STARTED means reader mode is currently in reader mode.
66 */
67 public static final int STARTED = 2;
68
69 /**
70 * JavaScript that can be executed to tell whether or not a page can be view ed in reader mode.
71 */
72 private static final String sIsReadableJs = DomDistillerUrlUtils.getIsDistil lableJs();
73
74 /**
75 * The url of the last page visited if the last page was reader mode page. Otherwise null.
76 */
77 private String mReaderModePageUrl;
78
79 /**
80 * Whether the page is an article or not.
81 */
82 private int mReaderModeStatus = NOT_POSSIBLE;
83
84 /**
85 * Whether the fact that the current web page was distillable or not has bee n recorded.
86 */
87 private boolean mIsUmaRecorded;
88
89 private WebContentsObserver mWebContentsObserver;
90
91 private final Tab mTab;
92
93 private final ReaderModePanel mReaderModePanel;
94
95 private final ObserverList<ReaderModeManagerObserver> mObservers;
96
97 private final int mHeaderBackgroundColor;
98
99 public ReaderModeManager(Tab tab, Context context) {
100 mTab = tab;
101 mTab.addObserver(this);
102 mObservers = new ObserverList<ReaderModeManagerObserver>();
103 mReaderModePanel = isEnabled(context) ? new ReaderModePanel(this) : null ;
104 mHeaderBackgroundColor = context != null
105 ? context.getResources().getColor(R.color.reader_mode_header_bg) : 0;
106 }
107
108 /**
109 * Adds an observer to be notified about changes to the reader mode status.
110 */
111 public void addObserver(ReaderModeManagerObserver observer) {
112 mObservers.addObserver(observer);
113 }
114
115 /**
116 * Removes an observer from receiving updates about the reader mode status c hanges.
117 */
118 public void removeObserver(ReaderModeManagerObserver observer) {
119 mObservers.removeObserver(observer);
120 }
121
122 // EmptyTabObserver:
123 @Override
124 public void onDestroyed(Tab tab) {
125 ContextualSearchManager contextualSearchManager = getContextualSearchMan ager(tab);
126 if (contextualSearchManager != null) contextualSearchManager.removeObser ver(this);
127
128 if (mReaderModePanel != null) mReaderModePanel.onDestroy();
129
130 if (mWebContentsObserver != null) {
131 mWebContentsObserver.destroy();
132 mWebContentsObserver = null;
133 }
134 }
135
136 @Override
137 public void onContentChanged(Tab tab) {
138 if (mWebContentsObserver != null) {
139 mWebContentsObserver.destroy();
140 mWebContentsObserver = null;
141 }
142 if (tab.getWebContents() != null) {
143 mWebContentsObserver = createWebContentsObserver(tab.getWebContents( ));
144 if (DomDistillerUrlUtils.isDistilledPage(tab.getUrl())) {
145 mReaderModeStatus = STARTED;
146 mReaderModePageUrl = tab.getUrl();
147 sendReaderModeStatusChangedNotification();
148 }
149 }
150 ContextualSearchManager contextualSearchManager = getContextualSearchMan ager(tab);
151 if (contextualSearchManager != null) contextualSearchManager.addObserver (this);
152 }
153
154 // ContextualSearchObserver:
155 @Override
156 public void onShowContextualSearch(GSAContextDisplaySelection selectionConte xt) {
157 if (mReaderModePanel != null) mReaderModePanel.hideButtonBar();
158 }
159
160 @Override
161 public void onHideContextualSearch() {
162 if (mReaderModePanel != null) mReaderModePanel.unhideButtonBar();
163 }
164
165 // ReaderModePanelHost:
166
167 // TODO(aruslan): use the one in ChromeSwitches once it's rolled.
168 private static final String ENABLE_READER_MODE_BUTTON_ANIMATION =
169 "enable-dom-distiller-button-animation";
170
171 @Override
172 public boolean allowReaderModeButtonAnimation() {
173 return CommandLine.getInstance().hasSwitch(
174 ENABLE_READER_MODE_BUTTON_ANIMATION);
175 }
176
177 @Override
178 public int getReaderModeHeaderBackgroundColor() {
179 return mHeaderBackgroundColor;
180 }
181
182 @Override
183 public int getReaderModeStatus() {
184 return mReaderModeStatus;
185 }
186
187 @Override
188 public Tab getTab() {
189 return mTab;
190 }
191
192 @Override
193 public boolean isInsideDismissButton(float x, float y) {
194 if (!(mTab instanceof ChromeTab)) return false;
195 ReaderModeActivityDelegate delegate = ((ChromeTab) mTab).getReaderModeAc tivityDelegate();
196 if (delegate == null) return false;
197 return delegate.getReaderModeControl().isInsideDismissButton(x, y);
198 }
199
200 /**
201 * @return The panel associated with the managed tab.
202 */
203 public ReaderModePanel getReaderModePanel() {
204 return mReaderModePanel;
205 }
206
207 private WebContentsObserver createWebContentsObserver(WebContents webContent s) {
208 return new WebContentsObserver(webContents) {
209 @Override
210 public void didFinishLoad(long frameId, String validatedUrl, boolean isMainFrame) {
211 if (!isMainFrame) return;
212 if (DomDistillerUrlUtils.isDistilledPage(mTab.getUrl())) return;
213 updateStatusBasedOnReaderModeCriteria(true);
214 }
215
216 @Override
217 public void didStartProvisionalLoadForFrame(long frameId, long paren tFrameId,
218 boolean isMainFrame, String validatedUrl, boolean isErrorPag e,
219 boolean isIframeSrcdoc) {
220 if (!isMainFrame) return;
221 if (DomDistillerUrlUtils.isDistilledPage(validatedUrl)) {
222 mReaderModeStatus = STARTED;
223 sendReaderModeStatusChangedNotification();
224 mReaderModePageUrl = validatedUrl;
225 }
226 }
227
228 @Override
229 public void didNavigateMainFrame(String url, String baseUrl,
230 boolean isNavigationToDifferentPage, boolean isNavigationInP age,
231 int statusCode) {
232 // TODO(cjhopman): This should possibly ignore navigations that replace the entry
233 // (like those from history.replaceState()).
234 if (isNavigationInPage) return;
235 if (DomDistillerUrlUtils.isDistilledPage(url)) return;
236
237 mReaderModeStatus = POSSIBLE;
238 if (!TextUtils.equals(url,
239 DomDistillerUrlUtils.getOriginalUrlFromDistillerUrl(
240 mReaderModePageUrl))) {
241 mReaderModeStatus = NOT_POSSIBLE;
242 mIsUmaRecorded = false;
243 updateStatusBasedOnReaderModeCriteria(false);
244 }
245 mReaderModePageUrl = null;
246 sendReaderModeStatusChangedNotification();
247 }
248 };
249 }
250
251 // Updates reader mode status based on whether or not the page should be vie wed in reader mode.
252 private void updateStatusBasedOnReaderModeCriteria(final boolean forceRecord ) {
253 if (mTab.getWebContents() == null) return;
254 if (mTab.getContentViewCore() == null) return;
255
256 DistillablePageUtils.isPageDistillable(mTab.getWebContents(),
257 mTab.getContentViewCore().getIsMobileOptimizedHint(),
258 new DistillablePageUtils.PageDistillableCallback() {
259 @Override
260 public void onIsPageDistillableResult(boolean isDistillable) {
261 if (isDistillable) {
262 mReaderModeStatus = POSSIBLE;
263 } else {
264 mReaderModeStatus = NOT_POSSIBLE;
265 }
266 if (!mIsUmaRecorded && (mReaderModeStatus == POSSIBLE || forceRecord)) {
267 mIsUmaRecorded = true;
268 RecordHistogram.recordBooleanHistogram(
269 "DomDistiller.PageDistillable", mReaderModeS tatus == POSSIBLE);
270 }
271 sendReaderModeStatusChangedNotification();
272 }
273 });
274 }
275
276 private void sendReaderModeStatusChangedNotification() {
277 for (ReaderModeManagerObserver observer : mObservers) {
278 observer.onReaderModeStatusChanged(mReaderModeStatus);
279 }
280 if (mReaderModePanel != null) mReaderModePanel.updateBottomButtonBar();
281 }
282
283 private ContextualSearchManager getContextualSearchManager(Tab tab) {
284 if (tab == null || tab.getWindowAndroid() == null) return null;
285 Activity activity = tab.getWindowAndroid().getActivity().get();
286 if (!(activity instanceof CompositorChromeActivity)) return null;
287 return ((CompositorChromeActivity) activity).getContextualSearchManager( );
288 }
289
290 /**
291 * @return Whether Reader mode and its new UI are enabled.
292 * @param context A context
293 */
294 public static boolean isEnabled(Context context) {
295 if (context == null) return false;
296
297 boolean enabled = CommandLine.getInstance().hasSwitch(ChromeSwitches.ENA BLE_DOM_DISTILLER)
298 && !CommandLine.getInstance().hasSwitch(
299 ApplicationSwitches.DISABLE_READER_MODE_BOTTOM_BAR)
300 && !DeviceFormFactor.isTablet(context);
301 if (ChromeVersionInfo.isBetaBuild() || ChromeVersionInfo.isStableBuild() ) {
302 enabled = enabled
303 && CommandLine.getInstance().hasSwitch(
304 ApplicationSwitches.ENABLE_READER_MODE_BUTTON);
305 }
306 return enabled;
307 }
308 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698