From 0ef6cc60d2c161a1403a30806f69488b8de2e292 Mon Sep 17 00:00:00 2001 From: Manuel Martin Date: Thu, 9 Apr 2020 11:16:04 +0200 Subject: [PATCH] DRM --- .../vrbrowser/browser/PermissionDelegate.java | 61 ++++-- .../vrbrowser/browser/PromptDelegate.java | 176 ++---------------- .../vrbrowser/browser/SettingsStore.java | 14 +- .../content/TrackingProtectionStore.java | 4 +- .../vrbrowser/browser/engine/Session.java | 37 ++++ .../browser/engine/SessionState.java | 7 + .../browser/engine/SessionStore.java | 10 +- .../mozilla/vrbrowser/db/DataRepository.java | 2 +- .../mozilla/vrbrowser/db/SitePermission.java | 9 +- .../ui/viewmodel/SettingsViewModel.java | 42 ++++- .../ui/viewmodel/WindowViewModel.java | 24 +++ .../vrbrowser/ui/views/NavigationURLBar.java | 20 +- .../ui/views/settings/SwitchSetting.java | 1 + .../ui/widgets/NavigationBarWidget.java | 73 +++++--- .../vrbrowser/ui/widgets/WindowWidget.java | 69 +++++-- .../dialogs/PopUpBlockDialogWidget.java | 48 ----- .../dialogs/QuickPermissionWidget.java | 73 +++++--- .../widgets/settings/PrivacyOptionsView.java | 2 +- .../ui/widgets/settings/SettingsFooter.java | 16 +- .../ui/widgets/settings/SettingsHeader.java | 32 ++-- .../settings/SitePermissionsOptionsView.java | 8 +- .../main/res/drawable/ic_icon_drm_allowed.xml | 9 + .../main/res/drawable/ic_icon_drm_blocked.xml | 15 ++ ...popup_awesomebar.xml => ic_icon_popup.xml} | 0 .../res/drawable/ic_icon_popup_blocked.xml | 18 ++ app/src/main/res/layout/navigation_url.xml | 50 +++-- .../main/res/layout/options_exceptions.xml | 8 +- app/src/main/res/layout/options_header.xml | 4 +- app/src/main/res/layout/options_privacy.xml | 24 ++- .../res/layout/quick_permission_dialog.xml | 76 +++----- app/src/main/res/values-da/strings.xml | 2 +- app/src/main/res/values-de/strings.xml | 2 +- app/src/main/res/values-en-rGB/strings.xml | 2 +- app/src/main/res/values-es-rES/strings.xml | 2 +- app/src/main/res/values-fr/strings.xml | 2 +- app/src/main/res/values-it/strings.xml | 2 +- app/src/main/res/values-ko/strings.xml | 2 +- app/src/main/res/values-nl/strings.xml | 2 +- app/src/main/res/values-pl/strings.xml | 2 +- app/src/main/res/values-ru/strings.xml | 2 +- app/src/main/res/values-sv-rSE/strings.xml | 2 +- app/src/main/res/values-zh-rCN/strings.xml | 2 +- app/src/main/res/values-zh-rTW/strings.xml | 2 +- app/src/main/res/values/non_L10n.xml | 1 + app/src/main/res/values/strings.xml | 87 +++++++-- 45 files changed, 602 insertions(+), 444 deletions(-) delete mode 100644 app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/dialogs/PopUpBlockDialogWidget.java create mode 100644 app/src/main/res/drawable/ic_icon_drm_allowed.xml create mode 100644 app/src/main/res/drawable/ic_icon_drm_blocked.xml rename app/src/main/res/drawable/{ic_icon_popup_awesomebar.xml => ic_icon_popup.xml} (100%) create mode 100644 app/src/main/res/drawable/ic_icon_popup_blocked.xml diff --git a/app/src/common/shared/org/mozilla/vrbrowser/browser/PermissionDelegate.java b/app/src/common/shared/org/mozilla/vrbrowser/browser/PermissionDelegate.java index 0a13248a0..34c289da2 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/browser/PermissionDelegate.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/browser/PermissionDelegate.java @@ -105,7 +105,7 @@ void handleWebXRPermission(GeckoSession aGeckoSession, final String aUri, final .findFirst().orElse(null); } - if (site == null || site.allowed) { + if (site == null) { aCallback.grant(); session.setWebXRState(SessionState.WEBXR_ALLOWED); } else { @@ -127,11 +127,11 @@ public void release() { public void onAndroidPermissionsRequest(GeckoSession aSession, String[] permissions, Callback aCallback) { Log.d(LOGTAG, "onAndroidPermissionsRequest: " + Arrays.toString(permissions)); ArrayList missingPermissions = new ArrayList<>(); - ArrayList filteredPemissions = new ArrayList<>(); + ArrayList filteredPermissions = new ArrayList<>(); for (String permission: permissions) { if (PlatformActivity.filterPermission(permission)) { Log.d(LOGTAG, "Skipping permission: " + permission); - filteredPemissions.add(permission); + filteredPermissions.add(permission); continue; } Log.d(LOGTAG, "permission = " + permission); @@ -141,7 +141,7 @@ public void onAndroidPermissionsRequest(GeckoSession aSession, String[] permissi } if (missingPermissions.size() == 0) { - if (filteredPemissions.size() == 0) { + if (filteredPermissions.size() == 0) { Log.d(LOGTAG, "Android permissions granted"); aCallback.grant(); } else { @@ -178,7 +178,21 @@ public void onContentPermissionRequest(GeckoSession aSession, String aUri, int a } else if (aType == PERMISSION_GEOLOCATION) { type = PermissionWidget.PermissionType.Location; } else if (aType == PERMISSION_MEDIA_KEY_SYSTEM_ACCESS) { - callback.grant(); + WindowWidget windowWidget = mWidgetManager.getFocusedWindow(); + Runnable enableDrm = () -> { + if (SettingsStore.getInstance(mContext).isDrmContentPlaybackEnabled()) { + callback.grant(); + } else { + callback.reject(); + } + }; + if (SettingsStore.getInstance(mContext).isDrmContentPlaybackSet()) { + enableDrm.run(); + + } else { + windowWidget.showFirstTimeDrmDialog(enableDrm); + } + windowWidget.setDrmUsed(true); return; } else { Log.e(LOGTAG, "onContentPermissionRequest unknown permission: " + aType); @@ -274,24 +288,35 @@ public void reject() { } } - public void setPermissionAllowed(String uri, @SitePermission.Category int category, boolean allowed) { + public void addPermissionException(String uri, @SitePermission.Category int category) { @Nullable SitePermission site = mSitePermissions.stream() .filter((item) -> item.category == category && item.url.equals(uri)) .findFirst().orElse(null); - boolean wasAllowed = site == null || site.allowed; - if (allowed == wasAllowed) { - return; + + if (site == null) { + site = new SitePermission(uri, uri, category); + mSitePermissions.add(site); } - if (allowed) { - mSitePermissions.removeIf(sitePermission -> sitePermission.url.equals(uri)); - mSitePermissionModel.deleteSite(site); - } else { - if (site == null) { - site = new SitePermission(uri, uri, false, category); - mSitePermissions.add(site); + mSitePermissionModel.insertSite(site); + + // Reload URIs with the same domain + for (WindowWidget window: mWidgetManager.getWindows().getCurrentWindows()) { + Session session = window.getSession(); + if (uri.equalsIgnoreCase(UrlUtils.getHost(session.getCurrentUri()))) { + session.reload(GeckoSession.LOAD_FLAGS_BYPASS_CACHE); } - site.allowed = false; - mSitePermissionModel.insertSite(site); + } + + } + + public void removePermissionException(String uri, @SitePermission.Category int category) { + @Nullable SitePermission site = mSitePermissions.stream() + .filter((item) -> item.category == category && item.url.equals(uri)) + .findFirst().orElse(null); + + mSitePermissions.removeIf(sitePermission -> sitePermission.url.equals(uri)); + if (site != null) { + mSitePermissionModel.deleteSite(site); } // Reload URIs with the same domain diff --git a/app/src/common/shared/org/mozilla/vrbrowser/browser/PromptDelegate.java b/app/src/common/shared/org/mozilla/vrbrowser/browser/PromptDelegate.java index faab03b5c..bf4d33c4b 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/browser/PromptDelegate.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/browser/PromptDelegate.java @@ -2,8 +2,6 @@ import android.app.Application; import android.content.Context; -import android.util.Pair; -import android.util.SparseArray; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -13,28 +11,24 @@ import org.mozilla.geckoview.GeckoResult; import org.mozilla.geckoview.GeckoSession; import org.mozilla.geckoview.SlowScriptResponse; -import org.mozilla.vrbrowser.AppExecutors; import org.mozilla.vrbrowser.R; -import org.mozilla.vrbrowser.VRBrowserApplication; import org.mozilla.vrbrowser.browser.engine.Session; +import org.mozilla.vrbrowser.browser.engine.SessionState; import org.mozilla.vrbrowser.db.SitePermission; import org.mozilla.vrbrowser.ui.viewmodel.SitePermissionViewModel; 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.PopUpBlockDialogWidget; -import org.mozilla.vrbrowser.ui.widgets.dialogs.QuickPermissionWidget; import org.mozilla.vrbrowser.ui.widgets.prompts.AlertPromptWidget; import org.mozilla.vrbrowser.ui.widgets.prompts.AuthPromptWidget; import org.mozilla.vrbrowser.ui.widgets.prompts.ChoicePromptWidget; import org.mozilla.vrbrowser.ui.widgets.prompts.ConfirmPromptWidget; import org.mozilla.vrbrowser.ui.widgets.prompts.PromptWidget; import org.mozilla.vrbrowser.ui.widgets.prompts.TextPromptWidget; +import org.mozilla.vrbrowser.utils.UrlUtils; import java.util.ArrayList; -import java.util.LinkedList; import java.util.List; -import java.util.Optional; public class PromptDelegate implements GeckoSession.PromptDelegate, @@ -42,24 +36,15 @@ public class PromptDelegate implements GeckoSession.NavigationDelegate, GeckoSession.ContentDelegate { - public interface PopUpDelegate { - void onPopUpAvailable(); - void onPopUpsCleared(); - } - private PromptWidget mPrompt; - private PopUpBlockDialogWidget mPopUpPrompt; private ConfirmPromptWidget mSlowScriptPrompt; private Context mContext; private WindowWidget mAttachedWindow; private List mAllowedPopUpSites; private SitePermissionViewModel mViewModel; - private AppExecutors mExecutors; - private PopUpDelegate mPopupDelegate; public PromptDelegate(@NonNull Context context) { mContext = context; - mExecutors = ((VRBrowserApplication)context.getApplicationContext()).getExecutors(); mViewModel = new SitePermissionViewModel(((Application)context.getApplicationContext())); mAllowedPopUpSites = new ArrayList<>(); } @@ -89,8 +74,6 @@ public void detachFromWindow() { mAttachedWindow = null; } mViewModel.getAll(SitePermission.SITE_PERMISSION_POPUP).removeObserver(mPopUpSiteObserver); - - clearPopUps(); } private Session getSession() { @@ -110,19 +93,6 @@ private void cleanSession(@NonNull Session aSession) { aSession.setPromptDelegate(null); aSession.removeNavigationListener(this); aSession.removeContentListener(this); - mPopUpRequests.remove(aSession.hashCode()); - } - - public void setPopupDelegate(@Nullable PopUpDelegate delegate) { - mPopupDelegate = delegate; - } - - public void clearPopUps() { - mPopUpRequests.clear(); - - if (mPopupDelegate != null) { - mPopupDelegate.onPopUpsCleared(); - } } @Nullable @@ -276,136 +246,31 @@ public GeckoResult onPopupPrompt(@NonNull GeckoSession geckoSess result.complete(popupPrompt.confirm(AllowOrDeny.ALLOW)); } else { - final int sessionId = geckoSession.hashCode(); - final String uri = mAttachedWindow.getSession().getCurrentUri(); - - Optional site = mAllowedPopUpSites.stream().filter((item) -> item.url.equals(uri)).findFirst(); - if (site.isPresent()) { - mAttachedWindow.postDelayed(() -> { - if (site.get().allowed) { + Session session = mAttachedWindow.getSession(); + if (session != null) { + final String uri = UrlUtils.getHost(session.getCurrentUri()); + SitePermission site = mAllowedPopUpSites.stream().filter((item) -> item.url.equals(uri)).findFirst().orElse(null); + if (site != null) { + mAttachedWindow.postDelayed(() -> { result.complete(popupPrompt.confirm(AllowOrDeny.ALLOW)); + session.setPopUpState(SessionState.POPUP_ALLOWED); + }, 500); - } else { - result.complete(popupPrompt.dismiss()); - } - }, 500); - - } else { - PopUpRequest request = PopUpRequest.newRequest(popupPrompt, result, sessionId); - Pair> domainRequestList = mPopUpRequests.get(sessionId); - if (domainRequestList == null) { - LinkedList requestList = new LinkedList<>(); - domainRequestList = new Pair<>(uri, requestList); - mPopUpRequests.put(sessionId, domainRequestList); + } else { + mAttachedWindow.postDelayed(() -> { + result.complete(popupPrompt.confirm(AllowOrDeny.DENY)); + session.setPopUpState(SessionState.POPUP_BLOCKED); + }, 500); } - domainRequestList.second.add(request); - if (mPopupDelegate != null) { - mPopupDelegate.onPopUpAvailable(); - } + } else { + result.complete(popupPrompt.confirm(AllowOrDeny.DENY)); } } return result; } - static class PopUpRequest { - - public static PopUpRequest newRequest(@NonNull PopupPrompt prompt, @NonNull GeckoResult response, int sessionId) { - PopUpRequest request = new PopUpRequest(); - request.prompt = prompt; - request.response = response; - request.sessionId = sessionId; - - return request; - } - - PopupPrompt prompt; - GeckoResult response; - int sessionId; - } - - private SparseArray>> mPopUpRequests = new SparseArray<>(); - - public void showPopUps(GeckoSession session) { - if (session == null) { - return; - } - Pair> requests = mPopUpRequests.get(session.hashCode()); - if (requests != null && !requests.second.isEmpty()) { - showPopUp(session.hashCode(), requests); - } - } - - public boolean hasPendingPopUps(GeckoSession session) { - if (session != null) { - Pair> requests = mPopUpRequests.get(session.hashCode()); - if (requests != null) { - return !requests.second.isEmpty(); - } - } - - return false; - } - - private void showPopUp(int sessionId, @NonNull Pair> requests) { - String uri = requests.first; - Optional site = mAllowedPopUpSites.stream().filter((item) -> item.url.equals(uri)).findFirst(); - if (!site.isPresent()) { - mPopUpPrompt = new PopUpBlockDialogWidget(mContext); - mPopUpPrompt.setButtonsDelegate(index -> { - boolean allowed = index != PopUpBlockDialogWidget.NEGATIVE; - boolean askAgain = mPopUpPrompt.askAgain(); - if (allowed && !askAgain) { - SitePermission permission = new SitePermission(uri, uri, allowed, SitePermission.SITE_PERMISSION_POPUP); - mAllowedPopUpSites.add(permission); - mViewModel.insertSite(permission); - } - - if (allowed) { - requests.second.forEach((request) -> { - request.response.complete(request.prompt.confirm(AllowOrDeny.ALLOW)); - }); - - mPopUpRequests.remove(sessionId); - - mExecutors.mainThread().execute(() -> { - if (mPopupDelegate != null) { - mPopupDelegate.onPopUpsCleared(); - } - }); - - } else { - mExecutors.mainThread().execute(() -> { - if (mPopupDelegate != null) { - mPopupDelegate.onPopUpAvailable(); - } - }); - } - - mPopUpPrompt.hide(UIWidget.REMOVE_WIDGET); - mPopUpPrompt.releaseWidget(); - mPopUpPrompt = null; - }); - mPopUpPrompt.setDelegate(() -> mExecutors.mainThread().execute(() -> { - if (mPopupDelegate != null) { - mPopupDelegate.onPopUpAvailable(); - } - })); - mPopUpPrompt.show(UIWidget.REQUEST_FOCUS); - - } else { - requests.second.forEach((request) -> { - if (site.get().allowed) { - request.response.complete(request.prompt.confirm(AllowOrDeny.ALLOW)); - - } else { - request.response.complete(request.prompt.dismiss()); - } - }); - } - } - @Nullable @Override public GeckoResult onSlowScript(@NonNull GeckoSession aSession, @NonNull String aScriptFileName) { @@ -450,11 +315,4 @@ public void onSessionChanged(@NonNull Session aOldSession, @NonNull Session aSes cleanSession(aOldSession); setUpSession(aSession); } - - // NavigationDelegate - - @Override - public void onLocationChange(@NonNull GeckoSession geckoSession, @Nullable String s) { - clearPopUps(); - } } diff --git a/app/src/common/shared/org/mozilla/vrbrowser/browser/SettingsStore.java b/app/src/common/shared/org/mozilla/vrbrowser/browser/SettingsStore.java index e2ede5473..10f99d502 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/browser/SettingsStore.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/browser/SettingsStore.java @@ -2,12 +2,15 @@ import android.content.Context; import android.content.SharedPreferences; +import android.database.Observable; import android.graphics.Color; import android.os.StrictMode; import android.preference.PreferenceManager; import android.util.Log; import androidx.annotation.NonNull; +import androidx.databinding.ObservableBoolean; +import androidx.lifecycle.Observer; import androidx.lifecycle.ViewModelProvider; import org.json.JSONArray; @@ -17,7 +20,6 @@ import org.mozilla.telemetry.TelemetryHolder; import org.mozilla.vrbrowser.R; import org.mozilla.vrbrowser.VRBrowserActivity; -import org.mozilla.vrbrowser.VRBrowserApplication; import org.mozilla.vrbrowser.telemetry.GleanMetricsService; import org.mozilla.vrbrowser.telemetry.TelemetryWrapper; import org.mozilla.vrbrowser.ui.viewmodel.SettingsViewModel; @@ -219,10 +221,16 @@ public boolean isDrmContentPlaybackEnabled() { mContext.getString(R.string.settings_key_drm_playback), DRM_PLAYBACK_DEFAULT); } + public boolean isDrmContentPlaybackSet() { + return mPrefs.contains(mContext.getString(R.string.settings_key_drm_playback)); + } + public void setDrmContentPlaybackEnabled(boolean isEnabled) { SharedPreferences.Editor editor = mPrefs.edit(); editor.putBoolean(mContext.getString(R.string.settings_key_drm_playback), isEnabled); editor.commit(); + + mSettingsViewModel.setIsDrmEnabled(isEnabled); } public int getTrackingProtectionLevel() { @@ -616,6 +624,8 @@ public void setPopUpsBlockingEnabled(boolean isEnabled) { SharedPreferences.Editor editor = mPrefs.edit(); editor.putBoolean(mContext.getString(R.string.settings_key_pop_up_blocking), isEnabled); editor.commit(); + + mSettingsViewModel.setIsPopUpBlockingEnabled(isEnabled); } public boolean isWebXREnabled() { @@ -626,6 +636,8 @@ public void setWebXREnabled(boolean isEnabled) { SharedPreferences.Editor editor = mPrefs.edit(); editor.putBoolean(mContext.getString(R.string.settings_key_webxr), isEnabled); editor.commit(); + + mSettingsViewModel.setIsWebXREnabled(isEnabled); } public void setWhatsNewDisplayed(boolean isEnabled) { diff --git a/app/src/common/shared/org/mozilla/vrbrowser/browser/content/TrackingProtectionStore.java b/app/src/common/shared/org/mozilla/vrbrowser/browser/content/TrackingProtectionStore.java index b7830ec3b..c39497685 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/browser/content/TrackingProtectionStore.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/browser/content/TrackingProtectionStore.java @@ -183,8 +183,7 @@ public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) { SitePermission olSite = mSitePermissions.get(oldItemPosition); return newSite.url.equals(olSite.url) && Objects.equals(newSite.category, olSite.category) - && Objects.equals(newSite.principal, olSite.principal) - && newSite.allowed == olSite.allowed; + && Objects.equals(newSite.principal, olSite.principal); } }); @@ -281,7 +280,6 @@ private static SitePermission toSitePermission(@NonNull ContentBlockingException return new SitePermission( json.getString("uri"), json.getString("principal"), - false, SitePermission.SITE_PERMISSION_TRACKING); } catch (JSONException e) { diff --git a/app/src/common/shared/org/mozilla/vrbrowser/browser/engine/Session.java b/app/src/common/shared/org/mozilla/vrbrowser/browser/engine/Session.java index 41f3a2b64..ccac32ba0 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/browser/engine/Session.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/browser/engine/Session.java @@ -77,6 +77,7 @@ public class Session implements ContentBlocking.Delegate, GeckoSession.Navigatio private transient CopyOnWriteArrayList mBitmapChangedListeners; private transient CopyOnWriteArrayList mSelectionActionListeners; private transient CopyOnWriteArrayList mWebXRStateListeners; + private transient CopyOnWriteArrayList mPopUpStateStateListeners; private SessionState mState; private transient CopyOnWriteArrayList mQueuedCalls = new CopyOnWriteArrayList<>(); @@ -98,6 +99,10 @@ public interface WebXRStateChangedListener { void onWebXRStateChanged(Session aSession, @SessionState.WebXRState int aWebXRState); } + public interface PopUpStateChangedListener { + void onPopUpStateChanged(Session aSession, @SessionState.PopupState int aPopUpState); + } + @IntDef(value = { SESSION_OPEN, SESSION_DO_NOT_OPEN}) public @interface SessionOpenModeFlags {} public static final int SESSION_OPEN = 0; @@ -129,6 +134,7 @@ private void initialize() { mSelectionActionListeners = new CopyOnWriteArrayList<>(); mBitmapChangedListeners = new CopyOnWriteArrayList<>(); mWebXRStateListeners = new CopyOnWriteArrayList<>(); + mPopUpStateStateListeners = new CopyOnWriteArrayList<>(); if (mPrefs != null) { mPrefs.registerOnSharedPreferenceChangeListener(this); @@ -174,6 +180,7 @@ protected void shutdown() { mSelectionActionListeners.clear(); mBitmapChangedListeners.clear(); mWebXRStateListeners.clear(); + mPopUpStateStateListeners.clear(); if (mPrefs != null) { mPrefs.unregisterOnSharedPreferenceChangeListener(this); @@ -198,6 +205,10 @@ private void dumpAllState() { for (WebXRStateChangedListener listener: mWebXRStateListeners) { dumpState(listener); } + + for (PopUpStateChangedListener listener: mPopUpStateStateListeners) { + dumpState(listener); + } } private void dumpState(GeckoSession.NavigationDelegate aListener) { @@ -232,6 +243,10 @@ private void dumpState(WebXRStateChangedListener aListener) { aListener.onWebXRStateChanged(this, mState.mWebXRState); } + private void dumpState(PopUpStateChangedListener aListener) { + aListener.onPopUpStateChanged(this, mState.mPopUpState); + } + private void flushQueuedEvents() { for (Runnable call: mQueuedCalls) { call.run(); @@ -328,6 +343,15 @@ public void removeWebXRStateChangedListener(WebXRStateChangedListener aListener) mWebXRStateListeners.remove(aListener); } + public void addPopUpStateChangedListener(PopUpStateChangedListener aListener) { + mPopUpStateStateListeners.add(aListener); + dumpState(aListener); + } + + public void removePopUpStateChangedListener(PopUpStateChangedListener aListener) { + mPopUpStateStateListeners.remove(aListener); + } + private void setupSessionListeners(GeckoSession aSession) { aSession.setNavigationDelegate(this); aSession.setProgressDelegate(this); @@ -806,6 +830,17 @@ public void setWebXRState(@SessionState.WebXRState int aWebXRState) { return mState.mWebXRState; } + public void setPopUpState(@SessionState.PopupState int aPopUpstate) { + mState.mPopUpState = aPopUpstate; + for (PopUpStateChangedListener listener: mPopUpStateStateListeners) { + dumpState(listener); + } + } + + public @SessionState.PopupState int getPopUpState() { + return mState.mPopUpState; + } + // Session Settings protected void setServo(final boolean enabled) { @@ -901,6 +936,8 @@ public void onLocationChange(@NonNull GeckoSession aSession, String aUri) { return; } + setPopUpState(SessionState.POPUP_UNUSED); + mState.mPreviousUri = mState.mUri; mState.mUri = aUri; diff --git a/app/src/common/shared/org/mozilla/vrbrowser/browser/engine/SessionState.java b/app/src/common/shared/org/mozilla/vrbrowser/browser/engine/SessionState.java index 56bb467a2..d737f7d3f 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/browser/engine/SessionState.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/browser/engine/SessionState.java @@ -28,6 +28,12 @@ public class SessionState { public static final int WEBXR_ALLOWED = 1; public static final int WEBXR_BLOCKED = 2; + @IntDef(value = { POPUP_UNUSED, POPUP_ALLOWED, POPUP_BLOCKED}) + public @interface PopupState {} + public static final int POPUP_UNUSED = 0; + public static final int POPUP_ALLOWED = 1; + public static final int POPUP_BLOCKED = 2; + private transient boolean mIsActive; public boolean mCanGoBack; public boolean mCanGoForward; @@ -43,6 +49,7 @@ public class SessionState { public SessionSettings mSettings; public transient ArrayList mMediaElements = new ArrayList<>(); public transient @WebXRState int mWebXRState = WEBXR_UNUSED; + public transient @PopupState int mPopUpState = POPUP_UNUSED; @JsonAdapter(SessionState.GeckoSessionStateAdapter.class) public GeckoSession.SessionState mSessionState; public long mLastUse; diff --git a/app/src/common/shared/org/mozilla/vrbrowser/browser/engine/SessionStore.java b/app/src/common/shared/org/mozilla/vrbrowser/browser/engine/SessionStore.java index ab2f2fd2d..eeee545c7 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/browser/engine/SessionStore.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/browser/engine/SessionStore.java @@ -332,9 +332,15 @@ public void onMediaPermissionRequest(@NonNull GeckoSession session, @NonNull Str } } - public void setPermissionAllowed(String uri, @SitePermission.Category int category, boolean allowed) { + public void addPermissionException(String uri, @SitePermission.Category int category) { if (mPermissionDelegate != null) { - mPermissionDelegate.setPermissionAllowed(uri, category, allowed); + mPermissionDelegate.addPermissionException(uri, category); + } + } + + public void removePermissionException(String uri, @SitePermission.Category int category) { + if (mPermissionDelegate != null) { + mPermissionDelegate.removePermissionException(uri, category); } } } diff --git a/app/src/common/shared/org/mozilla/vrbrowser/db/DataRepository.java b/app/src/common/shared/org/mozilla/vrbrowser/db/DataRepository.java index d2dae61a2..a05d21033 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/db/DataRepository.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/db/DataRepository.java @@ -25,7 +25,7 @@ private DataRepository(final @NonNull AppDatabase database, final @NonNull AppEx mDatabase = database; mExecutors = executors; mLifeCycle = new LifecycleRegistry(this); - mLifeCycle.markState(Lifecycle.State.STARTED); + mLifeCycle.setCurrentState(Lifecycle.State.STARTED); mObservablePopUps = new MediatorLiveData<>(); mObservablePopUps.addSource(mDatabase.sitePermissionDao().loadAll(), diff --git a/app/src/common/shared/org/mozilla/vrbrowser/db/SitePermission.java b/app/src/common/shared/org/mozilla/vrbrowser/db/SitePermission.java index 3da5f3657..c0c900e23 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/db/SitePermission.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/db/SitePermission.java @@ -9,16 +9,16 @@ @Entity public class SitePermission { - @IntDef(value = { SITE_PERMISSION_POPUP, SITE_PERMISSION_WEBXR, SITE_PERMISSION_TRACKING}) + @IntDef(value = { SITE_PERMISSION_POPUP, SITE_PERMISSION_WEBXR, SITE_PERMISSION_TRACKING, SITE_PERMISSION_DRM}) public @interface Category {} public static final int SITE_PERMISSION_POPUP = 0; public static final int SITE_PERMISSION_WEBXR = 1; public static final int SITE_PERMISSION_TRACKING = 2; + public static final int SITE_PERMISSION_DRM = 3; - public SitePermission(@NonNull String url, @NonNull String principal, boolean allowed, @Category int category) { + public SitePermission(@NonNull String url, @NonNull String principal, @Category int category) { this.url = url; this.principal = principal; - this.allowed = allowed; this.category = category; } @@ -32,9 +32,6 @@ public SitePermission(@NonNull String url, @NonNull String principal, boolean al @ColumnInfo(name = "principal") public String principal; - @ColumnInfo(name = "allowed") - public boolean allowed; - @ColumnInfo(name = "category") public @Category int category; } diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/viewmodel/SettingsViewModel.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/viewmodel/SettingsViewModel.java index 94b47c2f4..038e4b12f 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/viewmodel/SettingsViewModel.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/viewmodel/SettingsViewModel.java @@ -1,7 +1,6 @@ package org.mozilla.vrbrowser.ui.viewmodel; import android.app.Application; -import android.content.SharedPreferences; import androidx.annotation.NonNull; import androidx.databinding.ObservableBoolean; @@ -14,17 +13,32 @@ public class SettingsViewModel extends AndroidViewModel { private MutableLiveData isTrackingProtectionEnabled; + private MutableLiveData isDRMEnabled; + private MutableLiveData isPopupBlockingEnabled; + private MutableLiveData isWebXREnabled; public SettingsViewModel(@NonNull Application application) { super(application); - isTrackingProtectionEnabled = new MutableLiveData<>(new ObservableBoolean(true)); + isTrackingProtectionEnabled = new MutableLiveData<>(new ObservableBoolean(false)); + isDRMEnabled = new MutableLiveData<>(new ObservableBoolean(false)); + isPopupBlockingEnabled = new MutableLiveData<>(new ObservableBoolean(false)); + isWebXREnabled = new MutableLiveData<>(new ObservableBoolean(false)); } public void refresh() { int level = SettingsStore.getInstance(getApplication().getBaseContext()).getTrackingProtectionLevel(); boolean isEnabled = level != ContentBlocking.EtpLevel.NONE; isTrackingProtectionEnabled.setValue(new ObservableBoolean(isEnabled)); + + boolean drmEnabled = SettingsStore.getInstance(getApplication().getBaseContext()).isDrmContentPlaybackEnabled(); + isDRMEnabled = new MutableLiveData<>(new ObservableBoolean(drmEnabled)); + + boolean popupBlockingEnabled = SettingsStore.getInstance(getApplication().getBaseContext()).isPopUpsBlockingEnabled(); + isPopupBlockingEnabled = new MutableLiveData<>(new ObservableBoolean(popupBlockingEnabled)); + + boolean webxrEnabled = SettingsStore.getInstance(getApplication().getBaseContext()).isWebXREnabled(); + isWebXREnabled = new MutableLiveData<>(new ObservableBoolean(webxrEnabled)); } public void setIsTrackingProtectionEnabled(boolean isEnabled) { @@ -35,4 +49,28 @@ public MutableLiveData getIsTrackingProtectionEnabled() { return isTrackingProtectionEnabled; } + public void setIsDrmEnabled(boolean isEnabled) { + this.isDRMEnabled.setValue(new ObservableBoolean(isEnabled)); + } + + public MutableLiveData getIsDrmEnabled() { + return isDRMEnabled; + } + + public void setIsPopUpBlockingEnabled(boolean isEnabled) { + this.isPopupBlockingEnabled.setValue(new ObservableBoolean(isEnabled)); + } + + public MutableLiveData getIsPopUpBlockingEnabled() { + return isPopupBlockingEnabled; + } + + public void setIsWebXREnabled(boolean isEnabled) { + this.isWebXREnabled.setValue(new ObservableBoolean(isEnabled)); + } + + public MutableLiveData getIsWebXREnabled() { + return isWebXREnabled; + } + } diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/viewmodel/WindowViewModel.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/viewmodel/WindowViewModel.java index e0f962aef..cdd7d2fa7 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/viewmodel/WindowViewModel.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/viewmodel/WindowViewModel.java @@ -55,6 +55,7 @@ public class WindowViewModel extends AndroidViewModel { private MutableLiveData isFocused; private MutableLiveData isUrlEmpty; private MutableLiveData isPopUpAvailable; + private MutableLiveData isPopUpBlocked; private MutableLiveData canGoForward; private MutableLiveData canGoBack; private MutableLiveData isInVRVideo; @@ -68,6 +69,7 @@ public class WindowViewModel extends AndroidViewModel { private MutableLiveData isWebXRUsed; private MutableLiveData isWebXRBlocked; private MutableLiveData isTrackingEnabled; + private MutableLiveData isDrmUsed; public WindowViewModel(Application application) { super(application); @@ -131,6 +133,7 @@ public WindowViewModel(Application application) { isFocused = new MutableLiveData<>(new ObservableBoolean(false)); isUrlEmpty = new MutableLiveData<>(new ObservableBoolean(true)); isPopUpAvailable = new MutableLiveData<>(new ObservableBoolean(false)); + isPopUpBlocked = new MutableLiveData<>(new ObservableBoolean(false)); canGoForward = new MutableLiveData<>(new ObservableBoolean(false)); canGoBack = new MutableLiveData<>(new ObservableBoolean(false)); isInVRVideo = new MutableLiveData<>(new ObservableBoolean(false)); @@ -161,6 +164,7 @@ public WindowViewModel(Application application) { isWebXRBlocked = new MutableLiveData<>(new ObservableBoolean(false)); isTrackingEnabled = new MutableLiveData<>(new ObservableBoolean(true)); + isDrmUsed = new MutableLiveData<>(new ObservableBoolean(false)); } private Observer mIsTopBarVisibleObserver = new Observer() { @@ -303,6 +307,7 @@ public void refresh() { isFocused.postValue(isFocused.getValue()); isUrlEmpty.postValue(isUrlEmpty.getValue()); isPopUpAvailable.postValue(isPopUpAvailable.getValue()); + isPopUpBlocked.postValue(isPopUpBlocked.getValue()); canGoForward.postValue(canGoForward.getValue()); canGoBack.postValue(canGoBack.getValue()); isInVRVideo.postValue(isInVRVideo.getValue()); @@ -313,6 +318,7 @@ public void refresh() { isWebXRUsed.postValue(isWebXRUsed.getValue()); isWebXRBlocked.postValue(isWebXRBlocked.getValue()); isTrackingEnabled.postValue(isTrackingEnabled.getValue()); + isDrmUsed.postValue(isDrmUsed.getValue()); } @NonNull @@ -667,6 +673,15 @@ public void setIsPopUpAvailable(boolean isPopUpAvailable) { this.isPopUpAvailable.postValue(new ObservableBoolean(isPopUpAvailable)); } + @NonNull + public MutableLiveData getIsPopUpBlocked() { + return isPopUpBlocked; + } + + public void setIsPopUpBlocked(boolean isPopUpBlocked) { + this.isPopUpBlocked.postValue(new ObservableBoolean(isPopUpBlocked)); + } + @NonNull public MutableLiveData getIsTrackingEnabled() { return isTrackingEnabled; @@ -675,4 +690,13 @@ public MutableLiveData getIsTrackingEnabled() { public void setIsTrackingEnabled(boolean isTrackingEnabled) { this.isTrackingEnabled.postValue(new ObservableBoolean(isTrackingEnabled)); } + + @NonNull + public MutableLiveData getIsDrmUsed() { + return isDrmUsed; + } + + public void setIsDrmUsed(boolean isEnabled) { + this.isDrmUsed.postValue(new ObservableBoolean(isEnabled)); + } } diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/views/NavigationURLBar.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/views/NavigationURLBar.java index ae20cc44a..c95fcf08a 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/views/NavigationURLBar.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/views/NavigationURLBar.java @@ -99,6 +99,7 @@ public interface NavigationURLBarDelegate { void onPopUpButtonClicked(); void onWebXRButtonClicked(); void onTrackingButtonClicked(); + void onDrmButtonClicked(); } public NavigationURLBar(Context context, AttributeSet attrs) { @@ -229,6 +230,7 @@ private void initialize(Context aContext) { mBinding.popup.setOnClickListener(mPopUpListener); mBinding.webxr.setOnClickListener(mWebXRButtonClick); mBinding.tracking.setOnClickListener(mTrackingButtonClick); + mBinding.drm.setOnClickListener(mDrmButtonClick); // Bookmarks mBinding.bookmarkButton.setOnClickListener(v -> handleBookmarkClick()); @@ -342,14 +344,18 @@ public UIButton getPopUpButton() { return mBinding.popup; } - public UIButton getWebxRButton() { + public UIButton getWebXRButton() { return mBinding.webxr; } - public UIButton getTrackingRButton() { + public UIButton getTrackingButton() { return mBinding.tracking; } + public UIButton getDrmButton() { + return mBinding.drm; + } + public void handleURLEdit(String text) { text = text.trim(); @@ -434,6 +440,16 @@ public void setClickable(boolean clickable) { } }; + private OnClickListener mDrmButtonClick = view -> { + if (mAudio != null) { + mAudio.playSound(AudioEngine.Sound.CLICK); + } + + if (mDelegate != null) { + mDelegate.onDrmButtonClicked(); + } + }; + private TextWatcher mURLTextWatcher = new TextWatcher() { @Override public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) { diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/views/settings/SwitchSetting.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/views/settings/SwitchSetting.java index 7fb0f6548..1333970e8 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/views/settings/SwitchSetting.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/views/settings/SwitchSetting.java @@ -10,6 +10,7 @@ import android.widget.TextView; import androidx.annotation.NonNull; +import androidx.annotation.StringRes; import org.mozilla.vrbrowser.R; import org.mozilla.vrbrowser.audio.AudioEngine; diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/NavigationBarWidget.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/NavigationBarWidget.java index 88d6d3da9..7104c9878 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/NavigationBarWidget.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/NavigationBarWidget.java @@ -33,12 +33,11 @@ import org.mozilla.vrbrowser.VRBrowserApplication; import org.mozilla.vrbrowser.audio.AudioEngine; import org.mozilla.vrbrowser.browser.Media; -import org.mozilla.vrbrowser.browser.PromptDelegate; import org.mozilla.vrbrowser.browser.SessionChangeListener; import org.mozilla.vrbrowser.browser.SettingsStore; +import org.mozilla.vrbrowser.browser.content.TrackingProtectionStore; import org.mozilla.vrbrowser.browser.engine.Session; import org.mozilla.vrbrowser.browser.engine.SessionStore; -import org.mozilla.vrbrowser.browser.content.TrackingProtectionStore; import org.mozilla.vrbrowser.databinding.NavigationBarBinding; import org.mozilla.vrbrowser.db.SitePermission; import org.mozilla.vrbrowser.search.suggestions.SuggestionsProvider; @@ -64,6 +63,8 @@ import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicBoolean; +import static org.mozilla.vrbrowser.db.SitePermission.SITE_PERMISSION_DRM; +import static org.mozilla.vrbrowser.db.SitePermission.SITE_PERMISSION_POPUP; import static org.mozilla.vrbrowser.db.SitePermission.SITE_PERMISSION_TRACKING; import static org.mozilla.vrbrowser.ui.widgets.menus.VideoProjectionMenuWidget.VIDEO_PROJECTION_NONE; @@ -475,7 +476,6 @@ public void detachFromWindow() { } if (mAttachedWindow != null) { mAttachedWindow.removeWindowListener(this); - mAttachedWindow.setPopUpDelegate(null); } mAttachedWindow = null; if (mAwesomeBar != null && mAwesomeBar.isVisible()) { @@ -489,6 +489,7 @@ public void detachFromWindow() { if (mViewModel != null) { mViewModel.getIsFullscreen().removeObserver(mIsFullscreenObserver); mViewModel.getIsActiveWindow().removeObserver(mIsActiveWindowObserver); + mViewModel.getIsPopUpBlocked().removeObserver(mIsPopUpBlockedListener); mViewModel.getUrl().removeObserver(mUrlObserver); mViewModel = null; } @@ -515,13 +516,13 @@ public void attachToWindow(@NonNull WindowWidget aWindow) { mViewModel.getIsFullscreen().observeForever( mIsFullscreenObserver); mViewModel.getIsActiveWindow().observeForever(mIsActiveWindowObserver); + mViewModel.getIsPopUpBlocked().observeForever(mIsPopUpBlockedListener); mViewModel.getUrl().observeForever(mUrlObserver); mBinding.navigationBarNavigation.urlBar.attachToWindow(mAttachedWindow); mTrackingDelegate.addListener(mTrackingListener); mAttachedWindow.addWindowListener(this); - mAttachedWindow.setPopUpDelegate(mPopUpDelegate); clearFocus(); @@ -555,8 +556,6 @@ private void cleanSession(@NonNull Session aSession) { @Override public void onSessionChanged(@NonNull Session aOldSession, @NonNull Session aSession) { - mViewModel.setIsPopUpAvailable(mAttachedWindow.hasPendingPopUps()); - cleanSession(aOldSession); setUpSession(aSession); } @@ -838,6 +837,15 @@ private void closeFloatingMenus() { private Observer mIsActiveWindowObserver = aIsActiveWindow -> updateTrackingProtection(); + private Observer mIsPopUpBlockedListener = observableBoolean -> { + if (observableBoolean.get()) { + showPopUpsBlockedNotification(); + + } else { + hidePopUpsBlockedNotification(); + } + }; + private void updateTrackingProtection() { if (getSession() != null) { mTrackingDelegate.contains(getSession(), isExcluded -> { @@ -850,7 +858,7 @@ private void updateTrackingProtection() { mTrackingDelegate.fetchAll(sitePermissions -> { Log.d(LOGTAG, "Start"); - sitePermissions.forEach(site -> Log.d(LOGTAG, site.url + " - " + site.allowed)); + sitePermissions.forEach(site -> Log.d(LOGTAG, site.url)); Log.d(LOGTAG, "End"); return null; @@ -965,21 +973,30 @@ public void onURLSelectionAction(EditText aURLEdit, float centerX, SelectionActi @Override public void onPopUpButtonClicked() { - mAttachedWindow.showPopUps(); + toggleQuickPermission(mBinding.navigationBarNavigation.urlBar.getWebXRButton(), + SitePermission.SITE_PERMISSION_POPUP, + !mViewModel.getIsPopUpBlocked().getValue().get()); } @Override public void onWebXRButtonClicked() { - toggleQuickPermission(mBinding.navigationBarNavigation.urlBar.getWebxRButton(), + toggleQuickPermission(mBinding.navigationBarNavigation.urlBar.getWebXRButton(), SitePermission.SITE_PERMISSION_WEBXR, mViewModel.getIsWebXRBlocked().getValue().get()); } @Override public void onTrackingButtonClicked() { - toggleQuickPermission(mBinding.navigationBarNavigation.urlBar.getTrackingRButton(), + toggleQuickPermission(mBinding.navigationBarNavigation.urlBar.getTrackingButton(), SitePermission.SITE_PERMISSION_TRACKING, - mViewModel.getIsTrackingEnabled().getValue().get()); + !mViewModel.getIsTrackingEnabled().getValue().get()); + } + + @Override + public void onDrmButtonClicked() { + toggleQuickPermission(mBinding.navigationBarNavigation.urlBar.getTrackingButton(), + SitePermission.SITE_PERMISSION_DRM, + !SettingsStore.getInstance(getContext()).isDrmContentPlaybackEnabled()); } // VoiceSearch Delegate @@ -1135,20 +1152,6 @@ public void showSendTabDialog() { mSendTabDialog.show(UIWidget.REQUEST_FOCUS); } - private PromptDelegate.PopUpDelegate mPopUpDelegate = new PromptDelegate.PopUpDelegate() { - @Override - public void onPopUpAvailable() { - showPopUpsBlockedNotification(); - mViewModel.setIsPopUpAvailable(true); - } - - @Override - public void onPopUpsCleared() { - mViewModel.setIsPopUpAvailable(false); - hidePopUpsBlockedNotification(); - } - }; - public void showPopUpsBlockedNotification() { final int POP_UP_NOTIFICATION_DELAY = 800; mBlockedCount++; @@ -1242,11 +1245,17 @@ private void toggleQuickPermission(UIButton target, @SitePermission.Category int public void onBlock() { if (aCategory == SITE_PERMISSION_TRACKING) { if (getSession() != null) { - mTrackingDelegate.remove(getSession()); + mTrackingDelegate.add(getSession()); } + } else if (aCategory == SITE_PERMISSION_DRM) { + SettingsStore.getInstance(getContext()).setDrmContentPlaybackEnabled(false); + + } else if (aCategory == SITE_PERMISSION_POPUP) { + SessionStore.get().addPermissionException(uri, aCategory); + } else { - SessionStore.get().setPermissionAllowed(uri, aCategory, false); + SessionStore.get().addPermissionException(uri, aCategory); } mQuickPermissionWidget.onDismiss(); } @@ -1255,11 +1264,17 @@ public void onBlock() { public void onAllow() { if (aCategory == SITE_PERMISSION_TRACKING) { if (getSession() != null) { - mTrackingDelegate.add(getSession()); + mTrackingDelegate.remove(getSession()); } + } else if (aCategory == SITE_PERMISSION_DRM) { + SettingsStore.getInstance(getContext()).setDrmContentPlaybackEnabled(true); + + } else if (aCategory == SITE_PERMISSION_POPUP) { + SessionStore.get().removePermissionException(uri, aCategory); + } else { - SessionStore.get().setPermissionAllowed(uri, aCategory, true); + SessionStore.get().removePermissionException(uri, aCategory); } mQuickPermissionWidget.onDismiss(); } diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/WindowWidget.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/WindowWidget.java index 6d7a355bf..e2a1737a1 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/WindowWidget.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/WindowWidget.java @@ -6,6 +6,7 @@ package org.mozilla.vrbrowser.ui.widgets; import android.content.Context; +import android.content.SharedPreferences; import android.content.res.Configuration; import android.graphics.Canvas; import android.graphics.Matrix; @@ -14,6 +15,7 @@ import android.graphics.RectF; import android.graphics.SurfaceTexture; import android.net.Uri; +import android.preference.PreferenceManager; import android.util.Log; import android.util.Pair; import android.view.KeyEvent; @@ -84,7 +86,8 @@ public class WindowWidget extends UIWidget implements SessionChangeListener, GeckoSession.ContentDelegate, GeckoSession.NavigationDelegate, VideoAvailabilityListener, GeckoSession.HistoryDelegate, GeckoSession.ProgressDelegate, GeckoSession.SelectionActionDelegate, - Session.WebXRStateChangedListener { + Session.WebXRStateChangedListener, Session.PopUpStateChangedListener, + SharedPreferences.OnSharedPreferenceChangeListener { @IntDef(value = { SESSION_RELEASE_DISPLAY, SESSION_DO_NOT_RELEASE_DISPLAY}) public @interface OldSessionDisplayAction {} @@ -136,6 +139,7 @@ public class WindowWidget extends UIWidget implements SessionChangeListener, private Executor mUIThreadExecutor; private WindowViewModel mViewModel; private CopyOnWriteArrayList mSetViewQueuedCalls; + private SharedPreferences mPrefs; public interface WindowListener { default void onFocusRequest(@NonNull WindowWidget aWindow) {} @@ -145,6 +149,15 @@ default void onFullScreen(@NonNull WindowWidget aWindow, boolean aFullScreen) {} default void onVideoAvailabilityChanged(@NonNull WindowWidget aWindow) {} } + @Override + public void onSharedPreferenceChanged(@NonNull SharedPreferences sharedPreferences, String key) { + if (key.equals(getContext().getString(R.string.settings_key_drm_playback))) { + if (mViewModel.getIsDrmUsed().getValue().get() && getSession() != null) { + getSession().reload(GeckoSession.LOAD_FLAGS_BYPASS_CACHE); + } + } + } + public WindowWidget(Context aContext, int windowId, boolean privateMode) { super(aContext); mWindowId = windowId; @@ -162,6 +175,9 @@ public WindowWidget(Context aContext, int windowId, Session aSession) { private void initialize(Context aContext) { mSetViewQueuedCalls = new CopyOnWriteArrayList<>(); + mPrefs = PreferenceManager.getDefaultSharedPreferences(getContext()); + mPrefs.registerOnSharedPreferenceChangeListener(this); + mWidgetManager = (WidgetManagerDelegate) aContext; mBorderWidth = SettingsStore.getInstance(aContext).getTransparentBorderWidth(); @@ -232,10 +248,6 @@ protected void initializeWidgetPlacement(WidgetPlacement aPlacement) { // Check Windows.placeWindow method for remaining placement set-up } - public void setPopUpDelegate(@Nullable PromptDelegate.PopUpDelegate delegate) { - mPromptDelegate.setPopupDelegate(delegate); - } - void setupListeners(Session aSession) { aSession.addSessionChangeListener(this); aSession.addContentListener(this); @@ -245,6 +257,7 @@ void setupListeners(Session aSession) { aSession.setHistoryDelegate(this); aSession.addSelectionActionListener(this); aSession.addWebXRStateChangedListener(this); + aSession.addPopUpStateChangedListener(this); } void cleanListeners(Session aSession) { @@ -256,6 +269,7 @@ void cleanListeners(Session aSession) { aSession.setHistoryDelegate(null); aSession.removeSelectionActionListener(this); aSession.removeWebXRStateChangedListener(this); + aSession.removePopUpStateChangedListener(this); } @Override @@ -937,6 +951,8 @@ public void releaseWidget() { cleanListeners(mSession); GeckoSession session = mSession.getGeckoSession(); + mPrefs.unregisterOnSharedPreferenceChangeListener(this); + mSetViewQueuedCalls.clear(); if (mSession != null) { mSession.releaseDisplay(); @@ -1063,19 +1079,8 @@ public void setSession(@NonNull Session aSession, @OldSessionDisplayAction int a hideLibraryPanels(); } - - public void showPopUps() { - if (mPromptDelegate != null) { - mPromptDelegate.showPopUps(getSession().getGeckoSession()); - } - } - - public boolean hasPendingPopUps() { - if (mPromptDelegate != null) { - return mPromptDelegate.hasPendingPopUps(getSession().getGeckoSession()); - } - - return false; + public void setDrmUsed(boolean isEnabled) { + mViewModel.setIsDrmUsed(isEnabled); } // Session.GeckoSessionChange @@ -1280,6 +1285,24 @@ public void showClearCacheDialog() { mClearHistoryDialog.show(REQUEST_FOCUS); } + public void showFirstTimeDrmDialog(@NonNull Runnable callback) { + showConfirmPrompt( + getContext().getString(R.string.drm_first_use_title), + getContext().getString(R.string.drm_first_use_body), + new String[]{ + getContext().getString(R.string.drm_first_use_do_not_enable), + getContext().getString(R.string.drm_first_use_enable), + }, + index -> { + // We remove the prefs listener before the first DRM update to avoid reloading the session + mPrefs.unregisterOnSharedPreferenceChangeListener(this); + SettingsStore.getInstance(getContext()).setDrmContentPlaybackEnabled(index == PromptDialogWidget.POSITIVE); + mPrefs.registerOnSharedPreferenceChangeListener(this); + callback.run(); + } + ); + } + public void setMaxWindowScale(float aScale) { if (mMaxWindowScale != aScale) { mMaxWindowScale = aScale; @@ -1692,6 +1715,7 @@ public void captureImage() { @Override public void onLocationChange(@NonNull GeckoSession session, @Nullable String url) { mViewModel.setUrl(url); + mViewModel.setIsDrmUsed(false); if (StringUtils.isEmpty(url)) { mViewModel.setIsBookmarked(false); @@ -1952,9 +1976,18 @@ public void onHideAction(@NonNull GeckoSession aSession, int aHideReason) { } // WebXRStateChangedListener + @Override public void onWebXRStateChanged(Session aSession, @SessionState.WebXRState int aWebXRState) { mViewModel.setIsWebXRBlocked(aWebXRState == SessionState.WEBXR_BLOCKED); mViewModel.setIsWebXRUsed(aWebXRState != SessionState.WEBXR_UNUSED); } + + // PopUpStateChangedListener + + @Override + public void onPopUpStateChanged(Session aSession, @SessionState.PopupState int aPopUpState) { + mViewModel.setIsPopUpBlocked(aPopUpState == SessionState.POPUP_BLOCKED); + mViewModel.setIsPopUpAvailable(aPopUpState != SessionState.POPUP_UNUSED); + } } diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/dialogs/PopUpBlockDialogWidget.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/dialogs/PopUpBlockDialogWidget.java deleted file mode 100644 index 220709a2a..000000000 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/dialogs/PopUpBlockDialogWidget.java +++ /dev/null @@ -1,48 +0,0 @@ -/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*- - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -package org.mozilla.vrbrowser.ui.widgets.dialogs; - -import android.content.Context; - -import org.mozilla.vrbrowser.R; - -public class PopUpBlockDialogWidget extends PromptDialogWidget { - - private boolean mIsChecked; - - public PopUpBlockDialogWidget(Context aContext) { - super(aContext); - } - - @Override - protected void initialize(Context aContext) { - super.initialize(aContext); - } - - @Override - public void updateUI() { - super.updateUI(); - - setDescriptionVisible(false); - - setButtons(new int[] { - R.string.popup_block_button_cancel, - R.string.popup_block_button_show - }); - - setIcon(R.drawable.ff_logo); - setTitle(String.format(getContext().getString(R.string.popup_block_title), getContext().getString(R.string.app_name))); - setBody(R.string.popup_block_description); - setCheckboxText(R.string.popup_block_checkbox); - - mBinding.checkbox.setOnCheckedChangeListener((buttonView, isChecked) -> mIsChecked = isChecked); - } - - public boolean askAgain() { - return !mIsChecked; - } - -} diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/dialogs/QuickPermissionWidget.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/dialogs/QuickPermissionWidget.java index 922584c8c..0c2610f8f 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/dialogs/QuickPermissionWidget.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/dialogs/QuickPermissionWidget.java @@ -4,11 +4,11 @@ import android.content.res.Configuration; import android.view.LayoutInflater; import android.view.View; +import android.widget.CompoundButton; -import androidx.annotation.NonNull; import androidx.databinding.DataBindingUtil; + import org.mozilla.vrbrowser.R; -import org.mozilla.vrbrowser.browser.engine.SessionStore; import org.mozilla.vrbrowser.databinding.QuickPermissionDialogBinding; import org.mozilla.vrbrowser.db.SitePermission; import org.mozilla.vrbrowser.ui.widgets.UIWidget; @@ -24,7 +24,7 @@ public interface Delegate { private Delegate mDelegate; private String mDomain = ""; - QuickPermissionDialogBinding mBinding; + private QuickPermissionDialogBinding mBinding; private @SitePermission.Category int mCategory = SitePermission.SITE_PERMISSION_WEBXR; public QuickPermissionWidget(Context aContext) { @@ -35,49 +35,58 @@ public QuickPermissionWidget(Context aContext) { private void initialize() { LayoutInflater inflater = LayoutInflater.from(getContext()); mBinding = DataBindingUtil.inflate(inflater, R.layout.quick_permission_dialog, this, true); - mBinding.setBlockButtonVisible(false); - mBinding.allowButton.setOnClickListener(v -> { - if (mDelegate != null) { - mDelegate.onAllow(); - } - }); - mBinding.blockButton.setOnClickListener(v -> { - if (mDelegate != null) { - mDelegate.onBlock(); - } - }); + mBinding.setIsBlocked(false); updateUI(); } public void setData(String uri, int aCategory, boolean aBlocked) { mCategory = aCategory; mDomain = uri; - mBinding.setBlockButtonVisible(aBlocked); + mBinding.setIsBlocked(aBlocked); updateUI(); } public void updateUI() { switch (mCategory) { + case SitePermission.SITE_PERMISSION_POPUP: { + mBinding.message.setText( + getResources().getString(R.string.popup_permission_dialog_message, + mBinding.getIsBlocked() ? + getResources().getString(R.string.off).toUpperCase() : + getResources().getString(R.string.on).toUpperCase())); + mBinding.setOnText(getResources().getString(R.string.popup_dialog_button_on)); + mBinding.setOffText(getResources().getString(R.string.popup_dialog_button_off)); + break; + } case SitePermission.SITE_PERMISSION_WEBXR: { mBinding.message.setText( getResources().getString(R.string.webxr_permission_dialog_message, - mBinding.getBlockButtonVisible() ? + mBinding.getIsBlocked() ? getResources().getString(R.string.off).toUpperCase() : getResources().getString(R.string.on).toUpperCase(), getResources().getString(R.string.sumo_webxr_url))); - mBinding.allowButton.setText(R.string.permission_allow); - mBinding.blockButton.setText(R.string.pop_up_site_switch_block); + mBinding.setOnText(getResources().getString(R.string.webxr_dialog_button_on)); + mBinding.setOffText(getResources().getString(R.string.webxr_dialog_button_off)); break; } case SitePermission.SITE_PERMISSION_TRACKING: { mBinding.message.setText( getResources().getString(R.string.tracking_dialog_message, - mBinding.getBlockButtonVisible() ? - getResources().getString(R.string.on).toUpperCase() : - getResources().getString(R.string.off).toUpperCase(), + mBinding.getIsBlocked() ? + getResources().getString(R.string.off).toUpperCase() : + getResources().getString(R.string.on).toUpperCase(), getResources().getString(R.string.sumo_etp_url))); - mBinding.allowButton.setText(R.string.tracking_dialog_button_disable); - mBinding.blockButton.setText(R.string.tracking_dialog_button_enable); + mBinding.setOnText(getResources().getString(R.string.tracking_dialog_button_on)); + mBinding.setOffText(getResources().getString(R.string.tracking_dialog_button_off)); + break; + } + case SitePermission.SITE_PERMISSION_DRM: { + mBinding.message.setText( + getResources().getString(R.string.drm_dialog_message, + getResources().getString(R.string.app_name), + getResources().getString(R.string.sumo_drm_url))); + mBinding.setOnText(getResources().getString(R.string.drm_dialog_button_on)); + mBinding.setOffText(getResources().getString(R.string.drm_dialog_button_off)); break; } } @@ -87,6 +96,10 @@ public void updateUI() { onDismiss(); }); + mBinding.enableSwitch.setOnCheckedChangeListener (null); + mBinding.enableSwitch.setChecked(!mBinding.getIsBlocked()); + mBinding.enableSwitch.setOnCheckedChangeListener(mSwitchListener); + mBinding.executePendingBindings(); } @@ -131,7 +144,21 @@ public void hide(@HideFlags int aHideFlags) { mWidgetManager.removeFocusChangeListener(this); } + private CompoundButton.OnCheckedChangeListener mSwitchListener = new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + if (mDelegate != null) { + if (isChecked) { + mDelegate.onAllow(); + } else { + mDelegate.onBlock(); + } + } + } + }; + // WidgetManagerDelegate.FocusChangeListener + @Override public void onGlobalFocusChanged(View oldFocus, View newFocus) { if (!ViewUtils.isEqualOrChildrenOf(this, newFocus)) { diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/settings/PrivacyOptionsView.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/settings/PrivacyOptionsView.java index 19c215aef..e885915ff 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/settings/PrivacyOptionsView.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/settings/PrivacyOptionsView.java @@ -105,6 +105,7 @@ protected void updateUI() { } mBinding.drmContentPlaybackSwitch.setOnCheckedChangeListener(mDrmContentListener); + mBinding.drmContentPlaybackSwitch.setDescription(getResources().getString(R.string.security_options_drm_content_v1, getResources().getString(R.string.sumo_drm_url))); mBinding.drmContentPlaybackSwitch.setLinkClickListener((widget, url) -> { mWidgetManager.openNewTabForeground(url); exitWholeSettings(); @@ -246,7 +247,6 @@ private void setDrmContent(boolean value, boolean doApply) { if (doApply) { SettingsStore.getInstance(getContext()).setDrmContentPlaybackEnabled(value); - // TODO Enable/Disable DRM content playback } } diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/settings/SettingsFooter.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/settings/SettingsFooter.java index a807f0c2b..e8150d8ba 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/settings/SettingsFooter.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/settings/SettingsFooter.java @@ -50,17 +50,15 @@ private void initialize(@NonNull Context aContext, @Nullable AttributeSet attrs, mBinding = DataBindingUtil.inflate(inflater, R.layout.options_footer, this, true); TypedArray attributes = aContext.obtainStyledAttributes(attrs, R.styleable.SettingsFooter, defStyleAttr, defStyleRes); - if (attributes != null) { - String buttonText = attributes.getString(R.styleable.SettingsFooter_buttonText); - String description = attributes.getString(R.styleable.SettingsFooter_description); + String buttonText = attributes.getString(R.styleable.SettingsFooter_buttonText); + String description = attributes.getString(R.styleable.SettingsFooter_description); - if (buttonText != null) { - mBinding.resetButton.setButtonText(buttonText); - } + if (buttonText != null) { + mBinding.resetButton.setButtonText(buttonText); + } - if (description != null) { - mBinding.resetButton.setDescription(description); - } + if (description != null) { + mBinding.resetButton.setDescription(description); } attributes.recycle(); } diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/settings/SettingsHeader.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/settings/SettingsHeader.java index 9d443673b..ddf6b9aeb 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/settings/SettingsHeader.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/settings/SettingsHeader.java @@ -55,23 +55,21 @@ private void initialize(@NonNull Context aContext, @NonNull TypedArray attribute // Inflate this data binding layout mBinding = DataBindingUtil.inflate(inflater, R.layout.options_header, this, true); - if (attributes != null) { - String title = attributes.getString(R.styleable.SettingsHeader_title); - String description = attributes.getString(R.styleable.SettingsHeader_description); - int helpVisibility = attributes.getInt(R.styleable.SettingsHeader_helpVisibility, VISIBLE); - - if (title != null) { - mBinding.setTitle(title); - } - - if (description != null) { - mBinding.setDescription(description); - } else { - mBinding.displayLanguageDescription.setVisibility(View.GONE); - } - - mBinding.setHelpVisibility(helpVisibility); + String title = attributes.getString(R.styleable.SettingsHeader_title); + String description = attributes.getString(R.styleable.SettingsHeader_description); + int helpVisibility = attributes.getInt(R.styleable.SettingsHeader_helpVisibility, VISIBLE); + + if (title != null) { + mBinding.setTitle(title); + } + + if (description != null) { + mBinding.setDescription(description); + } else { + mBinding.displayLanguageDescription.setVisibility(View.GONE); } + + mBinding.setHelpVisibility(helpVisibility); } public void setBackClickListener(@NonNull View.OnClickListener listener) { @@ -92,10 +90,12 @@ public void setTitle(@StringRes int textRes) { public void setDescription(@NonNull String text) { mBinding.setDescription(text); + mBinding.displayLanguageDescription.setVisibility(View.VISIBLE); } public void setDescription(@StringRes int textRes) { mBinding.setDescription(getResources().getString(textRes)); + mBinding.displayLanguageDescription.setVisibility(View.VISIBLE); } } diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/settings/SitePermissionsOptionsView.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/settings/SitePermissionsOptionsView.java index facf461a6..3747b98b2 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/settings/SitePermissionsOptionsView.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/settings/SitePermissionsOptionsView.java @@ -76,25 +76,19 @@ protected void updateUI() { switch (mCategory) { case SitePermission.SITE_PERMISSION_POPUP: mBinding.headerLayout.setTitle(R.string.settings_privacy_policy_popups_title); - mBinding.headerLayout.setDescription(R.string.privacy_options_popups_list_header); - mBinding.contentText.setText(R.string.privacy_options_popups_list_header); + mBinding.contentText.setText(R.string.privacy_options_popups_list_header_v1); mBinding.emptyText.setText(R.string.privacy_options_popups_list_empty_first); - mBinding.footerLayout.setDescription(R.string.privacy_options_popups_reset); break; case SitePermission.SITE_PERMISSION_WEBXR: mBinding.headerLayout.setTitle(R.string.settings_privacy_policy_webxr_title); - mBinding.headerLayout.setDescription(R.string.settings_privacy_policy_webxr_description); mBinding.contentText.setText(R.string.settings_privacy_policy_webxr_description); mBinding.emptyText.setText(R.string.settings_privacy_policy_webxr_empty_description); - mBinding.footerLayout.setDescription(R.string.settings_privacy_policy_webxr_reset); break; case SitePermission.SITE_PERMISSION_TRACKING: mBinding.headerLayout.setTitle(R.string.settings_privacy_policy_tracking_title); - mBinding.headerLayout.setDescription(R.string.settings_privacy_policy_tracking_description); mBinding.contentText.setText(R.string.settings_privacy_policy_tracking_description); mBinding.emptyText.setText(R.string.settings_privacy_policy_tracking_empty_description); mBinding.emptySecondText.setVisibility(GONE); - mBinding.footerLayout.setDescription(R.string.settings_privacy_policy_tracking_reset); break; } diff --git a/app/src/main/res/drawable/ic_icon_drm_allowed.xml b/app/src/main/res/drawable/ic_icon_drm_allowed.xml new file mode 100644 index 000000000..dd7bdcc5e --- /dev/null +++ b/app/src/main/res/drawable/ic_icon_drm_allowed.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_icon_drm_blocked.xml b/app/src/main/res/drawable/ic_icon_drm_blocked.xml new file mode 100644 index 000000000..a6d104929 --- /dev/null +++ b/app/src/main/res/drawable/ic_icon_drm_blocked.xml @@ -0,0 +1,15 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_icon_popup_awesomebar.xml b/app/src/main/res/drawable/ic_icon_popup.xml similarity index 100% rename from app/src/main/res/drawable/ic_icon_popup_awesomebar.xml rename to app/src/main/res/drawable/ic_icon_popup.xml diff --git a/app/src/main/res/drawable/ic_icon_popup_blocked.xml b/app/src/main/res/drawable/ic_icon_popup_blocked.xml new file mode 100644 index 000000000..8289d7fd0 --- /dev/null +++ b/app/src/main/res/drawable/ic_icon_popup_blocked.xml @@ -0,0 +1,18 @@ + + + + + + diff --git a/app/src/main/res/layout/navigation_url.xml b/app/src/main/res/layout/navigation_url.xml index 7e8ab0438..30546b89e 100644 --- a/app/src/main/res/layout/navigation_url.xml +++ b/app/src/main/res/layout/navigation_url.xml @@ -41,7 +41,7 @@ android:layout_marginStart="2dp" android:addStatesFromChildren="true" android:orientation="horizontal" - app:visibleGone="@{!viewmodel.isLibraryVisible}"> + app:visibleGone="@{!viewmodel.isLibraryVisible && !UrlUtils.isContentFeed(context, viewmodel.url.toString())}"> + app:visibleGone="@{viewmodel.isDrmUsed}"> + + + + + @@ -88,7 +116,7 @@ android:layout_width="wrap_content" android:layout_height="match_parent" android:orientation="horizontal" - app:visibleGone="@{viewmodel.isWebXRUsed && !UrlUtils.isContentFeed(context, viewmodel.url.toString())}"> + app:visibleGone="@{settingsViewmodel.isWebXREnabled && viewmodel.isWebXRUsed}"> + visibleGone="@{settingsViewmodel.isTrackingProtectionEnabled || (settingsViewmodel.isPopUpBlockingEnabled && viewmodel.isPopUpBlocked) || (settingsViewmodel.isDrmEnabled && viewmodel.isDrmUsed)}"/> + android:text="@string/privacy_options_popups_list_header_v1" + tools:text="@string/privacy_options_popups_list_header_v1" /> @@ -101,7 +100,6 @@ android:layout_width="match_parent" android:layout_height="wrap_content" app:buttonText="@string/privacy_options_popups_clear_all" - app:description="@string/privacy_options_popups_reset" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" /> diff --git a/app/src/main/res/layout/options_header.xml b/app/src/main/res/layout/options_header.xml index 7bdbbfcfe..4e9747565 100644 --- a/app/src/main/res/layout/options_header.xml +++ b/app/src/main/res/layout/options_header.xml @@ -33,7 +33,7 @@ @@ -49,7 +49,7 @@ + + + + + + + app:buttonText="@string/security_options_block_pup_up_settings_v2" /> + app:buttonText="@string/security_options_webxr_settings" /> - - - + + + - -