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