1 /* 2 * Copyright (C) 2018 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 android.content.Context; 20 import android.os.PersistableBundle; 21 import android.telephony.CarrierConfigManager; 22 import android.telephony.SubscriptionManager; 23 import android.telephony.TelephonyCallback; 24 import android.telephony.TelephonyManager; 25 import android.telephony.ims.ImsMmTelManager; 26 import android.util.Log; 27 28 import androidx.annotation.VisibleForTesting; 29 import androidx.preference.Preference; 30 import androidx.preference.PreferenceScreen; 31 import androidx.preference.SwitchPreference; 32 33 import com.android.settings.network.MobileDataEnabledListener; 34 import com.android.settings.network.ims.VolteQueryImsState; 35 import com.android.settings.network.ims.VtQueryImsState; 36 import com.android.settingslib.core.lifecycle.LifecycleObserver; 37 import com.android.settingslib.core.lifecycle.events.OnStart; 38 import com.android.settingslib.core.lifecycle.events.OnStop; 39 40 /** 41 * Preference controller for "Video Calling" 42 */ 43 public class VideoCallingPreferenceController extends TelephonyTogglePreferenceController implements 44 LifecycleObserver, OnStart, OnStop, 45 MobileDataEnabledListener.Client, 46 Enhanced4gBasePreferenceController.On4gLteUpdateListener { 47 48 private static final String TAG = "VideoCallingPreference"; 49 50 private Preference mPreference; 51 private CarrierConfigManager mCarrierConfigManager; 52 private PhoneTelephonyCallback mTelephonyCallback; 53 @VisibleForTesting 54 Integer mCallState; 55 private MobileDataEnabledListener mDataContentObserver; 56 VideoCallingPreferenceController(Context context, String key)57 public VideoCallingPreferenceController(Context context, String key) { 58 super(context, key); 59 mCarrierConfigManager = context.getSystemService(CarrierConfigManager.class); 60 mDataContentObserver = new MobileDataEnabledListener(context, this); 61 mTelephonyCallback = new PhoneTelephonyCallback(); 62 } 63 64 @Override getAvailabilityStatus(int subId)65 public int getAvailabilityStatus(int subId) { 66 return SubscriptionManager.isValidSubscriptionId(subId) 67 && isVideoCallEnabled(subId) 68 ? AVAILABLE 69 : CONDITIONALLY_UNAVAILABLE; 70 } 71 72 @Override displayPreference(PreferenceScreen screen)73 public void displayPreference(PreferenceScreen screen) { 74 super.displayPreference(screen); 75 mPreference = screen.findPreference(getPreferenceKey()); 76 } 77 78 @Override onStart()79 public void onStart() { 80 mTelephonyCallback.register(mContext, mSubId); 81 mDataContentObserver.start(mSubId); 82 } 83 84 @Override onStop()85 public void onStop() { 86 mTelephonyCallback.unregister(); 87 mDataContentObserver.stop(); 88 } 89 90 @Override updateState(Preference preference)91 public void updateState(Preference preference) { 92 super.updateState(preference); 93 if ((mCallState == null) || (preference == null)) { 94 Log.d(TAG, "Skip update under mCallState=" + mCallState); 95 return; 96 } 97 final SwitchPreference switchPreference = (SwitchPreference) preference; 98 final boolean videoCallEnabled = isVideoCallEnabled(mSubId); 99 switchPreference.setVisible(videoCallEnabled); 100 if (videoCallEnabled) { 101 final boolean videoCallEditable = queryVoLteState(mSubId).isEnabledByUser() 102 && queryImsState(mSubId).isAllowUserControl(); 103 preference.setEnabled(videoCallEditable 104 && mCallState == TelephonyManager.CALL_STATE_IDLE); 105 switchPreference.setChecked(videoCallEditable && isChecked()); 106 } 107 } 108 109 @Override setChecked(boolean isChecked)110 public boolean setChecked(boolean isChecked) { 111 if (!SubscriptionManager.isValidSubscriptionId(mSubId)) { 112 return false; 113 } 114 final ImsMmTelManager imsMmTelManager = ImsMmTelManager.createForSubscriptionId(mSubId); 115 if (imsMmTelManager == null) { 116 return false; 117 } 118 try { 119 imsMmTelManager.setVtSettingEnabled(isChecked); 120 return true; 121 } catch (IllegalArgumentException exception) { 122 Log.w(TAG, "Unable to set VT status " + isChecked + ". subId=" + mSubId, 123 exception); 124 } 125 return false; 126 } 127 128 @Override isChecked()129 public boolean isChecked() { 130 return queryImsState(mSubId).isEnabledByUser(); 131 } 132 init(int subId)133 public VideoCallingPreferenceController init(int subId) { 134 mSubId = subId; 135 136 return this; 137 } 138 139 @VisibleForTesting isVideoCallEnabled(int subId)140 boolean isVideoCallEnabled(int subId) { 141 if (!SubscriptionManager.isValidSubscriptionId(subId)) { 142 return false; 143 } 144 145 // When called within Settings Search, this variable may still be null. 146 if (mCarrierConfigManager == null) { 147 Log.e(TAG, "CarrierConfigManager set to null."); 148 mCarrierConfigManager = mContext.getSystemService(CarrierConfigManager.class); 149 if (mCarrierConfigManager == null) { 150 Log.e(TAG, "Unable to reinitialize CarrierConfigManager."); 151 return false; 152 } 153 } 154 155 final PersistableBundle carrierConfig = mCarrierConfigManager.getConfigForSubId(subId); 156 if (carrierConfig == null) { 157 return false; 158 } 159 160 if (!carrierConfig.getBoolean( 161 CarrierConfigManager.KEY_IGNORE_DATA_ENABLED_CHANGED_FOR_VIDEO_CALLS) 162 && (!mContext.getSystemService(TelephonyManager.class) 163 .createForSubscriptionId(subId).isDataEnabled())) { 164 return false; 165 } 166 167 return queryImsState(subId).isReadyToVideoCall(); 168 } 169 170 @Override on4gLteUpdated()171 public void on4gLteUpdated() { 172 updateState(mPreference); 173 } 174 175 private class PhoneTelephonyCallback extends TelephonyCallback implements 176 TelephonyCallback.CallStateListener { 177 178 private TelephonyManager mTelephonyManager; 179 180 @Override onCallStateChanged(int state)181 public void onCallStateChanged(int state) { 182 mCallState = state; 183 updateState(mPreference); 184 } 185 register(Context context, int subId)186 public void register(Context context, int subId) { 187 mTelephonyManager = context.getSystemService(TelephonyManager.class); 188 if (SubscriptionManager.isValidSubscriptionId(subId)) { 189 mTelephonyManager = mTelephonyManager.createForSubscriptionId(subId); 190 } 191 // assign current call state so that it helps to show correct preference state even 192 // before first onCallStateChanged() by initial registration. 193 mCallState = mTelephonyManager.getCallState(subId); 194 mTelephonyManager.registerTelephonyCallback(context.getMainExecutor(), this); 195 } 196 unregister()197 public void unregister() { 198 mCallState = null; 199 mTelephonyManager.unregisterTelephonyCallback(this); 200 } 201 } 202 203 /** 204 * Implementation of MobileDataEnabledListener.Client 205 */ onMobileDataEnabledChange()206 public void onMobileDataEnabledChange() { 207 updateState(mPreference); 208 } 209 210 @VisibleForTesting queryImsState(int subId)211 VtQueryImsState queryImsState(int subId) { 212 return new VtQueryImsState(mContext, subId); 213 } 214 215 @VisibleForTesting queryVoLteState(int subId)216 VolteQueryImsState queryVoLteState(int subId) { 217 return new VolteQueryImsState(mContext, subId); 218 } 219 } 220