下面列出了android.view.ViewTreeObserver.OnGlobalFocusChangeListener#org.chromium.chrome.browser.compositor.bottombar.OverlayPanel.StateChangeReason 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
/**
* @return A FindToolbarObserver capable of hiding the Reader Mode panel.
*/
public FindToolbarObserver getFindToolbarObserver() {
return new FindToolbarObserver() {
@Override
public void onFindToolbarShown() {
mIsFindToolbarShowing = true;
closeReaderPanel(StateChangeReason.UNKNOWN, true);
}
@Override
public void onFindToolbarHidden() {
mIsFindToolbarShowing = false;
requestReaderPanelShow(StateChangeReason.UNKNOWN);
}
};
}
@Override
public boolean shouldInterceptNavigation(ExternalNavigationHandler externalNavHandler,
NavigationParams navigationParams) {
mTabRedirectHandler.updateNewUrlLoading(navigationParams.pageTransitionType,
navigationParams.isRedirect,
navigationParams.hasUserGesture || navigationParams.hasUserGestureCarryover,
mActivity.getLastUserInteractionTime(), TabRedirectHandler.INVALID_ENTRY_INDEX);
ExternalNavigationParams params = new ExternalNavigationParams.Builder(
navigationParams.url, false, navigationParams.referrer,
navigationParams.pageTransitionType, navigationParams.isRedirect)
.setApplicationMustBeInForeground(true)
.setRedirectHandler(mTabRedirectHandler)
.setIsMainFrame(navigationParams.isMainFrame)
.build();
if (externalNavHandler.shouldOverrideUrlLoading(params)
!= OverrideUrlLoadingResult.NO_OVERRIDE) {
mSearchPanel.maximizePanelThenPromoteToTab(StateChangeReason.TAB_PROMOTION,
INTERCEPT_NAVIGATION_PROMOTION_ANIMATION_DURATION_MS);
return false;
}
if (navigationParams.isExternalProtocol) {
return false;
}
return true;
}
/**
* Request that a panel with the specified ID be shown. This does not necessarily mean the
* panel will be shown.
* @param panel The panel to show.
* @param reason The reason the panel is going to be shown.
*/
public void requestPanelShow(OverlayPanel panel, StateChangeReason reason) {
if (panel == null || panel == mActivePanel) return;
if (mActivePanel == null) {
// If no panel is currently showing, simply show the requesting panel.
mActivePanel = panel;
// TODO(mdjones): peekPanel should not be exposed publicly since the manager
// controls if a panel should show or not.
mActivePanel.peekPanel(reason);
} else if (panel.getPriority().ordinal() > mActivePanel.getPriority().ordinal()) {
// If a panel with higher priority than the active one requests to be shown, suppress
// the active panel and show the requesting one.
// NOTE(mdjones): closePanel will trigger notifyPanelClosed.
mPendingPanel = panel;
mPendingReason = reason;
mActivePanel.closePanel(StateChangeReason.SUPPRESS, true);
} else if (panel.canBeSuppressed()) {
// If a panel was showing and the requesting panel has a lower priority, suppress it
// if possible.
mSuppressedPanel = panel;
}
}
/**
* Called when layout-specific actions are needed after the animation finishes.
*/
protected void onAnimationFinished() {
// If animating to a particular PanelState, and after completing
// resizing the Panel to its desired state, then the Panel's state
// should be updated. This method also is called when an animation
// is cancelled (which can happen by a subsequent gesture while
// an animation is happening). That's why the actual height should
// be checked.
// TODO(mdjones): Move animations not directly related to the panel's state into their
// own animation handler (i.e. peek promo, G sprite, etc.). See https://crbug.com/617307.
if (mAnimatingState != null && mAnimatingState != PanelState.UNDEFINED
&& getHeight() == getPanelHeightFromState(mAnimatingState)) {
setPanelState(mAnimatingState, mAnimatingStateReason);
}
mAnimatingState = PanelState.UNDEFINED;
mAnimatingStateReason = StateChangeReason.UNKNOWN;
}
/**
* @return A FindToolbarObserver capable of hiding the Reader Mode panel.
*/
public FindToolbarObserver getFindToolbarObserver() {
return new FindToolbarObserver() {
@Override
public void onFindToolbarShown() {
mIsFindToolbarShowing = true;
closeReaderPanel(StateChangeReason.UNKNOWN, true);
}
@Override
public void onFindToolbarHidden() {
mIsFindToolbarShowing = false;
requestReaderPanelShow(StateChangeReason.UNKNOWN);
}
};
}
/**
* Initializes this manager.
* @param parentView The parent view to attach Contextual Search UX to.
*/
public void initialize(ViewGroup parentView) {
mNativeContextualSearchManagerPtr = nativeInit();
mParentView = parentView;
mParentView.getViewTreeObserver().addOnGlobalFocusChangeListener(mOnFocusChangeListener);
mTabRedirectHandler = new TabRedirectHandler(mActivity);
mIsShowingPromo = false;
mDidLogPromoOutcome = false;
mDidStartLoadingResolvedSearchRequest = false;
mWereSearchResultsSeen = false;
mIsInitialized = true;
mInternalStateController.reset(StateChangeReason.UNKNOWN);
listenForTabModelSelectorNotifications();
}
/**
* This is a wrapper for "requestPanelShow" that checks if reader mode is possible before
* showing.
* @param reason The reason the panel is requesting to be shown.
*/
protected void requestReaderPanelShow(StateChangeReason reason) {
if (mTabModelSelector == null) return;
int currentTabId = mTabModelSelector.getCurrentTabId();
if (currentTabId == Tab.INVALID_TAB_ID) return;
if (mReaderModePanel == null || !mTabStatusMap.containsKey(currentTabId)
|| mTabStatusMap.get(currentTabId).getStatus() != POSSIBLE
|| mTabStatusMap.get(currentTabId).isDismissed()
|| mIsInfoBarContainerShown
|| mIsFindToolbarShowing
|| mIsFullscreenModeEntered
|| mIsKeyboardShowing
|| DeviceClassManager.isAccessibilityModeEnabled(mChromeActivity)) {
return;
}
mReaderModePanel.requestPanelShow(reason);
}
/**
* Called when layout-specific actions are needed after the animation finishes.
*/
protected void onAnimationFinished() {
// If animating to a particular PanelState, and after completing
// resizing the Panel to its desired state, then the Panel's state
// should be updated. This method also is called when an animation
// is cancelled (which can happen by a subsequent gesture while
// an animation is happening). That's why the actual height should
// be checked.
// TODO(mdjones): Move animations not directly related to the panel's state into their
// own animation handler (i.e. peek promo, G sprite, etc.). See https://crbug.com/617307.
if (mAnimatingState != null && mAnimatingState != PanelState.UNDEFINED
&& getHeight() == getPanelHeightFromState(mAnimatingState)) {
setPanelState(mAnimatingState, mAnimatingStateReason);
}
mAnimatingState = PanelState.UNDEFINED;
mAnimatingStateReason = StateChangeReason.UNKNOWN;
}
/**
* Request that a panel with the specified ID be shown. This does not necessarily mean the
* panel will be shown.
* @param panel The panel to show.
* @param reason The reason the panel is going to be shown.
*/
public void requestPanelShow(OverlayPanel panel, StateChangeReason reason) {
if (panel == null || panel == mActivePanel) return;
if (mActivePanel == null) {
// If no panel is currently showing, simply show the requesting panel.
mActivePanel = panel;
// TODO(mdjones): peekPanel should not be exposed publicly since the manager
// controls if a panel should show or not.
mActivePanel.peekPanel(reason);
} else if (panel.getPriority().ordinal() > mActivePanel.getPriority().ordinal()) {
// If a panel with higher priority than the active one requests to be shown, suppress
// the active panel and show the requesting one. closePanel will trigger
// notifyPanelClosed.
mPendingPanel = panel;
mPendingReason = reason;
mActivePanel.closePanel(StateChangeReason.SUPPRESS, true);
} else if (panel.canBeSuppressed()) {
// If a panel was showing and the requesting panel has a lower priority, suppress it
// if possible.
if (!mSuppressedPanels.contains(panel)) mSuppressedPanels.add(panel);
}
}
@Override
public void onCloseContextualSearch(StateChangeReason reason) {
if (mSearchPanel == null) return;
mSelectionController.onSearchEnded(reason);
// Show the infobar container if it was visible before Contextual Search was shown.
if (mWereInfoBarsHidden) {
mWereInfoBarsHidden = false;
InfoBarContainer container = getInfoBarContainer();
if (container != null) {
container.setIsObscuredByOtherView(false);
}
}
if (!mWereSearchResultsSeen && mLoadedSearchUrlTimeMs != 0L) {
removeLastSearchVisit();
}
// Clear the timestamp. This is to avoid future calls to hideContextualSearch clearing
// the current URL.
mLoadedSearchUrlTimeMs = 0L;
mWereSearchResultsSeen = false;
mSearchRequest = null;
if (mIsShowingPeekPromo || mWouldShowPeekPromo) {
mPolicy.logPeekPromoMetrics(mIsShowingPeekPromo, mWouldShowPeekPromo);
}
if (mIsShowingPromo && !mDidLogPromoOutcome && mSearchPanel.wasPromoInteractive()) {
ContextualSearchUma.logPromoOutcome(mWasActivatedByTap, mIsMandatoryPromo);
mDidLogPromoOutcome = true;
}
mIsShowingPromo = false;
mSearchPanel.setIsPromoActive(false, false);
notifyHideContextualSearch();
}
/**
* Gets the state-change code for the given parameters by doing a lookup in the given map.
* @param state The panel state.
* @param reason The reason the state changed.
* @param stateChangeCodes The map of state and reason to code.
* @param defaultCode The code to return if the given values are not found in the map.
* @return The code to write into an enum histogram, based on the given map.
*/
private static int getStateChangeCode(PanelState state, StateChangeReason reason,
Map<StateChangeKey, Integer> stateChangeCodes, int defaultCode) {
Integer code = stateChangeCodes.get(new StateChangeKey(state, reason));
if (code != null) {
return code;
}
return defaultCode;
}
/**
* This is a wrapper for "requestPanelShow" that checks if reader mode is possible before
* showing.
* @param reason The reason the panel is requesting to be shown.
*/
protected void requestReaderPanelShow(StateChangeReason reason) {
if (mTabModelSelector == null) return;
int currentTabId = mTabModelSelector.getCurrentTabId();
if (currentTabId == Tab.INVALID_TAB_ID) return;
// Test if the user is requesting the desktop site. Ignore this if distiller is set to
// ALWAYS_TRUE.
boolean usingRequestDesktopSite = getBasePageWebContents() != null
&& getBasePageWebContents().getNavigationController().getUseDesktopUserAgent()
&& !mIsReaderHeuristicAlwaysTrue;
if (mReaderModePanel == null || !mTabStatusMap.containsKey(currentTabId)
|| usingRequestDesktopSite
|| mTabStatusMap.get(currentTabId).getStatus() != POSSIBLE
|| mTabStatusMap.get(currentTabId).isDismissed()
|| mIsInfoBarContainerShown
|| mIsFindToolbarShowing
|| mIsFullscreenModeEntered
|| mIsKeyboardShowing
|| AccessibilityUtil.isAccessibilityEnabled()) {
return;
}
mReaderModePanel.requestPanelShow(reason);
}
@Override
public void handleBarClick(long time, float x, float y) {
super.handleBarClick(time, x, y);
if (isCoordinateInsideCloseButton(x)) {
closePanel(StateChangeReason.CLOSE_BUTTON, true);
} else {
maximizePanel(StateChangeReason.SEARCH_BAR_TAP);
}
}
@Override
protected void onClosed(StateChangeReason reason) {
super.onClosed(reason);
if (mSceneLayer != null) mSceneLayer.hideTree();
if (mManagerDelegate == null) return;
mManagerDelegate.onClosed(reason);
}
/**
* Animates the Panel to its nearest state.
*/
protected void animateToNearestState() {
// Calculate the nearest state from the current position, and then calculate the duration
// of the animation that will start with a desired initial velocity and move the desired
// amount of dps (displacement).
final PanelState nearestState = findNearestPanelStateFromHeight(getHeight(), 0.0f);
final float displacement = getPanelHeightFromState(nearestState) - getHeight();
final long duration = calculateAnimationDuration(
INITIAL_ANIMATION_VELOCITY_DP_PER_SECOND, displacement);
animatePanelToState(nearestState, StateChangeReason.SWIPE, duration);
}
@Override
public void closePanel(StateChangeReason reason, boolean animate) {
super.closePanel(reason, animate);
if (mTimerRunning) {
onTimerEnded();
}
}
/**
* Restore any infobars that may have been hidden by Reader Mode.
*/
private void restoreInfobars() {
if (!mIsInfoBarContainerShown) return;
Tab curTab = mTabModelSelector.getCurrentTab();
if (curTab == null) return;
InfoBarContainer container = curTab.getInfoBarContainer();
if (container == null) return;
container.setIsObscuredByOtherView(false);
// Temporarily hides the reader mode button while the infobars are shown.
closeReaderPanel(StateChangeReason.INFOBAR_SHOWN, false);
}
@Override
protected void closePanel(StateChangeReason reason, boolean animate) {
if (animate) {
// Only animates the closing action if not doing that already.
if (mAnimatingState != PanelState.CLOSED) {
animatePanelToState(PanelState.CLOSED, reason);
}
} else {
resizePanelToState(PanelState.CLOSED, reason);
}
}
/**
* Resizes the Overlay Panel to a given |state|.
*
* @param state The state to resize to.
* @param reason The reason for the change of panel state.
*/
protected void resizePanelToState(PanelState state, StateChangeReason reason) {
cancelHeightAnimation();
final float height = getPanelHeightFromState(state);
setPanelHeight(height);
setPanelState(state, reason);
requestUpdate();
}
/**
* Animates the Panel to its projected state, given a particular vertical |velocity|.
*
* @param velocity The velocity of the gesture in dps per second.
*/
protected void animateToProjectedState(float velocity) {
PanelState projectedState = getProjectedState(velocity);
final float displacement = getPanelHeightFromState(projectedState) - getHeight();
final long duration = calculateAnimationDuration(velocity, displacement);
animatePanelToState(projectedState, StateChangeReason.FLING, duration);
}
@Override
public void promoteToTab() {
// TODO(pedrosimonetti): Consider removing this member.
mIsPromotingToTab = true;
// If the request object is null that means that a Contextual Search has just started
// and the Search Term Resolution response hasn't arrived yet. In this case, promoting
// the Panel to a Tab will result in creating a new tab with URL about:blank. To prevent
// this problem, we are ignoring tap gestures in the Search Bar if we don't know what
// to search for.
if (mSearchRequest != null
&& mSearchPanel.getContentViewCore() != null
&& mSearchPanel.getContentViewCore().getWebContents() != null) {
String url = getContentViewUrl(mSearchPanel.getContentViewCore());
// If it's a search URL, format it so the SearchBox becomes visible.
if (mSearchRequest.isContextualSearchUrl(url)) {
url = mSearchRequest.getSearchUrlForPromotion();
}
if (url != null) {
mTabPromotionDelegate.createContextualSearchTab(url);
mSearchPanel.closePanel(StateChangeReason.TAB_PROMOTION, false);
}
}
mIsPromotingToTab = false;
}
@Override
public void onContentChanged(Tab tab) {
// Only listen to events on the currently active tab.
if (tab.getId() != mTabId) return;
closeReaderPanel(StateChangeReason.UNKNOWN, false);
if (mTabStatusMap.containsKey(mTabId)) {
// If the panel was closed using the "x" icon, don't show it again for this tab.
if (mTabStatusMap.get(mTabId).isDismissed()) return;
removeTabState(mTabId);
}
ReaderModeTabInfo tabInfo = new ReaderModeTabInfo();
tabInfo.setStatus(NOT_POSSIBLE);
tabInfo.setUrl(tab.getUrl());
mTabStatusMap.put(tab.getId(), tabInfo);
if (tab.getWebContents() != null) {
tabInfo.setWebContentsObserver(createWebContentsObserver(tab.getWebContents()));
if (DomDistillerUrlUtils.isDistilledPage(tab.getUrl())) {
tabInfo.setStatus(STARTED);
mReaderModePageUrl = tab.getUrl();
closeReaderPanel(StateChangeReason.CONTENT_CHANGED, true);
}
// Make sure there is a distillability delegate set on the WebContents.
setDistillabilityCallback(tab.getId());
}
if (tab.getInfoBarContainer() != null) tab.getInfoBarContainer().addObserver(this);
}
@Override
public void onToggleFullscreenMode(Tab tab, boolean enable) {
// Temporarily hide the reader mode panel while fullscreen is enabled.
if (enable) {
mIsFullscreenModeEntered = true;
closeReaderPanel(StateChangeReason.FULLSCREEN_ENTERED, false);
} else {
mIsFullscreenModeEntered = false;
requestReaderPanelShow(StateChangeReason.FULLSCREEN_EXITED);
}
}
/**
* Logs how a state was exited for the first time within a Contextual Search.
* @param fromState The state to transition from.
* @param toState The state to transition to.
* @param reason The reason for the state transition.
*/
public static void logFirstStateExit(PanelState fromState, PanelState toState,
StateChangeReason reason) {
int code;
switch (fromState) {
case UNDEFINED:
case CLOSED:
code = getStateChangeCode(toState, reason,
EXIT_CLOSED_TO_STATE_CHANGE_CODES, EXIT_CLOSED_TO_OTHER);
RecordHistogram.recordEnumeratedHistogram(
"Search.ContextualSearchExitClosed", code, EXIT_CLOSED_TO_BOUNDARY);
break;
case PEEKED:
code = getStateChangeCode(toState, reason,
EXIT_PEEKED_TO_STATE_CHANGE_CODES, EXIT_PEEKED_TO_OTHER);
RecordHistogram.recordEnumeratedHistogram(
"Search.ContextualSearchExitPeeked", code, EXIT_PEEKED_TO_BOUNDARY);
break;
case EXPANDED:
code = getStateChangeCode(toState, reason,
EXIT_EXPANDED_TO_STATE_CHANGE_CODES, EXIT_EXPANDED_TO_OTHER);
RecordHistogram.recordEnumeratedHistogram(
"Search.ContextualSearchExitExpanded", code, EXIT_EXPANDED_TO_BOUNDARY);
break;
case MAXIMIZED:
code = getStateChangeCode(toState, reason,
EXIT_MAXIMIZED_TO_STATE_CHANGE_CODES, EXIT_MAXIMIZED_TO_OTHER);
RecordHistogram.recordEnumeratedHistogram(
"Search.ContextualSearchExitMaximized", code, EXIT_MAXIMIZED_TO_BOUNDARY);
break;
default:
break;
}
}
@Override
public void onLayoutChanged() {
if (isKeyboardShowing()) {
mIsKeyboardShowing = true;
closeReaderPanel(StateChangeReason.KEYBOARD_SHOWN, false);
} else if (mIsKeyboardShowing) {
mIsKeyboardShowing = false;
requestReaderPanelShow(StateChangeReason.KEYBOARD_HIDDEN);
}
}
@Override
public void onInfoBarContainerAttachedToWindow(boolean hasInfoBars) {
mIsInfoBarContainerShown = hasInfoBars;
if (mIsInfoBarContainerShown) {
closeReaderPanel(StateChangeReason.INFOBAR_SHOWN, false);
} else {
requestReaderPanelShow(StateChangeReason.INFOBAR_HIDDEN);
}
}
/**
* Logs how a state was entered for the first time within a Contextual Search.
* @param fromState The state to transition from.
* @param toState The state to transition to.
* @param reason The reason for the state transition.
*/
public static void logFirstStateEntry(PanelState fromState, PanelState toState,
StateChangeReason reason) {
int code;
switch (toState) {
case CLOSED:
code = getStateChangeCode(fromState, reason,
ENTER_CLOSED_STATE_CHANGE_CODES, ENTER_CLOSED_FROM_OTHER);
RecordHistogram.recordEnumeratedHistogram(
"Search.ContextualSearchEnterClosed",
code, ENTER_CLOSED_FROM_BOUNDARY);
break;
case PEEKED:
code = getStateChangeCode(fromState, reason,
ENTER_PEEKED_STATE_CHANGE_CODES, ENTER_PEEKED_FROM_OTHER);
RecordHistogram.recordEnumeratedHistogram(
"Search.ContextualSearchEnterPeeked",
code, ENTER_PEEKED_FROM_BOUNDARY);
break;
case EXPANDED:
code = getStateChangeCode(fromState, reason,
ENTER_EXPANDED_STATE_CHANGE_CODES, ENTER_EXPANDED_FROM_OTHER);
RecordHistogram.recordEnumeratedHistogram(
"Search.ContextualSearchEnterExpanded",
code, ENTER_EXPANDED_FROM_BOUNDARY);
break;
case MAXIMIZED:
code = getStateChangeCode(fromState, reason,
ENTER_MAXIMIZED_STATE_CHANGE_CODES, ENTER_MAXIMIZED_FROM_OTHER);
RecordHistogram.recordEnumeratedHistogram(
"Search.ContextualSearchEnterMaximized",
code, ENTER_MAXIMIZED_FROM_BOUNDARY);
break;
default:
break;
}
}
@Override
public void handleSelectionDismissal() {
if (mIsAccessibilityModeEnabled) return;
if (mSearchPanel.isShowing()
&& !mIsPromotingToTab
// If the selection is dismissed when the Panel is not peeking anymore,
// which means the Panel is at least partially expanded, then it means
// the selection was cleared by an external source (like JavaScript),
// so we should not dismiss the UI in here.
// See crbug.com/516665
&& mSearchPanel.isPeeking()) {
hideContextualSearch(StateChangeReason.CLEARED_SELECTION);
}
}
@Override
public boolean shouldInterceptNavigation(
ExternalNavigationHandler externalNavHandler, NavigationParams navigationParams) {
mTabRedirectHandler.updateNewUrlLoading(navigationParams.pageTransitionType,
navigationParams.isRedirect,
navigationParams.hasUserGesture || navigationParams.hasUserGestureCarryover,
mActivity.getLastUserInteractionTime(), TabRedirectHandler.INVALID_ENTRY_INDEX);
ExternalNavigationParams params =
new ExternalNavigationParams
.Builder(navigationParams.url, false, navigationParams.referrer,
navigationParams.pageTransitionType,
navigationParams.isRedirect)
.setApplicationMustBeInForeground(true)
.setRedirectHandler(mTabRedirectHandler)
.setIsMainFrame(navigationParams.isMainFrame)
.build();
if (externalNavHandler.shouldOverrideUrlLoading(params)
!= OverrideUrlLoadingResult.NO_OVERRIDE) {
mSearchPanel.maximizePanelThenPromoteToTab(StateChangeReason.TAB_PROMOTION,
INTERCEPT_NAVIGATION_PROMOTION_ANIMATION_DURATION_MS);
return false;
}
if (navigationParams.isExternalProtocol) {
return false;
}
return true;
}
/**
* Animates the Panel to its projected state, given a particular vertical |velocity|.
*
* @param velocity The velocity of the gesture in dps per second.
*/
protected void animateToProjectedState(float velocity) {
PanelState projectedState = getProjectedState(velocity);
final float displacement = getPanelHeightFromState(projectedState) - getHeight();
final long duration = calculateAnimationDuration(velocity, displacement);
animatePanelToState(projectedState, StateChangeReason.FLING, duration);
}