Index: chrome/android/java/src/org/chromium/chrome/browser/tab/TransitionPageHelper.java |
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TransitionPageHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/TransitionPageHelper.java |
deleted file mode 100644 |
index e97f8b50fe037c1f285e403d094166d0f3ef9196..0000000000000000000000000000000000000000 |
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/TransitionPageHelper.java |
+++ /dev/null |
@@ -1,951 +0,0 @@ |
-// Copyright 2015 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.chrome.browser.tab; |
- |
-import android.animation.Animator; |
-import android.animation.AnimatorListenerAdapter; |
-import android.animation.ObjectAnimator; |
-import android.annotation.TargetApi; |
-import android.app.Activity; |
-import android.app.ActivityOptions; |
-import android.content.Context; |
-import android.content.Intent; |
-import android.graphics.Rect; |
-import android.os.Build; |
-import android.os.Handler; |
-import android.util.Pair; |
-import android.view.View; |
-import android.widget.FrameLayout; |
- |
-import org.chromium.base.ActivityState; |
-import org.chromium.base.ApplicationStatus; |
-import org.chromium.base.ApplicationStatus.ActivityStateListener; |
-import org.chromium.base.CalledByNative; |
-import org.chromium.base.FieldTrialList; |
-import org.chromium.chrome.browser.ContentViewUtil; |
-import org.chromium.chrome.browser.EmptyTabObserver; |
-import org.chromium.chrome.browser.Tab; |
-import org.chromium.content.browser.ContentView; |
-import org.chromium.content.browser.ContentViewClient; |
-import org.chromium.content.browser.ContentViewCore; |
-import org.chromium.content_public.browser.JavaScriptCallback; |
-import org.chromium.content_public.browser.LoadUrlParams; |
-import org.chromium.content_public.browser.NavigationTransitionDelegate; |
-import org.chromium.content_public.browser.WebContentsObserver; |
-import org.chromium.ui.base.WindowAndroid; |
- |
-import java.util.ArrayList; |
- |
-/** |
- * Responsible for transition content view creation and management. |
- */ |
-public class TransitionPageHelper extends EmptyTabObserver { |
- private static final String TRANSITION_URL = "about:blank"; |
- |
- private static final int TRANSITION_MS = 300; |
- private static final int TRANSITION_DEFAULT_TIMEOUT = 500; |
- private static final int TRANSITION_DEFAULT_FRAMES = 2; |
- |
- // Transition state when the transition page is active. |
- private static final int STATE_NONE = 0; |
- private static final int STATE_TRANSITION_STARTING = 1; |
- private static final int STATE_WAIT_FOR_OUTGOING_UNLOADED = 2; |
- private static final int STATE_WAIT_FOR_INCOMING_DCL = 3; |
- private static final int STATE_UNLOAD_TRANSITION = 4; |
- private static final int STATE_WAIT_FOR_TRANSITION_UNLOAD = 5; |
- // Web to native app transition states |
- private static final int STATE_WAIT_FOR_FETCH_TRANSITION_ELEMENTS = 6; |
- private static final int STATE_WAIT_FOR_CURRENT_UNLOAD_TO_NATIVE_APP = 7; |
- private static final int STATE_WAIT_FOR_NAVIGATE_TO_NATIVE_APP = 8; |
- private static final int STATE_WAIT_FOR_BACK_FROM_NATIVE_APP = 9; |
- |
- // The activity associated with the tab. |
- private final Activity mActivity; |
- |
- // Native pointer corresponding to the current object. |
- private long mNativeTransitionPageHelperPtr; |
- |
- // The webcontents observer on current content view of the transition page. |
- private WebContentsObserver mTransitionObserver; |
- |
- // The webcontents observer on current content view of the tab. |
- private WebContentsObserver mSourceObserver; |
- |
- // The context used to create content view. |
- private final Context mContext; |
- |
- // Android window used to created content view. |
- private final WindowAndroid mWindowAndroid; |
- |
- // The transition content view created to display over the tab. |
- private ContentViewCore mTransitionContentViewCore; |
- |
- // The source content view being navigated. |
- private ContentViewCore mSourceContentViewCore; |
- |
- // The tab associated with the background view. |
- private final Tab mTab; |
- |
- // Set when the transition has had TRANSITION_MS ms to show. |
- private boolean mTransitionFinished; |
- |
- // Set once the incoming page is ready to be shown, either because it's |
- // fired DOMContentLoaded, or timed out. |
- private boolean mDestinationReady; |
- |
- // Set once the transition page has been painted. |
- private boolean mTransitionPainted; |
- |
- // Incremented when the transition page is painted. |
- private int mTransitionFramesPainted; |
- |
- // Set once the transition content view has fully loaded. |
- private boolean mTransitionLoaded; |
- |
- // Set once the transition page has been unloaded (stylesheets have been applied |
- // and TRANSITION_MS ms have passed). |
- private boolean mTransitionUnloaded; |
- |
- // Set once the incoming page has signalled that it's received bytes and has |
- // paused the navigation. |
- private boolean mDestinationReadyToResume; |
- |
- // Set once the incoming page has been painted. |
- private boolean mDestinationPainted; |
- |
- // Set once the incoming page has signaled DOMContentLoaded. |
- private boolean mDestinationDOMContentLoaded; |
- |
- // Set once current page starts navigation transition to the native app. |
- private boolean mTransitionToNativeApp; |
- |
- // Set once current page has been unloaded (exit transitions have been applied and |
- // TRANSITION_MS ms have passed). |
- private boolean mCurrentUnloadedToNativeApp; |
- |
- // Set once current page has finished navigation to the native app. |
- private boolean mNavigateToNativeAppFinished; |
- |
- // Set once current page is back from the native app. |
- private boolean mBackFromNativeApp; |
- |
- // The id of the main frame of the navigating page. |
- private long mDestinationMainFrameID; |
- |
- // An array of stylesheet URL's to apply to the transition page. |
- private final ArrayList<String> mTransitionStylesheets; |
- |
- // The background colour of the incoming app. |
- private String mTransitionColor; |
- |
- // The CSS selector that selects the transition elements of the source page. |
- private String mCSSSelector; |
- |
- // The background of the outgoing app. |
- private String mSourceColor; |
- |
- // The current state of the transition. |
- private int mState; |
- |
- // The current visibility state of the transition page. |
- private boolean mVisible; |
- |
- // The current opacity of the transition page. |
- private float mOpacity; |
- |
- // Used to animate the opacity when fading the transition page. |
- private final ObjectAnimator mAnimator; |
- |
- private final Handler mHandler; |
- |
- // The Intent URL used during web to native app navigation transitions. |
- private String mIntentUrl; |
- |
- // The Intent used during web to native app navigation transitions. |
- private Intent mIntent; |
- |
- // The offset of the visible content. |
- private int mVisibleContentOffset; |
- |
- // The transition elements. |
- private ArrayList<TransitionElement> mTransitionElements; |
- |
- // The Views for the transition elements. |
- private ArrayList<TransitionElementView> mTransitionElementViews; |
- |
- // Set once the transition elements are fetched. |
- private boolean mTransitionElementsFetched; |
- |
- // Used to check if the transition elements are visible. |
- private boolean mTransitionElementVisible; |
- |
- private ActivityStateListener mActivityStateListener = new ActivityStateListener() { |
- @Override |
- public void onActivityStateChange(Activity activity, int newState) { |
- assert activity == mActivity; |
- |
- if (newState == ActivityState.RESUMED) { |
- backFromNativeAppOnResume(); |
- } else if (newState == ActivityState.STARTED) { |
- backFromNativeAppOnStart(); |
- } |
- } |
- }; |
- |
- private static class TransitionElement { |
- // Transition element's name. |
- private final String mName; |
- |
- // Transition element's position and size. |
- private final Rect mRect; |
- |
- public TransitionElement(String name, Rect rect) { |
- mName = name; |
- mRect = rect; |
- } |
- |
- public String name() { |
- return mName; |
- } |
- |
- public Rect rect() { |
- return mRect; |
- } |
- } |
- |
- @TargetApi(Build.VERSION_CODES.LOLLIPOP) |
- private class TransitionElementView extends View { |
- public TransitionElementView(Context context) { |
- super(context); |
- } |
- |
- @Override |
- public void setAlpha(float alpha) { |
- if (mCSSSelector != null) { |
- if (!mTransitionElementVisible && Float.compare(alpha, 0) != 0) { |
- mTransitionElementVisible = true; |
- mSourceContentViewCore.getWebContents().showTransitionElements(mCSSSelector); |
- |
- // This is a hack. May only work on Android 5.0. |
- // Delay 150ms. We need to wait for the CSS opacity property to take effect |
- // before hiding the view. Thread.sleep(150ms) does not work because it pauses |
- // the whole UI thread, including the CSS opacity effect. In Android 5.0, |
- // Activity Transitions uses 3 postOnAnimation()s to delay hiding the view for |
- // double-buffering. So we can add more delays there and give the run loop |
- // chances to push frames. |
- // Reference - Android 5.0 Lollipop source code: |
- // frameworks/base/core/java/android/app/EnterTransitionCoordinator.java |
- // - startSharedElementTransition() |
- postOnAnimation(new Runnable() { |
- static final int MIN_ANIMATION_FRAMES = 3; |
- int mIterations = 0; |
- @Override |
- public void run() { |
- try { |
- Thread.sleep(50); |
- } catch (InterruptedException e) { |
- // Ignore |
- } |
- mIterations++; |
- if (mIterations < MIN_ANIMATION_FRAMES) { |
- postOnAnimation(this); |
- } |
- } |
- }); |
- } else if (mTransitionElementVisible && Float.compare(alpha, 0) == 0) { |
- mTransitionElementVisible = false; |
- mSourceContentViewCore.getWebContents().hideTransitionElements(mCSSSelector); |
- } |
- } |
- super.setAlpha(alpha); |
- } |
- } |
- |
- /** |
- * Creates an instance of TransitionPageHelper. |
- * @param activity An instance of a {@link Activity}. |
- * @param windowAndroid An instance of a {@link WindowAndroid}. |
- * @param tab The {@link Tab} associated with current background view. |
- */ |
- public TransitionPageHelper(Activity activity, WindowAndroid windowAndroid, Tab tab) { |
- mActivity = activity; |
- mContext = activity.getApplicationContext(); |
- mWindowAndroid = windowAndroid; |
- mTab = tab; |
- mTab.addObserver(this); |
- |
- mNativeTransitionPageHelperPtr = nativeInit(); |
- mHandler = new Handler(); |
- mTransitionStylesheets = new ArrayList<String>(); |
- mTransitionElements = new ArrayList<TransitionElement>(); |
- mTransitionElementViews = new ArrayList<TransitionElementView>(); |
- mTransitionElementVisible = true; |
- mAnimator = ObjectAnimator.ofFloat(this, "transitionOpacity", 1.0f, 0.0f); |
- mAnimator.setDuration(TRANSITION_MS); |
- mAnimator.addListener(new AnimatorListenerAdapter() { |
- @Override |
- public void onAnimationEnd(Animator animation) { |
- if (mTransitionContentViewCore != null) { |
- mTransitionContentViewCore.onHide(); |
- } |
- mTransitionUnloaded = true; |
- updateState(); |
- } |
- }); |
- ApplicationStatus.registerStateListenerForActivity(mActivityStateListener, mActivity); |
- |
- // Access the field trial so that it gets saved. |
- FieldTrialList.findFullName("NavigationTransitions"); |
- |
- resetTransitionState(); |
- } |
- |
- /** |
- * @return The {@link ContentViewCore} associated with the transition page. |
- */ |
- public ContentViewCore getTransitionContentViewCore() { |
- return mTransitionContentViewCore; |
- } |
- |
- /** |
- * Destroys the content view and the corresponding native object. |
- */ |
- private void destroy() { |
- if (mNativeTransitionPageHelperPtr == 0) return; |
- |
- ApplicationStatus.unregisterActivityStateListener(mActivityStateListener); |
- |
- teardownNavigation(); |
- |
- if (mSourceObserver != null) { |
- mSourceObserver.destroy(); |
- mSourceObserver = null; |
- } |
- |
- nativeDestroy(mNativeTransitionPageHelperPtr); |
- mNativeTransitionPageHelperPtr = 0; |
- } |
- |
- /** |
- * @return True iff a navigation transition is currently underway. |
- */ |
- public boolean isTransitionRunning() { |
- return mState != STATE_NONE; |
- } |
- |
- /** |
- * Schedules a default timeout to signal if we haven't seen enough frames painted. |
- */ |
- private void scheduleTransitionFramesTimeout() { |
- mHandler.postDelayed(new Runnable() { |
- @Override |
- public void run() { |
- mTransitionFramesPainted = TRANSITION_DEFAULT_FRAMES; |
- updateState(); |
- } |
- }, TRANSITION_DEFAULT_TIMEOUT); |
- } |
- |
- /** |
- * Notifies the outgoing page that the transition elements have been shown, |
- * and posts a task to wait TRANSITION_MS ms for it to run. |
- */ |
- private void scheduleCurrentToUnload() { |
- mHandler.postDelayed( |
- new Runnable() { |
- @Override |
- public void run() { |
- mTransitionFinished = true; |
- mTransitionContentViewCore.getWebContents().insertCSS(String.format( |
- "@-webkit-keyframes __transition_crossfade {" |
- + "from {background: %s; }%n" |
- + "to {background: %s; }}%n" |
- + "-webkit-animation: __transition_crossfade %dms forwards;", |
- mSourceColor, mTransitionColor, TRANSITION_MS)); |
- scheduleTransitionFramesTimeout(); |
- updateState(); |
- } |
- }, TRANSITION_MS); |
- |
- setTransitionVisibility(true); |
- setTransitionOpacity(1.0f); |
- |
- if (mTransitionContentViewCore != null && mSourceContentViewCore != null) { |
- // Notify the outgoing page that the transition elements have |
- // been shown in the transition page, so that they can be hidden |
- // in the outgoing page. |
- mSourceContentViewCore.getWebContents().beginExitTransition(mCSSSelector, false); |
- } |
- |
- applyTransitionStylesheets(); |
- } |
- |
- /** |
- * Adds the transition stylesheets to the document. |
- */ |
- private void applyTransitionStylesheets() { |
- for (int i = 0; i < mTransitionStylesheets.size(); i++) { |
- mTransitionContentViewCore.getWebContents().addStyleSheetByURL( |
- mTransitionStylesheets.get(i)); |
- } |
- } |
- |
- /** |
- * Smoothly fades out the transition page to cover up any per-pixel |
- * imperfections. |
- */ |
- private void fadeOutTransition() { |
- mAnimator.start(); |
- } |
- |
- /** |
- * Handles the current state of the transition state machine. The state |
- * machine has two routes. The first one is web-to-web transition and the |
- * second one is web-to-native-app transition. Both routes start with |
- * STATE_TRANSITION_STARTING. |
- */ |
- private void updateState() { |
- // Web to web transition state machine |
- if (mState == STATE_TRANSITION_STARTING) { |
- // Transition page hasn't been shown yet. If it's ready to go, show |
- // it and we can move on to waiting 300 ms for outgoing page to |
- // unload. |
- if (mTransitionPainted && mTransitionLoaded) { |
- scheduleCurrentToUnload(); |
- mState = STATE_WAIT_FOR_OUTGOING_UNLOADED; |
- } |
- } else if (mState == STATE_WAIT_FOR_OUTGOING_UNLOADED) { |
- // Outgoing page gets 300 ms to unload. Once that's done, we can |
- // resume navigation, assuming the incoming page is ready to |
- // to navigate. |
- if (mDestinationReadyToResume && mTransitionFinished |
- && mTransitionFramesPainted >= TRANSITION_DEFAULT_FRAMES) { |
- if (mSourceContentViewCore != null) { |
- mSourceContentViewCore.getWebContents().resumeResponseDeferredAtStart(); |
- } |
- mState = STATE_WAIT_FOR_INCOMING_DCL; |
- updateState(); |
- } |
- } else if (mState == STATE_WAIT_FOR_INCOMING_DCL) { |
- // Once the navigation is resumed, we wait until we get the |
- // DOMContentLoaded signal from the incoming page before starting |
- // to unload the transition page. |
- if (mDestinationReady) { |
- mState = STATE_UNLOAD_TRANSITION; |
- updateState(); |
- } |
- } else if (mState == STATE_UNLOAD_TRANSITION) { |
- // Once the transition page is unloaded, need to give it 300 ms |
- // to fade out to hide any per-pixel positioning differences. |
- fadeOutTransition(); |
- mState = STATE_WAIT_FOR_TRANSITION_UNLOAD; |
- } else if (mState == STATE_WAIT_FOR_TRANSITION_UNLOAD) { |
- // Wait until the fade is done and tear down the transition page. |
- if (mTransitionUnloaded) { |
- teardownNavigation(); |
- mState = STATE_NONE; |
- } |
- } |
- |
- // Web to native app transition state machine |
- if (mState == STATE_TRANSITION_STARTING) { |
- if (mTransitionToNativeApp) { |
- mState = STATE_WAIT_FOR_FETCH_TRANSITION_ELEMENTS; |
- fetchTransitionElements(); |
- } |
- } else if (mState == STATE_WAIT_FOR_FETCH_TRANSITION_ELEMENTS) { |
- if (mTransitionElementsFetched) { |
- mState = STATE_WAIT_FOR_CURRENT_UNLOAD_TO_NATIVE_APP; |
- scheduleCurrentToUnloadToNativeApp(); |
- } |
- } else if (mState == STATE_WAIT_FOR_CURRENT_UNLOAD_TO_NATIVE_APP) { |
- if (mCurrentUnloadedToNativeApp) { |
- mState = STATE_WAIT_FOR_NAVIGATE_TO_NATIVE_APP; |
- navigateToNativeApp(); |
- } |
- } else if (mState == STATE_WAIT_FOR_NAVIGATE_TO_NATIVE_APP) { |
- if (mNavigateToNativeAppFinished) { |
- mState = STATE_WAIT_FOR_BACK_FROM_NATIVE_APP; |
- } |
- } else if (mState == STATE_WAIT_FOR_BACK_FROM_NATIVE_APP) { |
- if (mBackFromNativeApp) { |
- cleanUpBackFromNativeApp(); |
- teardownNavigation(); |
- mState = STATE_NONE; |
- } |
- } |
- } |
- |
- /** |
- * Notifies any listeners of opacity changes. |
- */ |
- private void setTransitionOpacity(float opacity) { |
- mOpacity = opacity; |
- |
- nativeSetOpacity(mNativeTransitionPageHelperPtr, mTransitionContentViewCore, opacity); |
- } |
- |
- /** |
- * Notifies any listeners of visibility changes. |
- */ |
- private void setTransitionVisibility(boolean visible) { |
- mVisible = visible; |
- |
- if (mTransitionContentViewCore != null) mTransitionContentViewCore.setDrawsContent(visible); |
- } |
- |
- /** |
- * @return The visibility state of the transition page. |
- */ |
- public boolean isTransitionVisible() { |
- return mVisible; |
- } |
- |
- /** |
- * @return The opacity of the transition page. |
- */ |
- public float getTransitionOpacity() { |
- return mOpacity; |
- } |
- |
- /** |
- * Called when a transition navigation is initiated to reset values to their defaults. |
- */ |
- private void resetTransitionState() { |
- mTransitionUnloaded = false; |
- mTransitionFinished = false; |
- mDestinationReady = false; |
- mDestinationReadyToResume = false; |
- mDestinationPainted = false; |
- mDestinationDOMContentLoaded = false; |
- mDestinationMainFrameID = -1; |
- mTransitionPainted = false; |
- mTransitionFramesPainted = 0; |
- mTransitionLoaded = false; |
- mState = STATE_NONE; |
- mVisible = false; |
- mOpacity = 0.0f; |
- mTransitionStylesheets.clear(); |
- mTransitionColor = null; |
- mCSSSelector = null; |
- mAnimator.cancel(); |
- mTransitionElements.clear(); |
- mTransitionElementsFetched = false; |
- removeTransitionElementViewsFromLayout(); |
- mTransitionElementVisible = true; |
- mTransitionToNativeApp = false; |
- mCurrentUnloadedToNativeApp = false; |
- mNavigateToNativeAppFinished = false; |
- mBackFromNativeApp = false; |
- mIntentUrl = null; |
- mIntent = null; |
- if (mSourceContentViewCore != null) { |
- mVisibleContentOffset = mSourceContentViewCore.getViewportSizeOffsetHeightPix(); |
- } |
- } |
- |
- /** |
- * Called when a transition navigation is initiated. Creates a new transition |
- * content view and resets the state machine. |
- */ |
- private void startTransitionNavigation() { |
- if (mState != STATE_NONE) return; |
- |
- teardownNavigation(); |
- resetTransitionState(); |
- |
- mState = STATE_TRANSITION_STARTING; |
- |
- buildContentView(); |
- |
- // Grab the background color from the outgoing page, so we can add it |
- // to the transition layer. |
- JavaScriptCallback jsCallback = new JavaScriptCallback() { |
- @Override |
- public void handleJavaScriptResult(String jsonResult) { |
- mSourceColor = jsonResult.replaceAll("\"", ""); |
- } |
- }; |
- |
- String script = "getComputedStyle(document.body).backgroundColor"; |
- mSourceContentViewCore.getWebContents().evaluateJavaScript(script, jsCallback); |
- } |
- |
- /** |
- * Detaches any observers and destroys the transition content view. |
- */ |
- private void teardownNavigation() { |
- mHandler.removeCallbacksAndMessages(null); |
- if (mNativeTransitionPageHelperPtr == 0) return; |
- |
- if (mTransitionObserver != null) { |
- mTransitionObserver.destroy(); |
- mTransitionObserver = null; |
- } |
- if (mTransitionContentViewCore != null) { |
- if (mTab != null) mTab.detachOverlayContentViewCore(mTransitionContentViewCore); |
- mTransitionContentViewCore.destroy(); |
- mTransitionContentViewCore = null; |
- nativeReleaseWebContents(mNativeTransitionPageHelperPtr); |
- } |
- mState = STATE_NONE; |
- } |
- |
- /** |
- * Creates a new transition content view and notifies listeners. |
- */ |
- private void buildContentView() { |
- if (mNativeTransitionPageHelperPtr == 0) return; |
- |
- mTransitionContentViewCore = new ContentViewCore(mContext); |
- ContentView cv = new ContentView(mContext, mTransitionContentViewCore); |
- mTransitionContentViewCore.initialize(cv, cv, |
- ContentViewUtil.createWebContentsWithSharedSiteInstance(mSourceContentViewCore), |
- mWindowAndroid); |
- |
- // The renderer should be set with the height considering the top controls(non-fullscreen |
- // mode). |
- mTransitionContentViewCore.setTopControlsHeight( |
- mTransitionContentViewCore.getTopControlsHeightPix(), true); |
- |
- mTransitionObserver = createTransitionObserver(); |
- |
- if (mTab != null) mTab.attachOverlayContentViewCore(mTransitionContentViewCore, true, true); |
- |
- nativeSetWebContents(mNativeTransitionPageHelperPtr, mTransitionContentViewCore); |
- setTransitionOpacity(0.0f); |
- |
- mTransitionContentViewCore.setContentViewClient(new ContentViewClient() { |
- @Override |
- public void onOffsetsForFullscreenChanged( |
- float topControlsOffsetYPix, |
- float contentOffsetYPix, |
- float overdrawBottomHeightPix) { |
- if (mState != STATE_WAIT_FOR_OUTGOING_UNLOADED) return; |
- |
- if (mTransitionContentViewCore.getContentWidthCss() |
- == mTab.getContentViewCore().getContentWidthCss()) { |
- mTransitionFramesPainted++; |
- updateState(); |
- } |
- } |
- }); |
- } |
- |
- /** |
- * Creates an observer for the transition web contents, and listens specifically |
- * for paint and loading events. |
- */ |
- private WebContentsObserver createTransitionObserver() { |
- return new WebContentsObserver(mTransitionContentViewCore.getWebContents()) { |
- @Override |
- public void didFirstVisuallyNonEmptyPaint() { |
- if (!mTransitionPainted) { |
- mTransitionPainted = true; |
- updateState(); |
- } |
- } |
- |
- @Override |
- public void didFinishLoad(long frameId, String validatedUrl, boolean isMainFrame) { |
- if (isMainFrame) { |
- mTransitionLoaded = true; |
- updateState(); |
- } |
- } |
- }; |
- } |
- |
- /** |
- * Creates an observer for the tab's web contents, and listens specifically |
- * for transition, paint, and DOMContentLoaded events. |
- */ |
- private WebContentsObserver createSourceObserver() { |
- return new WebContentsObserver(mSourceContentViewCore.getWebContents()) { |
- private void signalDestinationMaybeReady() { |
- if ((mDestinationDOMContentLoaded && mDestinationPainted) && !mDestinationReady) { |
- mDestinationReady = true; |
- updateState(); |
- } |
- } |
- |
- @Override |
- public void didFirstVisuallyNonEmptyPaint() { |
- mDestinationPainted = true; |
- signalDestinationMaybeReady(); |
- } |
- |
- @Override |
- public void documentLoadedInFrame(long frameId) { |
- if (frameId == mDestinationMainFrameID) { |
- mDestinationDOMContentLoaded = true; |
- signalDestinationMaybeReady(); |
- mHandler.postDelayed( |
- new Runnable() { |
- @Override |
- public void run() { |
- mDestinationPainted = true; |
- signalDestinationMaybeReady(); |
- } |
- }, TRANSITION_DEFAULT_TIMEOUT); |
- } |
- } |
- |
- @Override |
- public void didFailLoad(boolean isProvisionalLoad, |
- boolean isMainFrame, int errorCode, String description, String failingUrl) { |
- // Just consider a failed load as the destination is ready. The transition |
- // page will fade out naturally. |
- if (isMainFrame) { |
- mDestinationReady = true; |
- updateState(); |
- } |
- } |
- }; |
- } |
- |
- @Override |
- public void onContentChanged(Tab tab) { |
- if (tab == mTab) { |
- if (mSourceContentViewCore != null && mSourceContentViewCore.getWebContents() != null) { |
- mSourceContentViewCore.getWebContents().setNavigationTransitionDelegate(null); |
- } |
- |
- mSourceContentViewCore = tab.getContentViewCore(); |
- |
- if (mSourceObserver != null) { |
- mSourceObserver.destroy(); |
- mSourceObserver = null; |
- } |
- |
- if (mSourceContentViewCore == null) return; |
- |
- mSourceObserver = createSourceObserver(); |
- mSourceContentViewCore.getWebContents().setNavigationTransitionDelegate( |
- new NavigationTransitionDelegate() { |
- @Override |
- public void didDeferAfterResponseStarted(String markup, String cssSelector, |
- String color) { |
- if (mTransitionContentViewCore != null && isTransitionRunning()) { |
- mDestinationReadyToResume = true; |
- |
- LoadUrlParams navigationParams = new LoadUrlParams(TRANSITION_URL); |
- |
- mTransitionContentViewCore.getWebContents() |
- .getNavigationController().loadUrl(navigationParams); |
- mTransitionContentViewCore.setBackgroundOpaque(false); |
- mTransitionContentViewCore.getWebContents().setupTransitionView( |
- markup); |
- mTransitionContentViewCore.onShow(); |
- |
- setTransitionOpacity(0.0f); |
- setTransitionVisibility(false); |
- |
- mTransitionColor = color; |
- mCSSSelector = cssSelector; |
- } |
- } |
- |
- @Override |
- public void didStartNavigationTransitionForFrame(long frameId) { |
- startTransitionNavigation(); |
- mDestinationMainFrameID = frameId; |
- } |
- |
- @Override |
- public boolean willHandleDeferAfterResponseStarted() { |
- return true; |
- } |
- |
- @Override |
- public void addEnteringStylesheetToTransition(String stylesheet) { |
- if (mTransitionContentViewCore != null && isTransitionRunning()) { |
- mTransitionStylesheets.add(stylesheet); |
- } |
- } |
- |
- @Override |
- public void addNavigationTransitionElements( |
- String name, int x, int y, int width, int height) { |
- if (isTransitionRunning()) { |
- Rect rect = new Rect(x, y, x + width, y + height); |
- TransitionElement element = new TransitionElement(name, rect); |
- mTransitionElements.add(element); |
- } |
- } |
- |
- @Override |
- public void onTransitionElementsFetched(String cssSelector) { |
- if (isTransitionRunning()) { |
- mCSSSelector = cssSelector; |
- mTransitionElementsFetched = true; |
- updateState(); |
- } |
- } |
- }); |
- } |
- } |
- |
- @Override |
- public void onDestroyed(Tab tab) { |
- if (tab == mTab) { |
- destroy(); |
- } |
- } |
- |
- /** |
- * Check Whether transition is starting. |
- * @return Whether the transition is starting. |
- */ |
- public boolean isTransitionStarting() { |
- return mState == STATE_TRANSITION_STARTING; |
- } |
- |
- /** |
- * Transition to native app. This is the starting point of the web-to-native-app navigation |
- * transitions. |
- * @param url The Intent URL of the native app. |
- * @param intent The Intent of the native app. |
- */ |
- public void transitionToNativeApp(String url, Intent intent) { |
- if (!isTransitionStarting()) return; |
- mIntentUrl = url; |
- mIntent = intent; |
- mTransitionToNativeApp = true; |
- updateState(); |
- } |
- |
- private void fetchTransitionElements() { |
- mSourceContentViewCore.getWebContents().fetchTransitionElements(mIntentUrl); |
- } |
- |
- private void scheduleCurrentToUnloadToNativeApp() { |
- // Let the exit transition run for TRANSITION_MS. |
- mHandler.postDelayed(new Runnable() { |
- @Override |
- public void run() { |
- mCurrentUnloadedToNativeApp = true; |
- updateState(); |
- } |
- }, TRANSITION_MS); |
- |
- if (mSourceContentViewCore != null) { |
- mSourceContentViewCore.getWebContents().beginExitTransition(mCSSSelector, true); |
- } |
- } |
- |
- @TargetApi(Build.VERSION_CODES.LOLLIPOP) |
- private void navigateToNativeApp() { |
- FrameLayout rootContentView = (FrameLayout) mActivity.findViewById(android.R.id.content); |
- @SuppressWarnings("unchecked") |
- Pair<View, String>[] sharedElements = new Pair[mTransitionElements.size()]; |
- for (int i = 0; i < mTransitionElements.size(); i++) { |
- // Create TransitionElementViews and add them to the root view |
- Rect r = mTransitionElements.get(i).rect(); |
- int left = convertPagePxToDpi(r.left); |
- int top = convertPagePxToDpi(r.top) + mVisibleContentOffset; |
- int right = convertPagePxToDpi(r.right); |
- int bottom = convertPagePxToDpi(r.bottom) + mVisibleContentOffset; |
- FrameLayout.LayoutParams layoutParams = |
- new FrameLayout.LayoutParams(right - left, bottom - top); |
- layoutParams.setMargins(left, top, right, bottom); |
- |
- TransitionElementView v = new TransitionElementView(mActivity); |
- v.setId(View.generateViewId()); |
- v.setTransitionName(mTransitionElements.get(i).name()); |
- // Both setLayoutParams() and setLeft() etc are needed when setting the position and |
- // size. |
- v.setLayoutParams(layoutParams); |
- v.setLeft(left); |
- v.setTop(top); |
- v.setRight(right); |
- v.setBottom(bottom); |
- |
- rootContentView.addView(v); |
- mTransitionElementViews.add(v); |
- sharedElements[i] = Pair.create((View) v, mTransitionElements.get(i).name()); |
- } |
- ActivityOptions activityOptions = |
- ActivityOptions.makeSceneTransitionAnimation(mActivity, sharedElements); |
- // Remove FLAG_ACTIVITY_NEW_TASK. |
- int flags = mIntent.getFlags(); |
- flags &= ~Intent.FLAG_ACTIVITY_NEW_TASK; |
- mIntent.setFlags(flags); |
- mActivity.startActivity(mIntent, activityOptions.toBundle()); |
- transitionToNativeAppFinished(); |
- } |
- |
- /** |
- * The web page is now transitioned to the native app. Set the tab to be covered by the native |
- * app and update the state machine. |
- */ |
- public void transitionToNativeAppFinished() { |
- if (mState != STATE_WAIT_FOR_NAVIGATE_TO_NATIVE_APP) return; |
- mNavigateToNativeAppFinished = true; |
- mTab.setCoveredByChildActivity(true); |
- updateState(); |
- } |
- |
- /** |
- * The web page is back from the native app when Chrome is in onStart() stage. Revert the exit |
- * transitions. |
- */ |
- public void backFromNativeAppOnStart() { |
- if (mState != STATE_WAIT_FOR_BACK_FROM_NATIVE_APP) return; |
- if (mSourceContentViewCore != null) { |
- mSourceContentViewCore.getWebContents().revertExitTransition(); |
- } |
- } |
- |
- /** |
- * The web page is back from the native app when Chrome is in onResume() stage. Set the tab to |
- * be uncovered by the native app and update the state machine. |
- */ |
- public void backFromNativeAppOnResume() { |
- if (mState != STATE_WAIT_FOR_BACK_FROM_NATIVE_APP) return; |
- mTab.setCoveredByChildActivity(false); |
- mBackFromNativeApp = true; |
- updateState(); |
- } |
- |
- private void cleanUpBackFromNativeApp() { |
- // Currently there is data left in TransitionRequestManager. We need to |
- // clear them to get correct future navigation behavior. |
- mSourceContentViewCore.getWebContents().clearNavigationTransitionData(); |
- removeTransitionElementViewsFromLayout(); |
- } |
- |
- private void removeTransitionElementViewsFromLayout() { |
- // Remove the TransitionElementViews from the layout's view hierarchy. |
- FrameLayout rootContentView = (FrameLayout) mActivity.findViewById(android.R.id.content); |
- for (int i = 0; i < mTransitionElementViews.size(); i++) { |
- rootContentView.removeView(mTransitionElementViews.get(i)); |
- } |
- mTransitionElementViews.clear(); |
- } |
- |
- /** |
- * Convert page pixels to dpis. |
- * @param pagePixel Page pixel value from the renderer. |
- * @return Page pixel in dpis. |
- */ |
- private int convertPagePxToDpi(int pagePixel) { |
- float scale = mActivity.getResources().getDisplayMetrics().density; |
- return (int) Math.ceil(pagePixel * scale); |
- } |
- |
- @CalledByNative |
- private long getNativePtr() { |
- return mNativeTransitionPageHelperPtr; |
- } |
- |
- private native long nativeInit(); |
- private native void nativeDestroy(long nativeTransitionPageHelper); |
- private native void nativeSetWebContents(long nativeTransitionPageHelper, |
- ContentViewCore contentViewCore); |
- private native void nativeReleaseWebContents(long nativeTransitionPageHelper); |
- private native void nativeSetOpacity(long nativeTransitionPageHelper, |
- ContentViewCore contentViewCore, float opacity); |
-} |