44import android .content .Context ;
55import android .content .SharedPreferences ;
66import android .preference .PreferenceManager ;
7- import android .util .Log ;
87
98import androidx .annotation .NonNull ;
109import androidx .annotation .Nullable ;
1110import androidx .lifecycle .DefaultLifecycleObserver ;
1211import androidx .lifecycle .Lifecycle ;
1312import androidx .lifecycle .LifecycleOwner ;
1413import androidx .lifecycle .Observer ;
15- import androidx .recyclerview .widget .DiffUtil ;
16- import androidx .recyclerview .widget .ListUpdateCallback ;
1714
1815import org .json .JSONException ;
1916import org .json .JSONObject ;
2724import org .mozilla .vrbrowser .browser .engine .Session ;
2825import org .mozilla .vrbrowser .db .SitePermission ;
2926import org .mozilla .vrbrowser .ui .viewmodel .SitePermissionViewModel ;
30- import org .mozilla .vrbrowser .utils .UrlUtils ;
3127
3228import java .util .ArrayList ;
3329import java .util .List ;
34- import java .util .Objects ;
3530import java .util .function .Function ;
31+ import java .util .stream .Collectors ;
32+
33+ import static org .mozilla .vrbrowser .db .SitePermission .SITE_PERMISSION_TRACKING ;
3634
3735public 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 }
0 commit comments