1 /*
2  * Copyright (C) 2019 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.settings.network.telephony;
18 
19 import static androidx.lifecycle.Lifecycle.Event.ON_PAUSE;
20 import static androidx.lifecycle.Lifecycle.Event.ON_RESUME;
21 
22 import android.content.Context;
23 import android.os.Handler;
24 import android.os.Looper;
25 import android.telephony.SubscriptionManager;
26 import android.telephony.TelephonyManager;
27 
28 import androidx.annotation.NonNull;
29 import androidx.annotation.Nullable;
30 import androidx.lifecycle.LifecycleObserver;
31 import androidx.lifecycle.OnLifecycleEvent;
32 import androidx.preference.Preference;
33 import androidx.preference.PreferenceScreen;
34 import androidx.preference.TwoStatePreference;
35 
36 import com.android.internal.annotations.VisibleForTesting;
37 import com.android.settings.datausage.DataUsageUtils;
38 import com.android.settings.flags.Flags;
39 import com.android.settings.network.MobileDataContentObserver;
40 import com.android.settings.network.SubscriptionsChangeListener;
41 import com.android.settings.network.telephony.wificalling.CrossSimCallingViewModel;
42 
43 /**
44  * Controls whether switch mobile data to the non-default SIM if the non-default SIM has better
45  * availability.
46  *
47  * This is used for temporarily allowing data on the non-default data SIM when on-default SIM
48  * has better availability on DSDS devices, where better availability means strong
49  * signal/connectivity.
50  * If this feature is enabled, data will be temporarily enabled on the non-default data SIM,
51  * including during any voice calls.
52  */
53 public class AutoDataSwitchPreferenceController extends TelephonyTogglePreferenceController
54         implements LifecycleObserver,
55         SubscriptionsChangeListener.SubscriptionsChangeListenerClient {
56 
57     @Nullable
58     private TwoStatePreference mPreference;
59     @Nullable
60     private SubscriptionsChangeListener mChangeListener;
61     @Nullable
62     private TelephonyManager mManager;
63     @Nullable
64     private MobileDataContentObserver mMobileDataContentObserver;
65     @Nullable
66     private CrossSimCallingViewModel mCrossSimCallingViewModel;
67     @Nullable
68     private PreferenceScreen mScreen;
69 
AutoDataSwitchPreferenceController( @onNull Context context, @NonNull String preferenceKey)70     public AutoDataSwitchPreferenceController(
71             @NonNull Context context, @NonNull String preferenceKey) {
72         super(context, preferenceKey);
73     }
74 
init(int subId, @Nullable CrossSimCallingViewModel crossSimCallingViewModel)75     void init(int subId, @Nullable CrossSimCallingViewModel crossSimCallingViewModel) {
76         this.mSubId = subId;
77         mManager = mContext.getSystemService(TelephonyManager.class).createForSubscriptionId(subId);
78         mCrossSimCallingViewModel = crossSimCallingViewModel;
79     }
80 
81     @OnLifecycleEvent(ON_RESUME)
onResume()82     public void onResume() {
83         if (mChangeListener == null) {
84             mChangeListener = new SubscriptionsChangeListener(mContext, this);
85         }
86         mChangeListener.start();
87         if (mMobileDataContentObserver == null) {
88             mMobileDataContentObserver = new MobileDataContentObserver(
89                     new Handler(Looper.getMainLooper()));
90             mMobileDataContentObserver.setOnMobileDataChangedListener(() -> refreshPreference());
91         }
92         mMobileDataContentObserver.register(mContext, mSubId);
93     }
94 
95     @OnLifecycleEvent(ON_PAUSE)
onPause()96     public void onPause() {
97         if (mChangeListener != null) {
98             mChangeListener.stop();
99         }
100         if (mMobileDataContentObserver != null) {
101             mMobileDataContentObserver.unRegister(mContext);
102         }
103     }
104 
105     @Override
displayPreference(PreferenceScreen screen)106     public void displayPreference(PreferenceScreen screen) {
107         super.displayPreference(screen);
108         mPreference = screen.findPreference(getPreferenceKey());
109         mScreen = screen;
110     }
111 
112     @Override
isChecked()113     public boolean isChecked() {
114         return mManager != null && mManager.isMobileDataPolicyEnabled(
115                 TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH);
116     }
117 
118     @Override
setChecked(boolean isChecked)119     public boolean setChecked(boolean isChecked) {
120         if (mManager != null) {
121             mManager.setMobileDataPolicyEnabled(
122                     TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH,
123                     isChecked);
124         }
125         if (mCrossSimCallingViewModel != null) {
126             mCrossSimCallingViewModel.updateCrossSimCalling();
127         }
128         return true;
129     }
130 
131     @VisibleForTesting
hasMobileData()132     protected boolean hasMobileData() {
133         return DataUsageUtils.hasMobileData(mContext);
134     }
135 
136     @Override
getAvailabilityStatus(int subId)137     public int getAvailabilityStatus(int subId) {
138         if (Flags.isDualSimOnboardingEnabled()
139                 || !SubscriptionManager.isValidSubscriptionId(subId)
140                 || SubscriptionManager.getDefaultDataSubscriptionId() == subId
141                 || (!hasMobileData())) {
142             return CONDITIONALLY_UNAVAILABLE;
143         }
144         return AVAILABLE;
145     }
146 
147     @Override
updateState(Preference preference)148     public void updateState(Preference preference) {
149         super.updateState(preference);
150         if (preference == null) {
151             return;
152         }
153         preference.setVisible(isAvailable());
154     }
155 
156     @Override
onAirplaneModeChanged(boolean airplaneModeEnabled)157     public void onAirplaneModeChanged(boolean airplaneModeEnabled) {}
158 
159     @Override
onSubscriptionsChanged()160     public void onSubscriptionsChanged() {
161         updateState(mPreference);
162     }
163 
164     /**
165      * Trigger displaying preference when Mobile data content changed.
166      */
167     @VisibleForTesting
refreshPreference()168     public void refreshPreference() {
169         if (mScreen != null) {
170             super.displayPreference(mScreen);
171         }
172     }
173 }
174