• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.phone.sip;
18 
19 import com.android.internal.telephony.CallManager;
20 import com.android.internal.telephony.Phone;
21 import com.android.phone.R;
22 import com.android.phone.SipUtil;
23 
24 import android.app.AlertDialog;
25 import android.content.Context;
26 import android.content.DialogInterface;
27 import android.content.Intent;
28 import android.content.pm.ApplicationInfo;
29 import android.content.pm.PackageManager;
30 import android.net.sip.SipException;
31 import android.net.sip.SipErrorCode;
32 import android.net.sip.SipProfile;
33 import android.net.sip.SipManager;
34 import android.net.sip.SipRegistrationListener;
35 import android.os.Bundle;
36 import android.os.Parcelable;
37 import android.os.Process;
38 import android.preference.CheckBoxPreference;
39 import android.preference.Preference;
40 import android.preference.Preference.OnPreferenceClickListener;
41 import android.preference.PreferenceActivity;
42 import android.preference.PreferenceCategory;
43 import android.preference.PreferenceScreen;
44 import android.text.TextUtils;
45 import android.util.Log;
46 import android.view.MenuItem;
47 import android.view.View;
48 import android.view.ContextMenu;
49 import android.view.ContextMenu.ContextMenuInfo;
50 import android.widget.AdapterView.AdapterContextMenuInfo;
51 import android.widget.Button;
52 
53 import java.io.IOException;
54 import java.util.Collections;
55 import java.util.Comparator;
56 import java.util.LinkedHashMap;
57 import java.util.List;
58 import java.util.Map;
59 
60 /**
61  * The PreferenceActivity class for managing sip profile preferences.
62  */
63 public class SipSettings extends PreferenceActivity {
64     public static final String SIP_SHARED_PREFERENCES = "SIP_PREFERENCES";
65 
66     static final String KEY_SIP_PROFILE = "sip_profile";
67 
68     private static final String BUTTON_SIP_RECEIVE_CALLS =
69             "sip_receive_calls_key";
70     private static final String PREF_SIP_LIST = "sip_account_list";
71     private static final String TAG = "SipSettings";
72 
73     private static final int REQUEST_ADD_OR_EDIT_SIP_PROFILE = 1;
74 
75     private PackageManager mPackageManager;
76     private SipManager mSipManager;
77     private CallManager mCallManager;
78     private SipProfileDb mProfileDb;
79 
80     private SipProfile mProfile; // profile that's being edited
81 
82     private Button mButtonAddSipAccount;
83     private CheckBoxPreference mButtonSipReceiveCalls;
84     private PreferenceCategory mSipListContainer;
85     private Map<String, SipPreference> mSipPreferenceMap;
86     private List<SipProfile> mSipProfileList;
87     private SipSharedPreferences mSipSharedPreferences;
88     private int mUid = Process.myUid();
89 
90     private class SipPreference extends Preference {
91         SipProfile mProfile;
SipPreference(Context c, SipProfile p)92         SipPreference(Context c, SipProfile p) {
93             super(c);
94             setProfile(p);
95         }
96 
getProfile()97         SipProfile getProfile() {
98             return mProfile;
99         }
100 
setProfile(SipProfile p)101         void setProfile(SipProfile p) {
102             mProfile = p;
103             setTitle(getProfileName(p));
104             updateSummary(mSipSharedPreferences.isReceivingCallsEnabled()
105                     ? getString(R.string.registration_status_checking_status)
106                     : getString(R.string.registration_status_not_receiving));
107         }
108 
updateSummary(String registrationStatus)109         void updateSummary(String registrationStatus) {
110             int profileUid = mProfile.getCallingUid();
111             boolean isPrimary = mProfile.getUriString().equals(
112                     mSipSharedPreferences.getPrimaryAccount());
113             Log.v(TAG, "profile uid is " + profileUid + " isPrimary:"
114                     + isPrimary + " registration:" + registrationStatus
115                     + " Primary:" + mSipSharedPreferences.getPrimaryAccount()
116                     + " status:" + registrationStatus);
117             String summary = "";
118             if ((profileUid > 0) && (profileUid != mUid)) {
119                 // from third party apps
120                 summary = getString(R.string.third_party_account_summary,
121                         getPackageNameFromUid(profileUid));
122             } else if (isPrimary) {
123                 summary = getString(R.string.primary_account_summary_with,
124                         registrationStatus);
125             } else {
126                 summary = registrationStatus;
127             }
128             setSummary(summary);
129         }
130     }
131 
getPackageNameFromUid(int uid)132     private String getPackageNameFromUid(int uid) {
133         try {
134             String[] pkgs = mPackageManager.getPackagesForUid(uid);
135             ApplicationInfo ai =
136                     mPackageManager.getApplicationInfo(pkgs[0], 0);
137             return ai.loadLabel(mPackageManager).toString();
138         } catch (PackageManager.NameNotFoundException e) {
139             Log.e(TAG, "cannot find name of uid " + uid, e);
140         }
141         return "uid:" + uid;
142     }
143 
144     @Override
onCreate(Bundle savedInstanceState)145     public void onCreate(Bundle savedInstanceState) {
146         super.onCreate(savedInstanceState);
147 
148         mSipManager = SipManager.newInstance(this);
149         mSipSharedPreferences = new SipSharedPreferences(this);
150         mProfileDb = new SipProfileDb(this);
151 
152         mPackageManager = getPackageManager();
153         setContentView(R.layout.sip_settings_ui);
154         addPreferencesFromResource(R.xml.sip_setting);
155         mSipListContainer = (PreferenceCategory) findPreference(PREF_SIP_LIST);
156         registerForAddSipListener();
157         registerForReceiveCallsCheckBox();
158         mCallManager = CallManager.getInstance();
159 
160         updateProfilesStatus();
161     }
162 
163     @Override
onResume()164     public void onResume() {
165         super.onResume();
166 
167         if (mCallManager.getState() != Phone.State.IDLE) {
168             mButtonAddSipAccount.setEnabled(false);
169             mButtonSipReceiveCalls.setEnabled(false);
170         } else {
171             mButtonAddSipAccount.setEnabled(true);
172             mButtonSipReceiveCalls.setEnabled(true);
173         }
174     }
175 
176     @Override
onDestroy()177     protected void onDestroy() {
178         super.onDestroy();
179         unregisterForContextMenu(getListView());
180     }
181 
182     @Override
onActivityResult(final int requestCode, final int resultCode, final Intent intent)183     protected void onActivityResult(final int requestCode, final int resultCode,
184             final Intent intent) {
185         if (resultCode != RESULT_OK && resultCode != RESULT_FIRST_USER) return;
186         new Thread() {
187             public void run() {
188             try {
189                 if (mProfile != null) {
190                     Log.v(TAG, "Removed Profile:" + mProfile.getProfileName());
191                     deleteProfile(mProfile);
192                 }
193 
194                 SipProfile profile = intent.getParcelableExtra(KEY_SIP_PROFILE);
195                 if (resultCode == RESULT_OK) {
196                     Log.v(TAG, "New Profile Name:" + profile.getProfileName());
197                     addProfile(profile);
198                 }
199                 updateProfilesStatus();
200             } catch (IOException e) {
201                 Log.v(TAG, "Can not handle the profile : " + e.getMessage());
202             }
203         }}.start();
204     }
205 
registerForAddSipListener()206     private void registerForAddSipListener() {
207         mButtonAddSipAccount =
208                 (Button) findViewById(R.id.add_remove_account_button);
209         mButtonAddSipAccount.setOnClickListener(
210                 new android.view.View.OnClickListener() {
211                     public void onClick(View v) {
212                         startSipEditor(null);
213                     }
214                 });
215     }
216 
registerForReceiveCallsCheckBox()217     private void registerForReceiveCallsCheckBox() {
218         mButtonSipReceiveCalls = (CheckBoxPreference) findPreference
219                 (BUTTON_SIP_RECEIVE_CALLS);
220         mButtonSipReceiveCalls.setChecked(
221                 mSipSharedPreferences.isReceivingCallsEnabled());
222         mButtonSipReceiveCalls.setOnPreferenceClickListener(
223                 new OnPreferenceClickListener() {
224                     public boolean onPreferenceClick(Preference preference) {
225                         final boolean enabled =
226                                 ((CheckBoxPreference) preference).isChecked();
227                         new Thread(new Runnable() {
228                                 public void run() {
229                                     handleSipReceiveCallsOption(enabled);
230                                 }
231                         }).start();
232                         return true;
233                     }
234                 });
235     }
236 
handleSipReceiveCallsOption(boolean enabled)237     private synchronized void handleSipReceiveCallsOption(boolean enabled) {
238         mSipSharedPreferences.setReceivingCallsEnabled(enabled);
239         List<SipProfile> sipProfileList = mProfileDb.retrieveSipProfileList();
240         for (SipProfile p : sipProfileList) {
241             String sipUri = p.getUriString();
242             p = updateAutoRegistrationFlag(p, enabled);
243             try {
244                 if (enabled) {
245                     mSipManager.open(p,
246                             SipUtil.createIncomingCallPendingIntent(), null);
247                 } else {
248                     mSipManager.close(sipUri);
249                     if (mSipSharedPreferences.isPrimaryAccount(sipUri)) {
250                         // re-open in order to make calls
251                         mSipManager.open(p);
252                     }
253                 }
254             } catch (Exception e) {
255                 Log.e(TAG, "register failed", e);
256             }
257         }
258         updateProfilesStatus();
259     }
260 
updateAutoRegistrationFlag( SipProfile p, boolean enabled)261     private SipProfile updateAutoRegistrationFlag(
262             SipProfile p, boolean enabled) {
263         SipProfile newProfile = new SipProfile.Builder(p)
264                 .setAutoRegistration(enabled)
265                 .build();
266         try {
267             mProfileDb.deleteProfile(p);
268             mProfileDb.saveProfile(newProfile);
269         } catch (Exception e) {
270             Log.e(TAG, "updateAutoRegistrationFlag error", e);
271         }
272         return newProfile;
273     }
274 
updateProfilesStatus()275     private void updateProfilesStatus() {
276         new Thread(new Runnable() {
277             public void run() {
278                 try {
279                     retrieveSipLists();
280                 } catch (Exception e) {
281                     Log.e(TAG, "isRegistered", e);
282                 }
283             }
284         }).start();
285     }
286 
getProfileName(SipProfile profile)287     private String getProfileName(SipProfile profile) {
288         String profileName = profile.getProfileName();
289         if (TextUtils.isEmpty(profileName)) {
290             profileName = profile.getUserName() + "@" + profile.getSipDomain();
291         }
292         return profileName;
293     }
294 
retrieveSipLists()295     private void retrieveSipLists() {
296         mSipPreferenceMap = new LinkedHashMap<String, SipPreference>();
297         mSipProfileList = mProfileDb.retrieveSipProfileList();
298         processActiveProfilesFromSipService();
299         Collections.sort(mSipProfileList, new Comparator<SipProfile>() {
300             public int compare(SipProfile p1, SipProfile p2) {
301                 return getProfileName(p1).compareTo(getProfileName(p2));
302             }
303 
304             public boolean equals(SipProfile p) {
305                 // not used
306                 return false;
307             }
308         });
309         mSipListContainer.removeAll();
310         for (SipProfile p : mSipProfileList) {
311             addPreferenceFor(p);
312         }
313 
314         if (!mSipSharedPreferences.isReceivingCallsEnabled()) return;
315         for (SipProfile p : mSipProfileList) {
316             if (mUid == p.getCallingUid()) {
317                 try {
318                     mSipManager.setRegistrationListener(
319                             p.getUriString(), createRegistrationListener());
320                 } catch (SipException e) {
321                     Log.e(TAG, "cannot set registration listener", e);
322                 }
323             }
324         }
325     }
326 
processActiveProfilesFromSipService()327     private void processActiveProfilesFromSipService() {
328         SipProfile[] activeList = mSipManager.getListOfProfiles();
329         for (SipProfile activeProfile : activeList) {
330             SipProfile profile = getProfileFromList(activeProfile);
331             if (profile == null) {
332                 mSipProfileList.add(activeProfile);
333             } else {
334                 profile.setCallingUid(activeProfile.getCallingUid());
335             }
336         }
337     }
338 
getProfileFromList(SipProfile activeProfile)339     private SipProfile getProfileFromList(SipProfile activeProfile) {
340         for (SipProfile p : mSipProfileList) {
341             if (p.getUriString().equals(activeProfile.getUriString())) {
342                 return p;
343             }
344         }
345         return null;
346     }
347 
addPreferenceFor(SipProfile p)348     private void addPreferenceFor(SipProfile p) {
349         String status;
350         Log.v(TAG, "addPreferenceFor profile uri" + p.getUri());
351         SipPreference pref = new SipPreference(this, p);
352         mSipPreferenceMap.put(p.getUriString(), pref);
353         mSipListContainer.addPreference(pref);
354 
355         pref.setOnPreferenceClickListener(
356                 new Preference.OnPreferenceClickListener() {
357                     public boolean onPreferenceClick(Preference pref) {
358                         handleProfileClick(((SipPreference) pref).mProfile);
359                         return true;
360                     }
361                 });
362     }
363 
handleProfileClick(final SipProfile profile)364     private void handleProfileClick(final SipProfile profile) {
365         int uid = profile.getCallingUid();
366         if (uid == mUid || uid == 0) {
367             startSipEditor(profile);
368             return;
369         }
370         new AlertDialog.Builder(this)
371                 .setTitle(R.string.alert_dialog_close)
372                 .setIcon(android.R.drawable.ic_dialog_alert)
373                 .setPositiveButton(R.string.close_profile,
374                         new DialogInterface.OnClickListener() {
375                             public void onClick(DialogInterface dialog, int w) {
376                                 deleteProfile(profile);
377                                 unregisterProfile(profile);
378                             }
379                         })
380                 .setNegativeButton(android.R.string.cancel, null)
381                 .show();
382     }
383 
unregisterProfile(final SipProfile p)384     private void unregisterProfile(final SipProfile p) {
385         // run it on background thread for better UI response
386         new Thread(new Runnable() {
387             public void run() {
388                 try {
389                     mSipManager.close(p.getUriString());
390                 } catch (Exception e) {
391                     Log.e(TAG, "unregister failed, SipService died?", e);
392                 }
393             }
394         }, "unregisterProfile").start();
395     }
396 
deleteProfile(SipProfile p)397     void deleteProfile(SipProfile p) {
398         mSipProfileList.remove(p);
399         SipPreference pref = mSipPreferenceMap.remove(p.getUriString());
400         mSipListContainer.removePreference(pref);
401     }
402 
addProfile(SipProfile p)403     private void addProfile(SipProfile p) throws IOException {
404         try {
405             mSipManager.setRegistrationListener(p.getUriString(),
406                     createRegistrationListener());
407         } catch (Exception e) {
408             Log.e(TAG, "cannot set registration listener", e);
409         }
410         mSipProfileList.add(p);
411         addPreferenceFor(p);
412     }
413 
startSipEditor(final SipProfile profile)414     private void startSipEditor(final SipProfile profile) {
415         mProfile = profile;
416         Intent intent = new Intent(this, SipEditor.class);
417         intent.putExtra(KEY_SIP_PROFILE, (Parcelable) profile);
418         startActivityForResult(intent, REQUEST_ADD_OR_EDIT_SIP_PROFILE);
419     }
420 
showRegistrationMessage(final String profileUri, final String message)421     private void showRegistrationMessage(final String profileUri,
422             final String message) {
423         runOnUiThread(new Runnable() {
424             public void run() {
425                 SipPreference pref = mSipPreferenceMap.get(profileUri);
426                 if (pref != null) {
427                     pref.updateSummary(message);
428                 }
429             }
430         });
431     }
432 
createRegistrationListener()433     private SipRegistrationListener createRegistrationListener() {
434         return new SipRegistrationListener() {
435             public void onRegistrationDone(String profileUri, long expiryTime) {
436                 showRegistrationMessage(profileUri, getString(
437                         R.string.registration_status_done));
438             }
439 
440             public void onRegistering(String profileUri) {
441                 showRegistrationMessage(profileUri, getString(
442                         R.string.registration_status_registering));
443             }
444 
445             public void onRegistrationFailed(String profileUri, int errorCode,
446                     String message) {
447                 switch (errorCode) {
448                     case SipErrorCode.IN_PROGRESS:
449                         showRegistrationMessage(profileUri, getString(
450                                 R.string.registration_status_still_trying));
451                         break;
452                     case SipErrorCode.INVALID_CREDENTIALS:
453                         showRegistrationMessage(profileUri, getString(
454                                 R.string.registration_status_invalid_credentials));
455                         break;
456                     case SipErrorCode.SERVER_UNREACHABLE:
457                         showRegistrationMessage(profileUri, getString(
458                                 R.string.registration_status_server_unreachable));
459                         break;
460                     case SipErrorCode.DATA_CONNECTION_LOST:
461                         if (SipManager.isSipWifiOnly(getApplicationContext())){
462                             showRegistrationMessage(profileUri, getString(
463                                     R.string.registration_status_no_wifi_data));
464                         } else {
465                             showRegistrationMessage(profileUri, getString(
466                                     R.string.registration_status_no_data));
467                         }
468                         break;
469                     case SipErrorCode.CLIENT_ERROR:
470                         showRegistrationMessage(profileUri, getString(
471                                 R.string.registration_status_not_running));
472                         break;
473                     default:
474                         showRegistrationMessage(profileUri, getString(
475                                 R.string.registration_status_failed_try_later,
476                                 message));
477                 }
478             }
479         };
480     }
481 }
482