• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.systemui.car.qc;
18 
19 import static android.Manifest.permission.ACCESS_NETWORK_STATE;
20 import static android.Manifest.permission.INTERNET;
21 import static android.widget.PopupWindow.INPUT_METHOD_NOT_NEEDED;
22 
23 import android.annotation.Nullable;
24 import android.annotation.SuppressLint;
25 import android.app.ActivityManager;
26 import android.app.ActivityTaskManager;
27 import android.app.TaskStackListener;
28 import android.car.drivingstate.CarUxRestrictions;
29 import android.content.Context;
30 import android.content.Intent;
31 import android.content.SharedPreferences;
32 import android.content.pm.ApplicationInfo;
33 import android.content.pm.PackageInfo;
34 import android.content.pm.PackageManager;
35 import android.content.res.Resources;
36 import android.net.ConnectivityManager;
37 import android.net.Network;
38 import android.net.NetworkCapabilities;
39 import android.os.Build;
40 import android.os.Handler;
41 import android.text.TextUtils;
42 import android.util.Log;
43 import android.view.LayoutInflater;
44 import android.view.MotionEvent;
45 import android.view.View;
46 import android.widget.Button;
47 import android.widget.LinearLayout;
48 import android.widget.PopupWindow;
49 import android.widget.TextView;
50 
51 import androidx.annotation.NonNull;
52 import androidx.annotation.VisibleForTesting;
53 
54 import com.android.car.datasubscription.DataSubscription;
55 import com.android.car.datasubscription.DataSubscriptionStatus;
56 import com.android.car.ui.utils.CarUxRestrictionsUtil;
57 import com.android.systemui.R;
58 import com.android.systemui.car.qc.DataSubscriptionStatsLogHelper.DataSubscriptionMessageType;
59 import com.android.systemui.dagger.SysUISingleton;
60 import com.android.systemui.dagger.qualifiers.Background;
61 import com.android.systemui.dagger.qualifiers.Main;
62 import com.android.systemui.settings.UserTracker;
63 
64 import java.time.LocalDate;
65 import java.time.ZoneId;
66 import java.time.format.DateTimeFormatter;
67 import java.time.temporal.ChronoUnit;
68 import java.util.Arrays;
69 import java.util.HashSet;
70 import java.util.List;
71 import java.util.Set;
72 import java.util.concurrent.CountDownLatch;
73 import java.util.concurrent.Executor;
74 import java.util.concurrent.TimeUnit;
75 
76 import javax.inject.Inject;
77 
78 /**
79  * Controller to display the data subscription pop-up
80  */
81 @SysUISingleton
82 public class DataSubscriptionController implements DataSubscription.DataSubscriptionChangeListener {
83     private static final boolean DEBUG = Build.IS_DEBUGGABLE;
84     private static final String TAG = DataSubscriptionController.class.toString();
85     private static final String DATA_SUBSCRIPTION_ACTION =
86             "android.intent.action.DATA_SUBSCRIPTION";
87     private static final String DATA_SUBSCRIPTION_SHARED_PREFERENCE_PATH =
88             "com.android.car.systemui.car.qc.DataSubscriptionController";
89     // Timeout for network callback in ms
90     private static final int CALLBACK_TIMEOUT_MS = 1000;
91     private final Context mContext;
92     private DataSubscription mSubscription;
93     private final UserTracker mUserTracker;
94     private PopupWindow mPopupWindow;
95     private final View mPopupView;
96     private Button mExplorationButton;
97     private final Intent mIntent;
98     private ConnectivityManager mConnectivityManager;
99     private DataSubscriptionNetworkCallback mNetworkCallback;
100     private final Handler mMainHandler;
101     private final Executor mBackGroundExecutor;
102     private Set<String> mActivitiesBlocklist;
103     private Set<String> mPackagesBlocklist;
104     private CountDownLatch mLatch;
105     private boolean mIsNetworkCallbackRegistered;
106     private final DataSubscriptionStatsLogHelper mDataSubscriptionStatsLogHelper;
107     private final TaskStackListener mTaskStackListener = new TaskStackListener() {
108         @SuppressLint("MissingPermission")
109         @Override
110         public void onTaskMovedToFront(ActivityManager.RunningTaskInfo taskInfo) {
111             if (mIsNetworkCallbackRegistered && mConnectivityManager != null) {
112                 mConnectivityManager.unregisterNetworkCallback(mNetworkCallback);
113                 mIsNetworkCallbackRegistered = false;
114             }
115 
116             if (taskInfo.topActivity == null || mConnectivityManager == null) {
117                 return;
118             }
119             mTopPackage = taskInfo.topActivity.getPackageName();
120             if (mPackagesBlocklist.contains(mTopPackage)) {
121                 return;
122             }
123 
124             mTopActivity = taskInfo.topActivity.flattenToString();
125             if (mActivitiesBlocklist.contains(mTopActivity)) {
126                 return;
127             }
128 
129             PackageInfo info;
130             int userId = mUserTracker.getUserId();
131             try {
132                 info = mContext.getPackageManager().getPackageInfoAsUser(mTopPackage,
133                         PackageManager.GET_PERMISSIONS, userId);
134                 if (info != null) {
135                     String[] permissions = info.requestedPermissions;
136                     boolean appReqInternet = Arrays.asList(permissions).contains(
137                             ACCESS_NETWORK_STATE)
138                             && Arrays.asList(permissions).contains(INTERNET);
139                     if (!appReqInternet) {
140                         mActivitiesBlocklist.add(mTopActivity);
141                         return;
142                     }
143                 }
144 
145                 ApplicationInfo appInfo = mContext.getPackageManager().getApplicationInfoAsUser(
146                         mTopPackage, 0, mUserTracker.getUserId());
147                 mTopLabel = appInfo.loadLabel(mContext.getPackageManager());
148                 int uid = appInfo.uid;
149                 mConnectivityManager.registerDefaultNetworkCallbackForUid(uid, mNetworkCallback,
150                         mMainHandler);
151                 mIsNetworkCallbackRegistered = true;
152                 // since we don't have the option of using the synchronous call of getting the
153                 // default network by UID, we need to set a timeout period to make sure the network
154                 // from the callback is updated correctly before deciding to display the message
155                 //TODO: b/336869328 use the synchronous call to update network status
156                 mLatch = new CountDownLatch(CALLBACK_TIMEOUT_MS);
157                 mBackGroundExecutor.execute(() -> {
158                     try {
159                         mLatch.await(CALLBACK_TIMEOUT_MS, TimeUnit.MILLISECONDS);
160                     } catch (InterruptedException e) {
161                         Log.e(TAG, "error updating network callback" + e);
162                     } finally {
163                         if (mNetworkCallback.mNetwork == null) {
164                             mNetworkCapabilities = null;
165                             updateShouldDisplayReactiveMsg();
166                         }
167                     }
168                 });
169             } catch (Exception e) {
170                 Log.e(TAG, mTopPackage + " not found : " + e);
171             }
172         }
173     };
174 
175     private final CarUxRestrictionsUtil.OnUxRestrictionsChangedListener
176             mUxRestrictionsChangedListener =
177             new CarUxRestrictionsUtil.OnUxRestrictionsChangedListener() {
178                 @Override
179                 public void onRestrictionsChanged(@NonNull CarUxRestrictions carUxRestrictions) {
180                     mIsDistractionOptimizationRequired =
181                             carUxRestrictions.isRequiresDistractionOptimization();
182                     if (mIsProactiveMsg) {
183                         if (mIsDistractionOptimizationRequired
184                                 && mPopupWindow != null
185                                 && mPopupWindow.isShowing()) {
186                             mPopupWindow.dismiss();
187                             mDataSubscriptionStatsLogHelper.logSessionFinished();
188                         }
189                     } else {
190                         if (mIsDistractionOptimizationRequired && mPopupWindow != null) {
191                             mExplorationButton.setVisibility(View.GONE);
192 
193                         } else {
194                             mExplorationButton.setVisibility(View.VISIBLE);
195                         }
196                         mPopupWindow.update();
197                     }
198                 }
199             };
200 
201     // Determines whether a proactive message was already displayed
202     private boolean mWasProactiveMsgDisplayed;
203     // Determines whether the current message being displayed is proactive or reactive
204     private boolean mIsProactiveMsg;
205     private boolean mIsDistractionOptimizationRequired;
206     private View mAnchorView;
207     private boolean mShouldDisplayProactiveMsg;
208 
209     private final int mPopUpTimeOut;
210     private boolean mShouldDisplayReactiveMsg;
211     private String mTopActivity;
212     private String mTopPackage;
213     private CharSequence mTopLabel;
214     private NetworkCapabilities mNetworkCapabilities;
215     private boolean mIsUxRestrictionsListenerRegistered;
216     private SharedPreferences mSharedPreferences;
217     private SharedPreferences.Editor mEditor;
218     private int mCurrentInterval;
219     private int mCurrentCycle;
220     private int mCurrentActiveDays;
221 
222     @VisibleForTesting
223     static final String KEY_PREV_POPUP_DATE =
224             "com.android.car.systemui.car.qc.PREV_DATE";
225     @VisibleForTesting
226     static final String KEY_PREV_POPUP_CYCLE =
227             "com.android.car.systemui.car.qc.PREV_CYCLE";
228     @VisibleForTesting
229     static final String KEY_PREV_POPUP_ACTIVE_DAYS =
230             "com.android.car.systemui.car.qc.PREV_ACTIVE_DAYS";
231     @VisibleForTesting
232     static final String KEY_PREV_POPUP_STATUS =
233             "com.android.car.systemui.car.qc.PREV_STATUS";
234 
235     @SuppressLint("MissingPermission")
236     @Inject
DataSubscriptionController(Context context, UserTracker userTracker, @Main Handler mainHandler, @Background Executor backgroundExecutor, DataSubscriptionStatsLogHelper dataSubscriptionStatsLogHelper)237     public DataSubscriptionController(Context context,
238             UserTracker userTracker,
239             @Main Handler mainHandler,
240             @Background Executor backgroundExecutor,
241             DataSubscriptionStatsLogHelper dataSubscriptionStatsLogHelper) {
242         mContext = context;
243         mSubscription = new DataSubscription(context);
244         mUserTracker = userTracker;
245         mMainHandler = mainHandler;
246         mBackGroundExecutor = backgroundExecutor;
247         mDataSubscriptionStatsLogHelper = dataSubscriptionStatsLogHelper;
248         mIntent = new Intent(DATA_SUBSCRIPTION_ACTION);
249         mIntent.setPackage(mContext.getString(
250                 R.string.connectivity_flow_app));
251         mIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
252         LayoutInflater inflater = LayoutInflater.from(mContext);
253         mPopupView = inflater.inflate(R.layout.data_subscription_popup_window, null);
254         mPopUpTimeOut = mContext.getResources().getInteger(
255                 R.integer.data_subscription_pop_up_timeout);
256         int width = LinearLayout.LayoutParams.WRAP_CONTENT;
257         int height = LinearLayout.LayoutParams.WRAP_CONTENT;
258         boolean focusable = true;
259         mPopupWindow = new PopupWindow(mPopupView, width, height, focusable);
260         mPopupWindow.setTouchModal(false);
261         mPopupWindow.setOutsideTouchable(true);
262         mPopupWindow.setInputMethodMode(INPUT_METHOD_NOT_NEEDED);
263         mPopupView.setOnTouchListener(new View.OnTouchListener() {
264             @Override
265             public boolean onTouch(View v, MotionEvent event) {
266                 if (mPopupWindow != null) {
267                     mPopupWindow.dismiss();
268                     if (!mWasProactiveMsgDisplayed) {
269                         mWasProactiveMsgDisplayed = true;
270                     }
271                     mDataSubscriptionStatsLogHelper.logSessionFinished();
272                 }
273                 return true;
274             }
275         });
276 
277         mExplorationButton = mPopupView.findViewById(
278                 R.id.data_subscription_explore_options_button);
279         mExplorationButton.setOnClickListener(v -> {
280             mPopupWindow.dismiss();
281             mContext.startActivityAsUser(mIntent, mUserTracker.getUserHandle());
282             mDataSubscriptionStatsLogHelper.logButtonClicked();
283         });
284         mConnectivityManager = mContext.getSystemService(ConnectivityManager.class);
285         mNetworkCallback = new DataSubscriptionNetworkCallback();
286         mActivitiesBlocklist = new HashSet<>();
287         mPackagesBlocklist = new HashSet<>();
288 
289         Resources res = mContext.getResources();
290         String[] blockActivities = res.getStringArray(
291                 R.array.config_dataSubscriptionBlockedActivitiesList);
292         mActivitiesBlocklist.addAll(List.of(blockActivities));
293         String[] blockComponents = res.getStringArray(
294                 R.array.config_dataSubscriptionBlockedPackagesList);
295         mPackagesBlocklist.addAll(List.of(blockComponents));
296         try {
297             ActivityTaskManager.getService().registerTaskStackListener(mTaskStackListener);
298         } catch (Exception e) {
299             Log.e(TAG, "error while registering TaskStackListener " + e);
300         }
301         mSharedPreferences = mContext.getSharedPreferences(
302                 DATA_SUBSCRIPTION_SHARED_PREFERENCE_PATH, Context.MODE_PRIVATE);
303         mEditor = mSharedPreferences.edit();
304     }
305 
updateShouldDisplayProactiveMsg()306     void updateShouldDisplayProactiveMsg() {
307         if (mIsDistractionOptimizationRequired) {
308             if (mPopupWindow != null && mPopupWindow.isShowing()) {
309                 mPopupWindow.dismiss();
310                 mDataSubscriptionStatsLogHelper.logSessionFinished();
311             }
312         } else {
313             // Determines whether a proactive message should be displayed
314             mShouldDisplayProactiveMsg = !mWasProactiveMsgDisplayed
315                     && mSubscription.isDataSubscriptionInactive()
316                     && isValidTimeInterval()
317                     && isValidCycle()
318                     && isValidActiveDays();
319             if (mShouldDisplayProactiveMsg && mPopupWindow != null
320                     && !mPopupWindow.isShowing()) {
321                 mIsProactiveMsg = true;
322                 showPopUpWindow();
323                 writeLatestPopupDate();
324                 writeLatestPopupCycle();
325                 writeLatestPopupActiveDays();
326             }
327         }
328     }
329 
updateShouldDisplayReactiveMsg()330     private void updateShouldDisplayReactiveMsg() {
331         if (mIsDistractionOptimizationRequired) {
332             mExplorationButton.setVisibility(View.GONE);
333 
334         } else {
335             mExplorationButton.setVisibility(View.VISIBLE);
336         }
337         if (!mPopupWindow.isShowing()) {
338             mShouldDisplayReactiveMsg = ((mNetworkCapabilities == null
339                     || (!isSuspendedNetwork() && !isValidNetwork()))
340                     && mSubscription.isDataSubscriptionInactive());
341             if (mShouldDisplayReactiveMsg) {
342                 mIsProactiveMsg = false;
343                 showPopUpWindow();
344                 mActivitiesBlocklist.add(mTopActivity);
345             } else {
346                 if (mPopupWindow != null && mPopupWindow.isShowing()) {
347                     mPopupWindow.dismiss();
348                     mDataSubscriptionStatsLogHelper.logSessionFinished();
349                 }
350             }
351         }
352     }
353 
354     @VisibleForTesting
showPopUpWindow()355     void showPopUpWindow() {
356         if (mAnchorView != null) {
357             mAnchorView.post(new Runnable() {
358                 @Override
359                 public void run() {
360                     TextView popUpPrompt = mPopupView.findViewById(R.id.popup_text_view);
361                     if (popUpPrompt != null) {
362                         if (mIsProactiveMsg) {
363                             popUpPrompt.setText(R.string.data_subscription_proactive_msg_prompt);
364                             mDataSubscriptionStatsLogHelper.logSessionStarted(
365                                     DataSubscriptionMessageType.PROACTIVE);
366                         } else {
367                             popUpPrompt.setText(getReactiveMsg());
368                             mDataSubscriptionStatsLogHelper.logSessionStarted(
369                                     DataSubscriptionMessageType.REACTIVE);
370                         }
371                     }
372                     int xOffsetInPx = mContext.getResources().getDimensionPixelSize(
373                             R.dimen.data_subscription_pop_up_horizontal_offset);
374                     int yOffsetInPx = mContext.getResources().getDimensionPixelSize(
375                             R.dimen.data_subscription_pop_up_vertical_offset);
376                     mPopupWindow.showAsDropDown(mAnchorView, -xOffsetInPx, yOffsetInPx);
377                     mAnchorView.getHandler().postDelayed(new Runnable() {
378 
379                         public void run() {
380                             if (mPopupWindow.isShowing()) {
381                                 mPopupWindow.dismiss();
382                                 mWasProactiveMsgDisplayed = true;
383                                 // after the proactive msg dismisses, it won't get displayed again
384                                 // hence the msg from now on will just be reactive
385                                 mIsProactiveMsg = false;
386                                 mDataSubscriptionStatsLogHelper.logSessionFinished();
387                             }
388                         }
389                     }, mPopUpTimeOut);
390                 }
391             });
392         }
393     }
394 
395     /** Set the anchor view. If null, unregisters active data subscription listeners */
setAnchorView(@ullable View view)396     public void setAnchorView(@Nullable View view) {
397         mAnchorView = view;
398         if (mAnchorView != null) {
399             mSubscription.addDataSubscriptionListener(this);
400             updateCurrentStatus();
401             updateCurrentInterval();
402             updateCurrentCycle();
403             updateCurrentActiveDays();
404             updateShouldDisplayProactiveMsg();
405             if (!mIsUxRestrictionsListenerRegistered) {
406                 CarUxRestrictionsUtil.getInstance(mContext).register(
407                         mUxRestrictionsChangedListener);
408                 mIsUxRestrictionsListenerRegistered = true;
409             }
410         } else {
411             mSubscription.removeDataSubscriptionListener();
412             if (mIsUxRestrictionsListenerRegistered) {
413                 CarUxRestrictionsUtil.getInstance(mContext).unregister(
414                         mUxRestrictionsChangedListener);
415                 mIsUxRestrictionsListenerRegistered = false;
416             }
417         }
418     }
419 
isValidNetwork()420     boolean isValidNetwork() {
421         return mNetworkCapabilities.hasCapability(
422                 NetworkCapabilities.NET_CAPABILITY_VALIDATED);
423     }
424 
isSuspendedNetwork()425     boolean isSuspendedNetwork() {
426         return !mNetworkCapabilities.hasCapability(
427                 NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED);
428     }
429 
getReactiveMsg()430     private CharSequence getReactiveMsg() {
431         return mContext.getString(
432                 R.string.data_subscription_reactive_msg_prompt, mTopLabel.isEmpty()
433                 ? mContext.getResources().getString(
434                         R.string.data_subscription_reactive_generic_app_label) :
435                         mTopLabel);
436 
437     }
438 
439     @Override
onChange(int value)440     public void onChange(int value) {
441         updateCurrentStatus();
442         updateShouldDisplayProactiveMsg();
443     }
444 
445     public class DataSubscriptionNetworkCallback extends ConnectivityManager.NetworkCallback {
446         Network mNetwork;
447 
448         @Override
onAvailable(@onNull Network network)449         public void onAvailable(@NonNull Network network) {
450             if (DEBUG) {
451                 Log.d(TAG, "onAvailable " + network);
452             }
453             mNetwork = network;
454             mLatch.countDown();
455         }
456 
457         @Override
onCapabilitiesChanged(@onNull Network network, @NonNull NetworkCapabilities networkCapabilities)458         public void onCapabilitiesChanged(@NonNull Network network,
459                 @NonNull NetworkCapabilities networkCapabilities) {
460             if (DEBUG) {
461                 Log.d(TAG, "onCapabilitiesChanged " + network);
462             }
463             mNetwork = network;
464             mNetworkCapabilities = networkCapabilities;
465             updateShouldDisplayReactiveMsg();
466         }
467     }
468 
isValidTimeInterval()469     private boolean isValidTimeInterval() {
470         return mCurrentInterval >= mContext.getResources().getInteger(
471                 R.integer.data_subscription_pop_up_frequency);
472     }
473 
isValidCycle()474     private boolean isValidCycle() {
475         if (mCurrentCycle == 1) {
476             return true;
477         }
478         return mCurrentCycle <= mContext.getResources().getInteger(
479                 R.integer.data_subscription_pop_up_startup_cycle_limit);
480     }
481 
isValidActiveDays()482     private boolean isValidActiveDays() {
483         if (mCurrentActiveDays == 1) {
484             return true;
485         }
486         return mCurrentActiveDays <= mContext.getResources().getInteger(
487                 R.integer.data_subscription_pop_up_active_days_limit);
488     }
489 
updateCurrentStatus()490     private void updateCurrentStatus() {
491         int prevStatus = mSharedPreferences.getInt(KEY_PREV_POPUP_STATUS, 0);
492         int currentStatus = mSubscription.getDataSubscriptionStatus();
493         if (prevStatus == DataSubscriptionStatus.INACTIVE && prevStatus != currentStatus) {
494             mEditor.clear();
495             mEditor.apply();
496         }
497         mEditor.putInt(KEY_PREV_POPUP_STATUS, currentStatus);
498         mEditor.apply();
499     }
500 
updateCurrentInterval()501     private void updateCurrentInterval() {
502         mCurrentInterval = mContext.getResources().getInteger(
503                 R.integer.data_subscription_pop_up_frequency);
504         String prevDate = mSharedPreferences.getString(KEY_PREV_POPUP_DATE, /* defValue=*/ "");
505         if (!TextUtils.isEmpty(prevDate)) {
506             mCurrentInterval = (int) ChronoUnit.DAYS.between(LocalDate.parse(prevDate),
507                     LocalDate.now(ZoneId.systemDefault()));
508         }
509     }
510 
updateCurrentCycle()511     private void updateCurrentCycle() {
512         mCurrentCycle = mSharedPreferences.getInt(
513                 KEY_PREV_POPUP_CYCLE, /* defValue=*/ 0);
514     }
515 
updateCurrentActiveDays()516     private void updateCurrentActiveDays() {
517         mCurrentActiveDays = mSharedPreferences.getInt(
518                 KEY_PREV_POPUP_ACTIVE_DAYS, /* defValue=*/ 0);
519     }
520 
writeLatestPopupDate()521     private void writeLatestPopupDate() {
522         DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
523         LocalDate newDate = LocalDate.now(ZoneId.systemDefault());
524         String formattedNewDate = newDate.format(formatter);
525         mEditor.putString(KEY_PREV_POPUP_DATE, formattedNewDate);
526         mEditor.apply();
527     }
528 
writeLatestPopupCycle()529     private void writeLatestPopupCycle() {
530         mEditor.putInt(KEY_PREV_POPUP_CYCLE, mSharedPreferences.getInt(
531                 KEY_PREV_POPUP_CYCLE, /* defValue=*/ 1) + 1);
532         mEditor.apply();
533     }
534 
writeLatestPopupActiveDays()535     private void writeLatestPopupActiveDays() {
536         mEditor.putInt(KEY_PREV_POPUP_ACTIVE_DAYS, mSharedPreferences.getInt(
537                 KEY_PREV_POPUP_ACTIVE_DAYS, /* defValue=*/ 1) + 1);
538         mEditor.apply();
539     }
540 
541     @VisibleForTesting
setPopupWindow(PopupWindow popupWindow)542     void setPopupWindow(PopupWindow popupWindow) {
543         mPopupWindow = popupWindow;
544     }
545 
546     @VisibleForTesting
setSubscription(DataSubscription dataSubscription)547     void setSubscription(DataSubscription dataSubscription) {
548         mSubscription = dataSubscription;
549     }
550 
551     @VisibleForTesting
getShouldDisplayProactiveMsg()552     boolean getShouldDisplayProactiveMsg() {
553         return mShouldDisplayProactiveMsg;
554     }
555 
556     @VisibleForTesting
setPackagesBlocklist(Set<String> list)557     void setPackagesBlocklist(Set<String> list) {
558         mPackagesBlocklist = list;
559     }
560 
561     @VisibleForTesting
setActivitiesBlocklist(Set<String> list)562     void setActivitiesBlocklist(Set<String> list) {
563         mActivitiesBlocklist = list;
564     }
565 
566     @VisibleForTesting
setConnectivityManager(ConnectivityManager connectivityManager)567     void setConnectivityManager(ConnectivityManager connectivityManager) {
568         mConnectivityManager = connectivityManager;
569     }
570 
571     @VisibleForTesting
getTaskStackListener()572     TaskStackListener getTaskStackListener() {
573         return mTaskStackListener;
574     }
575 
576     @VisibleForTesting
getShouldDisplayReactiveMsg()577     boolean getShouldDisplayReactiveMsg() {
578         return mShouldDisplayReactiveMsg;
579     }
580 
581     @VisibleForTesting
setNetworkCallback(DataSubscriptionNetworkCallback callback)582     void setNetworkCallback(DataSubscriptionNetworkCallback callback) {
583         mNetworkCallback = callback;
584     }
585 
586     @VisibleForTesting
setIsCallbackRegistered(boolean value)587     void setIsCallbackRegistered(boolean value) {
588         mIsNetworkCallbackRegistered = value;
589     }
590 
591     @VisibleForTesting
setIsProactiveMsg(boolean value)592     void setIsProactiveMsg(boolean value) {
593         mIsProactiveMsg = value;
594     }
595 
596     @VisibleForTesting
setExplorationButton(Button button)597     void setExplorationButton(Button button) {
598         mExplorationButton = button;
599     }
600 
601     @VisibleForTesting
setIsUxRestrictionsListenerRegistered(boolean value)602     void setIsUxRestrictionsListenerRegistered(boolean value) {
603         mIsUxRestrictionsListenerRegistered = value;
604     }
605 
606     @VisibleForTesting
setSharedPreference(SharedPreferences sharedPreference)607     void setSharedPreference(SharedPreferences sharedPreference) {
608         mSharedPreferences = sharedPreference;
609     }
610 
611     @VisibleForTesting
setCurrentInterval(int currentInterval)612     void setCurrentInterval(int currentInterval) {
613         mCurrentInterval = currentInterval;
614     }
615 
616     @VisibleForTesting
setCurrentCycle(int cycle)617     void setCurrentCycle(int cycle) {
618         mCurrentCycle = cycle;
619     }
620 
621     @VisibleForTesting
setCurrentActiveDays(int activeDays)622     void setCurrentActiveDays(int activeDays) {
623         mCurrentActiveDays = activeDays;
624     }
625 
626     @VisibleForTesting
setWasProactiveMsgDisplayed(boolean value)627     void setWasProactiveMsgDisplayed(boolean value) {
628         mWasProactiveMsgDisplayed = value;
629     }
630 }
631