1 /* 2 * Copyright (C) 2015 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 package com.android.phone.vvm.omtp; 17 18 import android.content.BroadcastReceiver; 19 import android.content.Context; 20 import android.content.Intent; 21 import android.content.pm.IPackageManager; 22 import android.os.RemoteException; 23 import android.os.ServiceManager; 24 import android.os.UserManager; 25 import android.telecom.PhoneAccountHandle; 26 import android.telephony.CarrierConfigManager; 27 import android.telephony.ServiceState; 28 import android.telephony.SubscriptionManager; 29 import android.telephony.TelephonyManager; 30 import android.text.TextUtils; 31 import com.android.internal.telephony.IccCardConstants; 32 import com.android.internal.telephony.PhoneConstants; 33 import com.android.internal.telephony.TelephonyIntents; 34 import com.android.phone.settings.VisualVoicemailSettingsUtil; 35 import com.android.phone.vvm.omtp.sync.OmtpVvmSourceManager; 36 import com.android.phone.vvm.omtp.utils.PhoneAccountHandleConverter; 37 38 /** 39 * This class listens to the {@link CarrierConfigManager#ACTION_CARRIER_CONFIG_CHANGED} and {@link 40 * TelephonyIntents#ACTION_SIM_STATE_CHANGED} to determine when a SIM is added, replaced, or 41 * removed. 42 * 43 * When a SIM is added, send an activate SMS. When a SIM is removed, remove the sync accounts and 44 * change the status in the voicemail_status table. 45 */ 46 public class SimChangeReceiver extends BroadcastReceiver { 47 48 private static final String TAG = "VvmSimChangeReceiver"; 49 50 @Override onReceive(Context context, Intent intent)51 public void onReceive(Context context, Intent intent) { 52 final String action = intent.getAction(); 53 if (action == null) { 54 VvmLog.w(TAG, "Null action for intent."); 55 return; 56 } 57 58 switch (action) { 59 case TelephonyIntents.ACTION_SIM_STATE_CHANGED: 60 if (IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals( 61 intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE))) { 62 VvmLog.i(TAG, "Sim removed, removing inactive accounts"); 63 OmtpVvmSourceManager.getInstance(context).removeInactiveSources(); 64 } 65 break; 66 case CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED: 67 int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY, 68 SubscriptionManager.INVALID_SUBSCRIPTION_ID); 69 70 if (!SubscriptionManager.isValidSubscriptionId(subId)) { 71 VvmLog.i(TAG, "Received SIM change for invalid subscription id."); 72 return; 73 } 74 75 TelephonyManager telephonyManager = context 76 .getSystemService(TelephonyManager.class); 77 if(TextUtils.isEmpty(telephonyManager.getSimOperator())){ 78 VvmLog.e(TAG, 79 "Empty MCCMNC, possible modem crash." 80 + " Ignoring carrier config changed event"); 81 return; 82 } 83 84 PhoneAccountHandle phoneAccountHandle = PhoneAccountHandleConverter 85 .fromSubId(subId); 86 if("null".equals(phoneAccountHandle.getId())){ 87 VvmLog.e(TAG, 88 "null phone account handle ID, possible modem crash." 89 + " Ignoring carrier config changed event"); 90 return; 91 } 92 93 VvmLog.d(TAG, "Carrier config changed"); 94 if (UserManager.get(context).isUserUnlocked() && !isCryptKeeperMode()) { 95 processSubId(context, subId); 96 } else { 97 VvmLog.d(TAG, "User locked, activation request delayed until unlock"); 98 // After the device is unlocked, VvmBootCompletedReceiver will iterate through 99 // all call capable subIds, nothing need to be done here. 100 } 101 break; 102 } 103 } 104 processSubId(Context context, int subId)105 public static void processSubId(Context context, int subId) { 106 PhoneAccountHandle phoneAccount = PhoneAccountHandleConverter.fromSubId(subId); 107 if (phoneAccount == null) { 108 // This should never happen 109 VvmLog.e(TAG, "unable to convert subId " + subId + " to PhoneAccountHandle"); 110 return; 111 } 112 113 OmtpVvmCarrierConfigHelper carrierConfigHelper = 114 new OmtpVvmCarrierConfigHelper(context, subId); 115 if (carrierConfigHelper.isValid()) { 116 if (VisualVoicemailSettingsUtil.isEnabled(context, phoneAccount)) { 117 VvmLog.i(TAG, "Sim state or carrier config changed for " + subId); 118 // Add a phone state listener so that changes to the communication channels 119 // can be recorded. 120 OmtpVvmSourceManager.getInstance(context).addPhoneStateListener( 121 phoneAccount); 122 if (context.getSystemService(TelephonyManager.class) 123 .getServiceStateForSubscriber(subId).getState() 124 != ServiceState.STATE_IN_SERVICE) { 125 VvmLog.i(TAG, "Cellular signal not available, not activating"); 126 return; 127 } 128 carrierConfigHelper.startActivation(); 129 } else { 130 if (carrierConfigHelper.isLegacyModeEnabled()) { 131 // SMS still need to be filtered under legacy mode. 132 VvmLog.i(TAG, "activating SMS filter for legacy mode"); 133 carrierConfigHelper.activateSmsFilter(); 134 } 135 // It may be that the source was not registered to begin with but we want 136 // to run through the steps to remove the source just in case. 137 OmtpVvmSourceManager.getInstance(context).removeSource(phoneAccount); 138 VvmLog.v(TAG, "Sim change for disabled account."); 139 } 140 } else { 141 String mccMnc = context.getSystemService(TelephonyManager.class).getSimOperator(subId); 142 VvmLog.d(TAG, 143 "visual voicemail not supported for carrier " + mccMnc + " on subId " + subId); 144 OmtpVvmSourceManager.getInstance(context).removeSource(phoneAccount); 145 } 146 } 147 148 /** 149 * CryptKeeper mode is the pre-file based encryption locked state, when the user has selected 150 * "Require password to boot" and the device hasn't been unlocked yet during a reboot. {@link 151 * UserManager#isUserUnlocked()} will still return true in this mode, but storage in /data and 152 * all content providers will not be available(including SharedPreference). 153 */ isCryptKeeperMode()154 private static boolean isCryptKeeperMode() { 155 try { 156 return IPackageManager.Stub.asInterface(ServiceManager.getService("package")). 157 isOnlyCoreApps(); 158 } catch (RemoteException e) { 159 } 160 return false; 161 } 162 }