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 com.android.phone.R; 20 21 import android.app.PendingIntent; 22 import android.content.ComponentName; 23 import android.content.Context; 24 import android.content.Intent; 25 import android.graphics.BitmapFactory; 26 import android.net.Uri; 27 import android.net.sip.SipManager; 28 import android.net.sip.SipProfile; 29 import android.provider.Settings; 30 import android.telecom.PhoneAccount; 31 import android.telecom.PhoneAccountHandle; 32 import android.telecom.TelecomManager; 33 import android.text.TextUtils; 34 import android.util.Log; 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 sipUri)57 static PendingIntent createIncomingCallPendingIntent( 58 Context context, String sipUri) { 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, sipUri)); 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 URI. 76 */ createAccountHandle(Context context, String sipUri)77 static PhoneAccountHandle createAccountHandle(Context context, String sipUri) { 78 return new PhoneAccountHandle( 79 new ComponentName(context, SipConnectionService.class), sipUri); 80 } 81 82 /** 83 * Determines the SIP Uri for a specified {@link PhoneAccountHandle}. 84 * 85 * @param phoneAccountHandle The {@link PhoneAccountHandle}. 86 * @return The SIP Uri. 87 */ getSipUriFromPhoneAccount(PhoneAccountHandle phoneAccountHandle)88 static String getSipUriFromPhoneAccount(PhoneAccountHandle phoneAccountHandle) { 89 if (phoneAccountHandle == null) { 90 return null; 91 } 92 93 String sipUri = phoneAccountHandle.getId(); 94 if (TextUtils.isEmpty(sipUri)) { 95 return null; 96 } 97 return sipUri; 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 109 PhoneAccountHandle accountHandle = 110 SipUtil.createAccountHandle(context, profile.getUriString()); 111 112 final ArrayList<String> supportedUriSchemes = new ArrayList<String>(); 113 supportedUriSchemes.add(PhoneAccount.SCHEME_SIP); 114 if (useSipForPstnCalls(context)) { 115 supportedUriSchemes.add(PhoneAccount.SCHEME_TEL); 116 } 117 118 PhoneAccount.Builder builder = PhoneAccount.builder(accountHandle, profile.getDisplayName()) 119 .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER 120 | PhoneAccount.CAPABILITY_MULTI_USER) 121 .setAddress(Uri.parse(profile.getUriString())) 122 .setShortDescription(profile.getDisplayName()) 123 .setIcon(context, R.drawable.ic_dialer_sip_black_24dp) 124 .setSupportedUriSchemes(supportedUriSchemes); 125 126 return builder.build(); 127 } 128 129 /** 130 * Determines if the user has chosen to use SIP for PSTN calls as well as SIP calls. 131 * @param context The context. 132 * @return {@code True} if SIP should be used for PSTN calls. 133 */ useSipForPstnCalls(Context context)134 private static boolean useSipForPstnCalls(Context context) { 135 final SipSharedPreferences sipSharedPreferences = new SipSharedPreferences(context); 136 return sipSharedPreferences.getSipCallOption().equals(Settings.System.SIP_ALWAYS); 137 } 138 139 /** 140 * Updates SIP accounts to indicate whether they are enabled to receive incoming SIP calls. 141 * 142 * @param isEnabled {@code True} if receiving incoming SIP calls. 143 */ useSipToReceiveIncomingCalls(Context context, boolean isEnabled)144 public static void useSipToReceiveIncomingCalls(Context context, boolean isEnabled) { 145 SipProfileDb profileDb = new SipProfileDb(context); 146 147 // Mark all profiles as auto-register if we are now receiving calls. 148 List<SipProfile> sipProfileList = profileDb.retrieveSipProfileList(); 149 for (SipProfile p : sipProfileList) { 150 updateAutoRegistrationFlag(p, profileDb, isEnabled); 151 } 152 } 153 updateAutoRegistrationFlag( SipProfile p, SipProfileDb db, boolean isEnabled)154 private static void updateAutoRegistrationFlag( 155 SipProfile p, SipProfileDb db, boolean isEnabled) { 156 SipProfile newProfile = new SipProfile.Builder(p).setAutoRegistration(isEnabled).build(); 157 158 try { 159 // Note: The profile is updated, but the associated PhoneAccount is left alone since 160 // the only thing that changed is the auto-registration flag, which is not part of the 161 // PhoneAccount. 162 db.deleteProfile(p); 163 db.saveProfile(newProfile); 164 } catch (Exception e) { 165 Log.d(LOG_TAG, "updateAutoRegistrationFlag, exception: " + e); 166 } 167 } 168 } 169