[go: up one dir, main page]

blob: 6a54f7b49bedc9a05461180cda6793ff21740a94 [file] [log] [blame]
// Copyright 2021 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.messages;
import org.chromium.components.messages.MessageScopeChange.ChangeType;
import org.chromium.content_public.browser.LoadCommittedDetails;
import org.chromium.content_public.browser.NavigationController;
import org.chromium.content_public.browser.NavigationEntry;
import org.chromium.content_public.browser.Visibility;
import org.chromium.content_public.browser.WebContents;
import org.chromium.content_public.browser.WebContentsObserver;
import org.chromium.ui.base.PageTransition;
import java.util.HashMap;
import java.util.Map;
/**
* Observe the webContents and notify queue manager of proper scope changes.
*/
class ScopeChangeController {
/**
* A delegate which can handle the scope change.
*/
public interface Delegate {
void onScopeChange(MessageScopeChange change);
}
private final Delegate mDelegate;
private final Map<ScopeKey, WebContentsObserver> mObservers;
public ScopeChangeController(Delegate delegate) {
mDelegate = delegate;
mObservers = new HashMap<>();
}
/**
* Notify every time a message is enqueued to a scope whose queue was previously empty.
* @param scopeKey The scope key of the scope which the first message is enqueued.
*/
void firstMessageEnqueued(ScopeKey scopeKey) {
WebContentsObserver observer = createObserver(scopeKey);
assert !mObservers.containsKey(scopeKey) : "This scope key has already been observed.";
mObservers.put(scopeKey, observer);
mDelegate.onScopeChange(new MessageScopeChange(scopeKey.scopeType, scopeKey,
scopeKey.webContents.getVisibility() == Visibility.VISIBLE ? ChangeType.ACTIVE
: ChangeType.INACTIVE));
}
/**
* Called when all Messages for the given {@code scopeKey} have been dismissed or removed.
* @param scopeKey The scope key of the scope which the last message is dismissed.
*/
void lastMessageDismissed(ScopeKey scopeKey) {
WebContentsObserver observer = mObservers.remove(scopeKey);
observer.destroy();
}
private WebContentsObserver createObserver(ScopeKey scopeKey) {
WebContents webContents = scopeKey.webContents;
@MessageScopeType
int scopeType = scopeKey.scopeType;
return new WebContentsObserver(webContents) {
@Override
public void wasShown() {
super.wasShown();
mDelegate.onScopeChange(
new MessageScopeChange(scopeType, scopeKey, ChangeType.ACTIVE));
}
@Override
public void wasHidden() {
super.wasHidden();
mDelegate.onScopeChange(
new MessageScopeChange(scopeKey.scopeType, scopeKey, ChangeType.INACTIVE));
}
@Override
public void navigationEntryCommitted(LoadCommittedDetails details) {
if (scopeKey.scopeType != MessageScopeType.NAVIGATION) {
return;
}
if (!details.isMainFrame() || details.isSameDocument()
|| details.didReplaceEntry()) {
return;
}
super.navigationEntryCommitted(details);
NavigationController controller = scopeKey.webContents.getNavigationController();
NavigationEntry entry =
controller.getEntryAtIndex(controller.getLastCommittedEntryIndex());
int transition = entry.getTransition();
if ((transition & PageTransition.RELOAD) != PageTransition.RELOAD
&& (transition & PageTransition.IS_REDIRECT_MASK) == 0) {
destroy();
}
}
@Override
public void destroy() {
super.destroy();
// #destroy will remove the observers.
mDelegate.onScopeChange(
new MessageScopeChange(scopeType, scopeKey, ChangeType.DESTROY));
}
};
}
}