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