OLD | NEW |
---|---|
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 package org.chromium.chrome.browser.dom_distiller; | 5 package org.chromium.chrome.browser.dom_distiller; |
6 | 6 |
7 import android.content.Context; | 7 import android.content.Context; |
8 import android.text.TextUtils; | 8 import android.text.TextUtils; |
9 | 9 |
10 import org.chromium.base.CommandLine; | 10 import org.chromium.base.CommandLine; |
11 import org.chromium.base.SysUtils; | |
12 import org.chromium.base.VisibleForTesting; | |
13 import org.chromium.base.library_loader.LibraryLoader; | 11 import org.chromium.base.library_loader.LibraryLoader; |
14 import org.chromium.base.metrics.RecordHistogram; | 12 import org.chromium.base.metrics.RecordHistogram; |
15 import org.chromium.chrome.browser.ChromeActivity; | 13 import org.chromium.chrome.browser.ChromeActivity; |
16 import org.chromium.chrome.browser.ChromeSwitches; | 14 import org.chromium.chrome.browser.ChromeSwitches; |
17 import org.chromium.chrome.browser.compositor.bottombar.OverlayPanel.PanelState; | |
18 import org.chromium.chrome.browser.compositor.bottombar.OverlayPanel.StateChange Reason; | 15 import org.chromium.chrome.browser.compositor.bottombar.OverlayPanel.StateChange Reason; |
19 import org.chromium.chrome.browser.compositor.bottombar.readermode.ReaderModePan el; | 16 import org.chromium.chrome.browser.infobar.ReaderModeInfoBar; |
20 import org.chromium.chrome.browser.infobar.InfoBar; | |
21 import org.chromium.chrome.browser.infobar.InfoBarContainer; | |
22 import org.chromium.chrome.browser.infobar.InfoBarContainer.InfoBarContainerObse rver; | |
23 import org.chromium.chrome.browser.rappor.RapporServiceBridge; | 17 import org.chromium.chrome.browser.rappor.RapporServiceBridge; |
24 import org.chromium.chrome.browser.tab.Tab; | 18 import org.chromium.chrome.browser.tab.Tab; |
25 import org.chromium.chrome.browser.tabmodel.TabCreatorManager; | 19 import org.chromium.chrome.browser.tabmodel.TabCreatorManager; |
26 import org.chromium.chrome.browser.tabmodel.TabModel; | 20 import org.chromium.chrome.browser.tabmodel.TabModel; |
27 import org.chromium.chrome.browser.tabmodel.TabModelSelector; | 21 import org.chromium.chrome.browser.tabmodel.TabModelSelector; |
28 import org.chromium.chrome.browser.tabmodel.TabModelSelectorTabObserver; | 22 import org.chromium.chrome.browser.tabmodel.TabModelSelectorTabObserver; |
29 import org.chromium.chrome.browser.util.AccessibilityUtil; | 23 import org.chromium.chrome.browser.util.AccessibilityUtil; |
30 import org.chromium.chrome.browser.widget.findinpage.FindToolbarObserver; | |
31 import org.chromium.components.dom_distiller.content.DistillablePageUtils; | 24 import org.chromium.components.dom_distiller.content.DistillablePageUtils; |
32 import org.chromium.components.dom_distiller.core.DomDistillerUrlUtils; | 25 import org.chromium.components.dom_distiller.core.DomDistillerUrlUtils; |
33 import org.chromium.content_public.browser.LoadUrlParams; | 26 import org.chromium.content_public.browser.LoadUrlParams; |
27 import org.chromium.content_public.browser.NavigationController; | |
28 import org.chromium.content_public.browser.NavigationEntry; | |
34 import org.chromium.content_public.browser.WebContents; | 29 import org.chromium.content_public.browser.WebContents; |
35 import org.chromium.content_public.browser.WebContentsObserver; | 30 import org.chromium.content_public.browser.WebContentsObserver; |
36 import org.chromium.ui.UiUtils; | 31 import org.chromium.ui.UiUtils; |
37 import org.chromium.ui.base.DeviceFormFactor; | |
38 import org.chromium.ui.base.PageTransition; | 32 import org.chromium.ui.base.PageTransition; |
39 | 33 |
40 import java.util.HashMap; | 34 import java.util.HashMap; |
41 import java.util.Map; | 35 import java.util.Map; |
42 import java.util.concurrent.TimeUnit; | 36 import java.util.concurrent.TimeUnit; |
43 | 37 |
44 /** | 38 /** |
45 * Manages UI effects for reader mode including hiding and showing the | 39 * Manages UI effects for reader mode including hiding and showing the |
46 * reader mode and reader mode preferences toolbar icon and hiding the | 40 * reader mode and reader mode preferences toolbar icon and hiding the |
47 * browser controls when a reader mode page has finished loading. | 41 * browser controls when a reader mode page has finished loading. |
48 */ | 42 */ |
49 public class ReaderModeManager extends TabModelSelectorTabObserver | 43 public class ReaderModeManager |
50 implements InfoBarContainerObserver, ReaderModeManagerDelegate { | 44 extends TabModelSelectorTabObserver implements ReaderModeManagerDelegate { |
51 | 45 /** POSSIBLE means reader mode can be entered. */ |
52 /** | |
53 * POSSIBLE means reader mode can be entered. | |
54 */ | |
55 public static final int POSSIBLE = 0; | 46 public static final int POSSIBLE = 0; |
56 | 47 |
57 /** | 48 /** NOT_POSSIBLE means reader mode cannot be entered. */ |
58 * NOT_POSSIBLE means reader mode cannot be entered. | |
59 */ | |
60 public static final int NOT_POSSIBLE = 1; | 49 public static final int NOT_POSSIBLE = 1; |
61 | 50 |
62 /** | 51 /** STARTED means reader mode is currently in reader mode. */ |
63 * STARTED means reader mode is currently in reader mode. | |
64 */ | |
65 public static final int STARTED = 2; | 52 public static final int STARTED = 2; |
66 | 53 |
67 // The url of the last page visited if the last page was reader mode page. Otherwise null. | 54 /** The url of the last page visited if the last page was reader mode page. Otherwise null. */ |
68 private String mReaderModePageUrl; | 55 private String mReaderModePageUrl; |
69 | 56 |
70 // Whether the fact that the current web page was distillable or not has bee n recorded. | 57 /** Whether the fact that the current web page was distillable or not has be en recorded. */ |
71 private boolean mIsUmaRecorded; | 58 private boolean mIsUmaRecorded; |
72 | 59 |
73 // The per-tab state of distillation. | 60 /** The per-tab state of distillation. */ |
74 protected Map<Integer, ReaderModeTabInfo> mTabStatusMap; | 61 protected Map<Integer, ReaderModeTabInfo> mTabStatusMap; |
75 | 62 |
76 // The current tab ID. This will change as the user switches between tabs. | 63 /** The current tab ID. This will change as the user switches between tabs. */ |
77 private int mTabId; | 64 private int mTabId; |
78 | 65 |
79 // The ReaderModePanel that this class is managing. | 66 /** The ChromeActivity that this panel exists in. */ |
80 protected ReaderModePanel mReaderModePanel; | |
81 | |
82 // The ChromeActivity that this panel exists in. | |
83 private ChromeActivity mChromeActivity; | 67 private ChromeActivity mChromeActivity; |
84 | 68 |
85 // The primary means of getting the currently active tab. | 69 /** The primary means of getting the currently active tab. */ |
86 private TabModelSelector mTabModelSelector; | 70 private TabModelSelector mTabModelSelector; |
87 | 71 |
88 private boolean mIsFullscreenModeEntered; | 72 /** If Reader Mode is detecting all pages as distillable. */ |
89 private boolean mIsFindToolbarShowing; | |
90 private boolean mIsKeyboardShowing; | |
91 | |
92 // InfoBar tracking. | |
93 private boolean mIsInfoBarContainerShown; | |
94 | |
95 // If Reader Mode is detecting all pages as distillable. | |
96 private boolean mIsReaderHeuristicAlwaysTrue; | 73 private boolean mIsReaderHeuristicAlwaysTrue; |
97 | 74 |
75 /** Whether or not the previous navigation should be removed. */ | |
76 private boolean mShouldRemovePreviousNavigation; | |
77 | |
78 /** The index of the last committed distiller page in history. */ | |
79 private int mLastDistillerPageIndex; | |
98 | 80 |
99 public ReaderModeManager(TabModelSelector selector, ChromeActivity activity) { | 81 public ReaderModeManager(TabModelSelector selector, ChromeActivity activity) { |
100 super(selector); | 82 super(selector); |
101 mTabId = Tab.INVALID_TAB_ID; | 83 mTabId = Tab.INVALID_TAB_ID; |
102 mTabModelSelector = selector; | 84 mTabModelSelector = selector; |
103 mChromeActivity = activity; | 85 mChromeActivity = activity; |
104 mTabStatusMap = new HashMap<>(); | 86 mTabStatusMap = new HashMap<>(); |
105 mIsReaderHeuristicAlwaysTrue = isDistillerHeuristicAlwaysTrue(); | 87 mIsReaderHeuristicAlwaysTrue = isDistillerHeuristicAlwaysTrue(); |
106 } | 88 } |
107 | 89 |
(...skipping 14 matching lines...) Expand all Loading... | |
122 for (Map.Entry<Integer, ReaderModeTabInfo> e : mTabStatusMap.entrySet()) { | 104 for (Map.Entry<Integer, ReaderModeTabInfo> e : mTabStatusMap.entrySet()) { |
123 if (e.getValue().getWebContentsObserver() != null) { | 105 if (e.getValue().getWebContentsObserver() != null) { |
124 e.getValue().getWebContentsObserver().destroy(); | 106 e.getValue().getWebContentsObserver().destroy(); |
125 } | 107 } |
126 } | 108 } |
127 mTabStatusMap.clear(); | 109 mTabStatusMap.clear(); |
128 | 110 |
129 DomDistillerUIUtils.destroy(this); | 111 DomDistillerUIUtils.destroy(this); |
130 | 112 |
131 mChromeActivity = null; | 113 mChromeActivity = null; |
132 mReaderModePanel = null; | |
133 mTabModelSelector = null; | 114 mTabModelSelector = null; |
134 } | 115 } |
135 | 116 |
136 /** | |
137 * @return A FindToolbarObserver capable of hiding the Reader Mode panel. | |
138 */ | |
139 public FindToolbarObserver getFindToolbarObserver() { | |
140 return new FindToolbarObserver() { | |
141 @Override | |
142 public void onFindToolbarShown() { | |
143 mIsFindToolbarShowing = true; | |
144 closeReaderPanel(StateChangeReason.UNKNOWN, true); | |
145 } | |
146 | |
147 @Override | |
148 public void onFindToolbarHidden() { | |
149 mIsFindToolbarShowing = false; | |
150 requestReaderPanelShow(StateChangeReason.UNKNOWN); | |
151 } | |
152 }; | |
153 } | |
154 | |
155 // TabModelSelectorTabObserver: | 117 // TabModelSelectorTabObserver: |
156 | 118 |
157 @Override | 119 @Override |
158 public void onShown(Tab shownTab) { | 120 public void onShown(Tab shownTab) { |
159 if (mTabModelSelector == null) return; | 121 if (mTabModelSelector == null) return; |
160 | 122 |
161 int shownTabId = shownTab.getId(); | 123 int shownTabId = shownTab.getId(); |
162 Tab previousTab = mTabModelSelector.getTabById(mTabId); | |
163 mTabId = shownTabId; | 124 mTabId = shownTabId; |
164 | 125 |
165 // If the reader panel was dismissed, stop here. | 126 // If the reader panel was dismissed, stop here. |
166 if (mTabStatusMap.containsKey(shownTabId) | 127 if (mTabStatusMap.containsKey(shownTabId) |
167 && mTabStatusMap.get(shownTabId).isDismissed()) { | 128 && mTabStatusMap.get(shownTabId).isDismissed()) { |
168 return; | 129 return; |
169 } | 130 } |
170 | 131 |
171 // Set this manager as the active one for the UI utils. | 132 // Set this manager as the active one for the UI utils. |
172 DomDistillerUIUtils.setReaderModeManagerDelegate(this); | 133 DomDistillerUIUtils.setReaderModeManagerDelegate(this); |
173 | 134 |
174 // Update infobar state based on current tab. | |
175 if (shownTab.getInfoBarContainer() != null) { | |
176 mIsInfoBarContainerShown = shownTab.getInfoBarContainer().hasInfoBar s(); | |
177 } | |
178 | |
179 // Remove the infobar observer from the previous tab and attach it to th e current one. | |
180 if (previousTab != null && previousTab.getInfoBarContainer() != null) { | |
181 previousTab.getInfoBarContainer().removeObserver(this); | |
182 } | |
183 | |
184 if (shownTab.getInfoBarContainer() != null) { | |
185 shownTab.getInfoBarContainer().addObserver(this); | |
186 } | |
187 | |
188 // If there is no state info for this tab, create it. | 135 // If there is no state info for this tab, create it. |
189 ReaderModeTabInfo tabInfo = mTabStatusMap.get(shownTabId); | 136 ReaderModeTabInfo tabInfo = mTabStatusMap.get(shownTabId); |
190 if (tabInfo == null) { | 137 if (tabInfo == null) { |
191 tabInfo = new ReaderModeTabInfo(); | 138 tabInfo = new ReaderModeTabInfo(); |
192 tabInfo.setStatus(NOT_POSSIBLE); | 139 tabInfo.setStatus(NOT_POSSIBLE); |
193 tabInfo.setUrl(shownTab.getUrl()); | 140 tabInfo.setUrl(shownTab.getUrl()); |
194 mTabStatusMap.put(shownTabId, tabInfo); | 141 mTabStatusMap.put(shownTabId, tabInfo); |
195 } | 142 } |
196 | 143 |
197 // Make sure there is a WebContentsObserver on this tab's WebContents. | 144 // Make sure there is a WebContentsObserver on this tab's WebContents. |
198 if (tabInfo.getWebContentsObserver() == null) { | 145 if (tabInfo.getWebContentsObserver() == null) { |
199 tabInfo.setWebContentsObserver(createWebContentsObserver(shownTab.ge tWebContents())); | 146 tabInfo.setWebContentsObserver(createWebContentsObserver(shownTab.ge tWebContents())); |
200 } | 147 } |
201 | 148 |
202 // Make sure there is a distillability delegate set on the WebContents. | 149 // Make sure there is a distillability delegate set on the WebContents. |
203 setDistillabilityCallback(shownTabId); | 150 setDistillabilityCallback(shownTabId); |
204 | 151 |
205 requestReaderPanelShow(StateChangeReason.UNKNOWN); | 152 tryShowingInfoBar(); |
206 } | 153 } |
207 | 154 |
208 @Override | 155 @Override |
209 public void onHidden(Tab tab) { | 156 public void onHidden(Tab tab) { |
210 closeReaderPanel(StateChangeReason.UNKNOWN, false); | 157 closeReaderPanel(StateChangeReason.UNKNOWN, false); |
211 } | 158 } |
212 | 159 |
213 @Override | 160 @Override |
214 public void onDestroyed(Tab tab) { | 161 public void onDestroyed(Tab tab) { |
215 if (tab == null) return; | 162 if (tab == null) return; |
216 if (tab.getInfoBarContainer() != null) { | 163 |
217 tab.getInfoBarContainer().removeObserver(this); | |
218 } | |
219 // If the panel was not shown for the previous navigation, record it now . | 164 // If the panel was not shown for the previous navigation, record it now . |
220 ReaderModeTabInfo info = mTabStatusMap.get(tab.getId()); | 165 ReaderModeTabInfo info = mTabStatusMap.get(tab.getId()); |
221 if (info != null && !info.isPanelShowRecorded()) { | 166 if (info != null && !info.isPanelShowRecorded()) { |
222 recordPanelVisibilityForNavigation(false); | 167 recordPanelVisibilityForNavigation(false); |
223 } | 168 } |
224 removeTabState(tab.getId()); | 169 removeTabState(tab.getId()); |
225 } | 170 } |
226 | 171 |
172 @Override | |
173 public void onPageLoadStarted(Tab tab, String url) { | |
174 // Reader Mode should not pollute the navigation stack. To avoid this, w atch for navigations | |
175 // and prepare to remove any that are "chrome-distiller" urls. | |
176 NavigationController controller = tab.getWebContents().getNavigationCont roller(); | |
177 int index = controller.getLastCommittedEntryIndex(); | |
178 NavigationEntry entry = controller.getEntryAtIndex(index); | |
179 if (entry == null) return; | |
180 | |
181 if (DomDistillerUrlUtils.isDistilledPage(entry.getUrl())) { | |
182 mShouldRemovePreviousNavigation = true; | |
183 mLastDistillerPageIndex = index; | |
184 } | |
185 } | |
186 | |
187 @Override | |
188 public void onDidFinishNavigation(Tab tab, String url, boolean isInMainFrame , | |
189 boolean isErrorPage, boolean hasCommitted, boolean isSameDocument, | |
190 boolean isFragmentNavigation, Integer pageTransition, int errorCode, | |
191 int httpStatusCode) { | |
192 if (!hasCommitted || !mShouldRemovePreviousNavigation || !isInMainFrame) return; | |
193 | |
194 mShouldRemovePreviousNavigation = false; | |
195 NavigationController controller = tab.getWebContents().getNavigationCont roller(); | |
196 controller.removeEntryAtIndex(mLastDistillerPageIndex); | |
197 } | |
198 | |
227 /** | 199 /** |
228 * Clean up the state associated with a tab. | 200 * Clean up the state associated with a tab. |
229 * @param tabId The target tab ID. | 201 * @param tabId The target tab ID. |
230 */ | 202 */ |
231 private void removeTabState(int tabId) { | 203 private void removeTabState(int tabId) { |
232 if (!mTabStatusMap.containsKey(tabId)) return; | 204 if (!mTabStatusMap.containsKey(tabId)) return; |
233 ReaderModeTabInfo tabInfo = mTabStatusMap.get(tabId); | 205 ReaderModeTabInfo tabInfo = mTabStatusMap.get(tabId); |
234 if (tabInfo.getWebContentsObserver() != null) { | 206 if (tabInfo.getWebContentsObserver() != null) { |
235 tabInfo.getWebContentsObserver().destroy(); | 207 tabInfo.getWebContentsObserver().destroy(); |
236 } | 208 } |
(...skipping 20 matching lines...) Expand all Loading... | |
257 if (tab.getWebContents() != null) { | 229 if (tab.getWebContents() != null) { |
258 tabInfo.setWebContentsObserver(createWebContentsObserver(tab.getWebC ontents())); | 230 tabInfo.setWebContentsObserver(createWebContentsObserver(tab.getWebC ontents())); |
259 if (DomDistillerUrlUtils.isDistilledPage(tab.getUrl())) { | 231 if (DomDistillerUrlUtils.isDistilledPage(tab.getUrl())) { |
260 tabInfo.setStatus(STARTED); | 232 tabInfo.setStatus(STARTED); |
261 mReaderModePageUrl = tab.getUrl(); | 233 mReaderModePageUrl = tab.getUrl(); |
262 closeReaderPanel(StateChangeReason.CONTENT_CHANGED, true); | 234 closeReaderPanel(StateChangeReason.CONTENT_CHANGED, true); |
263 } | 235 } |
264 // Make sure there is a distillability delegate set on the WebConten ts. | 236 // Make sure there is a distillability delegate set on the WebConten ts. |
265 setDistillabilityCallback(tab.getId()); | 237 setDistillabilityCallback(tab.getId()); |
266 } | 238 } |
267 | |
268 if (tab.getInfoBarContainer() != null) tab.getInfoBarContainer().addObse rver(this); | |
269 } | |
270 | |
271 @Override | |
272 public void onToggleFullscreenMode(Tab tab, boolean enable) { | |
273 // Temporarily hide the reader mode panel while fullscreen is enabled. | |
274 if (enable) { | |
275 mIsFullscreenModeEntered = true; | |
276 closeReaderPanel(StateChangeReason.FULLSCREEN_ENTERED, false); | |
277 } else { | |
278 mIsFullscreenModeEntered = false; | |
279 requestReaderPanelShow(StateChangeReason.FULLSCREEN_EXITED); | |
280 } | |
281 } | |
282 | |
283 // InfoBarContainerObserver: | |
284 | |
285 @Override | |
286 public void onAddInfoBar(InfoBarContainer container, InfoBar infoBar, boolea n isFirst) { | |
287 mIsInfoBarContainerShown = true; | |
288 // If the panel is opened past the peeking state, obscure the infobar. | |
289 if (mReaderModePanel != null && mReaderModePanel.isPanelOpened() && cont ainer != null) { | |
290 container.setIsObscuredByOtherView(true); | |
291 } else if (isFirst) { | |
292 // Temporarily hides the reader mode button while the infobars are s hown. | |
293 closeReaderPanel(StateChangeReason.INFOBAR_SHOWN, false); | |
294 } | |
295 } | |
296 | |
297 @Override | |
298 public void onRemoveInfoBar(InfoBarContainer container, InfoBar infoBar, boo lean isLast) { | |
299 // Re-shows the reader mode button if necessary once the infobars are di smissed. | |
300 if (isLast) { | |
301 mIsInfoBarContainerShown = false; | |
302 requestReaderPanelShow(StateChangeReason.INFOBAR_HIDDEN); | |
303 } | |
304 } | |
305 | |
306 @Override | |
307 public void onInfoBarContainerAttachedToWindow(boolean hasInfoBars) { | |
308 mIsInfoBarContainerShown = hasInfoBars; | |
309 if (mIsInfoBarContainerShown) { | |
310 closeReaderPanel(StateChangeReason.INFOBAR_SHOWN, false); | |
311 } else { | |
312 requestReaderPanelShow(StateChangeReason.INFOBAR_HIDDEN); | |
313 } | |
314 } | 239 } |
315 | 240 |
316 // ReaderModeManagerDelegate: | 241 // ReaderModeManagerDelegate: |
317 | 242 |
318 @Override | 243 @Override |
319 public void setReaderModePanel(ReaderModePanel panel) { | |
320 mReaderModePanel = panel; | |
321 } | |
322 | |
323 @Override | |
324 public ChromeActivity getChromeActivity() { | 244 public ChromeActivity getChromeActivity() { |
325 return mChromeActivity; | 245 return mChromeActivity; |
326 } | 246 } |
327 | 247 |
328 @Override | 248 @Override |
329 public void onPanelShown() { | 249 public void onPanelShown() { |
330 if (mTabModelSelector == null) return; | 250 if (mTabModelSelector == null) return; |
331 int tabId = mTabModelSelector.getCurrentTabId(); | 251 int tabId = mTabModelSelector.getCurrentTabId(); |
332 | 252 |
333 ReaderModeTabInfo info = mTabStatusMap.get(tabId); | 253 ReaderModeTabInfo info = mTabStatusMap.get(tabId); |
(...skipping 10 matching lines...) Expand all Loading... | |
344 /** | 264 /** |
345 * Record if the panel became visible on the current page. This can be overr idden for testing. | 265 * Record if the panel became visible on the current page. This can be overr idden for testing. |
346 * @param visible If the panel was visible at any time. | 266 * @param visible If the panel was visible at any time. |
347 */ | 267 */ |
348 protected void recordPanelVisibilityForNavigation(boolean visible) { | 268 protected void recordPanelVisibilityForNavigation(boolean visible) { |
349 RecordHistogram.recordBooleanHistogram("DomDistiller.ReaderShownForPageL oad", visible); | 269 RecordHistogram.recordBooleanHistogram("DomDistiller.ReaderShownForPageL oad", visible); |
350 } | 270 } |
351 | 271 |
352 @Override | 272 @Override |
353 public void onClosed(StateChangeReason reason) { | 273 public void onClosed(StateChangeReason reason) { |
354 if (mReaderModePanel == null || mTabModelSelector == null) return; | 274 if (mTabModelSelector == null) return; |
355 | |
356 restoreInfobars(); | |
357 | 275 |
358 // Only dismiss the panel if the close was a result of user interaction. | 276 // Only dismiss the panel if the close was a result of user interaction. |
359 if (reason != StateChangeReason.FLING && reason != StateChangeReason.SWI PE | 277 if (reason != StateChangeReason.FLING && reason != StateChangeReason.SWI PE |
Theresa
2017/05/11 22:31:19
StateChangeReason doesn't really apply anymore rig
mdjones
2017/05/12 19:13:10
Done.
| |
360 && reason != StateChangeReason.CLOSE_BUTTON) { | 278 && reason != StateChangeReason.CLOSE_BUTTON) { |
361 return; | 279 return; |
362 } | 280 } |
363 | 281 |
364 // Record close button usage. | 282 RecordHistogram.recordBooleanHistogram("DomDistiller.InfoBarUsage", fals e); |
365 if (reason == StateChangeReason.CLOSE_BUTTON) { | |
366 RecordHistogram.recordBooleanHistogram("DomDistiller.BarCloseButtonU sage", | |
367 mReaderModePanel.getPanelState() == PanelState.EXPANDED | |
368 || mReaderModePanel.getPanelState() == PanelState.MAXIMIZED) ; | |
369 } | |
370 | 283 |
371 int currentTabId = mTabModelSelector.getCurrentTabId(); | 284 int currentTabId = mTabModelSelector.getCurrentTabId(); |
372 if (!mTabStatusMap.containsKey(currentTabId)) return; | 285 if (!mTabStatusMap.containsKey(currentTabId)) return; |
373 mTabStatusMap.get(currentTabId).setIsDismissed(true); | 286 mTabStatusMap.get(currentTabId).setIsDismissed(true); |
374 } | 287 } |
375 | 288 |
376 @Override | 289 @Override |
377 public void onPeek() { | |
378 restoreInfobars(); | |
379 } | |
380 | |
381 /** | |
382 * Restore any infobars that may have been hidden by Reader Mode. | |
383 */ | |
384 private void restoreInfobars() { | |
385 if (!mIsInfoBarContainerShown) return; | |
386 | |
387 Tab curTab = mTabModelSelector.getCurrentTab(); | |
388 if (curTab == null) return; | |
389 | |
390 InfoBarContainer container = curTab.getInfoBarContainer(); | |
391 if (container == null) return; | |
392 | |
393 container.setIsObscuredByOtherView(false); | |
394 | |
395 // Temporarily hides the reader mode button while the infobars are shown . | |
396 closeReaderPanel(StateChangeReason.INFOBAR_SHOWN, false); | |
397 } | |
398 | |
399 @Override | |
400 public WebContents getBasePageWebContents() { | 290 public WebContents getBasePageWebContents() { |
401 Tab tab = mTabModelSelector.getCurrentTab(); | 291 Tab tab = mTabModelSelector.getCurrentTab(); |
402 if (tab == null) return null; | 292 if (tab == null) return null; |
403 | 293 |
404 return tab.getWebContents(); | 294 return tab.getWebContents(); |
405 } | 295 } |
406 | 296 |
407 @Override | 297 @Override |
408 public void closeReaderPanel(StateChangeReason reason, boolean animate) { | 298 public void closeReaderPanel(StateChangeReason reason, boolean animate) { |
409 if (mReaderModePanel == null) return; | 299 // TODO(mdjones): Remove this method and dependencies. |
Theresa
2017/05/11 22:31:19
InfoBar handles automatically dismissing itself?
mdjones
2017/05/12 19:13:10
In most cases where we want it, yes. That's the ni
| |
410 mReaderModePanel.closePanel(reason, animate); | |
411 } | 300 } |
412 | 301 |
413 @Override | 302 @Override |
414 public void recordTimeSpentInReader(long timeMs) { | 303 public void recordTimeSpentInReader(long timeMs) { |
415 RecordHistogram.recordLongTimesHistogram("DomDistiller.Time.ViewingReade rModePanel", | 304 RecordHistogram.recordLongTimesHistogram("DomDistiller.Time.ViewingReade rModePanel", |
416 timeMs, TimeUnit.MILLISECONDS); | 305 timeMs, TimeUnit.MILLISECONDS); |
417 } | 306 } |
418 | 307 |
419 @Override | |
420 public void onLayoutChanged() { | |
421 if (isKeyboardShowing()) { | |
422 mIsKeyboardShowing = true; | |
423 closeReaderPanel(StateChangeReason.KEYBOARD_SHOWN, false); | |
424 } else if (mIsKeyboardShowing) { | |
425 mIsKeyboardShowing = false; | |
426 requestReaderPanelShow(StateChangeReason.KEYBOARD_HIDDEN); | |
427 } | |
428 } | |
429 | |
430 /** | 308 /** |
431 * @return True if the keyboard might be showing. This is not 100% accurate; see | 309 * @return True if the keyboard might be showing. This is not 100% accurate; see |
432 * UiUtils.isKeyboardShowing(...). | 310 * UiUtils.isKeyboardShowing(...). |
433 */ | 311 */ |
434 protected boolean isKeyboardShowing() { | 312 protected boolean isKeyboardShowing() { |
435 return mChromeActivity != null && UiUtils.isKeyboardShowing(mChromeActiv ity, | 313 return mChromeActivity != null && UiUtils.isKeyboardShowing(mChromeActiv ity, |
436 mChromeActivity.findViewById(android.R.id.content)); | 314 mChromeActivity.findViewById(android.R.id.content)); |
437 } | 315 } |
438 | 316 |
439 protected WebContentsObserver createWebContentsObserver(WebContents webConte nts) { | 317 protected WebContentsObserver createWebContentsObserver(WebContents webConte nts) { |
(...skipping 16 matching lines...) Expand all Loading... | |
456 if (tabInfo == null) return; | 334 if (tabInfo == null) return; |
457 | 335 |
458 tabInfo.setUrl(url); | 336 tabInfo.setUrl(url); |
459 if (DomDistillerUrlUtils.isDistilledPage(url)) { | 337 if (DomDistillerUrlUtils.isDistilledPage(url)) { |
460 tabInfo.setStatus(STARTED); | 338 tabInfo.setStatus(STARTED); |
461 mReaderModePageUrl = url; | 339 mReaderModePageUrl = url; |
462 } | 340 } |
463 } | 341 } |
464 | 342 |
465 @Override | 343 @Override |
466 public void didFinishNavigation(String url, boolean isInMainFrame, b oolean isErrorPage, | 344 public void didFinishNavigation(String url, boolean isInMainFrame, b oolean isErrorPage, |
Theresa
2017/05/11 22:31:19
When is this called vs onDidFinishNavigation?
mdjones
2017/05/12 19:13:10
Not a big difference, I'll move those functions in
| |
467 boolean hasCommitted, boolean isSameDocument, boolean isFrag mentNavigation, | 345 boolean hasCommitted, boolean isSameDocument, boolean isFrag mentNavigation, |
468 Integer pageTransition, int errorCode, String errorDescripti on, | 346 Integer pageTransition, int errorCode, String errorDescripti on, |
469 int httpStatusCode) { | 347 int httpStatusCode) { |
470 // TODO(cjhopman): This should possibly ignore navigations that replace the entry | 348 // TODO(cjhopman): This should possibly ignore navigations that replace the entry |
471 // (like those from history.replaceState()). | 349 // (like those from history.replaceState()). |
472 if (!hasCommitted || !isInMainFrame || isSameDocument) return; | 350 if (!hasCommitted || !isInMainFrame || isSameDocument) return; |
473 if (DomDistillerUrlUtils.isDistilledPage(url)) return; | |
474 | 351 |
475 // Make sure the tab was not destroyed. | 352 // Make sure the tab was not destroyed. |
476 ReaderModeTabInfo tabInfo = mTabStatusMap.get(readerTabId); | 353 ReaderModeTabInfo tabInfo = mTabStatusMap.get(readerTabId); |
477 if (tabInfo == null) return; | 354 if (tabInfo == null) return; |
478 | 355 |
479 tabInfo.setStatus(POSSIBLE); | 356 tabInfo.setStatus(POSSIBLE); |
480 if (!TextUtils.equals(url, | 357 if (!TextUtils.equals(url, |
481 DomDistillerUrlUtils.getOriginalUrlFromDistillerUrl( | 358 DomDistillerUrlUtils.getOriginalUrlFromDistillerUrl( |
482 mReaderModePageUrl))) { | 359 mReaderModePageUrl))) { |
483 tabInfo.setStatus(NOT_POSSIBLE); | 360 tabInfo.setStatus(NOT_POSSIBLE); |
484 mIsUmaRecorded = false; | 361 mIsUmaRecorded = false; |
485 } | 362 } |
486 mReaderModePageUrl = null; | 363 mReaderModePageUrl = null; |
487 | 364 |
488 if (tabInfo.getStatus() != POSSIBLE) { | 365 if (tabInfo.getStatus() != POSSIBLE) { |
489 closeReaderPanel(StateChangeReason.UNKNOWN, false); | 366 closeReaderPanel(StateChangeReason.UNKNOWN, false); |
490 } else { | 367 } else { |
491 requestReaderPanelShow(StateChangeReason.UNKNOWN); | 368 tryShowingInfoBar(); |
492 } | 369 } |
493 } | 370 } |
494 | 371 |
495 @Override | 372 @Override |
496 public void navigationEntryCommitted() { | 373 public void navigationEntryCommitted() { |
497 // Make sure the tab was not destroyed. | 374 // Make sure the tab was not destroyed. |
498 ReaderModeTabInfo tabInfo = mTabStatusMap.get(readerTabId); | 375 ReaderModeTabInfo tabInfo = mTabStatusMap.get(readerTabId); |
499 if (tabInfo == null) return; | 376 if (tabInfo == null) return; |
500 // Reset closed state of reader mode in this tab once we know a navigation is | 377 // Reset closed state of reader mode in this tab once we know a navigation is |
501 // happening. | 378 // happening. |
502 tabInfo.setIsDismissed(false); | 379 tabInfo.setIsDismissed(false); |
503 | 380 |
504 // If the panel was not shown for the previous navigation, recor d it now. | 381 // If the panel was not shown for the previous navigation, recor d it now. |
505 Tab curTab = mTabModelSelector.getTabById(readerTabId); | 382 Tab curTab = mTabModelSelector.getTabById(readerTabId); |
506 if (curTab != null && !curTab.isNativePage() && !curTab.isBeingR estored()) { | 383 if (curTab != null && !curTab.isNativePage() && !curTab.isBeingR estored()) { |
507 recordPanelVisibilityForNavigation(false); | 384 recordPanelVisibilityForNavigation(false); |
508 } | 385 } |
509 tabInfo.setIsPanelShowRecorded(false); | 386 tabInfo.setIsPanelShowRecorded(false); |
510 } | 387 } |
511 }; | 388 }; |
512 } | 389 } |
513 | 390 |
514 /** | 391 /** |
515 * This is a wrapper for "requestPanelShow" that checks if reader mode is po ssible before | 392 * Try showing the reader mode infobar. |
516 * showing. | |
517 * @param reason The reason the panel is requesting to be shown. | |
518 */ | 393 */ |
519 protected void requestReaderPanelShow(StateChangeReason reason) { | 394 protected void tryShowingInfoBar() { |
520 if (mTabModelSelector == null) return; | 395 if (mTabModelSelector == null) return; |
521 | 396 |
522 int currentTabId = mTabModelSelector.getCurrentTabId(); | 397 int currentTabId = mTabModelSelector.getCurrentTabId(); |
523 if (currentTabId == Tab.INVALID_TAB_ID) return; | 398 if (currentTabId == Tab.INVALID_TAB_ID) return; |
524 | 399 |
525 // Test if the user is requesting the desktop site. Ignore this if disti ller is set to | 400 // Test if the user is requesting the desktop site. Ignore this if disti ller is set to |
526 // ALWAYS_TRUE. | 401 // ALWAYS_TRUE. |
527 boolean usingRequestDesktopSite = getBasePageWebContents() != null | 402 boolean usingRequestDesktopSite = getBasePageWebContents() != null |
528 && getBasePageWebContents().getNavigationController().getUseDesk topUserAgent() | 403 && getBasePageWebContents().getNavigationController().getUseDesk topUserAgent() |
529 && !mIsReaderHeuristicAlwaysTrue; | 404 && !mIsReaderHeuristicAlwaysTrue; |
530 | 405 |
531 if (mReaderModePanel == null || !mTabStatusMap.containsKey(currentTabId) | 406 if (!mTabStatusMap.containsKey(currentTabId) || usingRequestDesktopSite |
532 || usingRequestDesktopSite | |
533 || mTabStatusMap.get(currentTabId).getStatus() != POSSIBLE | 407 || mTabStatusMap.get(currentTabId).getStatus() != POSSIBLE |
534 || mTabStatusMap.get(currentTabId).isDismissed() | 408 || mTabStatusMap.get(currentTabId).isDismissed() |
535 || mIsInfoBarContainerShown | |
536 || mIsFindToolbarShowing | |
537 || mIsFullscreenModeEntered | |
538 || mIsKeyboardShowing | |
539 || AccessibilityUtil.isAccessibilityEnabled()) { | 409 || AccessibilityUtil.isAccessibilityEnabled()) { |
540 return; | 410 return; |
541 } | 411 } |
542 | 412 |
543 mReaderModePanel.requestPanelShow(reason); | 413 ReaderModeInfoBar.showReaderModeInfoBar(mTabModelSelector.getCurrentTab( ), this); |
544 } | 414 } |
545 | 415 |
546 /** | 416 /** |
417 * Navigate the current tab to a Reader Mode URL. | |
418 */ | |
419 public void navigateToReaderMode() { | |
420 RecordHistogram.recordBooleanHistogram("DomDistiller.InfoBarUsage", true ); | |
421 | |
422 WebContents baseWebContents = getBasePageWebContents(); | |
423 if (baseWebContents == null || mChromeActivity == null || mTabModelSelec tor == null) return; | |
424 | |
425 String url = baseWebContents.getUrl(); | |
426 if (url == null) return; | |
427 | |
428 DomDistillerTabUtils.distillCurrentPageAndView(getBasePageWebContents()) ; | |
429 } | |
430 | |
431 /** | |
547 * Open a link from the panel in a new tab. | 432 * Open a link from the panel in a new tab. |
548 * @param url The URL to load. | 433 * @param url The URL to load. |
549 */ | 434 */ |
550 @Override | 435 @Override |
551 public void createNewTab(String url) { | 436 public void createNewTab(String url) { |
552 if (mChromeActivity == null) return; | 437 if (mChromeActivity == null) return; |
553 | 438 |
554 Tab currentTab = mTabModelSelector.getCurrentTab(); | 439 Tab currentTab = mTabModelSelector.getCurrentTab(); |
555 if (currentTab == null) return; | 440 if (currentTab == null) return; |
556 | 441 |
557 TabCreatorManager.TabCreator tabCreator = | 442 TabCreatorManager.TabCreator tabCreator = |
558 mChromeActivity.getTabCreator(currentTab.isIncognito()); | 443 mChromeActivity.getTabCreator(currentTab.isIncognito()); |
559 if (tabCreator == null) return; | 444 if (tabCreator == null) return; |
560 | 445 |
561 tabCreator.createNewTab(new LoadUrlParams(url, PageTransition.LINK), | 446 tabCreator.createNewTab(new LoadUrlParams(url, PageTransition.LINK), |
562 TabModel.TabLaunchType.FROM_LINK, mChromeActivity.getActivityTab ()); | 447 TabModel.TabLaunchType.FROM_LINK, mChromeActivity.getActivityTab ()); |
563 } | 448 } |
564 | 449 |
565 /** | 450 /** |
566 * @return Whether the Reader Mode panel is opened (state is EXPANDED or MAX IMIZED). | |
567 */ | |
568 public boolean isPanelOpened() { | |
569 if (mReaderModePanel == null) return false; | |
570 return mReaderModePanel.isPanelOpened(); | |
571 } | |
572 | |
573 /** | |
574 * @return The ReaderModePanel for testing. | |
575 */ | |
576 @VisibleForTesting | |
577 public ReaderModePanel getPanelForTesting() { | |
578 return mReaderModePanel; | |
579 } | |
580 | |
581 /** | |
582 * Set the callback for updating reader mode status based on whether or not the page should | 451 * Set the callback for updating reader mode status based on whether or not the page should |
583 * be viewed in reader mode. | 452 * be viewed in reader mode. |
584 * @param tabId The ID of the tab having its callback set. | 453 * @param tabId The ID of the tab having its callback set. |
585 */ | 454 */ |
586 private void setDistillabilityCallback(final int tabId) { | 455 private void setDistillabilityCallback(final int tabId) { |
587 if (tabId == Tab.INVALID_TAB_ID || mTabStatusMap.get(tabId).isCallbackSe t()) { | 456 if (tabId == Tab.INVALID_TAB_ID || mTabStatusMap.get(tabId).isCallbackSe t()) { |
588 return; | 457 return; |
589 } | 458 } |
590 | 459 |
591 if (mTabModelSelector == null) return; | 460 if (mTabModelSelector == null) return; |
(...skipping 18 matching lines...) Expand all Loading... | |
610 // destroyed so that this never happens. | 479 // destroyed so that this never happens. |
611 if (readerTab == null || tabInfo == null) return; | 480 if (readerTab == null || tabInfo == null) return; |
612 | 481 |
613 // Make sure the page didn't navigate while waiting for a response. | 482 // Make sure the page didn't navigate while waiting for a response. |
614 if (!readerTab.getUrl().equals(tabInfo.getUrl())) return ; | 483 if (!readerTab.getUrl().equals(tabInfo.getUrl())) return ; |
615 | 484 |
616 if (isDistillable) { | 485 if (isDistillable) { |
617 tabInfo.setStatus(POSSIBLE); | 486 tabInfo.setStatus(POSSIBLE); |
618 // The user may have changed tabs. | 487 // The user may have changed tabs. |
619 if (tabId == mTabModelSelector.getCurrentTabId()) { | 488 if (tabId == mTabModelSelector.getCurrentTabId()) { |
620 // TODO(mdjones): Add reason DISTILLER_STATE_CHA NGE. | 489 tryShowingInfoBar(); |
621 requestReaderPanelShow(StateChangeReason.UNKNOWN ); | |
622 } | 490 } |
623 } else { | 491 } else { |
624 tabInfo.setStatus(NOT_POSSIBLE); | 492 tabInfo.setStatus(NOT_POSSIBLE); |
625 } | 493 } |
626 if (!mIsUmaRecorded && (tabInfo.getStatus() == POSSIBLE || isLast)) { | 494 if (!mIsUmaRecorded && (tabInfo.getStatus() == POSSIBLE || isLast)) { |
627 mIsUmaRecorded = true; | 495 mIsUmaRecorded = true; |
628 RecordHistogram.recordBooleanHistogram( | 496 RecordHistogram.recordBooleanHistogram( |
629 "DomDistiller.PageDistillable", | 497 "DomDistiller.PageDistillable", |
630 tabInfo.getStatus() == POSSIBLE); | 498 tabInfo.getStatus() == POSSIBLE); |
631 } | 499 } |
632 } | 500 } |
633 }); | 501 }); |
634 mTabStatusMap.get(tabId).setIsCallbackSet(true); | 502 mTabStatusMap.get(tabId).setIsCallbackSet(true); |
635 } | 503 } |
636 | 504 |
637 /** | 505 /** |
638 * @return Whether Reader mode and its new UI are enabled. | 506 * @return Whether Reader mode and its new UI are enabled. |
639 * @param context A context | 507 * @param context A context |
640 */ | 508 */ |
641 public static boolean isEnabled(Context context) { | 509 public static boolean isEnabled(Context context) { |
642 if (context == null) return false; | 510 if (context == null) return false; |
643 | 511 |
644 boolean enabled = CommandLine.getInstance().hasSwitch(ChromeSwitches.ENA BLE_DOM_DISTILLER) | 512 boolean enabled = CommandLine.getInstance().hasSwitch(ChromeSwitches.ENA BLE_DOM_DISTILLER) |
645 && !CommandLine.getInstance().hasSwitch( | 513 && !CommandLine.getInstance().hasSwitch( |
646 ChromeSwitches.DISABLE_READER_MODE_BOTTOM_BAR) | 514 ChromeSwitches.DISABLE_READER_MODE_BOTTOM_BAR) |
647 && !DeviceFormFactor.isTablet(context) | 515 && DomDistillerTabUtils.isDistillerHeuristicsEnabled(); |
648 && DomDistillerTabUtils.isDistillerHeuristicsEnabled() | |
649 && !SysUtils.isLowEndDevice(); | |
650 return enabled; | 516 return enabled; |
651 } | 517 } |
652 } | 518 } |
OLD | NEW |