1 /* 2 * Copyright (C) 2010 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.services.telephony.sip; 18 19 import android.app.PendingIntent; 20 import android.content.ComponentName; 21 import android.content.Context; 22 import android.content.Intent; 23 import android.graphics.drawable.Icon; 24 import android.net.Uri; 25 import android.net.sip.SipManager; 26 import android.net.sip.SipProfile; 27 import android.provider.Settings; 28 import android.telecom.PhoneAccount; 29 import android.telecom.PhoneAccountHandle; 30 import android.telecom.TelecomManager; 31 import android.text.TextUtils; 32 import android.util.Log; 33 34 import com.android.phone.R; 35 36 import java.util.ArrayList; 37 import java.util.List; 38 39 public class SipUtil { 40 static final String LOG_TAG = "SIP"; 41 static final String EXTRA_INCOMING_CALL_INTENT = 42 "com.android.services.telephony.sip.incoming_call_intent"; 43 static final String EXTRA_PHONE_ACCOUNT = 44 "com.android.services.telephony.sip.phone_account"; 45 SipUtil()46 private SipUtil() { 47 } 48 isVoipSupported(Context context)49 public static boolean isVoipSupported(Context context) { 50 return SipManager.isVoipSupported(context) && 51 context.getResources().getBoolean( 52 com.android.internal.R.bool.config_built_in_sip_phone) && 53 context.getResources().getBoolean( 54 com.android.internal.R.bool.config_voice_capable); 55 } 56 createIncomingCallPendingIntent( Context context, String sipProfileName)57 static PendingIntent createIncomingCallPendingIntent( 58 Context context, String sipProfileName) { 59 Intent intent = new Intent(context, SipBroadcastReceiver.class); 60 intent.setAction(SipManager.ACTION_SIP_INCOMING_CALL); 61 intent.putExtra(EXTRA_PHONE_ACCOUNT, SipUtil.createAccountHandle(context, sipProfileName)); 62 return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); 63 } 64 isPhoneIdle(Context context)65 public static boolean isPhoneIdle(Context context) { 66 TelecomManager manager = (TelecomManager) context.getSystemService( 67 Context.TELECOM_SERVICE); 68 if (manager != null) { 69 return !manager.isInCall(); 70 } 71 return true; 72 } 73 74 /** 75 * Creates a {@link PhoneAccountHandle} from the specified SIP profile name. 76 */ createAccountHandle(Context context, String sipProfileName)77 static PhoneAccountHandle createAccountHandle(Context context, String sipProfileName) { 78 return new PhoneAccountHandle( 79 new ComponentName(context, SipConnectionService.class), sipProfileName); 80 } 81 82 /** 83 * Determines the SIP profile name for a specified {@link PhoneAccountHandle}. 84 * 85 * @param phoneAccountHandle The {@link PhoneAccountHandle}. 86 * @return The SIP profile name. 87 */ getSipProfileNameFromPhoneAccount(PhoneAccountHandle phoneAccountHandle)88 static String getSipProfileNameFromPhoneAccount(PhoneAccountHandle phoneAccountHandle) { 89 if (phoneAccountHandle == null) { 90 return null; 91 } 92 93 String sipProfileName = phoneAccountHandle.getId(); 94 if (TextUtils.isEmpty(sipProfileName)) { 95 return null; 96 } 97 return sipProfileName; 98 } 99 100 /** 101 * Creates a PhoneAccount for a SipProfile. 102 * 103 * @param context The context 104 * @param profile The SipProfile. 105 * @return The PhoneAccount. 106 */ createPhoneAccount(Context context, SipProfile profile)107 static PhoneAccount createPhoneAccount(Context context, SipProfile profile) { 108 // Build a URI to represent the SIP account. Does not use SipProfile#getUriString() since 109 // that prototype can include transport information which we do not want to see in the 110 // phone account. 111 String sipAddress = profile.getUserName() + "@" + profile.getSipDomain(); 112 Uri sipUri = Uri.parse(profile.getUriString()); 113 114 PhoneAccountHandle accountHandle = 115 SipUtil.createAccountHandle(context, profile.getProfileName()); 116 117 final ArrayList<String> supportedUriSchemes = new ArrayList<String>(); 118 supportedUriSchemes.add(PhoneAccount.SCHEME_SIP); 119 if (useSipForPstnCalls(context)) { 120 supportedUriSchemes.add(PhoneAccount.SCHEME_TEL); 121 } 122 123 PhoneAccount.Builder builder = PhoneAccount.builder(accountHandle, profile.getDisplayName()) 124 .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER 125 | PhoneAccount.CAPABILITY_MULTI_USER) 126 .setAddress(sipUri) 127 .setShortDescription(sipAddress) 128 .setIcon(Icon.createWithResource( 129 context.getResources(), R.drawable.ic_dialer_sip_black_24dp)) 130 .setSupportedUriSchemes(supportedUriSchemes); 131 132 return builder.build(); 133 } 134 135 /** 136 * Determines if the user has chosen to use SIP for PSTN calls as well as SIP calls. 137 * @param context The context. 138 * @return {@code True} if SIP should be used for PSTN calls. 139 */ useSipForPstnCalls(Context context)140 private static boolean useSipForPstnCalls(Context context) { 141 final SipSharedPreferences sipSharedPreferences = new SipSharedPreferences(context); 142 return sipSharedPreferences.getSipCallOption().equals(Settings.System.SIP_ALWAYS); 143 } 144 145 /** 146 * Updates SIP accounts to indicate whether they are enabled to receive incoming SIP calls. 147 * 148 * @param isEnabled {@code True} if receiving incoming SIP calls. 149 */ useSipToReceiveIncomingCalls(Context context, boolean isEnabled)150 public static void useSipToReceiveIncomingCalls(Context context, boolean isEnabled) { 151 SipProfileDb profileDb = new SipProfileDb(context); 152 153 // Mark all profiles as auto-register if we are now receiving calls. 154 List<SipProfile> sipProfileList = profileDb.retrieveSipProfileList(); 155 for (SipProfile p : sipProfileList) { 156 updateAutoRegistrationFlag(p, profileDb, isEnabled); 157 } 158 } 159 updateAutoRegistrationFlag( SipProfile p, SipProfileDb db, boolean isEnabled)160 private static void updateAutoRegistrationFlag( 161 SipProfile p, SipProfileDb db, boolean isEnabled) { 162 SipProfile newProfile = new SipProfile.Builder(p).setAutoRegistration(isEnabled).build(); 163 164 try { 165 // Note: The profile is updated, but the associated PhoneAccount is left alone since 166 // the only thing that changed is the auto-registration flag, which is not part of the 167 // PhoneAccount. 168 db.deleteProfile(p); 169 db.saveProfile(newProfile); 170 } catch (Exception e) { 171 Log.d(LOG_TAG, "updateAutoRegistrationFlag, exception: " + e); 172 } 173 } 174 } 175