// Copyright 2016 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.content.Context;
import android.support.design.widget.CoordinatorLayout;
import android.support.design.widget.CoordinatorLayout.Behavior;
import android.view.Gravity;
import android.view.View;
import android.widget.FrameLayout;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.banners.SwipableOverlayView;
import org.chromium.ui.UiUtils;
import org.chromium.ui.base.DeviceFormFactor;
/**
* Parent {@link FrameLayout} holding the infobar and content of a tab. The content could be either
* a native page or a content view.
*/
public class TabContentViewParent extends FrameLayout {
private static final int CONTENT_INDEX = 0;
// A wrapper is needed because infobar's translation is controlled by SwipableOverlayView.
// Setting infobar's translation directly from this class will cause UI flickering.
private final FrameLayout mInfobarWrapper;
private final Behavior<?> mBehavior = new SnackbarAwareBehavior();
private EmptyTabObserver mTabObserver = new EmptyTabObserver() {
/**
* @return the {@link View} to show for the given {@link Tab}.
*/
private View getViewToShow(Tab tab) {
if (tab.getNativePage() != null) {
return tab.getNativePage().getView();
} else if (tab.getBlimpContents() != null) {
return tab.getBlimpContents().getView();
} else {
return tab.getContentViewCore().getContainerView();
}
}
@Override
public void onContentChanged(Tab tab) {
// If the tab is frozen, both native page and content view are not ready.
if (tab.isFrozen()) return;
View viewToShow = getViewToShow(tab);
if (isShowing(viewToShow)) return;
removeCurrentContent();
LayoutParams lp = (LayoutParams) viewToShow.getLayoutParams();
if (lp == null) {
lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
}
// Weirdly enough, if gravity is not top, top_margin is not respected by FrameLayout.
// Yet for many native pages on tablet, top_margin is necessary to not overlap the tab
// switcher.
lp.gravity = Gravity.TOP;
UiUtils.removeViewFromParent(viewToShow);
addView(viewToShow, CONTENT_INDEX, lp);
viewToShow.requestFocus();
}
};
public TabContentViewParent(Context context, Tab tab) {
super(context);
mInfobarWrapper = new FrameLayout(context);
mInfobarWrapper.setFocusable(true);
mInfobarWrapper.setFocusableInTouchMode(true);
addView(mInfobarWrapper,
new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
tab.addObserver(mTabObserver);
}
/**
* Attach the infobar container to the view hierarchy.
*/
public void addInfobarView(SwipableOverlayView infobarView, MarginLayoutParams lp) {
mInfobarWrapper.addView(infobarView, lp);
}
/**
* @return The {@link Behavior} that controls how children of this class animate together.
*/
public Behavior<?> getBehavior() {
return mBehavior;
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
mInfobarWrapper.setTranslationY(0f);
}
/**
* @return Whether the given {@link View} is already in the view hierarchy.
*/
private boolean isShowing(View view) {
return view.getParent() == this;
}
private void removeCurrentContent() {
// Native page or content view should always be at index 0.
if (getChildCount() > 1) removeViewAt(CONTENT_INDEX);
}
private static class SnackbarAwareBehavior
extends CoordinatorLayout.Behavior<TabContentViewParent> {
@Override
public boolean layoutDependsOn(CoordinatorLayout parent, TabContentViewParent child,
View dependency) {
// Disable coordination on tablet as they appear at different location on tablet.
return dependency.getId() == R.id.snackbar
&& !DeviceFormFactor.isTablet(child.getContext());
}
@Override
public boolean onDependentViewChanged(CoordinatorLayout parent, TabContentViewParent child,
View dependency) {
child.mInfobarWrapper
.setTranslationY(dependency.getTranslationY() - dependency.getHeight());
return true;
}
@Override
public void onDependentViewRemoved(CoordinatorLayout parent, TabContentViewParent child,
View dependency) {
child.mInfobarWrapper.setTranslationY(0);
}
}
}