blob: 73cd0ebc137ca31479aedf5c49d0e2d5a42abc4b [file] [log] [blame]
// Copyright 2018 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.autofill_assistant.overlay;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.RectF;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import org.chromium.chrome.browser.autofill_assistant.AutofillAssistantUiController;
import org.chromium.chrome.browser.browser_controls.BrowserControlsStateProvider;
import org.chromium.chrome.browser.compositor.CompositorViewHolder;
import org.chromium.chrome.browser.image_fetcher.ImageFetcher;
import org.chromium.chrome.browser.image_fetcher.ImageFetcherConfig;
import org.chromium.chrome.browser.image_fetcher.ImageFetcherFactory;
import org.chromium.chrome.browser.util.ChromeAccessibilityUtil;
import org.chromium.components.browser_ui.widget.scrim.ScrimCoordinator;
import org.chromium.components.browser_ui.widget.scrim.ScrimProperties;
import org.chromium.ui.modelutil.PropertyModel;
import java.util.List;
/**
* Coordinator responsible for showing a full or partial overlay on top of the web page currently
* displayed.
*/
public class AssistantOverlayCoordinator {
private final AssistantOverlayModel mModel;
private final AssistantOverlayEventFilter mEventFilter;
private final AssistantOverlayDrawable mDrawable;
private final CompositorViewHolder mCompositorViewHolder;
private final ScrimCoordinator mScrim;
private final ImageFetcher mImageFetcher;
private boolean mScrimEnabled;
public AssistantOverlayCoordinator(Context context,
BrowserControlsStateProvider browserControls, CompositorViewHolder compositorViewHolder,
ScrimCoordinator scrim, AssistantOverlayModel model) {
this(context, browserControls, compositorViewHolder, scrim, model,
ImageFetcherFactory.createImageFetcher(ImageFetcherConfig.DISK_CACHE_ONLY,
AutofillAssistantUiController.getProfile()));
}
public AssistantOverlayCoordinator(Context context,
BrowserControlsStateProvider browserControls, CompositorViewHolder compositorViewHolder,
ScrimCoordinator scrim, AssistantOverlayModel model, ImageFetcher imageFetcher) {
mModel = model;
mImageFetcher = imageFetcher;
mCompositorViewHolder = compositorViewHolder;
mScrim = scrim;
mEventFilter =
new AssistantOverlayEventFilter(context, browserControls, compositorViewHolder);
mDrawable = new AssistantOverlayDrawable(context, browserControls);
// Listen for changes in the state.
// TODO(crbug.com/806868): Bind model to view through a ViewBinder instead.
model.addObserver((source, propertyKey) -> {
if (AssistantOverlayModel.STATE == propertyKey) {
setState(model.get(AssistantOverlayModel.STATE));
} else if (AssistantOverlayModel.VISUAL_VIEWPORT == propertyKey) {
RectF rect = model.get(AssistantOverlayModel.VISUAL_VIEWPORT);
mEventFilter.setVisualViewport(rect);
mDrawable.setVisualViewport(rect);
} else if (AssistantOverlayModel.TOUCHABLE_AREA == propertyKey) {
List<RectF> area = model.get(AssistantOverlayModel.TOUCHABLE_AREA);
mEventFilter.setTouchableArea(area);
mDrawable.setTransparentArea(area);
} else if (AssistantOverlayModel.RESTRICTED_AREA == propertyKey) {
List<RectF> area = model.get(AssistantOverlayModel.RESTRICTED_AREA);
mEventFilter.setRestrictedArea(area);
mDrawable.setRestrictedArea(area);
} else if (AssistantOverlayModel.DELEGATE == propertyKey) {
mEventFilter.setDelegate(model.get(AssistantOverlayModel.DELEGATE));
} else if (AssistantOverlayModel.BACKGROUND_COLOR == propertyKey) {
mDrawable.setBackgroundColor(model.get(AssistantOverlayModel.BACKGROUND_COLOR));
} else if (AssistantOverlayModel.HIGHLIGHT_BORDER_COLOR == propertyKey) {
mDrawable.setHighlightBorderColor(
model.get(AssistantOverlayModel.HIGHLIGHT_BORDER_COLOR));
} else if (AssistantOverlayModel.TAP_TRACKING_COUNT == propertyKey) {
mEventFilter.setTapTrackingCount(
model.get(AssistantOverlayModel.TAP_TRACKING_COUNT));
} else if (AssistantOverlayModel.TAP_TRACKING_DURATION_MS == propertyKey) {
mEventFilter.setTapTrackingDurationMs(
model.get(AssistantOverlayModel.TAP_TRACKING_DURATION_MS));
} else if (AssistantOverlayModel.OVERLAY_IMAGE == propertyKey) {
AssistantOverlayImage image = model.get(AssistantOverlayModel.OVERLAY_IMAGE);
if (image != null && !TextUtils.isEmpty(image.mImageUrl)) {
DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
// TODO(b/143517837) Merge autofill assistant image fetcher UMA names.
ImageFetcher.Params params = ImageFetcher.Params.create(
image.mImageUrl, ImageFetcher.ASSISTANT_DETAILS_UMA_CLIENT_NAME);
mImageFetcher.fetchImage(
params, result -> {
image.mImageBitmap = result != null ? Bitmap.createScaledBitmap(
result, image.mImageSizeInPixels,
image.mImageSizeInPixels, true)
: null;
mDrawable.setFullOverlayImage(image);
});
} else {
mDrawable.setFullOverlayImage(image);
}
}
});
}
/** Return the model observed by this coordinator. */
public AssistantOverlayModel getModel() {
return mModel;
}
/**
* Destroy this coordinator.
*/
public void destroy() {
setScrimEnabled(false);
mEventFilter.destroy();
mDrawable.destroy();
}
/**
* Set the overlay state.
*/
private void setState(@AssistantOverlayState int state) {
if (state == AssistantOverlayState.PARTIAL
&& ChromeAccessibilityUtil.get().isAccessibilityEnabled()) {
// Touch exploration is fully disabled if there's an overlay in front. In this case, the
// overlay must be fully gone and filtering elements for touch exploration must happen
// at another level.
//
// TODO(crbug.com/806868): filter elements available to touch exploration, when it
// is enabled.
state = AssistantOverlayState.HIDDEN;
}
if (state == AssistantOverlayState.HIDDEN) {
setScrimEnabled(false);
mEventFilter.reset();
} else {
setScrimEnabled(true);
mDrawable.setPartial(state == AssistantOverlayState.PARTIAL);
mEventFilter.setPartial(state == AssistantOverlayState.PARTIAL);
}
}
private void setScrimEnabled(boolean enabled) {
if (enabled == mScrimEnabled) return;
if (enabled) {
PropertyModel params = new PropertyModel.Builder(ScrimProperties.ALL_KEYS)
.with(ScrimProperties.TOP_MARGIN, 0)
.with(ScrimProperties.AFFECTS_STATUS_BAR, false)
.with(ScrimProperties.ANCHOR_VIEW, mCompositorViewHolder)
.with(ScrimProperties.SHOW_IN_FRONT_OF_ANCHOR_VIEW, true)
.with(ScrimProperties.VISIBILITY_CALLBACK, null)
.with(ScrimProperties.CLICK_DELEGATE, null)
.with(ScrimProperties.BACKGROUND_DRAWABLE, mDrawable)
.with(ScrimProperties.GESTURE_DETECTOR, mEventFilter)
.build();
mScrim.showScrim(params);
} else {
mScrim.hideScrim(/* fadeOut= */ true);
}
mScrimEnabled = enabled;
}
}