Commit 69096d11 authored by Sinan Sahin's avatar Sinan Sahin Committed by Commit Bot

[Messages] Handle show/hide on Webapps

This CL also includes a bug fix for the show/hide animations so that
the "message dismissed" callback isn't called for animations that don't
actually hide the message.

Bug: 1137941
Change-Id: I8286feacf03196879642870ce5d582910d8df01e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2538338Reviewed-by: default avatarPavel Yatsuk <pavely@chromium.org>
Reviewed-by: default avatarTheresa  <twellington@chromium.org>
Commit-Queue: Sinan Sahin <sinansahin@google.com>
Cr-Commit-Position: refs/heads/master@{#829898}
parent 5ae79a3b
......@@ -16,10 +16,12 @@ import org.chromium.chrome.browser.layouts.LayoutStateProvider;
import org.chromium.chrome.browser.layouts.LayoutStateProvider.LayoutStateObserver;
import org.chromium.chrome.browser.layouts.LayoutType;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.tab.TabBrowserControlsConstraintsHelper;
import org.chromium.chrome.browser.tabmodel.TabModelObserver;
import org.chromium.chrome.browser.tabmodel.TabModelSelector;
import org.chromium.components.messages.ManagedMessageDispatcher;
import org.chromium.components.messages.MessageQueueDelegate;
import org.chromium.content_public.common.BrowserControlsState;
import org.chromium.ui.util.TokenHolder;
/**
......@@ -129,7 +131,9 @@ public class ChromeMessageQueueMediator implements MessageQueueDelegate {
mBrowserControlsToken =
mBrowserControlsManager.getBrowserVisibilityDelegate().showControlsPersistent();
mContainerCoordinator.showMessageContainer();
if (BrowserControlsUtils.areBrowserControlsFullyVisible(mBrowserControlsManager)) {
final Tab tab = mTabModelSelector != null ? mTabModelSelector.getCurrentTab() : null;
if (TabBrowserControlsConstraintsHelper.getConstraints(tab) == BrowserControlsState.HIDDEN
|| BrowserControlsUtils.areBrowserControlsFullyVisible(mBrowserControlsManager)) {
runnable.run();
} else {
mBrowserControlsObserver.setOneTimeRunnableOnControlsFullyVisible(runnable);
......
......@@ -54,14 +54,20 @@ public class MessageContainerCoordinator implements BrowserControlsStateProvider
}
/**
* If there are no browser controls visible, the {@link MessageContainer} view should be laid
* out for this method to return a meaningful value.
*
* @return The maximum translation Y value the message banner can have as a result of the
* animations or the gestures. Positive values mean the message banner can be translated
* upward from the top of the MessagesContainer.
*/
public int getMessageMaxTranslation() {
// TODO(sinansahin): We need to account for other scenarios where there are no browser
// controls visible (e.g. PWAs).
return getContainerTopOffset();
final int containerTopOffset = getContainerTopOffset();
if (containerTopOffset == 0) {
return mContainer.getHeight();
}
return containerTopOffset;
}
@Override
......@@ -77,8 +83,9 @@ public class MessageContainerCoordinator implements BrowserControlsStateProvider
/** @return Offset of the message container from the top of the screen. */
private int getContainerTopOffset() {
if (mControlsManager.getContentOffset() == 0) return 0;
final Resources res = mContainer.getResources();
return mControlsManager.getTopControlsHeight()
return mControlsManager.getContentOffset()
- res.getDimensionPixelOffset(R.dimen.message_bubble_inset)
- res.getDimensionPixelOffset(R.dimen.message_shadow_top_margin);
}
......
......@@ -51,7 +51,6 @@ class MessageBannerMediator implements SwipeHandler {
Resources resources, Runnable messageDismissed) {
mModel = model;
mMaxTranslationSupplier = maxTranslationSupplier;
mModel.set(TRANSLATION_Y, -mMaxTranslationSupplier.get());
mHideThresholdPx = resources.getDimensionPixelSize(R.dimen.message_hide_threshold);
mMessageDismissed = messageDismissed;
}
......@@ -61,6 +60,9 @@ class MessageBannerMediator implements SwipeHandler {
* @param messageShown The {@link Runnable} that will run once the message banner is shown.
*/
void show(Runnable messageShown) {
if (mAnimatorSet == null) {
mModel.set(TRANSLATION_Y, -mMaxTranslationSupplier.get());
}
cancelAnyAnimations();
mAnimatorSet = createAnimatorSet(true);
mAnimatorSet.addListener(new CancelAwareAnimatorListener() {
......@@ -119,11 +121,12 @@ class MessageBannerMediator implements SwipeHandler {
// No need to animate if the message banner is in resting position.
if (mModel.get(TRANSLATION_Y) == 0.f) return;
mAnimatorSet = createAnimatorSet(mModel.get(TRANSLATION_Y) > -mHideThresholdPx);
final boolean isShow = mModel.get(TRANSLATION_Y) > -mHideThresholdPx;
mAnimatorSet = createAnimatorSet(isShow);
mAnimatorSet.addListener(new CancelAwareAnimatorListener() {
@Override
public void onEnd(Animator animator) {
mMessageDismissed.run();
if (!isShow) mMessageDismissed.run();
mAnimatorSet = null;
}
});
......
......@@ -48,4 +48,27 @@ public class MessageContainer extends FrameLayout {
ViewUtils.setAncestorsShouldClipChildren(this, true);
removeAllViews();
}
/**
* Runs a {@link Runnable} after the initial layout. If the view is already laid out, the
* {@link Runnable} will be called immediately.
* @param runnable The {@link Runnable}.
*/
void runAfterInitialLayout(Runnable runnable) {
if (getHeight() > 0) {
runnable.run();
return;
}
addOnLayoutChangeListener(new OnLayoutChangeListener() {
@Override
public void onLayoutChange(View v, int left, int top, int right, int bottom,
int oldLeft, int oldTop, int oldRight, int oldBottom) {
if (v.getHeight() == 0) return;
runnable.run();
v.removeOnLayoutChangeListener(this);
}
});
}
}
......@@ -57,11 +57,16 @@ public class SingleActionMessage implements MessageStateHandler {
mContainer.getResources(), mDismissHandler.bind(mModel));
}
mContainer.addMessage(mView);
final Runnable onShown = () -> {
final Runnable showRunnable = () -> mMessageBanner.show(() -> {
mMessageBanner.setOnTouchRunnable(mAutoDismissTimer::resetTimer);
mAutoDismissTimer.startTimer(() -> { mDismissHandler.onResult(mModel); });
};
mMessageBanner.show(onShown);
});
// Wait until the message and the container are measured before showing the message. This
// is required in case the animation set-up requires the height of the container, e.g.
// showing messages without the top controls visible.
mContainer.runAfterInitialLayout(showRunnable);
}
/**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment