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

Commit 5bf1506

Browse files
authored
Tracking exception handling improvements (#3237)
1 parent 51ddf89 commit 5bf1506

File tree

10 files changed

+122
-153
lines changed

10 files changed

+122
-153
lines changed

app/src/common/shared/org/mozilla/vrbrowser/browser/PermissionDelegate.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -294,14 +294,13 @@ public void reject() {
294294
}
295295
}
296296
}
297-
298-
public void addPermissionException(String uri, @SitePermission.Category int category) {
297+
public void addPermissionException(@NonNull String uri, @SitePermission.Category int category) {
299298
@Nullable SitePermission site = mSitePermissions.stream()
300299
.filter((item) -> item.category == category && item.url.equals(uri))
301300
.findFirst().orElse(null);
302301

303302
if (site == null) {
304-
site = new SitePermission(uri, uri, category);
303+
site = new SitePermission(uri,null, category);
305304
mSitePermissions.add(site);
306305
}
307306
mSitePermissionModel.insertSite(site);

app/src/common/shared/org/mozilla/vrbrowser/browser/content/TrackingProtectionStore.java

Lines changed: 47 additions & 133 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,13 @@
44
import android.content.Context;
55
import android.content.SharedPreferences;
66
import android.preference.PreferenceManager;
7-
import android.util.Log;
87

98
import androidx.annotation.NonNull;
109
import androidx.annotation.Nullable;
1110
import androidx.lifecycle.DefaultLifecycleObserver;
1211
import androidx.lifecycle.Lifecycle;
1312
import androidx.lifecycle.LifecycleOwner;
1413
import androidx.lifecycle.Observer;
15-
import androidx.recyclerview.widget.DiffUtil;
16-
import androidx.recyclerview.widget.ListUpdateCallback;
1714

1815
import org.json.JSONException;
1916
import org.json.JSONObject;
@@ -27,18 +24,19 @@
2724
import org.mozilla.vrbrowser.browser.engine.Session;
2825
import org.mozilla.vrbrowser.db.SitePermission;
2926
import org.mozilla.vrbrowser.ui.viewmodel.SitePermissionViewModel;
30-
import org.mozilla.vrbrowser.utils.UrlUtils;
3127

3228
import java.util.ArrayList;
3329
import java.util.List;
34-
import java.util.Objects;
3530
import java.util.function.Function;
31+
import java.util.stream.Collectors;
32+
33+
import static org.mozilla.vrbrowser.db.SitePermission.SITE_PERMISSION_TRACKING;
3634

3735
public class TrackingProtectionStore implements DefaultLifecycleObserver,
38-
SharedPreferences.OnSharedPreferenceChangeListener, ListUpdateCallback {
36+
SharedPreferences.OnSharedPreferenceChangeListener {
3937

4038
public interface TrackingProtectionListener {
41-
default void onExcludedTrackingProtectionChange(@NonNull String uri, boolean excluded) {};
39+
default void onExcludedTrackingProtectionChange(@NonNull String url, boolean excluded, boolean isPrivate) {};
4240
default void onTrackingProtectionLevelUpdated(int level) {};
4341
}
4442

@@ -56,17 +54,17 @@ public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, Strin
5654
private SitePermissionViewModel mViewModel;
5755
private List<TrackingProtectionListener> mListeners;
5856
private SharedPreferences mPrefs;
59-
private List<SitePermission> mCurrentSitePermissions;
6057
private List<SitePermission> mSitePermissions;
58+
private boolean mIsFirstUpdate;
6159

6260
public TrackingProtectionStore(@NonNull Context context,
6361
@NonNull GeckoRuntime runtime) {
6462
mContext = context;
6563
mRuntime = runtime;
6664
mContentBlockingController = mRuntime.getContentBlockingController();
6765
mListeners = new ArrayList<>();
68-
mCurrentSitePermissions = new ArrayList<>();
6966
mSitePermissions = new ArrayList<>();
67+
mIsFirstUpdate = true;
7068

7169
mLifeCycle = ((VRBrowserActivity) context).getLifecycle();
7270
mLifeCycle.addObserver(this);
@@ -97,100 +95,24 @@ public void onStop(@NonNull LifecycleOwner owner) {
9795
mViewModel.getAll(SitePermission.SITE_PERMISSION_TRACKING).removeObserver(mSitePermissionObserver);
9896
}
9997

100-
private Observer<List<SitePermission>> mSitePermissionObserver = this::notifyDiff;
101-
102-
@Override
103-
public void onInserted(int position, int count) {
104-
if (mSitePermissions == null) {
105-
return;
106-
}
107-
108-
for (int i=0; i<count; i++) {
109-
SitePermission permission = mSitePermissions.get(position + i);
110-
ContentBlockingException exception = toContentBlockingException(permission);
111-
if (exception != null) {
112-
mListeners.forEach(listener -> listener.onExcludedTrackingProtectionChange(
113-
UrlUtils.getHost(exception.uri),
114-
true));
115-
}
116-
}
117-
118-
final List<ContentBlockingException> exceptionsList = new ArrayList<>();
119-
mContentBlockingController.clearExceptionList();
120-
for (SitePermission permission: mSitePermissions) {
121-
ContentBlockingException exception = toContentBlockingException(permission);
122-
if (exception != null) {
123-
exceptionsList.add(exception);
124-
}
125-
}
126-
mContentBlockingController.restoreExceptionList(exceptionsList);
127-
}
128-
129-
@Override
130-
public void onRemoved(int position, int count) {
131-
if (mCurrentSitePermissions == null) {
132-
return;
133-
}
134-
135-
for (int i=0; i<count; i++) {
136-
SitePermission permission = mCurrentSitePermissions.get(position + i);
137-
ContentBlockingException exception = toContentBlockingException(permission);
138-
if (exception != null) {
139-
mContentBlockingController.removeException(exception);
140-
mListeners.forEach(listener -> listener.onExcludedTrackingProtectionChange(
141-
UrlUtils.getHost(exception.uri),
142-
false));
98+
private Observer<List<SitePermission>> mSitePermissionObserver = new Observer<List<SitePermission>>() {
99+
@Override
100+
public void onChanged(List<SitePermission> sitePermissions) {
101+
if (sitePermissions != null) {
102+
mSitePermissions = sitePermissions;
103+
104+
// Restore the site list on the permissions storage notification
105+
if (mIsFirstUpdate) {
106+
List<ContentBlockingException> exceptions = sitePermissions
107+
.stream()
108+
.map(TrackingProtectionStore::toContentBlockingException)
109+
.collect(Collectors.toList());
110+
mContentBlockingController.restoreExceptionList(exceptions);
111+
mIsFirstUpdate = false;
112+
}
143113
}
144114
}
145-
}
146-
147-
@Override
148-
public void onMoved(int fromPosition, int toPosition) {
149-
// We never move from the exceptions list
150-
}
151-
152-
@Override
153-
public void onChanged(int position, int count, @Nullable Object payload) {
154-
// We never update from the exceptions list
155-
}
156-
157-
private void notifyDiff(List<SitePermission> newList) {
158-
if (newList == null) {
159-
return;
160-
}
161-
162-
DiffUtil.DiffResult result = DiffUtil.calculateDiff(new DiffUtil.Callback() {
163-
@Override
164-
public int getOldListSize() {
165-
return mSitePermissions.size();
166-
}
167-
168-
@Override
169-
public int getNewListSize() {
170-
return newList.size();
171-
}
172-
173-
@Override
174-
public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
175-
return mSitePermissions.get(oldItemPosition).url.equals(newList.get(newItemPosition).url) &&
176-
mSitePermissions.get(oldItemPosition).principal.equals(newList.get(newItemPosition).principal) &&
177-
mSitePermissions.get(oldItemPosition).category == newList.get(newItemPosition).category;
178-
}
179-
180-
@Override
181-
public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
182-
SitePermission newSite = newList.get(newItemPosition);
183-
SitePermission olSite = mSitePermissions.get(oldItemPosition);
184-
return newSite.url.equals(olSite.url)
185-
&& Objects.equals(newSite.category, olSite.category)
186-
&& Objects.equals(newSite.principal, olSite.principal);
187-
}
188-
});
189-
190-
mCurrentSitePermissions = mSitePermissions;
191-
mSitePermissions = newList;
192-
result.dispatchUpdatesTo(this);
193-
}
115+
};
194116

195117
@Override
196118
public void onDestroy(@NonNull LifecycleOwner owner) {
@@ -226,55 +148,47 @@ public void fetchAll(Function<List<SitePermission>, Void> onResult) {
226148

227149
public void add(@NonNull Session session) {
228150
mContentBlockingController.addException(session.getGeckoSession());
229-
// Private sessions don't persist to the content blocking controller exceptions list so we just notify
230-
if (session.isPrivateMode()) {
231-
mListeners.forEach(listener -> listener.onExcludedTrackingProtectionChange(
232-
UrlUtils.getHost(session.getCurrentUri()),
233-
true));
234-
} else {
235-
persist();
236-
}
151+
mListeners.forEach(listener -> listener.onExcludedTrackingProtectionChange(
152+
session.getCurrentUri(),
153+
true,
154+
session.isPrivateMode()));
155+
saveExceptions();
237156
}
238157

239158
public void remove(@NonNull Session session) {
240159
mContentBlockingController.removeException(session.getGeckoSession());
241-
// Private sessions don't persist to the content blocking controller exceptions list so we just notify
242-
if (session.isPrivateMode()) {
243-
mListeners.forEach(listener -> listener.onExcludedTrackingProtectionChange(
244-
UrlUtils.getHost(session.getCurrentUri()),
245-
true));
246-
} else {
247-
persist();
248-
}
160+
mListeners.forEach(listener -> listener.onExcludedTrackingProtectionChange(
161+
session.getCurrentUri(),
162+
false,
163+
session.isPrivateMode()));
164+
saveExceptions();
249165
}
250166

251167
public void remove(@NonNull SitePermission permission) {
252168
ContentBlockingException exception = toContentBlockingException(permission);
253169
if (exception != null) {
254170
mContentBlockingController.removeException(exception);
255-
persist();
256171
}
172+
mListeners.forEach(listener -> listener.onExcludedTrackingProtectionChange(
173+
permission.url,
174+
false,
175+
false));
176+
saveExceptions();
257177
}
258178

259-
public void removeAll(@NonNull List<Session> activeSessions) {
260-
mContentBlockingController.clearExceptionList();
261-
activeSessions.forEach(session ->
262-
mListeners.forEach(listener ->
263-
listener.onExcludedTrackingProtectionChange(
264-
UrlUtils.getHost(session.getCurrentUri()),
265-
false)));
266-
persist();
179+
public void removeAll() {
180+
// We can't use clearExceptionList as that clears also the private browsing exceptions
181+
mSitePermissions.forEach(this::remove);
267182
}
268183

269-
private void persist() {
270-
mViewModel.deleteAll(SitePermission.SITE_PERMISSION_TRACKING);
184+
private void saveExceptions() {
271185
mRuntime.getContentBlockingController().saveExceptionList().accept(contentBlockingExceptions -> {
272-
if (contentBlockingExceptions != null && !contentBlockingExceptions.isEmpty()) {
186+
mViewModel.deleteAll(SITE_PERMISSION_TRACKING);
187+
if (contentBlockingExceptions != null) {
273188
contentBlockingExceptions.forEach(exception -> {
274-
Log.d("TrackingProtectionStore", "Excluded site: " + exception.uri);
275-
SitePermission site = toSitePermission(exception);
276-
if (site != null) {
277-
mViewModel.insertSite(site);
189+
SitePermission permission = toSitePermission(exception);
190+
if (permission != null) {
191+
mViewModel.insertSite(permission);
278192
}
279193
});
280194
}

app/src/common/shared/org/mozilla/vrbrowser/browser/engine/SessionStore.java

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import java.util.LinkedList;
2525
import java.util.List;
2626
import java.util.concurrent.Executor;
27+
import java.util.stream.Collectors;
2728

2829
public class SessionStore implements GeckoSession.PermissionDelegate{
2930
private static final String LOGTAG = SystemUtils.createLogtag(SessionStore.class);
@@ -66,10 +67,11 @@ public void setContext(Context context, Bundle aExtras) {
6667
mTrackingProtectionStore = new TrackingProtectionStore(context, mRuntime);
6768
mTrackingProtectionStore.addListener(new TrackingProtectionStore.TrackingProtectionListener() {
6869
@Override
69-
public void onExcludedTrackingProtectionChange(@NonNull String host, boolean excluded) {
70+
public void onExcludedTrackingProtectionChange(@NonNull String url, boolean excluded, boolean isPrivate) {
7071
mSessions.forEach(existingSession -> {
71-
String existingHost = UrlUtils.getHost(existingSession.getCurrentUri());
72-
if (existingHost.equals(host)) {
72+
String currentSessionHost = UrlUtils.getHost(existingSession.getCurrentUri());
73+
String sessionHost = UrlUtils.getHost(url);
74+
if (currentSessionHost.equals(sessionHost) && existingSession.isPrivateMode() == isPrivate) {
7375
existingSession.reload(GeckoSession.LOAD_FLAGS_BYPASS_CACHE);
7476
}
7577
});
@@ -164,6 +166,13 @@ public void suspendAllInactiveSessions() {
164166
return mSessions.stream().filter(session -> session.getGeckoSession() == aGeckoSession).findFirst().orElse(null);
165167
}
166168

169+
public @NonNull List<Session> getSessionsByHost(@NonNull String aHost, boolean aIsPrivate) {
170+
return mSessions.stream()
171+
.filter(session -> session.isPrivateMode() == aIsPrivate)
172+
.filter(session -> UrlUtils.getHost(session.getCurrentUri()).equals(aHost))
173+
.collect(Collectors.toList());
174+
}
175+
167176
public void setActiveSession(Session aSession) {
168177
if (aSession != null) {
169178
aSession.setActive(true);
@@ -332,13 +341,13 @@ public void onMediaPermissionRequest(@NonNull GeckoSession session, @NonNull Str
332341
}
333342
}
334343

335-
public void addPermissionException(String uri, @SitePermission.Category int category) {
344+
public void addPermissionException(@NonNull String uri, @SitePermission.Category int category) {
336345
if (mPermissionDelegate != null) {
337346
mPermissionDelegate.addPermissionException(uri, category);
338347
}
339348
}
340349

341-
public void removePermissionException(String uri, @SitePermission.Category int category) {
350+
public void removePermissionException(@NonNull String uri, @SitePermission.Category int category) {
342351
if (mPermissionDelegate != null) {
343352
mPermissionDelegate.removePermissionException(uri, category);
344353
}

app/src/common/shared/org/mozilla/vrbrowser/db/DataRepository.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,10 @@ public void deleteSitePermission(final @NonNull SitePermission site) {
7272
mExecutors.diskIO().execute(() -> mDatabase.sitePermissionDao().delete(site));
7373
}
7474

75+
public void deleteSites(final @NonNull List<SitePermission> sites) {
76+
mExecutors.diskIO().execute(() -> mDatabase.sitePermissionDao().delete(sites));
77+
}
78+
7579
public void deleteAllSitePermission(@SitePermission.Category int category) {
7680
mExecutors.diskIO().execute(() -> mDatabase.sitePermissionDao().deleteAll(category));
7781
}

app/src/common/shared/org/mozilla/vrbrowser/db/SitePermissionDao.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ public interface SitePermissionDao {
2323
@Delete
2424
void delete(SitePermission site);
2525

26+
@Delete
27+
void delete(List<SitePermission> sites);
28+
2629
@Query("DELETE FROM SitePermission WHERE url = :url AND category = :category")
2730
void deleteByUrl(String url, @SitePermission.Category int category);
2831

app/src/common/shared/org/mozilla/vrbrowser/ui/viewmodel/SitePermissionViewModel.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,10 @@ public void deleteSite(@NonNull SitePermission site) {
5959
mRepository.deleteSitePermission(site);
6060
}
6161

62+
public void deleteSites(@NonNull List<SitePermission> sites) {
63+
mRepository.deleteSites(sites);
64+
}
65+
6266
public void deleteAll(@SitePermission.Category int category) {
6367
mRepository.deleteAllSitePermission(category);
6468
}

app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/NavigationBarWidget.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -385,11 +385,12 @@ private void updateUI() {
385385

386386
TrackingProtectionStore.TrackingProtectionListener mTrackingListener = new TrackingProtectionStore.TrackingProtectionListener() {
387387
@Override
388-
public void onExcludedTrackingProtectionChange(@NonNull String host, boolean excluded) {
388+
public void onExcludedTrackingProtectionChange(@NonNull String url, boolean excluded, boolean isPrivate) {
389389
Session currentSession = getSession();
390390
if (currentSession != null) {
391-
String existingHost = UrlUtils.getHost(currentSession.getCurrentUri());
392-
if (existingHost.equals(host)) {
391+
String currentSessionHost = UrlUtils.getHost(currentSession.getCurrentUri());
392+
String sessionHost = UrlUtils.getHost(url);
393+
if (currentSessionHost.equals(sessionHost) && currentSession.isPrivateMode() == isPrivate) {
393394
mViewModel.setIsTrackingEnabled(!excluded);
394395
}
395396
}

app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/settings/SettingsWidget.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -432,7 +432,7 @@ public void showView(SettingsView.SettingViewType aType) {
432432
showView(new ControllerOptionsView(getContext(), mWidgetManager));
433433
break;
434434
case TRACKING_EXCEPTION:
435-
showView(new SitePermissionsOptionsView(getContext(), mWidgetManager, SitePermission.SITE_PERMISSION_TRACKING));
435+
showView(new TrackingPermissionsOptionsView(getContext(), mWidgetManager));
436436
break;
437437
}
438438
}

0 commit comments

Comments
 (0)