/** * Animate opening a tab in the foreground. * * @param id The id of the new tab to animate. * @param sourceId The id of the tab that spawned this new tab. * @param newIsIncognito true if the new tab is an incognito tab. * @param originX The X coordinate of the last touch down event that spawned this tab. * @param originY The Y coordinate of the last touch down event that spawned this tab. */ private void tabCreatedInForeground( int id, int sourceId, boolean newIsIncognito, float originX, float originY) { LayoutTab newLayoutTab = createLayoutTab(id, newIsIncognito, NO_CLOSE_BUTTON, NO_TITLE); if (mLayoutTabs == null || mLayoutTabs.length == 0) { mLayoutTabs = new LayoutTab[] {newLayoutTab}; } else { mLayoutTabs = new LayoutTab[] {mLayoutTabs[0], newLayoutTab}; } updateCacheVisibleIds(new LinkedList<Integer>(Arrays.asList(id, sourceId))); newLayoutTab.setBorderAlpha(0.0f); newLayoutTab.setStaticToViewBlend(1.f); forceAnimationToFinish(); Interpolator interpolator = BakedBezierInterpolator.TRANSFORM_CURVE; addToAnimation( newLayoutTab, LayoutTab.Property.SCALE, 0.f, 1.f, FOREGROUND_ANIMATION_DURATION, 0, false, interpolator); addToAnimation( newLayoutTab, LayoutTab.Property.ALPHA, 0.f, 1.f, FOREGROUND_ANIMATION_DURATION, 0, false, interpolator); addToAnimation( newLayoutTab, LayoutTab.Property.X, originX, 0.f, FOREGROUND_ANIMATION_DURATION, 0, false, interpolator); addToAnimation( newLayoutTab, LayoutTab.Property.Y, originY, 0.f, FOREGROUND_ANIMATION_DURATION, 0, false, interpolator); mTabModelSelector.selectModel(newIsIncognito); startHiding(id, false); }
@Override protected void updateLayout(long time, long dt) { super.updateLayout(time, dt); if (mBaseTab == null) return; mBaseTab.setY(mSearchPanel.getBasePageY()); mBaseTab.setBrightness(mSearchPanel.getBasePageBrightness()); boolean needUpdate = mBaseTab.updateSnap(dt); if (needUpdate) requestUpdate(); }
private void ensureSourceTabCreated(int sourceTabId) { if (mLayoutTabs != null && mLayoutTabs.length == 1 && mLayoutTabs[0].getId() == sourceTabId) { return; } // Just draw the source tab on the screen. TabModel sourceModel = mTabModelSelector.getModelForTabId(sourceTabId); if (sourceModel == null) return; LayoutTab sourceLayoutTab = createLayoutTab(sourceTabId, sourceModel.isIncognito(), NO_CLOSE_BUTTON, NO_TITLE); sourceLayoutTab.setBorderAlpha(0.0f); mLayoutTabs = new LayoutTab[] {sourceLayoutTab}; updateCacheVisibleIds(new LinkedList<Integer>(Arrays.asList(sourceTabId))); }
@Override protected void hideContextualSearch(boolean immediately) { if (isActive() && mBaseTab != null) { startHiding(mBaseTab.getId(), false); if (immediately) doneHiding(); } }
/** * Creates the Base Page's LayoutTab to be presented in the screen. * * @param layoutTab The {@link Layout} instance. */ private void createBaseLayoutTab(LayoutTab layoutTab) { if (mTabModelSelector == null) return; int baseTabId = mTabModelSelector.getCurrentTabId(); if (baseTabId == Tab.INVALID_TAB_ID) return; mBaseTab = createLayoutTab( baseTabId, mTabModelSelector.isIncognitoSelected(), NO_CLOSE_BUTTON, NO_TITLE); assert mBaseTab != null; mBaseTab.setScale(1.f); mBaseTab.setBorderScale(1.f); mBaseTab.setBorderAlpha(0.f); mLayoutTabs = new LayoutTab[] {mBaseTab}; }
@Override protected void updateSceneLayer( Rect viewport, Rect contentViewport, LayerTitleCache layerTitleCache, TabContentManager tabContentManager, ResourceManager resourceManager, ChromeFullscreenManager fullscreenManager) { super.updateSceneLayer( viewport, contentViewport, layerTitleCache, tabContentManager, resourceManager, fullscreenManager); assert mSceneLayer != null; final LayoutTab[] tabs = getLayoutTabsToRender(); if (tabs == null || tabs.length != 1 || tabs[0].getId() == Tab.INVALID_TAB_ID) { return; } LayoutTab layoutTab = tabs[0]; final float dpToPx = getContext().getResources().getDisplayMetrics().density; mReaderModeSceneLayer.update(mReaderModePanel, resourceManager); mSceneLayer.update( dpToPx, contentViewport, layerTitleCache, tabContentManager, fullscreenManager, layoutTab); // TODO(pedrosimonetti): Coordinate w/ dtrainor@ to improve integration with TreeProvider. SceneLayer overlayLayer = null; if (mSearchPanel.isShowing()) { overlayLayer = super.getSceneLayer(); } else if (mReaderModePanel != null && mReaderModePanel.isShowing()) { overlayLayer = mReaderModeSceneLayer; } mSceneLayer.setContentSceneLayer(overlayLayer); // TODO(dtrainor): Find the best way to properly track this metric for cold starts. // We should probably erase the thumbnail when we select a tab that we need to restore. if (tabContentManager != null && tabContentManager.hasFullCachedThumbnail(layoutTab.getId())) { TabModelBase.logPerceivedTabSwitchLatencyMetric(); } }
@Override public boolean handlesTabCreating() { // Prevents the new Tab animation from happening when promoting to a new Tab. startHiding(mBaseTab.getId(), false); doneHiding(); // Updates TopControls' State so the Toolbar becomes visible. // TODO(pedrosimonetti): The transition when promoting to a new tab is only smooth // if the SearchContentView's vertical scroll position is zero. Otherwise the // ContentView will appear to jump in the screen. Coordinate with @dtrainor to solve // this problem. mSearchPanel.getManagementDelegate().updateTopControlsState(TopControlsState.BOTH, false); return true; }
/** Animate the closing of a tab */ @Override public void onTabClosed(long time, int id, int nextId, boolean incognito) { super.onTabClosed(time, id, nextId, incognito); if (mClosedTab != null) { TabModel nextModel = mTabModelSelector.getModelForTabId(nextId); if (nextModel != null) { LayoutTab nextLayoutTab = createLayoutTab(nextId, nextModel.isIncognito(), NO_CLOSE_BUTTON, NO_TITLE); nextLayoutTab.setDrawDecoration(false); mLayoutTabs = new LayoutTab[] {nextLayoutTab, mClosedTab}; updateCacheVisibleIds(new LinkedList<Integer>(Arrays.asList(nextId, mClosedTab.getId()))); } else { mLayoutTabs = new LayoutTab[] {mClosedTab}; } forceAnimationToFinish(); mAnimatedTab = mClosedTab; addToAnimation( this, Property.DISCARD_AMOUNT, 0, getDiscardRange(), TAB_CLOSED_ANIMATION_DURATION, 0, false, BakedBezierInterpolator.FADE_OUT_CURVE); mClosedTab = null; if (nextModel != null) { mTabModelSelector.selectModel(nextModel.isIncognito()); } } startHiding(nextId, false); }
/** * Updates the position, scale, rotation and alpha values of mAnimatedTab. * * @param discard The value that specify how far along are we in the discard animation. 0 is * filling the screen. Valid values are [-range .. range] where range is computed by {@link * SimpleAnimationLayout#getDiscardRange()}. */ private void setDiscardAmount(float discard) { if (mAnimatedTab != null) { final float range = getDiscardRange(); final float scale = Stack.computeDiscardScale(discard, range, true); final float deltaX = mAnimatedTab.getOriginalContentWidth(); final float deltaY = mAnimatedTab.getOriginalContentHeight() / 2.f; mAnimatedTab.setX(deltaX * (1.f - scale)); mAnimatedTab.setY(deltaY * (1.f - scale)); mAnimatedTab.setScale(scale); mAnimatedTab.setBorderScale(scale); mAnimatedTab.setAlpha(Stack.computeDiscardAlpha(discard, range)); } }
/** Set up for the tab closing animation */ @Override public void onTabClosing(long time, int id) { reset(); // Make sure any currently running animations can't influence tab if we are reusing it. forceAnimationToFinish(); // Create the {@link LayoutTab} for the tab before it is destroyed. TabModel model = mTabModelSelector.getModelForTabId(id); if (model != null) { mClosedTab = createLayoutTab(id, model.isIncognito(), NO_CLOSE_BUTTON, NO_TITLE); mClosedTab.setBorderAlpha(0.0f); mLayoutTabs = new LayoutTab[] {mClosedTab}; updateCacheVisibleIds(new LinkedList<Integer>(Arrays.asList(id))); } else { mLayoutTabs = null; mClosedTab = null; } // Only close the id at the end when we are done querying the model. super.onTabClosing(time, id); }
/** * Animate opening a tab in the background. * * @param id The id of the new tab to animate. * @param sourceId The id of the tab that spawned this new tab. * @param newIsIncognito true if the new tab is an incognito tab. * @param originX The X screen coordinate in dp of the last touch down event that spawned this * tab. * @param originY The Y screen coordinate in dp of the last touch down event that spawned this * tab. */ private void tabCreatedInBackground( int id, int sourceId, boolean newIsIncognito, float originX, float originY) { LayoutTab newLayoutTab = createLayoutTab(id, newIsIncognito, NO_CLOSE_BUTTON, NEED_TITLE); // mLayoutTabs should already have the source tab from tabCreating(). assert mLayoutTabs.length == 1; LayoutTab sourceLayoutTab = mLayoutTabs[0]; mLayoutTabs = new LayoutTab[] {sourceLayoutTab, newLayoutTab}; updateCacheVisibleIds(new LinkedList<Integer>(Arrays.asList(id, sourceId))); forceAnimationToFinish(); newLayoutTab.setBorderAlpha(0.0f); final float scale = StackAnimation.SCALE_AMOUNT; final float margin = Math.min(getWidth(), getHeight()) * (1.0f - scale) / 2.0f; // Step 1: zoom out the source tab and bring in the new tab addToAnimation( sourceLayoutTab, LayoutTab.Property.SCALE, 1.0f, scale, BACKGROUND_STEP1_DURATION, 0, false, BakedBezierInterpolator.TRANSFORM_CURVE); addToAnimation( sourceLayoutTab, LayoutTab.Property.X, 0.0f, margin, BACKGROUND_STEP1_DURATION, 0, false, BakedBezierInterpolator.TRANSFORM_CURVE); addToAnimation( sourceLayoutTab, LayoutTab.Property.Y, 0.0f, margin, BACKGROUND_STEP1_DURATION, 0, false, BakedBezierInterpolator.TRANSFORM_CURVE); addToAnimation( sourceLayoutTab, LayoutTab.Property.BORDER_SCALE, 1.0f / scale, 1.0f, BACKGROUND_STEP1_DURATION, 0, false, BakedBezierInterpolator.TRANSFORM_CURVE); addToAnimation( sourceLayoutTab, LayoutTab.Property.BORDER_ALPHA, 0.0f, 1.0f, BACKGROUND_STEP1_DURATION, 0, false, BakedBezierInterpolator.TRANSFORM_CURVE); float pauseX = margin; float pauseY = margin; if (getOrientation() == Orientation.PORTRAIT) { pauseY = BACKGROUND_COVER_PCTG * getHeight(); } else { pauseX = BACKGROUND_COVER_PCTG * getWidth(); } addToAnimation( newLayoutTab, LayoutTab.Property.ALPHA, 0.0f, 1.0f, BACKGROUND_STEP1_DURATION / 2, 0, false, BakedBezierInterpolator.FADE_IN_CURVE); addToAnimation( newLayoutTab, LayoutTab.Property.SCALE, 0.f, scale, BACKGROUND_STEP1_DURATION, 0, false, BakedBezierInterpolator.FADE_IN_CURVE); addToAnimation( newLayoutTab, LayoutTab.Property.X, originX, pauseX, BACKGROUND_STEP1_DURATION, 0, false, BakedBezierInterpolator.FADE_IN_CURVE); addToAnimation( newLayoutTab, LayoutTab.Property.Y, originY, pauseY, BACKGROUND_STEP1_DURATION, 0, false, BakedBezierInterpolator.FADE_IN_CURVE); // step 2: pause and admire the nice tabs // step 3: zoom in the source tab and slide down the new tab addToAnimation( sourceLayoutTab, LayoutTab.Property.SCALE, scale, 1.0f, BACKGROUND_STEP3_DURATION, BACKGROUND_STEP3_START, true, BakedBezierInterpolator.TRANSFORM_CURVE); addToAnimation( sourceLayoutTab, LayoutTab.Property.X, margin, 0.0f, BACKGROUND_STEP3_DURATION, BACKGROUND_STEP3_START, true, BakedBezierInterpolator.TRANSFORM_CURVE); addToAnimation( sourceLayoutTab, LayoutTab.Property.Y, margin, 0.0f, BACKGROUND_STEP3_DURATION, BACKGROUND_STEP3_START, true, BakedBezierInterpolator.TRANSFORM_CURVE); addToAnimation( sourceLayoutTab, LayoutTab.Property.BORDER_SCALE, 1.0f, 1.0f / scale, BACKGROUND_STEP3_DURATION, BACKGROUND_STEP3_START, true, BakedBezierInterpolator.TRANSFORM_CURVE); addToAnimation( sourceLayoutTab, LayoutTab.Property.BORDER_ALPHA, 1.0f, 0.0f, BACKGROUND_STEP3_DURATION, BACKGROUND_STEP3_START, true, BakedBezierInterpolator.TRANSFORM_CURVE); addToAnimation( newLayoutTab, LayoutTab.Property.ALPHA, 1.f, 0.f, BACKGROUND_STEP3_DURATION, BACKGROUND_STEP3_START, true, BakedBezierInterpolator.FADE_OUT_CURVE); if (getOrientation() == Orientation.PORTRAIT) { addToAnimation( newLayoutTab, LayoutTab.Property.Y, pauseY, getHeight(), BACKGROUND_STEP3_DURATION, BACKGROUND_STEP3_START, true, BakedBezierInterpolator.FADE_OUT_CURVE); } else { addToAnimation( newLayoutTab, LayoutTab.Property.X, pauseX, getWidth(), BACKGROUND_STEP3_DURATION, BACKGROUND_STEP3_START, true, BakedBezierInterpolator.FADE_OUT_CURVE); } mTabModelSelector.selectModel(newIsIncognito); startHiding(sourceId, false); }
/** * Pushes all relevant {@link LayoutTab}s from a {@link Layout} to the CC Layer tree. This will * let them be rendered on the screen. This should only be called when the Compositor has disabled * ScheduleComposite calls as this will change the tree and could subsequently cause unnecessary * follow up renders. * * @param context The {@link Context} to use to query device information. * @param layout The {@link Layout} to push to the screen. */ public void pushLayers( Context context, Rect viewport, Rect contentViewport, Layout layout, LayerTitleCache layerTitleCache, TabContentManager tabContentManager, ResourceManager resourceManager) { if (mNativePtr == 0) return; Resources res = context.getResources(); final float dpToPx = res.getDisplayMetrics().density; LayoutTab[] tabs = layout.getLayoutTabsToRender(); int tabsCount = tabs != null ? tabs.length : 0; nativeBeginBuildingFrame(mNativePtr); for (int i = 0; i < tabsCount; i++) { LayoutTab t = tabs[i]; assert t.isVisible() : "LayoutTab in that list should be visible"; final float decoration = t.getDecorationAlpha(); int borderResource = t.isIncognito() ? R.drawable.tabswitcher_border_frame_incognito : R.drawable.tabswitcher_border_frame; int closeBtnResource = t.isIncognito() ? R.drawable.btn_tab_close_white_normal : R.drawable.btn_tab_close_normal; int borderColorResource = t.isIncognito() ? R.color.tab_back_incognito : R.color.tab_back; // TODO(dtrainor, clholgat): remove "* dpToPx" once the native part fully supports dp. nativePutLayer( mNativePtr, t.getId(), R.id.control_container, closeBtnResource, R.drawable.tabswitcher_border_frame_shadow, R.drawable.tabswitcher_border_frame_decoration, R.drawable.logo_card_back, borderResource, t.canUseLiveTexture(), (t.getFallbackThumbnailId() == ChromeTab.NTP_TAB_ID), t.getBackgroundColor(), ApiCompatibilityUtils.getColor(res, R.color.tab_switcher_background), ApiCompatibilityUtils.getColor(res, borderColorResource), t.isIncognito(), layout.getOrientation() == Orientation.PORTRAIT, t.getRenderX() * dpToPx, t.getRenderY() * dpToPx, t.getScaledContentWidth() * dpToPx, t.getScaledContentHeight() * dpToPx, t.getOriginalContentWidth() * dpToPx, t.getOriginalContentHeight() * dpToPx, contentViewport.height(), viewport.left, viewport.top, viewport.width(), viewport.height(), t.getClippedX() * dpToPx, t.getClippedY() * dpToPx, Math.min(t.getClippedWidth(), t.getScaledContentWidth()) * dpToPx, Math.min(t.getClippedHeight(), t.getScaledContentHeight()) * dpToPx, t.getTiltXPivotOffset() * dpToPx, t.getTiltYPivotOffset() * dpToPx, t.getTiltX(), t.getTiltY(), t.getAlpha(), t.getBorderAlpha() * decoration, decoration, t.getShadowOpacity() * decoration, t.getBorderCloseButtonAlpha() * decoration, LayoutTab.CLOSE_BUTTON_WIDTH_DP * dpToPx, t.getStaticToViewBlend(), t.getBorderScale(), t.getSaturation(), t.getBrightness(), t.showToolbar(), t.anonymizeToolbar(), t.getTextBoxBackgroundColor(), t.getToolbarAlpha(), t.getToolbarYOffset() * dpToPx, t.getSideBorderScale(), true, t.insetBorderVertical(), layerTitleCache, tabContentManager, resourceManager); } nativeFinishBuildingFrame(mNativePtr); }
@Override public float getTopControlsOffset(float currentOffsetDp) { return MathUtils.clamp( mBaseTab.getY(), -mSearchPanel.getToolbarHeight(), Math.min(currentOffsetDp, 0f)); }