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 static android.app.slice.Slice.EXTRA_TOGGLE_STATE; 20 21 import static com.android.settings.Utils.SETTINGS_PACKAGE_NAME; 22 23 import android.app.PendingIntent; 24 import android.content.Context; 25 import android.content.Intent; 26 import android.content.pm.PackageManager; 27 import android.content.res.Resources; 28 import android.net.Uri; 29 import android.os.PersistableBundle; 30 import android.telephony.CarrierConfigManager; 31 import android.telephony.SubscriptionManager; 32 import android.telephony.ims.ImsMmTelManager; 33 import android.util.Log; 34 35 import androidx.annotation.VisibleForTesting; 36 import androidx.core.graphics.drawable.IconCompat; 37 import androidx.slice.Slice; 38 import androidx.slice.builders.ListBuilder; 39 import androidx.slice.builders.ListBuilder.RowBuilder; 40 import androidx.slice.builders.SliceAction; 41 42 import com.android.settings.R; 43 import com.android.settings.Utils; 44 import com.android.settings.network.ims.VolteQueryImsState; 45 import com.android.settings.slices.CustomSliceRegistry; 46 import com.android.settings.slices.SliceBroadcastReceiver; 47 48 /** 49 * Helper class to control slices for enhanced 4g LTE settings. 50 */ 51 public class Enhanced4gLteSliceHelper { 52 53 private static final String TAG = "Enhanced4gLteSlice"; 54 55 /** 56 * Action passed for changes to enhanced 4g LTE slice (toggle). 57 */ 58 public static final String ACTION_ENHANCED_4G_LTE_CHANGED = 59 "com.android.settings.mobilenetwork.action.ENHANCED_4G_LTE_CHANGED"; 60 61 /** 62 * Action for mobile network settings activity which 63 * allows setting configuration for Enhanced 4G LTE 64 * related settings 65 */ 66 public static final String ACTION_MOBILE_NETWORK_SETTINGS_ACTIVITY = 67 "android.settings.NETWORK_OPERATOR_SETTINGS"; 68 69 private final Context mContext; 70 71 /** 72 * Phone package name 73 */ 74 private static final String PACKAGE_PHONE = "com.android.phone"; 75 76 /** 77 * String resource type 78 */ 79 private static final String RESOURCE_TYPE_STRING = "string"; 80 81 /** 82 * Enhanced 4g lte mode title variant resource name 83 */ 84 private static final String RESOURCE_ENHANCED_4G_LTE_MODE_TITLE_VARIANT = 85 "enhanced_4g_lte_mode_title_variant"; 86 87 @VisibleForTesting Enhanced4gLteSliceHelper(Context context)88 public Enhanced4gLteSliceHelper(Context context) { 89 mContext = context; 90 } 91 92 /** 93 * Returns Slice object for enhanced_4g_lte settings. 94 * 95 * If enhanced 4g LTE is not supported for the current carrier, this method will return slice 96 * with not supported message. 97 * 98 * If enhanced 4g LTE is not editable for the current carrier, this method will return slice 99 * with not editable message. 100 * 101 * If enhanced 4g LTE setting can be changed, this method will return the slice to toggle 102 * enhanced 4g LTE option with ACTION_ENHANCED_4G_LTE_CHANGED as endItem. 103 */ createEnhanced4gLteSlice(Uri sliceUri)104 public Slice createEnhanced4gLteSlice(Uri sliceUri) { 105 final int subId = getDefaultVoiceSubId(); 106 107 if (!SubscriptionManager.isValidSubscriptionId(subId)) { 108 Log.d(TAG, "Invalid subscription Id"); 109 return null; 110 } 111 112 if (isCarrierConfigManagerKeyEnabled( 113 CarrierConfigManager.KEY_HIDE_ENHANCED_4G_LTE_BOOL, subId, false) 114 || !isCarrierConfigManagerKeyEnabled( 115 CarrierConfigManager.KEY_EDITABLE_ENHANCED_4G_LTE_BOOL, subId, 116 true)) { 117 Log.d(TAG, "Setting is either hidden or not editable"); 118 return null; 119 } 120 121 final VolteQueryImsState queryState = queryImsState(subId); 122 if (!queryState.isVoLteProvisioned()) { 123 Log.d(TAG, "Setting is either not provisioned or not enabled by Platform"); 124 return null; 125 } 126 127 try { 128 return getEnhanced4gLteSlice(sliceUri, 129 queryState.isEnabledByUser(), subId); 130 } catch (IllegalArgumentException e) { 131 Log.e(TAG, "Unable to read the current Enhanced 4g LTE status", e); 132 return null; 133 } 134 } 135 136 /** 137 * Builds a toggle slice where the intent takes you to the Enhanced 4G LTE page and the toggle 138 * enables/disables Enhanced 4G LTE mode setting. 139 */ getEnhanced4gLteSlice(Uri sliceUri, boolean isEnhanced4gLteEnabled, int subId)140 private Slice getEnhanced4gLteSlice(Uri sliceUri, boolean isEnhanced4gLteEnabled, int subId) { 141 final IconCompat icon = IconCompat.createWithResource(mContext, 142 R.drawable.ic_launcher_settings); 143 144 return new ListBuilder(mContext, sliceUri, ListBuilder.INFINITY) 145 .setAccentColor(Utils.getColorAccentDefaultColor(mContext)) 146 .addRow(new RowBuilder() 147 .setTitle(getEnhanced4glteModeTitle(subId)) 148 .addEndItem( 149 SliceAction.createToggle( 150 getBroadcastIntent(ACTION_ENHANCED_4G_LTE_CHANGED), 151 null /* actionTitle */, isEnhanced4gLteEnabled)) 152 .setPrimaryAction( 153 SliceAction.createDeeplink( 154 getActivityIntent(ACTION_MOBILE_NETWORK_SETTINGS_ACTIVITY), 155 icon, 156 ListBuilder.ICON_IMAGE, 157 getEnhanced4glteModeTitle(subId)))) 158 .build(); 159 } 160 161 /** 162 * Handles Enhanced 4G LTE mode setting change from Enhanced 4G LTE slice and posts 163 * notification. Should be called when intent action is ACTION_ENHANCED_4G_LTE_CHANGED 164 * 165 * @param intent action performed 166 */ handleEnhanced4gLteChanged(Intent intent)167 public void handleEnhanced4gLteChanged(Intent intent) { 168 // skip checking when no toggle state update contained within Intent 169 final boolean newValue = intent.getBooleanExtra(EXTRA_TOGGLE_STATE, false); 170 if (newValue != intent.getBooleanExtra(EXTRA_TOGGLE_STATE, true)) { 171 notifyEnhanced4gLteUpdate(); 172 return; 173 } 174 175 final int subId = getDefaultVoiceSubId(); 176 if (!SubscriptionManager.isValidSubscriptionId(subId)) { 177 notifyEnhanced4gLteUpdate(); 178 return; 179 } 180 181 final VolteQueryImsState queryState = queryImsState(subId); 182 final boolean currentValue = queryState.isEnabledByUser() 183 && queryState.isAllowUserControl(); 184 if (newValue == currentValue) { 185 notifyEnhanced4gLteUpdate(); 186 return; 187 } 188 189 // isVoLteProvisioned() is the last item to check since it might block the main thread 190 if (queryState.isVoLteProvisioned()) { 191 setEnhanced4gLteModeSetting(subId, newValue); 192 } 193 notifyEnhanced4gLteUpdate(); 194 } 195 notifyEnhanced4gLteUpdate()196 private void notifyEnhanced4gLteUpdate() { 197 // notify change in slice in any case to get re-queried. This would result in displaying 198 // appropriate message with the updated setting. 199 mContext.getContentResolver().notifyChange(CustomSliceRegistry.ENHANCED_4G_SLICE_URI, null); 200 } 201 202 @VisibleForTesting setEnhanced4gLteModeSetting(int subId, boolean isEnabled)203 void setEnhanced4gLteModeSetting(int subId, boolean isEnabled) { 204 if (!SubscriptionManager.isValidSubscriptionId(subId)) { 205 return; 206 } 207 final ImsMmTelManager imsMmTelManager = ImsMmTelManager.createForSubscriptionId(subId); 208 if (imsMmTelManager == null) { 209 return; 210 } 211 try { 212 imsMmTelManager.setAdvancedCallingSettingEnabled(isEnabled); 213 } catch (IllegalArgumentException exception) { 214 Log.w(TAG, "Unable to change the Enhanced 4g LTE to " + isEnabled + ". subId=" + subId, 215 exception); 216 } 217 } 218 getEnhanced4glteModeTitle(int subId)219 private CharSequence getEnhanced4glteModeTitle(int subId) { 220 CharSequence ret = mContext.getText(R.string.enhanced_4g_lte_mode_title); 221 try { 222 if (isCarrierConfigManagerKeyEnabled( 223 CarrierConfigManager.KEY_ENHANCED_4G_LTE_TITLE_VARIANT_BOOL, 224 subId, 225 false)) { 226 final PackageManager manager = mContext.getPackageManager(); 227 final Resources resources = manager.getResourcesForApplication( 228 PACKAGE_PHONE); 229 final int resId = resources.getIdentifier( 230 RESOURCE_ENHANCED_4G_LTE_MODE_TITLE_VARIANT, 231 RESOURCE_TYPE_STRING, PACKAGE_PHONE); 232 ret = resources.getText(resId); 233 } 234 } catch (PackageManager.NameNotFoundException e) { 235 Log.e(TAG, "package name not found"); 236 } 237 return ret; 238 } 239 240 /** 241 * Returns {@code true} when the key is enabled for the carrier, and {@code false} otherwise. 242 */ isCarrierConfigManagerKeyEnabled(String key, int subId, boolean defaultValue)243 private boolean isCarrierConfigManagerKeyEnabled(String key, 244 int subId, boolean defaultValue) { 245 final CarrierConfigManager configManager = getCarrierConfigManager(); 246 boolean ret = defaultValue; 247 if (configManager != null) { 248 final PersistableBundle bundle = configManager.getConfigForSubId(subId); 249 if (bundle != null) { 250 ret = bundle.getBoolean(key, defaultValue); 251 } 252 } 253 return ret; 254 } 255 getCarrierConfigManager()256 protected CarrierConfigManager getCarrierConfigManager() { 257 return mContext.getSystemService(CarrierConfigManager.class); 258 } 259 getBroadcastIntent(String action)260 private PendingIntent getBroadcastIntent(String action) { 261 final Intent intent = new Intent(action); 262 intent.setClass(mContext, SliceBroadcastReceiver.class); 263 return PendingIntent.getBroadcast(mContext, 0 /* requestCode */, intent, 264 PendingIntent.FLAG_CANCEL_CURRENT); 265 } 266 267 /** 268 * Returns the current default voice subId obtained from SubscriptionManager 269 */ getDefaultVoiceSubId()270 protected int getDefaultVoiceSubId() { 271 return SubscriptionManager.getDefaultVoiceSubscriptionId(); 272 } 273 274 /** 275 * Returns PendingIntent to start activity specified by action 276 */ getActivityIntent(String action)277 private PendingIntent getActivityIntent(String action) { 278 final Intent intent = new Intent(action); 279 intent.setPackage(SETTINGS_PACKAGE_NAME); 280 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 281 return PendingIntent.getActivity(mContext, 0 /* requestCode */, intent, 0 /* flags */); 282 } 283 284 @VisibleForTesting queryImsState(int subId)285 VolteQueryImsState queryImsState(int subId) { 286 return new VolteQueryImsState(mContext, subId); 287 } 288 } 289 290