blob: a0bb0b4a713519a9a19bbd8b5233b139b21cd92b [file] [log] [blame]
// Copyright 2020 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.components.browser_ui.widget.scrim;
import android.content.Context;
import android.view.MotionEvent;
import android.view.ViewGroup;
import androidx.annotation.ColorInt;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import org.chromium.base.supplier.Supplier;
import org.chromium.ui.UiUtils;
import org.chromium.ui.modelutil.PropertyModel;
import org.chromium.ui.modelutil.PropertyModelChangeProcessor;
/**
* The coordinator for the scrim widget used to bring focus to certain elements on screen.
*
* To use the scrim, {@link #showScrim(PropertyModel)} must be called to set the params for
* how the scrim will behave:
*
* PropertyModel model = new PropertyModel.Builder(ScrimProperties.ALL_KEYS)...
*
* After that, users can either allow the default animation to run or change the view's alpha
* manually using {@link #setAlpha(float)}. Once the scrim is done being used,
* {@link #hideScrim(boolean)} should be called.
*/
public class ScrimCoordinator {
/**
* A delegate to expose functionality that changes the scrim over the status bar. This will only
* affect Android versions >= M.
*/
public interface StatusBarScrimDelegate {
/**
* Set the amount of scrim over the status bar. The implementor may choose to not respect
* the value provided to this method.
* @param scrimFraction The scrim fraction over the status bar. 0 is completely hidden, 1 is
* completely shown.
*/
void setStatusBarScrimFraction(float scrimFraction);
}
/** A mechanism for delegating motion events out to the mediator. */
interface TouchEventDelegate {
/**
* @param event The event that occurred.
* @return Whether the event was consumed.
*/
boolean onTouchEvent(MotionEvent event);
}
/**
* A supplier of new {@link ScrimView}s to use when {@link #showScrim(PropertyModel)} is called.
*/
private final Supplier<ScrimView> mScrimViewBuilder;
/** The component's mediator for handling animation and model management. */
private final ScrimMediator mMediator;
/**
* A handle to the view to bind models to. This should otherwise remain untouched. Each time
* {@link #showScrim(PropertyModel)} is called, this view is recreated, so all old state is
* discarded.
*/
private ScrimView mView;
/** A handle to the object pushing updates from the model to the view. */
private PropertyModelChangeProcessor mChangeProcessor;
/**
* @param context An Android {@link Context} for creating the view.
* @param scrimDelegate A means of changing the scrim over the status bar.
* @param parent The {@link ViewGroup} the scrim should exist in.
* @param defaultColor The default color of the scrim.
*/
public ScrimCoordinator(Context context, @Nullable StatusBarScrimDelegate scrimDelegate,
ViewGroup parent, @ColorInt int defaultColor) {
mMediator = new ScrimMediator(() -> {
if (mChangeProcessor != null) mChangeProcessor.destroy();
if (mView != null) UiUtils.removeViewFromParent(mView);
mView = null;
mChangeProcessor = null;
}, scrimDelegate);
mScrimViewBuilder = () -> {
ScrimView view = new ScrimView(context, parent, defaultColor, mMediator);
view.setOnClickListener(mMediator);
return view;
};
}
/**
* Show the scrim.
* @param model The property model of {@link ScrimProperties} that define the scrim behavior.
*/
public void showScrim(PropertyModel model) {
assert model != null : "Showing the scrim requires a model.";
// Ensure the previous scrim is hidden before showing the new one. This logic should be in
// the mediator, but it depends on the old view and binder being available which are
// replaced prior to mediator#showScrim being called.
if (mMediator.isActive()) mMediator.hideScrim(false);
if (mChangeProcessor != null) mChangeProcessor.destroy();
mView = mScrimViewBuilder.get();
mChangeProcessor = PropertyModelChangeProcessor.create(model, mView, ScrimViewBinder::bind);
mMediator.showScrim(model);
}
/**
* Hide the scrim.
* @param animate Whether the scrim should animate and fade out.
*/
public void hideScrim(boolean animate) {
mMediator.hideScrim(animate);
}
/**
* Manually set the alpha for the scrim.
* @param alpha The alpha in range [0, 1].
*/
public void setAlpha(float alpha) {
mMediator.setAlpha(alpha);
}
@VisibleForTesting
public void disableAnimationForTesting(boolean disable) {
mMediator.disableAnimationForTesting(disable);
}
@VisibleForTesting
public ScrimView getViewForTesting() {
return mView;
}
@VisibleForTesting
ScrimMediator getMediatorForTesting() {
return mMediator;
}
@VisibleForTesting
boolean areAnimationsRunning() {
return mMediator.areAnimationsRunning();
}
}