1 /* 2 * Copyright (C) 2021 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.util.Log; 26 27 import androidx.annotation.VisibleForTesting; 28 import androidx.preference.Preference; 29 import androidx.preference.PreferenceScreen; 30 import androidx.preference.SwitchPreference; 31 32 import com.android.internal.telephony.util.ArrayUtils; 33 import com.android.settingslib.core.lifecycle.LifecycleObserver; 34 import com.android.settingslib.core.lifecycle.events.OnStart; 35 import com.android.settingslib.core.lifecycle.events.OnStop; 36 37 /** 38 * Preference controller for "Enhanced 4G LTE" 39 */ 40 public class NrAdvancedCallingPreferenceController extends TelephonyTogglePreferenceController 41 implements LifecycleObserver, OnStart, OnStop { 42 43 private static final String TAG = "VoNrSettings"; 44 45 @VisibleForTesting 46 Preference mPreference; 47 private TelephonyManager mTelephonyManager; 48 private PhoneCallStateTelephonyCallback mTelephonyCallback; 49 private boolean mIsVonrEnabledFromCarrierConfig = false; 50 private boolean mIsVonrVisibleFromCarrierConfig = false; 51 private boolean mIsNrEnableFromCarrierConfig = false; 52 private boolean mHas5gCapability = false; 53 private Integer mCallState; 54 NrAdvancedCallingPreferenceController(Context context, String key)55 public NrAdvancedCallingPreferenceController(Context context, String key) { 56 super(context, key); 57 mTelephonyManager = context.getSystemService(TelephonyManager.class); 58 } 59 60 /** 61 * Initial this PreferenceController. 62 * @param subId The subscription Id. 63 * @return This PreferenceController. 64 */ init(int subId)65 public NrAdvancedCallingPreferenceController init(int subId) { 66 Log.d(TAG, "init: "); 67 if (mTelephonyCallback == null) { 68 mTelephonyCallback = new PhoneCallStateTelephonyCallback(); 69 } 70 71 mSubId = subId; 72 73 if (mTelephonyManager == null) { 74 mTelephonyManager = mContext.getSystemService(TelephonyManager.class); 75 } 76 if (SubscriptionManager.isValidSubscriptionId(subId)) { 77 mTelephonyManager = mTelephonyManager.createForSubscriptionId(subId); 78 } 79 long supportedRadioBitmask = mTelephonyManager.getSupportedRadioAccessFamily(); 80 mHas5gCapability = 81 (supportedRadioBitmask & TelephonyManager.NETWORK_TYPE_BITMASK_NR) > 0; 82 83 PersistableBundle carrierConfig = getCarrierConfigForSubId(subId); 84 if (carrierConfig == null) { 85 return this; 86 } 87 mIsVonrEnabledFromCarrierConfig = carrierConfig.getBoolean( 88 CarrierConfigManager.KEY_VONR_ENABLED_BOOL); 89 90 mIsVonrVisibleFromCarrierConfig = carrierConfig.getBoolean( 91 CarrierConfigManager.KEY_VONR_SETTING_VISIBILITY_BOOL); 92 93 int[] nrAvailabilities = carrierConfig.getIntArray( 94 CarrierConfigManager.KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY); 95 mIsNrEnableFromCarrierConfig = !ArrayUtils.isEmpty(nrAvailabilities); 96 97 Log.d(TAG, "mHas5gCapability: " + mHas5gCapability 98 + ",mIsNrEnabledFromCarrierConfig: " + mIsNrEnableFromCarrierConfig 99 + ",mIsVonrEnabledFromCarrierConfig: " + mIsVonrEnabledFromCarrierConfig 100 + ",mIsVonrVisibleFromCarrierConfig: " + mIsVonrVisibleFromCarrierConfig); 101 return this; 102 } 103 104 @Override getAvailabilityStatus(int subId)105 public int getAvailabilityStatus(int subId) { 106 init(subId); 107 108 if (mHas5gCapability 109 && mIsNrEnableFromCarrierConfig 110 && mIsVonrEnabledFromCarrierConfig 111 && mIsVonrVisibleFromCarrierConfig) { 112 return AVAILABLE; 113 } 114 return CONDITIONALLY_UNAVAILABLE; 115 } 116 117 @Override displayPreference(PreferenceScreen screen)118 public void displayPreference(PreferenceScreen screen) { 119 super.displayPreference(screen); 120 mPreference = screen.findPreference(getPreferenceKey()); 121 } 122 123 @Override onStart()124 public void onStart() { 125 if (mTelephonyCallback == null) { 126 return; 127 } 128 mTelephonyCallback.register(mTelephonyManager); 129 } 130 131 @Override onStop()132 public void onStop() { 133 if (mTelephonyCallback == null) { 134 return; 135 } 136 mTelephonyCallback.unregister(); 137 } 138 139 @Override updateState(Preference preference)140 public void updateState(Preference preference) { 141 super.updateState(preference); 142 if (preference == null) { 143 return; 144 } 145 final SwitchPreference switchPreference = (SwitchPreference) preference; 146 switchPreference.setEnabled(isUserControlAllowed()); 147 } 148 149 @Override setChecked(boolean isChecked)150 public boolean setChecked(boolean isChecked) { 151 if (!SubscriptionManager.isValidSubscriptionId(mSubId)) { 152 return false; 153 } 154 Log.d(TAG, "setChecked: " + isChecked); 155 int result = mTelephonyManager.setVoNrEnabled(isChecked); 156 if (result == TelephonyManager.ENABLE_VONR_SUCCESS) { 157 return true; 158 } 159 Log.d(TAG, "Fail to set VoNR result= " + result + ". subId=" + mSubId); 160 return false; 161 } 162 163 @Override isChecked()164 public boolean isChecked() { 165 return mTelephonyManager.isVoNrEnabled(); 166 } 167 168 @VisibleForTesting isCallStateIdle()169 protected boolean isCallStateIdle() { 170 return (mCallState != null) && (mCallState == TelephonyManager.CALL_STATE_IDLE); 171 } 172 isUserControlAllowed()173 private boolean isUserControlAllowed() { 174 return isCallStateIdle(); 175 } 176 177 private class PhoneCallStateTelephonyCallback extends TelephonyCallback implements 178 TelephonyCallback.CallStateListener { 179 180 private TelephonyManager mLocalTelephonyManager; 181 182 @Override onCallStateChanged(int state)183 public void onCallStateChanged(int state) { 184 mCallState = state; 185 updateState(mPreference); 186 } 187 register(TelephonyManager telephonyManager)188 public void register(TelephonyManager telephonyManager) { 189 mLocalTelephonyManager = telephonyManager; 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 = mLocalTelephonyManager.getCallState(); 194 mLocalTelephonyManager.registerTelephonyCallback( 195 mContext.getMainExecutor(), mTelephonyCallback); 196 } 197 unregister()198 public void unregister() { 199 mCallState = null; 200 if (mLocalTelephonyManager != null) { 201 mLocalTelephonyManager.unregisterTelephonyCallback(this); 202 } 203 } 204 } 205 } 206