Skip to content
This repository has been archived by the owner on Jul 22, 2024. It is now read-only.

Updated Pop-up blocking flow #2097

Merged
merged 3 commits into from
Oct 30, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
206 changes: 145 additions & 61 deletions app/src/common/shared/org/mozilla/vrbrowser/browser/PromptDelegate.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import android.app.Application;
import android.content.Context;
import android.util.Pair;
import android.util.SparseArray;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
Expand All @@ -19,7 +21,6 @@
import org.mozilla.vrbrowser.ui.widgets.UIWidget;
import org.mozilla.vrbrowser.ui.widgets.WidgetPlacement;
import org.mozilla.vrbrowser.ui.widgets.WindowWidget;
import org.mozilla.vrbrowser.ui.widgets.dialogs.BaseAppDialogWidget;
import org.mozilla.vrbrowser.ui.widgets.dialogs.PopUpBlockDialogWidget;
import org.mozilla.vrbrowser.ui.widgets.prompts.AlertPromptWidget;
import org.mozilla.vrbrowser.ui.widgets.prompts.AuthPromptWidget;
Expand All @@ -31,10 +32,17 @@
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Optional;

public class PromptDelegate implements GeckoSession.PromptDelegate, WindowWidget.WindowListener {
public class PromptDelegate implements
GeckoSession.PromptDelegate,
WindowWidget.WindowListener,
GeckoSession.NavigationDelegate {

public interface PopUpDelegate {
void onPopUpAvailable();
void onPopUpsCleared();
}

private PromptWidget mPrompt;
private PopUpBlockDialogWidget mPopUpPrompt;
Expand All @@ -43,6 +51,7 @@ public class PromptDelegate implements GeckoSession.PromptDelegate, WindowWidget
private List<PopUpSite> mAllowedPopUpSites;
private PopUpsViewModel mViewModel;
private AppExecutors mExecutors;
private PopUpDelegate mPopupDelegate;

public PromptDelegate(@NonNull Context context) {
mContext = context;
Expand All @@ -59,16 +68,55 @@ public void attachToWindow(@NonNull WindowWidget window) {

mAttachedWindow = window;
mAttachedWindow.addWindowListener(this);
mAttachedWindow.getSession().setPromptDelegate(this);
mViewModel.getAll().observeForever(mObserver);

if (getSession() != null) {
setUpSession(getSession());
}
}

public void detachFromWindow() {
if (getSession() != null) {
cleanSession(getSession());
}

if (mAttachedWindow != null) {
mAttachedWindow.removeWindowListener(this);
mAttachedWindow = null;
}
mViewModel.getAll().removeObserver(mObserver);

clearPopUps();
}

private Session getSession() {
if (mAttachedWindow != null) {
return mAttachedWindow.getSession();
}
return null;
}

private void setUpSession(@NonNull Session aSession) {
aSession.setPromptDelegate(this);
aSession.addNavigationListener(this);
}

private void cleanSession(@NonNull Session aSession) {
aSession.setPromptDelegate(null);
aSession.removeNavigationListener(this);
mPopUpRequests.remove(aSession.hashCode());
}

public void setPopupDelegate(@Nullable PopUpDelegate delegate) {
mPopupDelegate = delegate;
}

public void clearPopUps() {
mPopUpRequests.clear();

if (mPopupDelegate != null) {
mPopupDelegate.onPopUpsCleared();
}
}

@Nullable
Expand Down Expand Up @@ -220,103 +268,139 @@ public GeckoResult<PromptResponse> onPopupPrompt(@NonNull GeckoSession geckoSess

if (!SettingsStore.getInstance(mContext).isPopUpsBlockingEnabled()) {
result.complete(popupPrompt.confirm(AllowOrDeny.ALLOW));

} else {
String uri = mAttachedWindow.getSession().getCurrentUri();
PopUpRequest request = PopUpRequest.newRequest(uri, popupPrompt, result);
handlePopUpRequest(request);
final int sessionId = geckoSession.hashCode();
final String uri = mAttachedWindow.getSession().getCurrentUri();

Optional<PopUpSite> site = mAllowedPopUpSites.stream().filter((item) -> item.url.equals(uri)).findFirst();
if (site.isPresent()) {
mAttachedWindow.postDelayed(() -> {
if (site.get().allowed) {
result.complete(popupPrompt.confirm(AllowOrDeny.ALLOW));

} else {
result.complete(popupPrompt.dismiss());
}
}, 500);

} else {
PopUpRequest request = PopUpRequest.newRequest(popupPrompt, result, sessionId);
Pair<String, LinkedList<PopUpRequest>> domainRequestList = mPopUpRequests.get(sessionId);
if (domainRequestList == null) {
LinkedList<PopUpRequest> requestList = new LinkedList<>();
domainRequestList = new Pair<>(uri, requestList);
mPopUpRequests.put(sessionId, domainRequestList);
}
domainRequestList.second.add(request);

if (mPopupDelegate != null) {
mPopupDelegate.onPopUpAvailable();
}
}
}

return result;
}

static class PopUpRequest {

public static PopUpRequest newRequest(@NonNull String uri, @NonNull PopupPrompt prompt, @NonNull GeckoResult<PromptResponse> response) {
public static PopUpRequest newRequest(@NonNull PopupPrompt prompt, @NonNull GeckoResult<PromptResponse> response, int sessionId) {
PopUpRequest request = new PopUpRequest();
request.uri = uri;
request.prompt = prompt;
request.response = response;
request.sessionId = sessionId;

return request;
}

String uri;
PopupPrompt prompt;
GeckoResult<PromptResponse> response;
int sessionId;
}

private LinkedList<PopUpRequest> mPopUpRequests = new LinkedList<>();
private SparseArray<Pair<String, LinkedList<PopUpRequest>>> mPopUpRequests = new SparseArray<>();

private void handlePopUpRequest(@NonNull PopUpRequest request) {
if (mPopUpPrompt != null && mPopUpPrompt.isVisible()) {
mPopUpRequests.add(request);

} else {
Optional<PopUpSite> site = mAllowedPopUpSites.stream().filter((item) -> item.url.equals(request.uri)).findFirst();
if (!site.isPresent()) {
mPopUpPrompt = new PopUpBlockDialogWidget(mContext);
mPopUpPrompt.getPlacement().parentHandle = mAttachedWindow.getHandle();
mPopUpPrompt.getPlacement().parentAnchorY = 0.0f;
mPopUpPrompt.getPlacement().translationY = WidgetPlacement.unitFromMeters(mContext, R.dimen.base_app_dialog_y_distance);
mPopUpPrompt.setTitle(request.uri);
mPopUpPrompt.setButtonsDelegate(new BaseAppDialogWidget.Delegate() {
@Override
public void onButtonClicked(int index) {
boolean allowed = index != PopUpBlockDialogWidget.NEGATIVE;
boolean askAgain = mPopUpPrompt.askAgain();
if (!askAgain) {
mAllowedPopUpSites.add(new PopUpSite(request.uri, allowed));
mViewModel.insertSite(request.uri, allowed);
}
public void showPopUps(GeckoSession session) {
Pair<String, LinkedList<PopUpRequest>> requests = mPopUpRequests.get(session.hashCode());
if (requests != null && !requests.second.isEmpty()) {
showPopUp(session.hashCode(), requests);
}
}

if (allowed) {
request.response.complete(request.prompt.confirm(AllowOrDeny.ALLOW));
public boolean hasPendingPopUps(GeckoSession session) {
Pair<String, LinkedList<PopUpRequest>> requests = mPopUpRequests.get(session.hashCode());
if (requests != null) {
return !requests.second.isEmpty();
}

} else {
request.response.complete(request.prompt.dismiss());
}
return false;
}

mExecutors.mainThread().execute(() -> {
try {
PopUpRequest next = mPopUpRequests.pop();
handlePopUpRequest(next);
private void showPopUp(int sessionId, @NonNull Pair<String, LinkedList<PopUpRequest>> requests) {
String uri = requests.first;
Optional<PopUpSite> site = mAllowedPopUpSites.stream().filter((item) -> item.url.equals(uri)).findFirst();
if (!site.isPresent()) {
mPopUpPrompt = new PopUpBlockDialogWidget(mContext);
mPopUpPrompt.getPlacement().parentHandle = mAttachedWindow.getHandle();
mPopUpPrompt.getPlacement().parentAnchorY = 0.0f;
mPopUpPrompt.getPlacement().translationY = WidgetPlacement.unitFromMeters(mContext, R.dimen.base_app_dialog_y_distance);
mPopUpPrompt.setTitle(uri);
mPopUpPrompt.setButtonsDelegate(index -> {
boolean allowed = index != PopUpBlockDialogWidget.NEGATIVE;
boolean askAgain = mPopUpPrompt.askAgain();
if (allowed && !askAgain) {
mAllowedPopUpSites.add(new PopUpSite(uri, allowed));
mViewModel.insertSite(uri, allowed);
}

} catch (NoSuchElementException ignored) {}
});
}
if (allowed) {
requests.second.forEach((request) -> {
request.response.complete(request.prompt.confirm(AllowOrDeny.ALLOW));
});

@Override
public void onDismiss() {
request.response.complete(request.prompt.dismiss());
mPopUpRequests.remove(sessionId);

mExecutors.mainThread().execute(() -> {
try {
PopUpRequest next = mPopUpRequests.pop();
handlePopUpRequest(next);
mExecutors.mainThread().execute(() -> {
if (mPopupDelegate != null) {
mPopupDelegate.onPopUpsCleared();
}
});

} catch (NoSuchElementException ignored) {}
});
}
});
mPopUpPrompt.show(UIWidget.REQUEST_FOCUS);
} else {
mExecutors.mainThread().execute(() -> {
if (mPopupDelegate != null) {
mPopupDelegate.onPopUpAvailable();
}
});
}
});
mPopUpPrompt.show(UIWidget.REQUEST_FOCUS);

} else {
} else {
requests.second.forEach((request) -> {
if (site.get().allowed) {
request.response.complete(request.prompt.confirm(AllowOrDeny.ALLOW));

} else {
request.response.complete(request.prompt.dismiss());
}
}

});
}
}

// WindowWidget.WindowListener

@Override
public void onSessionChanged(@NonNull Session aOldSession, @NonNull Session aSession) {
aOldSession.setPromptDelegate(null);
aSession.setPromptDelegate(this);
cleanSession(aOldSession);
setUpSession(aSession);
}

// NavigationDelegate

@Override
public void onLocationChange(@NonNull GeckoSession geckoSession, @Nullable String s) {
clearPopUps();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -93,11 +93,6 @@ public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int

return false;
});
binding.site.setOnCheckedChangeListener((compoundButton, value, apply) -> {
if (mCallback != null) {
mCallback.onSwitch(binding.getItem(), value);
}
});

return new PopUpSiteViewHolder(binding);
}
Expand All @@ -107,7 +102,6 @@ public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int positi
PopUpSiteViewHolder siteHolder = (PopUpSiteViewHolder) holder;
PopUpSite site = mDisplayList.get(position);
siteHolder.binding.setItem(site);
siteHolder.binding.site.setChecked(site.allowed);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,4 @@

public interface PopUpSiteItemCallback {
void onDelete(@NonNull PopUpSite item);
void onSwitch(@NonNull PopUpSite item, boolean value);
}
Loading