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