diff options
author | Hung-ying Tyan <tyanh@google.com> | 2010-06-28 23:00:45 -0700 |
---|---|---|
committer | Hung-ying Tyan <tyanh@google.com> | 2010-06-28 23:05:02 -0700 |
commit | fe68ef2763389d617be2a93d640090dff4e46581 (patch) | |
tree | f6301e27111326dcade498259ca53d85e7090dbb | |
parent | fcece04be25d6827c2fd279d0c4aa43820fd3622 (diff) | |
download | android_external_nist-sip-fe68ef2763389d617be2a93d640090dff4e46581.tar.gz android_external_nist-sip-fe68ef2763389d617be2a93d640090dff4e46581.tar.bz2 android_external_nist-sip-fe68ef2763389d617be2a93d640090dff4e46581.zip |
SIP: work-in-progress for telephony integration.
Outgoing call partially work.
Should be built in froyo as the PhoneApp is from froyo.
Change-Id: I5d934025f5786c96ee345ae428f1aa689a570bb4
94 files changed, 4207 insertions, 2759 deletions
diff --git a/demo/com/android/sip/demo/SipCallUi.java b/demo/com/android/sip/demo/SipCallUi.java index 0604e54..fe58773 100644 --- a/demo/com/android/sip/demo/SipCallUi.java +++ b/demo/com/android/sip/demo/SipCallUi.java @@ -307,7 +307,8 @@ public class SipCallUi extends Activity implements OnClickListener, private void addCallRecord(int callType, String address) { long insertDate = new Date().getTime(); ContentValues value = new ContentValues(); - value.put(Calls.NUMBER, address.substring(0, address.indexOf('@'))); + //value.put(Calls.NUMBER, address.substring(0, address.indexOf('@'))); + value.put(Calls.NUMBER, address); value.put(Calls.DATE, insertDate); value.put(Calls.DURATION, (mCallTime != 0) ? (insertDate - mCallTime)/1000 : 0); diff --git a/phone/.Android.mk.swp b/phone/.Android.mk.swp Binary files differdeleted file mode 100644 index 473935c..0000000 --- a/phone/.Android.mk.swp +++ /dev/null diff --git a/phone/Android.mk.sample b/phone/Android.mk.sample index 9b856ea..bb1a824 100644 --- a/phone/Android.mk.sample +++ b/phone/Android.mk.sample @@ -27,11 +27,15 @@ LOCAL_SRC_FILES += \ src/com/android/phone2/INetworkQueryService.aidl \ src/com/android/phone2/INetworkQueryServiceCallback.aidl +LOCAL_SRC_FILES += $(call all-java-files-under, src2) + LOCAL_PACKAGE_NAME := Phone2 -#LOCAL_CERTIFICATE := platform +LOCAL_CERTIFICATE := platform LOCAL_STATIC_JAVA_LIBRARIES := android.sip +LOCAL_PROGUARD_ENABLED := disabled + include $(BUILD_PACKAGE) -# Build the test package -include $(call all-makefiles-under,$(LOCAL_PATH)) +## Build the test package +#include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/phone/AndroidManifest.xml b/phone/AndroidManifest.xml index 0299d29..035edca 100644 --- a/phone/AndroidManifest.xml +++ b/phone/AndroidManifest.xml @@ -20,7 +20,6 @@ android:sharedUserLabel="@string/dialerIconLabel" > - <original-package android:name="com.android.phone" /> <protected-broadcast android:name="android.intent.action.SERVICE_STATE" /> <protected-broadcast android:name="android.intent.action.RADIO_TECHNOLOGY" /> @@ -72,6 +71,7 @@ <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> <uses-permission android:name="android.permission.SHUTDOWN" /> + <uses-permission android:name="android.permission.RECORD_AUDIO" /> <!-- This tells the activity manager to not delay any of our activity start requests, even if they happen immediately after the user @@ -83,7 +83,7 @@ android:label="@string/dialerIconLabel" android:icon="@drawable/ic_launcher_phone"> <provider android:name="IccProvider" - android:authorities="icc" + android:authorities="icc2" android:multiprocess="true" android:readPermission="android.permission.READ_CONTACTS" android:writePermission="android.permission.WRITE_CONTACTS" /> @@ -96,11 +96,6 @@ <action android:name="com.android.phone2.EmergencyDialer.DIAL" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> - <intent-filter> - <action android:name="com.android.phone2.EmergencyDialer.DIAL" /> - <category android:name="android.intent.category.DEFAULT" /> - <data android:scheme="tel" /> - </intent-filter> </activity> <activity android:name="ADNList" /> @@ -400,6 +395,14 @@ </intent-filter> </activity> + <receiver + android:name="SipBroadcastReceiver"> + <intent-filter> + <action android:name="com.android.phone.SIP_INCOMING_CALL" /> + <action android:name="com.android.phone.SIP_ADD_PHONE" /> + </intent-filter> + </receiver> + </application> </manifest> diff --git a/phone/res/color-finger/end_call_button_text.xml b/phone/res/color-finger/end_call_button_text.xml deleted file mode 100644 index a570c2b..0000000 --- a/phone/res/color-finger/end_call_button_text.xml +++ /dev/null @@ -1,24 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2010 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<selector xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:state_enabled="false" android:color="#80000000"/> - <item android:state_focused="true" android:color="#FF000000"/> - <item android:state_pressed="true" android:color="#FF000000"/> - <item android:state_selected="true" android:color="#FF000000"/> - <item android:color="@color/incall_endButtonLabel"/> <!-- not selected --> -</selector> - diff --git a/phone/res/color-finger/in_call_button_text.xml b/phone/res/color-finger/in_call_button_text.xml deleted file mode 100644 index 4a5a4a4..0000000 --- a/phone/res/color-finger/in_call_button_text.xml +++ /dev/null @@ -1,24 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2010 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<selector xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:state_enabled="false" android:color="#ff808080"/> - <item android:state_focused="true" android:color="#FF000000"/> - <item android:state_pressed="true" android:color="#FF000000"/> - <item android:state_selected="true" android:color="#FF000000"/> - <item android:color="#FFFFFFFF"/> <!-- not selected --> -</selector> - diff --git a/phone/res/drawable-hdpi/ic_btn_back.png b/phone/res/drawable-hdpi/ic_btn_back.png Binary files differdeleted file mode 100755 index 9051cb1..0000000 --- a/phone/res/drawable-hdpi/ic_btn_back.png +++ /dev/null diff --git a/phone/res/drawable-hdpi/ic_btn_next.png b/phone/res/drawable-hdpi/ic_btn_next.png Binary files differdeleted file mode 100755 index ad00a95..0000000 --- a/phone/res/drawable-hdpi/ic_btn_next.png +++ /dev/null diff --git a/phone/res/drawable-mdpi/ic_btn_back.png b/phone/res/drawable-mdpi/ic_btn_back.png Binary files differdeleted file mode 100644 index c9bff4c..0000000 --- a/phone/res/drawable-mdpi/ic_btn_back.png +++ /dev/null diff --git a/phone/res/layout/call_card.xml b/phone/res/layout/call_card.xml index 663f114..f32edb5 100644 --- a/phone/res/layout/call_card.xml +++ b/phone/res/layout/call_card.xml @@ -63,7 +63,6 @@ android:layout_height="101dp" android:layout_marginTop="-6dip" android:background="@drawable/incall_photo_border_med" - android:contentDescription="@string/onHold" /> </LinearLayout> diff --git a/phone/res/layout/call_card_person_info.xml b/phone/res/layout/call_card_person_info.xml index b5a6901..e2c9489 100644 --- a/phone/res/layout/call_card_person_info.xml +++ b/phone/res/layout/call_card_person_info.xml @@ -41,7 +41,6 @@ android:layout_height="166dp" android:layout_centerHorizontal="true" android:background="@drawable/incall_photo_border_lg" - android:contentDescription="@string/contactPhoto" /> <!-- The big "Manage conference" button that we show in place of diff --git a/phone/res/layout/caller_in_conference.xml b/phone/res/layout/caller_in_conference.xml index 93406ec..630b44b 100644 --- a/phone/res/layout/caller_in_conference.xml +++ b/phone/res/layout/caller_in_conference.xml @@ -36,8 +36,7 @@ android:layout_height="46dp" android:layout_marginTop="2dp" android:layout_marginLeft="6dp" - android:scaleType="center" - android:contentDescription="@string/onscreenEndCallText" /> + android:scaleType="center"/> <!-- Caller information --> <LinearLayout @@ -98,8 +97,7 @@ android:layout_height="46dp" android:layout_marginTop="2dp" android:layout_marginRight="6dp" - android:scaleType="center" - android:contentDescription="@string/goPrivate"/> + android:scaleType="center"/> </LinearLayout> <!-- End of single list element --> diff --git a/phone/res/layout/incall_screen.xml b/phone/res/layout/incall_screen.xml index 9a8a771..e291ac1 100644 --- a/phone/res/layout/incall_screen.xml +++ b/phone/res/layout/incall_screen.xml @@ -68,11 +68,9 @@ widget needs to be be a direct child of a FrameLayout anyway.) This is used only on devices that do *not* have an onscreen InCallTouchUi widget.--> - <ViewStub android:id="@+id/dtmf_dialer_stub" - android:layout="@layout/dtmf_twelve_key_dialer" - android:layout_width="match_parent" - android:layout_height="match_parent" - /> + <!-- TODO: this should be a ViewStub, and should only get inflated + on platforms that need it. --> + <include layout="@layout/dtmf_twelve_key_dialer"/> <!-- Finally, the "touch lock" overlay, drawn on top of the DTMF dialpad (after some delay) to prevent false touches from @@ -111,37 +109,28 @@ android:layout_height="match_parent" /> - <!-- Layout where the provider's badge will be + <!-- Frame where the provider's badge will be inflated. The badge must fit in the available height. The badge is displayed for 5s on top of the contact's picture. --> - <LinearLayout android:id="@+id/inCallProviderOverlay" + <FrameLayout android:id="@+id/inCallProviderOverlay" android:background="@drawable/dialog_bg_calling_via" android:layout_width="match_parent" - android:layout_height="88dip" + android:layout_height="wrap_content" + android:minHeight="88dip" android:layout_marginTop="8dip" android:layout_gravity="top" - android:gravity="center" - android:visibility="gone" - android:orientation="horizontal"> - - <ImageView android:id="@+id/callingViaIcon" - android:layout_width="40dip" - android:layout_height="40dip" - /> + android:visibility="gone"> <TextView android:id="@+id/callingVia" android:text="@string/calling_via_template" - android:layout_weight="1" - android:layout_width="0dip" - android:layout_height="match_parent" - android:textAppearance="?android:attr/textAppearanceSmallInverse" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center" android:gravity="center" + android:textAppearance="?android:attr/textAppearanceMediumInverse" + android:textSize="16sp" /> - <View - android:layout_width="40dip" - android:layout_height="40dip" - /> - </LinearLayout> + </FrameLayout> </FrameLayout> diff --git a/phone/res/layout/incall_touch_ui.xml b/phone/res/layout/incall_touch_ui.xml index 0217d02..a85f8cc 100644 --- a/phone/res/layout/incall_touch_ui.xml +++ b/phone/res/layout/incall_touch_ui.xml @@ -64,8 +64,7 @@ android:visibility="gone"> <ImageButton android:id="@+id/holdButton" style="@style/InCallRoundTouchButton" - android:src="@drawable/ic_in_call_touch_round_hold" - android:contentDescription="@string/onscreenHoldText" /> + android:src="@drawable/ic_in_call_touch_round_hold" /> <TextView android:id="@+id/holdButtonLabel" style="@style/InCallRoundButtonLabel" /> </LinearLayout> @@ -79,8 +78,7 @@ android:visibility="gone"> <ImageButton android:id="@+id/swapButton" style="@style/InCallRoundTouchButton" - android:src="@drawable/ic_in_call_touch_round_swap" - android:contentDescription="@string/onscreenSwapCallsText"/> + android:src="@drawable/ic_in_call_touch_round_swap" /> <TextView android:id="@+id/swapButtonLabel" style="@style/InCallRoundButtonLabel" /> </LinearLayout> @@ -96,8 +94,7 @@ android:visibility="gone"> <ImageButton android:id="@+id/cdmaMergeButton" style="@style/InCallRoundTouchButton" - android:src="@drawable/ic_in_call_touch_round_merge_call" - android:contentDescription="@string/onscreenMergeCallsText" /> + android:src="@drawable/ic_in_call_touch_round_merge_call" /> <TextView style="@style/InCallRoundButtonLabel" android:text="@string/onscreenMergeCallsText" /> @@ -105,11 +102,9 @@ <!-- DTMF dialpad shown in the upper part of the screen (above the main cluster of buttons.) --> - <ViewStub android:id="@+id/non_drawer_dialpad_stub" - android:layout="@layout/non_drawer_dialpad" - android:layout_width="match_parent" - android:layout_height="match_parent" - /> + <!-- TODO: this should be a ViewStub, and should only get inflated + when first needed. --> + <include layout="@layout/non_drawer_dialpad"/> <!-- Main cluster of onscreen buttons on the lower part of the screen. --> <LinearLayout android:id="@+id/bottomButtons" @@ -182,7 +177,7 @@ android:layout_height="wrap_content" android:text="@string/onscreenEndCallText" android:drawableTop="@drawable/ic_in_call_touch_end" - android:textColor="@color/end_call_button_text" + android:textColor="@color/incall_endButtonLabel" /> <!-- "Dialpad" --> diff --git a/phone/res/layout/ongoing_call_notification.xml b/phone/res/layout/ongoing_call_notification.xml index e08d1cb..a7302d3 100644 --- a/phone/res/layout/ongoing_call_notification.xml +++ b/phone/res/layout/ongoing_call_notification.xml @@ -15,53 +15,45 @@ --> <!-- Layout file for the custom "expanded view" used by the ongoing call - Notification; see NotificationMgr.updateInCallNotification(). - This is largely copied from status_bar_latest_event_content, - but with some customizations --> - + Notification; see NotificationMgr.updateInCallNotification(). --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:orientation="vertical" - android:paddingTop="7dp" - android:paddingLeft="5dp" - > + android:orientation="horizontal" + android:baselineAligned="false" + android:gravity="center_vertical" + android:layout_width="match_parent" + android:layout_height="65sp" + android:background="@android:drawable/status_bar_item_background" + > - <LinearLayout - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:orientation="horizontal" - android:paddingTop="3dp" - > - <ImageView android:id="@+id/icon" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:paddingLeft="4dip" - android:layout_marginRight="6dip" /> - <Chronometer android:id="@+id/text1" - android:textStyle="bold" - android:textSize="18sp" - android:textColor="#ff000000" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:singleLine="true" - /> - </LinearLayout> - <LinearLayout - android:layout_width="match_parent" + <ImageView android:id="@+id/icon" + android:layout_width="wrap_content" android:layout_height="wrap_content" - android:orientation="horizontal" - > - <TextView android:id="@+id/text2" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_weight="1" - android:textColor="#ff000000" - android:singleLine="true" - android:ellipsize="marquee" - android:fadingEdge="horizontal" - android:textSize="14sp" - android:paddingLeft="4dp" - /> - </LinearLayout> + android:paddingLeft="4dip" + android:layout_marginRight="6dip" /> + + <LinearLayout + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:orientation="vertical" + > + <!-- The appearance of these 2 lines of text matches the other + kinds of notifications (see status_bar_latest_event.xml). + TODO: There should probably be common styles for these, though. --> + <Chronometer android:id="@+id/text1" + android:textStyle="bold" + android:textSize="18sp" + android:textColor="#ff000000" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:singleLine="true" + /> + <TextView android:id="@+id/text2" + android:textSize="14sp" + android:textColor="#ff000000" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:singleLine="true" + /> + </LinearLayout> + </LinearLayout> diff --git a/phone/res/layout/otacall_card.xml b/phone/res/layout/otacall_card.xml index 3125892..246c042 100644 --- a/phone/res/layout/otacall_card.xml +++ b/phone/res/layout/otacall_card.xml @@ -136,8 +136,6 @@ <!-- "End" button --> <Button android:id="@+id/otaEndButton" android:text="@string/ota_call_end" - android:drawableLeft="@drawable/ic_btn_back" - android:drawablePadding="3dip" style="@style/ccOtaSkipButton" /> </RelativeLayout> @@ -149,8 +147,6 @@ <!-- "Next" button --> <Button android:id="@+id/otaNextButton" android:text="@string/ota_next" - android:drawableRight="@drawable/ic_btn_next" - android:drawablePadding="10dip" style="@style/ccOtaNextButton" /> <!-- "Try Again" button --> diff --git a/phone/res/layout/pref_dialog_editphonenumber.xml b/phone/res/layout/pref_dialog_editphonenumber.xml index 8031c70..fc25d8c 100644 --- a/phone/res/layout/pref_dialog_editphonenumber.xml +++ b/phone/res/layout/pref_dialog_editphonenumber.xml @@ -52,8 +52,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="10dip" - android:src="@drawable/ic_button_contacts" - android:contentDescription="@string/selectContact" /> + android:src="@drawable/ic_button_contacts" /> </LinearLayout> </LinearLayout> diff --git a/phone/res/values-da/strings.xml b/phone/res/values-da/strings.xml index dcd42ba..f303b93 100644 --- a/phone/res/values-da/strings.xml +++ b/phone/res/values-da/strings.xml @@ -127,22 +127,22 @@ <string name="labelCFU" msgid="8147177368148660600">"Viderestil altid"</string> <string name="messageCFU" msgid="3560082430662923687">"Brug altid dette nummer"</string> <string name="sum_cfu_enabled_indicator" msgid="4014187342724130197">"Viderestiller alle opkald"</string> - <string name="sum_cfu_enabled" msgid="956178654350554451">"Viderestiller alle opkald til {0}"</string> + <string name="sum_cfu_enabled" msgid="956178654350554451">"Viderestiller alle opkald til \\\\{0\\\\}"</string> <string name="sum_cfu_enabled_no_number" msgid="6591985777096823616">"Nummeret er ikke tilgængeligt"</string> <string name="sum_cfu_disabled" msgid="3698472522160364904">"Deaktiveret"</string> <string name="labelCFB" msgid="218938523102207587">"Viderestil ved optaget"</string> <string name="messageCFB" msgid="3711089705936187129">"Nummer ved optaget"</string> - <string name="sum_cfb_enabled" msgid="2501948432392255856">"Viderestiller til {0}"</string> + <string name="sum_cfb_enabled" msgid="2501948432392255856">"Viderestiller til \\\\{0\\\\}"</string> <string name="sum_cfb_disabled" msgid="227440009979537651">"Deaktiveret"</string> <string name="disable_cfb_forbidden" msgid="4524424437001441832">"Din udbyder understøtter ikke, deaktivering af viderestilling af opkald, når telefonen er optaget."</string> <string name="labelCFNRy" msgid="3646316323834351390">"Viderestil ved ubesvaret"</string> <string name="messageCFNRy" msgid="672317899884380374">"Nummer ved ubesvaret"</string> - <string name="sum_cfnry_enabled" msgid="3473526018876802076">"Viderestiller til {0}"</string> + <string name="sum_cfnry_enabled" msgid="3473526018876802076">"Viderestiller til \\\\{0\\\\}"</string> <string name="sum_cfnry_disabled" msgid="8422350929957344729">"Deaktiveret"</string> <string name="disable_cfnry_forbidden" msgid="7041605706777677935">"Din udbyder understøtter ikke, deaktivering af viderestilling af opkald, når telefonen ikke bliver taget."</string> <string name="labelCFNRc" msgid="47183615370850000">"Viderestil ved utilgængelig"</string> <string name="messageCFNRc" msgid="6380695421020295119">"Nummer ved utilgængelig"</string> - <string name="sum_cfnrc_enabled" msgid="3528648673654636587">"Viderestiller til {0}"</string> + <string name="sum_cfnrc_enabled" msgid="3528648673654636587">"Viderestiller til \\\\{0\\\\}"</string> <string name="sum_cfnrc_disabled" msgid="7222141261321276464">"Deaktiveret"</string> <string name="disable_cfnrc_forbidden" msgid="1093527570652781997">"Din udbyder understøtter ikke, deaktivering af viderestilling af opkald, når telefonen er utilgængelig."</string> <string name="updating_title" msgid="6146755386174019046">"Indstillinger for opkald"</string> diff --git a/phone/res/values-el/strings.xml b/phone/res/values-el/strings.xml index 982a24b..d79922f 100644 --- a/phone/res/values-el/strings.xml +++ b/phone/res/values-el/strings.xml @@ -127,22 +127,22 @@ <string name="labelCFU" msgid="8147177368148660600">"Προώθηση πάντα"</string> <string name="messageCFU" msgid="3560082430662923687">"Να γίνεται πάντα χρήση αυτού του αριθμού"</string> <string name="sum_cfu_enabled_indicator" msgid="4014187342724130197">"Προώθηση όλων των κλήσεων"</string> - <string name="sum_cfu_enabled" msgid="956178654350554451">"Προώθηση όλων των κλήσεων προς {0}"</string> + <string name="sum_cfu_enabled" msgid="956178654350554451">"Προώθηση όλων των κλήσεων προς \\\\{0\\\\}"</string> <string name="sum_cfu_enabled_no_number" msgid="6591985777096823616">"Ο αριθμός δεν είναι διαθέσιμος"</string> <string name="sum_cfu_disabled" msgid="3698472522160364904">"Απενεργοποιημένη"</string> <string name="labelCFB" msgid="218938523102207587">"Προώθηση όταν είμαι απασχολημένος/η"</string> <string name="messageCFB" msgid="3711089705936187129">"Αριθμός όταν είμαι απασχολημένος/ή"</string> - <string name="sum_cfb_enabled" msgid="2501948432392255856">"Προώθηση προς {0}"</string> + <string name="sum_cfb_enabled" msgid="2501948432392255856">"Προώθηση προς \\\\{0\\\\}"</string> <string name="sum_cfb_disabled" msgid="227440009979537651">"Απενεργοποιημένη"</string> <string name="disable_cfb_forbidden" msgid="4524424437001441832">"Ο φορέας σας δεν υποστηρίζει την απενεργοποίηση της προώθησης κλήσεων όταν το τηλέφωνό σας είναι απασχολημένο."</string> <string name="labelCFNRy" msgid="3646316323834351390">"Προώθηση όταν δεν απαντάω"</string> <string name="messageCFNRy" msgid="672317899884380374">"Αριθμός όταν δεν απαντάω"</string> - <string name="sum_cfnry_enabled" msgid="3473526018876802076">"Προώθηση προς {0}"</string> + <string name="sum_cfnry_enabled" msgid="3473526018876802076">"Προώθηση προς \\\\{0\\\\}"</string> <string name="sum_cfnry_disabled" msgid="8422350929957344729">"Απενεργοποιημένη"</string> <string name="disable_cfnry_forbidden" msgid="7041605706777677935">"Ο φορέας σας δεν υποστηρίζει την απενεργοποίηση της προώθησης κλήσεων όταν το τηλέφωνό σας δεν απαντάει."</string> <string name="labelCFNRc" msgid="47183615370850000">"Προώθηση όταν δεν είμαι διαθέσιμος/η"</string> <string name="messageCFNRc" msgid="6380695421020295119">"Αριθμός όταν δεν είμαι διαθέσιμος/η"</string> - <string name="sum_cfnrc_enabled" msgid="3528648673654636587">"Προώθηση προς {0}"</string> + <string name="sum_cfnrc_enabled" msgid="3528648673654636587">"Προώθηση προς \\\\{0\\\\}"</string> <string name="sum_cfnrc_disabled" msgid="7222141261321276464">"Απενεργοποιημένη"</string> <string name="disable_cfnrc_forbidden" msgid="1093527570652781997">"Ο φορέας σας δεν υποστηρίζει την απενεργοποίηση της προώθησης κλήσεων όταν το τηλέφωνό σας δεν έχει σήμα."</string> <string name="updating_title" msgid="6146755386174019046">"Ρυθμίσεις κλήσης"</string> diff --git a/phone/res/values-es-rUS/strings.xml b/phone/res/values-es-rUS/strings.xml index 26abd8f..11358b1 100644 --- a/phone/res/values-es-rUS/strings.xml +++ b/phone/res/values-es-rUS/strings.xml @@ -127,22 +127,22 @@ <string name="labelCFU" msgid="8147177368148660600">"Reenviar siempre"</string> <string name="messageCFU" msgid="3560082430662923687">"Usar este teléfono siempre"</string> <string name="sum_cfu_enabled_indicator" msgid="4014187342724130197">"Reenviar todas las llamadas"</string> - <string name="sum_cfu_enabled" msgid="956178654350554451">"Reenviar todas las llamadas a {0}"</string> + <string name="sum_cfu_enabled" msgid="956178654350554451">"Reenviar todas las llamadas a \\\\{0\\\\}"</string> <string name="sum_cfu_enabled_no_number" msgid="6591985777096823616">"El número no está disponible"</string> <string name="sum_cfu_disabled" msgid="3698472522160364904">"Desactivado"</string> <string name="labelCFB" msgid="218938523102207587">"Reenviar si está ocup."</string> <string name="messageCFB" msgid="3711089705936187129">"Número cuando está ocupado"</string> - <string name="sum_cfb_enabled" msgid="2501948432392255856">"Reenviar a {0}"</string> + <string name="sum_cfb_enabled" msgid="2501948432392255856">"Reenviar a \\\\{0\\\\}"</string> <string name="sum_cfb_disabled" msgid="227440009979537651">"Desactivado"</string> <string name="disable_cfb_forbidden" msgid="4524424437001441832">"Tu proveedor no es compatible con la desactivación del reenvío de llamadas cuando tu teléfono esté ocupado."</string> <string name="labelCFNRy" msgid="3646316323834351390">"Reenviar si no contesta"</string> <string name="messageCFNRy" msgid="672317899884380374">"Número cuando no contesta"</string> - <string name="sum_cfnry_enabled" msgid="3473526018876802076">"Reenviar a {0}"</string> + <string name="sum_cfnry_enabled" msgid="3473526018876802076">"Reenviar a \\\\{0\\\\}"</string> <string name="sum_cfnry_disabled" msgid="8422350929957344729">"Deshabilitado"</string> <string name="disable_cfnry_forbidden" msgid="7041605706777677935">"Tu proveedor no es compatible con la desactivación del reenvío de llamadas cuando tu teléfono no conteste."</string> <string name="labelCFNRc" msgid="47183615370850000">"Reenv. si no se alcanza"</string> <string name="messageCFNRc" msgid="6380695421020295119">"Número cuando no se puede alcanzar"</string> - <string name="sum_cfnrc_enabled" msgid="3528648673654636587">"Reenviar a {0}"</string> + <string name="sum_cfnrc_enabled" msgid="3528648673654636587">"Reenviar a \\\\{0\\\\}"</string> <string name="sum_cfnrc_disabled" msgid="7222141261321276464">"Desactivado"</string> <string name="disable_cfnrc_forbidden" msgid="1093527570652781997">"Tu proveedor no es compatible con la desactivación del reenvío de llamadas cuando tu teléfono se encuentre inaccesible."</string> <string name="updating_title" msgid="6146755386174019046">"Config. de llamada"</string> diff --git a/phone/res/values-it/strings.xml b/phone/res/values-it/strings.xml index 9a5fca0..cd53e62 100644 --- a/phone/res/values-it/strings.xml +++ b/phone/res/values-it/strings.xml @@ -57,7 +57,7 @@ <string name="ussdRunning" msgid="485588686340541690">"Esecuzione codice USSD..."</string> <string name="mmiCancelled" msgid="2771923949751842276">"Codice MMI annullato"</string> <string name="cancel" msgid="5044513931633602634">"Annulla"</string> - <string name="menu_speaker" msgid="6069700688651964705">"Vivavoce"</string> + <string name="menu_speaker" msgid="6069700688651964705">"Altoparlante"</string> <string name="menu_bluetooth" msgid="8842523654717305695">"Bluetooth"</string> <string name="menu_mute" msgid="4399723633363773145">"No audio"</string> <string name="menu_hold" msgid="6970441130344786273">"In attesa"</string> @@ -511,7 +511,7 @@ <string name="onscreenEndCallText" msgid="4403855834875398585">"Chiudi"</string> <string name="onscreenShowDialpadText" msgid="8561805492659639893">"Tastierino"</string> <string name="onscreenHideDialpadText" msgid="2572388822571686252">"Nascondi"</string> - <string name="onscreenSpeakerText" msgid="9013795366801657948">"Vivavoce"</string> + <string name="onscreenSpeakerText" msgid="9013795366801657948">"Altoparlante"</string> <string name="onscreenMuteText" msgid="5011369181754261374">"No audio"</string> <string name="onscreenBluetoothText" msgid="2479639597725504499">"Bluetooth"</string> <string name="onscreenAddCallText" msgid="5140385634712287403">"Aggiungi"</string> @@ -551,7 +551,7 @@ <string name="ota_title_problem_with_activation" msgid="7095824491970084367">"Problema con l\'attivazione"</string> <string name="ota_listen" msgid="162923839877584937">"Segui le istruzioni vocali fino al segnale di attivazione completata."</string> <string name="ota_dialpad" msgid="3530900997110658409">"Tastierino"</string> - <string name="ota_speaker" msgid="6904589278542719647">"Vivavoce"</string> + <string name="ota_speaker" msgid="6904589278542719647">"Altoparlante"</string> <string name="ota_progress" msgid="4644512049143969504">"Attendi la programmazione del telefono."</string> <string name="ota_failure" msgid="8600027551822478181">"Programmazione non riuscita"</string> <string name="ota_successful" msgid="1880780692887077407">"Il telefono è attivo. L\'avvio del servizio potrebbe richiedere fino a 15 minuti."</string> diff --git a/phone/res/values-ja/strings.xml b/phone/res/values-ja/strings.xml index b35fbd2..97f0952 100644 --- a/phone/res/values-ja/strings.xml +++ b/phone/res/values-ja/strings.xml @@ -132,17 +132,17 @@ <string name="sum_cfu_disabled" msgid="3698472522160364904">"無効"</string> <string name="labelCFB" msgid="218938523102207587">"通話中の着信時に転送"</string> <string name="messageCFB" msgid="3711089705936187129">"通話中着信の転送番号"</string> - <string name="sum_cfb_enabled" msgid="2501948432392255856">"{0}に転送する"</string> + <string name="sum_cfb_enabled" msgid="2501948432392255856">"\\\\{0\\\\}に転送する"</string> <string name="sum_cfb_disabled" msgid="227440009979537651">"無効"</string> <string name="disable_cfb_forbidden" msgid="4524424437001441832">"ご利用の携帯通信会社では通話中の着信時の転送を無効にすることができません。"</string> <string name="labelCFNRy" msgid="3646316323834351390">"不在着信時に転送"</string> <string name="messageCFNRy" msgid="672317899884380374">"不在着信時の転送番号"</string> - <string name="sum_cfnry_enabled" msgid="3473526018876802076">"{0}に転送する"</string> + <string name="sum_cfnry_enabled" msgid="3473526018876802076">"\\\\{0\\\\}に転送する"</string> <string name="sum_cfnry_disabled" msgid="8422350929957344729">"無効"</string> <string name="disable_cfnry_forbidden" msgid="7041605706777677935">"ご利用の携帯通信会社では不在着信時の転送を無効にすることができません。"</string> <string name="labelCFNRc" msgid="47183615370850000">"着信不能時に転送"</string> <string name="messageCFNRc" msgid="6380695421020295119">"着信不能時の転送番号"</string> - <string name="sum_cfnrc_enabled" msgid="3528648673654636587">"{0}に転送する"</string> + <string name="sum_cfnrc_enabled" msgid="3528648673654636587">"\\\\{0\\\\}に転送する"</string> <string name="sum_cfnrc_disabled" msgid="7222141261321276464">"無効"</string> <string name="disable_cfnrc_forbidden" msgid="1093527570652781997">"ご利用の携帯通信会社では着信不能時の転送を無効にすることができません。"</string> <string name="updating_title" msgid="6146755386174019046">"通話設定"</string> diff --git a/phone/res/values-ko/strings.xml b/phone/res/values-ko/strings.xml index 5b45539..578aec7 100644 --- a/phone/res/values-ko/strings.xml +++ b/phone/res/values-ko/strings.xml @@ -570,8 +570,8 @@ <item quantity="other" msgid="3122217344579273583">"<xliff:g id="COUNT">%s</xliff:g>분 동안 데이터 연결 없음"</item> </plurals> <plurals name="alert_dialog_exit_ecm"> - <item quantity="one" msgid="2181569650640386253">"전화의 긴급 콜백 모드가 <xliff:g id="COUNT">%s</xliff:g>분 동안 지속됩니다. 이 모드에서는 데이터 연결을 사용하는 애플리케이션을 사용할 수 없습니다. 지금 종료하시겠습니까?"</item> - <item quantity="other" msgid="3231879566243957821">"전화의 긴급 콜백 모드가 <xliff:g id="COUNT">%s</xliff:g>분 동안 지속됩니다. 이 모드에서는 데이터 연결을 사용하는 애플리케이션을 사용할 수 없습니다. 지금 종료하시겠습니까?"</item> + <item quantity="one" msgid="2181569650640386253">"전화의 긴급 콜백 모드가 <xliff:g id="COUNT">%s</xliff:g>분 동안 지속됩니다. 이 모드에서는 데이터 연결을 사용하는 응용프로그램을 사용할 수 없습니다. 지금 종료하시겠습니까?"</item> + <item quantity="other" msgid="3231879566243957821">"전화의 긴급 콜백 모드가 <xliff:g id="COUNT">%s</xliff:g>분 동안 지속됩니다. 이 모드에서는 데이터 연결을 사용하는 응용프로그램을 사용할 수 없습니다. 지금 종료하시겠습니까?"</item> </plurals> <plurals name="alert_dialog_not_avaialble_in_ecm"> <item quantity="one" msgid="8939225905428421722">"긴급 콜백 모드에서는 선택한 동작을 사용할 수 없습니다. 휴대전화의 긴급 콜백 모드 상태가 <xliff:g id="COUNT">%s</xliff:g>분 동안 지속됩니다. 지금 종료하시겠습니까?"</item> diff --git a/phone/res/values-pt-rPT/strings.xml b/phone/res/values-pt-rPT/strings.xml index c2b6489..b872d48 100644 --- a/phone/res/values-pt-rPT/strings.xml +++ b/phone/res/values-pt-rPT/strings.xml @@ -127,22 +127,22 @@ <string name="labelCFU" msgid="8147177368148660600">"Reencaminhar sempre"</string> <string name="messageCFU" msgid="3560082430662923687">"Utilizar sempre este número"</string> <string name="sum_cfu_enabled_indicator" msgid="4014187342724130197">"A reencaminhar todas as chamadas"</string> - <string name="sum_cfu_enabled" msgid="956178654350554451">"A reencaminhar todas as chamadas para {0}"</string> + <string name="sum_cfu_enabled" msgid="956178654350554451">"A reencaminhar todas as chamadas para \\\\{0\\\\}"</string> <string name="sum_cfu_enabled_no_number" msgid="6591985777096823616">"O número está indisponível"</string> <string name="sum_cfu_disabled" msgid="3698472522160364904">"Desactivado"</string> <string name="labelCFB" msgid="218938523102207587">"Reencaminhar quando ocupado"</string> <string name="messageCFB" msgid="3711089705936187129">"Número no caso de estar ocupado"</string> - <string name="sum_cfb_enabled" msgid="2501948432392255856">"A reencaminhar para {0}"</string> + <string name="sum_cfb_enabled" msgid="2501948432392255856">"A redireccionar para \\\\{0\\\\}"</string> <string name="sum_cfb_disabled" msgid="227440009979537651">"Desactivado"</string> <string name="disable_cfb_forbidden" msgid="4524424437001441832">"O seu operador não suporta a desactivação do reencaminhamento de chamadas quando o telefone está ocupado."</string> <string name="labelCFNRy" msgid="3646316323834351390">"Reencaminhar quando não atende"</string> <string name="messageCFNRy" msgid="672317899884380374">"Número no caso de não atender"</string> - <string name="sum_cfnry_enabled" msgid="3473526018876802076">"A reencaminhar para {0}"</string> + <string name="sum_cfnry_enabled" msgid="3473526018876802076">"A reencaminhar para \\\\{0\\\\}"</string> <string name="sum_cfnry_disabled" msgid="8422350929957344729">"Desactivado"</string> <string name="disable_cfnry_forbidden" msgid="7041605706777677935">"O seu operador não suporta a desactivação do reencaminhamento de chamadas quando o telefone não atende."</string> <string name="labelCFNRc" msgid="47183615370850000">"Reencaminhar quando está inacessível"</string> <string name="messageCFNRc" msgid="6380695421020295119">"Número no caso de estar inacessível"</string> - <string name="sum_cfnrc_enabled" msgid="3528648673654636587">"A reencaminhar para {0}"</string> + <string name="sum_cfnrc_enabled" msgid="3528648673654636587">"A reencaminhar para \\\\{0\\\\}"</string> <string name="sum_cfnrc_disabled" msgid="7222141261321276464">"Desactivado"</string> <string name="disable_cfnrc_forbidden" msgid="1093527570652781997">"O seu operador não suporta a desactivação do reencaminhamento de chamadas quando o telefone não está acessível."</string> <string name="updating_title" msgid="6146755386174019046">"Definições de chamadas"</string> diff --git a/phone/res/values-ru/strings.xml b/phone/res/values-ru/strings.xml index 331f8f3..018ab5a 100644 --- a/phone/res/values-ru/strings.xml +++ b/phone/res/values-ru/strings.xml @@ -63,8 +63,8 @@ <string name="menu_hold" msgid="6970441130344786273">"Удержание"</string> <string name="menu_endCall" msgid="2142958047156634241">"Завершить вызов"</string> <string name="menu_swapCalls" msgid="1548647524816600795">"Другой вызов"</string> - <string name="menu_mergeCalls" msgid="6414754941392181303">"Соединить"</string> - <string name="menu_addCall" msgid="7829255032442131930">"+ вызов"</string> + <string name="menu_mergeCalls" msgid="6414754941392181303">"Объединить вызовы"</string> + <string name="menu_addCall" msgid="7829255032442131930">"Добавить вызов"</string> <string name="menu_manageConference" msgid="3770984362002266733">"Управление конференц-связью"</string> <string name="menu_showDialpad" msgid="5198200217528406980">"Показать кнопки"</string> <string name="menu_hideDialpad" msgid="2733813546746296771">"Скрыть кнопки"</string> @@ -118,31 +118,31 @@ <string name="labelCallerId" msgid="3888899447379069198">"АОН"</string> <string name="sum_hide_caller_id" msgid="1071407020290873782">"Скрывать номер при исходящих вызовах"</string> <string name="sum_show_caller_id" msgid="6768534125447290401">"Номер, отображающийся при исходящих вызовах"</string> - <string name="sum_default_caller_id" msgid="1954518825510901365">"При исходящих вызовах использовать для отображения моего номера настройки, предоставляемые оператором"</string> + <string name="sum_default_caller_id" msgid="1954518825510901365">"При исходящих вызовах использовать для отображения моего номера настройки, предоставляемые оператором по умолчанию"</string> <string name="labelCW" msgid="6120513814915920200">"Параллельный вызов"</string> <string name="sum_cw_enabled" msgid="8083061901633671397">"Извещать меня о входящих вызовах во время разговора"</string> <string name="sum_cw_disabled" msgid="3648693907300104575">"Извещать меня о входящих вызовах во время разговора"</string> <string name="call_forwarding_settings" msgid="3378927671091537173">"Настройки переадресации вызова"</string> <string name="labelCF" msgid="2574386948026924737">"Переадресация вызова"</string> - <string name="labelCFU" msgid="8147177368148660600">"Всегда на номер"</string> - <string name="messageCFU" msgid="3560082430662923687">"Всегда переадресовывать вызов на этот номер"</string> + <string name="labelCFU" msgid="8147177368148660600">"Всегда"</string> + <string name="messageCFU" msgid="3560082430662923687">"Всегда использовать этот номер"</string> <string name="sum_cfu_enabled_indicator" msgid="4014187342724130197">"Переадресация всех вызовов"</string> - <string name="sum_cfu_enabled" msgid="956178654350554451">"Переадресация всех вызовов на номер {0}"</string> + <string name="sum_cfu_enabled" msgid="956178654350554451">"Переадресация всех вызовов на номер \\\\{0\\\\}"</string> <string name="sum_cfu_enabled_no_number" msgid="6591985777096823616">"Номер не указан"</string> <string name="sum_cfu_disabled" msgid="3698472522160364904">"Отключено"</string> - <string name="labelCFB" msgid="218938523102207587">"Если занято"</string> + <string name="labelCFB" msgid="218938523102207587">"Если аб. занят"</string> <string name="messageCFB" msgid="3711089705936187129">"Номер, использующийся, когда линия занята"</string> - <string name="sum_cfb_enabled" msgid="2501948432392255856">"Переадресация на номер {0}"</string> + <string name="sum_cfb_enabled" msgid="2501948432392255856">"Переадресация на номер \\\\{0\\\\}"</string> <string name="sum_cfb_disabled" msgid="227440009979537651">"Отключено"</string> <string name="disable_cfb_forbidden" msgid="4524424437001441832">"Ваш оператор не поддерживает отключение переадресации звонков, если телефон занят."</string> - <string name="labelCFNRy" msgid="3646316323834351390">"При отсутствии ответа"</string> + <string name="labelCFNRy" msgid="3646316323834351390">"Если аб. не отвечает"</string> <string name="messageCFNRy" msgid="672317899884380374">"Номер для переадресации при отсутствии ответа"</string> - <string name="sum_cfnry_enabled" msgid="3473526018876802076">"Переадресация на номер {0}"</string> + <string name="sum_cfnry_enabled" msgid="3473526018876802076">"Переадресация на номер \\\\{0\\\\}"</string> <string name="sum_cfnry_disabled" msgid="8422350929957344729">"Отключено"</string> <string name="disable_cfnry_forbidden" msgid="7041605706777677935">"Ваш оператор не поддерживает отключение переадресации звонков, если нет ответа."</string> - <string name="labelCFNRc" msgid="47183615370850000">"Если недоступен"</string> + <string name="labelCFNRc" msgid="47183615370850000">"Если аб. недоступен"</string> <string name="messageCFNRc" msgid="6380695421020295119">"Номер для переадресации, если абонент недоступен"</string> - <string name="sum_cfnrc_enabled" msgid="3528648673654636587">"Переадресация на номер {0}"</string> + <string name="sum_cfnrc_enabled" msgid="3528648673654636587">"Переадресация на номер \\\\{0\\\\}"</string> <string name="sum_cfnrc_disabled" msgid="7222141261321276464">"Отключено"</string> <string name="disable_cfnrc_forbidden" msgid="1093527570652781997">"Ваш оператор не поддерживает отключение переадресации звонков, если телефон находится вне зоны доступа."</string> <string name="updating_title" msgid="6146755386174019046">"Настройки вызовов"</string> @@ -514,8 +514,8 @@ <string name="onscreenSpeakerText" msgid="9013795366801657948">"Динамик"</string> <string name="onscreenMuteText" msgid="5011369181754261374">"Откл. звук"</string> <string name="onscreenBluetoothText" msgid="2479639597725504499">"Bluetooth"</string> - <string name="onscreenAddCallText" msgid="5140385634712287403">"+ вызов"</string> - <string name="onscreenMergeCallsText" msgid="6640195098064538950">"Соединить"</string> + <string name="onscreenAddCallText" msgid="5140385634712287403">"Добавить вызов"</string> + <string name="onscreenMergeCallsText" msgid="6640195098064538950">"Объединить вызовы"</string> <string name="onscreenSwapCallsText" msgid="1602990689244030047">"Перевод звонка"</string> <string name="onscreenManageCallsText" msgid="5473231160123254154">"Управление вызовами"</string> <string name="onscreenManageConferenceText" msgid="6952581578445378981">"Управлять"</string> diff --git a/phone/res/values-sv/strings.xml b/phone/res/values-sv/strings.xml index a510ee2..eaaae77 100644 --- a/phone/res/values-sv/strings.xml +++ b/phone/res/values-sv/strings.xml @@ -127,22 +127,22 @@ <string name="labelCFU" msgid="8147177368148660600">"Vidarebefordra alltid"</string> <string name="messageCFU" msgid="3560082430662923687">"Använd alltid detta nummer"</string> <string name="sum_cfu_enabled_indicator" msgid="4014187342724130197">"Vidarebefordra alla samtal"</string> - <string name="sum_cfu_enabled" msgid="956178654350554451">"Vidarebefordrar alla samtal till {0}"</string> + <string name="sum_cfu_enabled" msgid="956178654350554451">"Vidarebefordrar alla samtal till \\\\{0\\\\}"</string> <string name="sum_cfu_enabled_no_number" msgid="6591985777096823616">"Numret är inte tillgängligt"</string> <string name="sum_cfu_disabled" msgid="3698472522160364904">"Inaktiverat"</string> <string name="labelCFB" msgid="218938523102207587">"Vidarebefordra vid upptaget"</string> <string name="messageCFB" msgid="3711089705936187129">"Nummer vid upptagen"</string> - <string name="sum_cfb_enabled" msgid="2501948432392255856">"Vidarebefordrar till {0}"</string> + <string name="sum_cfb_enabled" msgid="2501948432392255856">"Vidarebefordrar till \\\\{0\\\\}"</string> <string name="sum_cfb_disabled" msgid="227440009979537651">"Inaktiverat"</string> <string name="disable_cfb_forbidden" msgid="4524424437001441832">"Operatören stöder inte inaktivering av vidarebefordran av samtal när telefonen används."</string> <string name="labelCFNRy" msgid="3646316323834351390">"Vidarebefordra vid ej svar"</string> <string name="messageCFNRy" msgid="672317899884380374">"Nummer vid ej svar"</string> - <string name="sum_cfnry_enabled" msgid="3473526018876802076">"Vidarebefordrar till {0}"</string> + <string name="sum_cfnry_enabled" msgid="3473526018876802076">"Vidarebefordrar till \\\\{0\\\\}"</string> <string name="sum_cfnry_disabled" msgid="8422350929957344729">"Inaktiverat"</string> <string name="disable_cfnry_forbidden" msgid="7041605706777677935">"Operatören stöder inte inaktivering av vidarebefordran av samtal när ingen svarar i telefonen."</string> <string name="labelCFNRc" msgid="47183615370850000">"Vidarebefordra när du inte är tillgänglig"</string> <string name="messageCFNRc" msgid="6380695421020295119">"Nummer när du inte är tillgänglig"</string> - <string name="sum_cfnrc_enabled" msgid="3528648673654636587">"Vidarebefordrar till {0}"</string> + <string name="sum_cfnrc_enabled" msgid="3528648673654636587">"Vidarebefordrar till \\\\{0\\\\}"</string> <string name="sum_cfnrc_disabled" msgid="7222141261321276464">"Inaktiverat"</string> <string name="disable_cfnrc_forbidden" msgid="1093527570652781997">"Operatören stöder inte inaktivering av vidarebefordran av samtal när det inte går att nå telefonen."</string> <string name="updating_title" msgid="6146755386174019046">"Samtalsinställningar"</string> diff --git a/phone/res/values-zh-rTW/strings.xml b/phone/res/values-zh-rTW/strings.xml index c4d4795..1a48a7e 100644 --- a/phone/res/values-zh-rTW/strings.xml +++ b/phone/res/values-zh-rTW/strings.xml @@ -132,17 +132,17 @@ <string name="sum_cfu_disabled" msgid="3698472522160364904">"停用"</string> <string name="labelCFB" msgid="218938523102207587">"忙線時轉接"</string> <string name="messageCFB" msgid="3711089705936187129">"忙線時轉接號碼"</string> - <string name="sum_cfb_enabled" msgid="2501948432392255856">"轉接到 {0}"</string> + <string name="sum_cfb_enabled" msgid="2501948432392255856">"轉接到 \\\\{0\\\\}"</string> <string name="sum_cfb_disabled" msgid="227440009979537651">"停用"</string> <string name="disable_cfb_forbidden" msgid="4524424437001441832">"您的電信業者不支援於手機通話中停用轉接功能。"</string> <string name="labelCFNRy" msgid="3646316323834351390">"未接聽時轉接"</string> <string name="messageCFNRy" msgid="672317899884380374">"未接聽時的轉接號碼"</string> - <string name="sum_cfnry_enabled" msgid="3473526018876802076">"轉接到 {0}"</string> + <string name="sum_cfnry_enabled" msgid="3473526018876802076">"轉接到 \\\\{0\\\\}"</string> <string name="sum_cfnry_disabled" msgid="8422350929957344729">"停用"</string> <string name="disable_cfnry_forbidden" msgid="7041605706777677935">"您的電信業者不支援於手機未接聽時停用轉接功能。"</string> <string name="labelCFNRc" msgid="47183615370850000">"未能接通時轉接"</string> <string name="messageCFNRc" msgid="6380695421020295119">"無法接通時的轉接號碼"</string> - <string name="sum_cfnrc_enabled" msgid="3528648673654636587">"轉接到 {0}"</string> + <string name="sum_cfnrc_enabled" msgid="3528648673654636587">"轉接到 \\\\{0\\\\}"</string> <string name="sum_cfnrc_disabled" msgid="7222141261321276464">"停用"</string> <string name="disable_cfnrc_forbidden" msgid="1093527570652781997">"您的電信業者不支援於手機無收訊時停用轉接功能。"</string> <string name="updating_title" msgid="6146755386174019046">"通話設定"</string> diff --git a/phone/res/values/config.xml b/phone/res/values/config.xml index 3e9dee0..5c84336 100644 --- a/phone/res/values/config.xml +++ b/phone/res/values/config.xml @@ -119,8 +119,4 @@ <!-- Determines if device implements a noise suppression device for in call audio--> <bool name="has_in_call_noise_suppression">false</bool> - <!-- Determines if the current device should allow emergency numbers - to be logged in the Call Log. --> - <bool name="allow_emergency_numbers_in_call_log">true</bool> - </resources> diff --git a/phone/res/values/strings.xml b/phone/res/values/strings.xml index 1ff406c..f6d4839 100755 --- a/phone/res/values/strings.xml +++ b/phone/res/values/strings.xml @@ -85,8 +85,6 @@ <string name="callFailed_cdma_preempted">CDMA: Preempted.</string> <!-- In-call screen: call failure reason (Only Emergency calls are possible)--> <string name="callFailed_cdma_notEmergency">Only Emergency calls are possible.</string> - <!-- In-call screen: call failure reason (Dialed number doesn't exist) --> - <string name="callFailed_unobtainable_number">Invalid Number</string> <!-- In-call screen: status label for a conference call --> <string name="confCall">Conference call</string> <!-- In-call screen: call lost dialog text --> @@ -325,8 +323,6 @@ <string name="response_error">Unexpected response from network.</string> <!-- Status message displayed in the "Call settings error" dialog --> <string name="exception_error">Network or SIM card error.</string> - <!-- Status message displayed in the "Call settings error" dialog when operation fails due to FDN --> - <string name="fdn_only_error">Operations are only allowed on fixed dialing numbers.</string> <!-- Status message displayed in the "Call settings error" dialog --> <string name="radio_off_error">Please turn on the radio before viewing these settings.</string> <!-- Button label used to dismiss the "Call settings error" dialog --> @@ -659,14 +655,14 @@ <item>"1"</item> <item>"2"</item> </string-array> - <string name="cdma_subscription_title">CDMA Subscription</string> - <string name="cdma_subscription_summary">Change between RUIM/SIM and NV</string> - <string name="cdma_subscription_dialogtitle">subscription</string> - <string-array name="cdma_subscription_choices"> + <string name="subscription_title">CDMA Subscription TEST</string> + <string name="subscription_summary">Change between RUIM/SIM and NV</string> + <string name="subscription_dialogtitle">subscription</string> + <string-array name="subscription_choices"> <item>RUIM/SIM</item> <item>NV</item> </string-array> - <string-array name="cdma_subscription_values"> + <string-array name="subscription_values"> <item>"0"</item> <item>"1"</item> </string-array> @@ -1193,10 +1189,4 @@ <!-- Incoming call hint shown on tab (must be kept very short): decline incoming call --> <string name="slide_to_decline_hint">Decline</string> - <!-- Use this as a default to describe the contact photo; currently for screen readers through accessibility. --> - <string name="contactPhoto">contact photo</string> - <!-- Use this to describe the separate conference call button; currently for screen readers through accessibility. --> - <string name="goPrivate">go private</string> - <!-- Use this to describe the select contact button in EditPhoneNumberPreference; currently for screen readers through accessibility. --> - <string name="selectContact">select contact</string> </resources> diff --git a/phone/res/values/styles.xml b/phone/res/values/styles.xml index 0850ade..fdc1766 100644 --- a/phone/res/values/styles.xml +++ b/phone/res/values/styles.xml @@ -176,7 +176,7 @@ <item name="android:layout_marginLeft">8dip</item> <item name="android:layout_marginRight">8dip</item> <item name="android:textAppearance">?android:attr/textAppearanceSmall</item> - <item name="android:textColor">@color/in_call_button_text</item> + <item name="android:textColor">?android:attr/textColorPrimary</item> <item name="android:singleLine">true</item> <item name="android:ellipsize">marquee</item> </style> @@ -190,7 +190,7 @@ <item name="android:layout_marginLeft">8dip</item> <item name="android:layout_marginRight">8dip</item> <item name="android:textAppearance">?android:attr/textAppearanceSmall</item> - <item name="android:textColor">@color/in_call_button_text</item> + <item name="android:textColor">?android:attr/textColorPrimary</item> <item name="android:singleLine">true</item> <item name="android:ellipsize">marquee</item> </style> diff --git a/phone/res/xml/cdma_options.xml b/phone/res/xml/cdma_options.xml index 3ca8c2f..e2ff8df 100644 --- a/phone/res/xml/cdma_options.xml +++ b/phone/res/xml/cdma_options.xml @@ -17,20 +17,11 @@ <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" xmlns:settings="http://schemas.android.com/apk/res/com.android.phone2"> - <com.android.phone2.CdmaSystemSelectListPreference - android:key="cdma_system_select_key" + <com.android.phone2.CdmaRoamingListPreference + android:key="cdma_roaming_mode_key" android:title="@string/cdma_system_select_title" android:summary="@string/cdma_system_select_summary" android:entries="@array/cdma_system_select_choices" android:entryValues="@array/cdma_system_select_values" android:dialogTitle="@string/cdma_system_select_dialogtitle" /> - - <com.android.phone2.CdmaSubscriptionListPreference - android:key="cdma_subscription_key" - android:title="@string/cdma_subscription_title" - android:summary="@string/cdma_subscription_summary" - android:entries="@array/cdma_subscription_choices" - android:entryValues="@array/cdma_subscription_values" - android:dialogTitle="@string/cdma_subscription_dialogtitle" /> - </PreferenceScreen> diff --git a/phone/res/xml/network_setting.xml b/phone/res/xml/network_setting.xml index 43b688a..0c579a3 100644 --- a/phone/res/xml/network_setting.xml +++ b/phone/res/xml/network_setting.xml @@ -48,4 +48,26 @@ android:entryValues="@array/preferred_network_mode_values" android:dialogTitle="@string/preferred_network_mode_dialogtitle" /> + <PreferenceScreen + android:key="gsm_umts_options_key" + android:title="@string/gsm_umts_options" + android:persistent="false"> + + <intent android:action="android.intent.action.MAIN" + android:targetPackage="com.android.phone2" + android:targetClass="com.android.phone2.GsmUmtsOptions" /> + + </PreferenceScreen> + + <PreferenceScreen + android:key="cdma_options_key" + android:title="@string/cdma_options" + android:persistent="false"> + + <intent android:action="android.intent.action.MAIN" + android:targetPackage="com.android.phone2" + android:targetClass="com.android.phone2.CdmaOptions" /> + + </PreferenceScreen> + </PreferenceScreen> diff --git a/phone/src/com/android/phone2/BluetoothHandsfree.java b/phone/src/com/android/phone2/BluetoothHandsfree.java index 29a6c8b..63ad4f3 100644 --- a/phone/src/com/android/phone2/BluetoothHandsfree.java +++ b/phone/src/com/android/phone2/BluetoothHandsfree.java @@ -241,7 +241,7 @@ public class BluetoothHandsfree { return mHeadset.isConnected(); } - /* package */ synchronized void connectHeadset(HeadsetBase headset, int headsetType) { + /* package */ void connectHeadset(HeadsetBase headset, int headsetType) { mHeadset = headset; mHeadsetType = headsetType; if (mHeadsetType == TYPE_HEADSET) { @@ -277,7 +277,7 @@ public class BluetoothHandsfree { resetAtState(); } - /* package */ synchronized void resetAtState() { + private void resetAtState() { mClip = false; mIndicatorsEnabled = false; mServiceConnectionEstablished = false; diff --git a/phone/src/com/android/phone2/BluetoothHeadsetService.java b/phone/src/com/android/phone2/BluetoothHeadsetService.java index ca4c9e2..ac4dce3 100644 --- a/phone/src/com/android/phone2/BluetoothHeadsetService.java +++ b/phone/src/com/android/phone2/BluetoothHeadsetService.java @@ -17,15 +17,14 @@ package com.android.phone2; import android.app.Service; -import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothAudioGateway; -import android.bluetooth.BluetoothAudioGateway.IncomingConnectionInfo; +import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothHeadset; import android.bluetooth.BluetoothUuid; import android.bluetooth.HeadsetBase; -import android.bluetooth.IBluetooth; import android.bluetooth.IBluetoothHeadset; +import android.os.ParcelUuid; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -34,18 +33,20 @@ import android.media.AudioManager; import android.os.Handler; import android.os.IBinder; import android.os.Message; -import android.os.ParcelUuid; import android.os.PowerManager; import android.os.RemoteException; -import android.os.ServiceManager; +import android.os.SystemProperties; import android.provider.Settings; import android.util.Log; import com.android.internal.telephony.Call; import com.android.internal.telephony.Phone; -import com.android.internal.telephony.PhoneFactory; +import com.android.internal.telephony.SipPhoneFactory; import java.util.HashMap; +import java.util.LinkedList; +import java.util.ListIterator; +import java.util.Set; /** * Provides Bluetooth Headset and Handsfree profile, as a service in @@ -68,14 +69,24 @@ public class BluetoothHeadsetService extends Service { private BluetoothDevice mDeviceSdpQuery; private BluetoothAdapter mAdapter; - private IBluetooth mBluetoothService; private PowerManager mPowerManager; private BluetoothAudioGateway mAg; + private HeadsetBase mHeadset; + private int mState; + private int mHeadsetType; private BluetoothHandsfree mBtHandsfree; + private BluetoothDevice mRemoteDevice; + private LinkedList<BluetoothDevice> mAutoConnectQueue; private Call mForegroundCall; private Call mRingingCall; private Phone mPhone; - private HashMap<BluetoothDevice, BluetoothRemoteHeadset> mRemoteHeadsets; + + private final HeadsetPriority mHeadsetPriority = new HeadsetPriority(); + + public BluetoothHeadsetService() { + mState = BluetoothHeadset.STATE_DISCONNECTED; + mHeadsetType = BluetoothHandsfree.TYPE_UNKNOWN; + } @Override public void onCreate() { @@ -84,10 +95,12 @@ public class BluetoothHeadsetService extends Service { mPowerManager = (PowerManager) getSystemService(Context.POWER_SERVICE); mBtHandsfree = PhoneApp.getInstance().getBluetoothHandsfree(); mAg = new BluetoothAudioGateway(mAdapter); - mPhone = PhoneFactory.getDefaultPhone(); + mPhone = SipPhoneFactory.getDefaultPhone(); mRingingCall = mPhone.getRingingCall(); mForegroundCall = mPhone.getForegroundCall(); - adjustPriorities(); + if (mAdapter.isEnabled()) { + mHeadsetPriority.load(); + } IntentFilter filter = new IntentFilter( BluetoothDevice.ACTION_ACL_DISCONNECT_REQUESTED); filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED); @@ -95,45 +108,6 @@ public class BluetoothHeadsetService extends Service { filter.addAction(AudioManager.VOLUME_CHANGED_ACTION); filter.addAction(BluetoothDevice.ACTION_UUID); registerReceiver(mBluetoothReceiver, filter); - - IBinder b = ServiceManager.getService(BluetoothAdapter.BLUETOOTH_SERVICE); - if (b == null) { - throw new RuntimeException("Bluetooth service not available"); - } - mBluetoothService = IBluetooth.Stub.asInterface(b); - mRemoteHeadsets = new HashMap<BluetoothDevice, BluetoothRemoteHeadset>(); - } - - private class BluetoothRemoteHeadset { - private int mState; - private int mHeadsetType; - private HeadsetBase mHeadset; - private IncomingConnectionInfo mIncomingInfo; - - BluetoothRemoteHeadset() { - mState = BluetoothHeadset.STATE_DISCONNECTED; - mHeadsetType = BluetoothHandsfree.TYPE_UNKNOWN; - mHeadset = null; - mIncomingInfo = null; - } - - BluetoothRemoteHeadset(int headsetType, IncomingConnectionInfo incomingInfo) { - mState = BluetoothHeadset.STATE_DISCONNECTED; - mHeadsetType = headsetType; - mHeadset = null; - mIncomingInfo = incomingInfo; - } - } - - synchronized private BluetoothDevice getCurrentDevice() { - for (BluetoothDevice device : mRemoteHeadsets.keySet()) { - int state = mRemoteHeadsets.get(device).mState; - if (state == BluetoothHeadset.STATE_CONNECTING || - state == BluetoothHeadset.STATE_CONNECTED) { - return device; - } - } - return null; } @Override @@ -147,6 +121,10 @@ public class BluetoothHeadsetService extends Service { if (mAdapter.isEnabled()) { mAg.start(mIncomingConnectionHandler); mBtHandsfree.onBluetoothEnabled(); + // BT might have only just started, wait 6 seconds until + // SDP records are registered before reconnecting headset + mHandler.sendMessageDelayed(mHandler.obtainMessage(RECONNECT_LAST_HEADSET), + 6000); } sHasStarted = true; } @@ -156,93 +134,100 @@ public class BluetoothHeadsetService extends Service { private final Handler mIncomingConnectionHandler = new Handler() { @Override public void handleMessage(Message msg) { - synchronized(BluetoothHeadsetService.this) { - IncomingConnectionInfo info = (IncomingConnectionInfo)msg.obj; - int type = BluetoothHandsfree.TYPE_UNKNOWN; - switch(msg.what) { - case BluetoothAudioGateway.MSG_INCOMING_HEADSET_CONNECTION: - type = BluetoothHandsfree.TYPE_HEADSET; - break; - case BluetoothAudioGateway.MSG_INCOMING_HANDSFREE_CONNECTION: - type = BluetoothHandsfree.TYPE_HANDSFREE; - break; - } + BluetoothAudioGateway.IncomingConnectionInfo info = + (BluetoothAudioGateway.IncomingConnectionInfo)msg.obj; + int type = BluetoothHandsfree.TYPE_UNKNOWN; + switch(msg.what) { + case BluetoothAudioGateway.MSG_INCOMING_HEADSET_CONNECTION: + type = BluetoothHandsfree.TYPE_HEADSET; + break; + case BluetoothAudioGateway.MSG_INCOMING_HANDSFREE_CONNECTION: + type = BluetoothHandsfree.TYPE_HANDSFREE; + break; + } - Log.i(TAG, "Incoming rfcomm (" + BluetoothHandsfree.typeToString(type) + - ") connection from " + info.mRemoteDevice + "on channel " + - info.mRfcommChan); + Log.i(TAG, "Incoming rfcomm (" + BluetoothHandsfree.typeToString(type) + + ") connection from " + info.mRemoteDevice + "on channel " + info.mRfcommChan); + + int priority = BluetoothHeadset.PRIORITY_OFF; + HeadsetBase headset; + try { + priority = mBinder.getPriority(info.mRemoteDevice); + } catch (RemoteException e) {} + if (priority <= BluetoothHeadset.PRIORITY_OFF) { + Log.i(TAG, "Rejecting incoming connection because priority = " + priority); + + headset = new HeadsetBase(mPowerManager, mAdapter, info.mRemoteDevice, + info.mSocketFd, info.mRfcommChan, null); + headset.disconnect(); + return; + } + switch (mState) { + case BluetoothHeadset.STATE_DISCONNECTED: + // headset connecting us, lets join + mRemoteDevice = info.mRemoteDevice; + setState(BluetoothHeadset.STATE_CONNECTING); + headset = new HeadsetBase(mPowerManager, mAdapter, mRemoteDevice, info.mSocketFd, + info.mRfcommChan, mConnectedStatusHandler); + mHeadsetType = type; + + mConnectingStatusHandler.obtainMessage(RFCOMM_CONNECTED, headset).sendToTarget(); - int priority = BluetoothHeadset.PRIORITY_OFF; - HeadsetBase headset; - priority = getPriority(info.mRemoteDevice); - if (priority <= BluetoothHeadset.PRIORITY_OFF) { - Log.i(TAG, "Rejecting incoming connection because priority = " + priority); + break; + case BluetoothHeadset.STATE_CONNECTING: + if (!info.mRemoteDevice.equals(mRemoteDevice)) { + // different headset, ignoring + Log.i(TAG, "Already attempting connect to " + mRemoteDevice + + ", disconnecting " + info.mRemoteDevice); headset = new HeadsetBase(mPowerManager, mAdapter, info.mRemoteDevice, info.mSocketFd, info.mRfcommChan, null); headset.disconnect(); - return; } - - BluetoothRemoteHeadset remoteHeadset; - BluetoothDevice device = getCurrentDevice(); - - int state = BluetoothHeadset.STATE_DISCONNECTED; - if (device != null) { - state = mRemoteHeadsets.get(device).mState; + // If we are here, we are in danger of a race condition + // incoming rfcomm connection, but we are also attempting an + // outgoing connection. Lets try and interrupt the outgoing + // connection. + Log.i(TAG, "Incoming and outgoing connections to " + info.mRemoteDevice + + ". Cancel outgoing connection."); + if (mConnectThread != null) { + mConnectThread.interrupt(); + mConnectThread = null; } - switch (state) { - case BluetoothHeadset.STATE_DISCONNECTED: - // headset connecting us, lets join - remoteHeadset = new BluetoothRemoteHeadset(type, info); - mRemoteHeadsets.put(info.mRemoteDevice, remoteHeadset); - - try { - mBluetoothService.notifyIncomingConnection( - info.mRemoteDevice.getAddress()); - } catch (RemoteException e) { - Log.e(TAG, "notifyIncomingConnection"); - } - break; - case BluetoothHeadset.STATE_CONNECTING: - if (!info.mRemoteDevice.equals(device)) { - // different headset, ignoring - Log.i(TAG, "Already attempting connect to " + device + - ", disconnecting " + info.mRemoteDevice); - - headset = new HeadsetBase(mPowerManager, mAdapter, info.mRemoteDevice, - info.mSocketFd, info.mRfcommChan, null); - headset.disconnect(); - break; - } + // Now continue with new connection, including calling callback + mHeadset = new HeadsetBase(mPowerManager, mAdapter, mRemoteDevice, + info.mSocketFd, info.mRfcommChan, mConnectedStatusHandler); + mHeadsetType = type; - // Incoming and Outgoing connections to the same headset. - // The state machine manager will cancel outgoing and accept the incoming one. - // Update the state - mRemoteHeadsets.get(info.mRemoteDevice).mHeadsetType = type; - mRemoteHeadsets.get(info.mRemoteDevice).mIncomingInfo = info; + setState(BluetoothHeadset.STATE_CONNECTED, BluetoothHeadset.RESULT_SUCCESS); + mBtHandsfree.connectHeadset(mHeadset, mHeadsetType); - try { - mBluetoothService.notifyIncomingConnection( - info.mRemoteDevice.getAddress()); - } catch (RemoteException e) { - Log.e(TAG, "notifyIncomingConnection"); - } - break; - case BluetoothHeadset.STATE_CONNECTED: - Log.i(TAG, "Already connected to " + device + ", disconnecting " + - info.mRemoteDevice); + if (DBG) log("Successfully used incoming connection"); + break; + case BluetoothHeadset.STATE_CONNECTED: + Log.i(TAG, "Already connected to " + mRemoteDevice + ", disconnecting " + + info.mRemoteDevice); - headset = new HeadsetBase(mPowerManager, mAdapter, info.mRemoteDevice, - info.mSocketFd, info.mRfcommChan, null); - headset.disconnect(); - break; - } + headset = new HeadsetBase(mPowerManager, mAdapter, info.mRemoteDevice, + info.mSocketFd, info.mRfcommChan, null); + headset.disconnect(); + break; } } }; + private synchronized void autoConnectHeadset() { + if (DBG && debugDontReconnect()) { + return; + } + if (mAdapter.isEnabled()) { + try { + mBinder.connectHeadset(null); + } catch (RemoteException e) {} + } + } + private final BroadcastReceiver mBluetoothReceiver = new BroadcastReceiver() { @Override @@ -251,34 +236,27 @@ public class BluetoothHeadsetService extends Service { BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); - BluetoothDevice currDevice = getCurrentDevice(); - int state = BluetoothHeadset.STATE_DISCONNECTED; - if (currDevice != null) { - state = mRemoteHeadsets.get(currDevice).mState; - } - - if ((state == BluetoothHeadset.STATE_CONNECTED || - state == BluetoothHeadset.STATE_CONNECTING) && + if ((mState == BluetoothHeadset.STATE_CONNECTED || + mState == BluetoothHeadset.STATE_CONNECTING) && action.equals(BluetoothDevice.ACTION_ACL_DISCONNECT_REQUESTED) && - device.equals(currDevice)) { + device.equals(mRemoteDevice)) { try { - mBinder.disconnectHeadset(currDevice); + mBinder.disconnectHeadset(); } catch (RemoteException e) {} } else if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) { switch (intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR)) { case BluetoothAdapter.STATE_ON: + mHeadsetPriority.load(); + mHandler.sendMessageDelayed(mHandler.obtainMessage(RECONNECT_LAST_HEADSET), 8000); mAg.start(mIncomingConnectionHandler); mBtHandsfree.onBluetoothEnabled(); break; case BluetoothAdapter.STATE_TURNING_OFF: mBtHandsfree.onBluetoothDisabled(); mAg.stop(); - if (currDevice != null) { - setState(currDevice, BluetoothHeadset.STATE_DISCONNECTED, - BluetoothHeadset.RESULT_FAILURE, - BluetoothHeadset.LOCAL_DISCONNECT); - } + setState(BluetoothHeadset.STATE_DISCONNECTED, BluetoothHeadset.RESULT_FAILURE, + BluetoothHeadset.LOCAL_DISCONNECT); break; } } else if (action.equals(BluetoothDevice.ACTION_BOND_STATE_CHANGED)) { @@ -286,12 +264,12 @@ public class BluetoothHeadsetService extends Service { BluetoothDevice.ERROR); switch(bondState) { case BluetoothDevice.BOND_BONDED: - if (getPriority(device) == BluetoothHeadset.PRIORITY_UNDEFINED) { - setPriority(device, BluetoothHeadset.PRIORITY_ON); + if (mHeadsetPriority.get(device) == BluetoothHeadset.PRIORITY_UNDEFINED) { + mHeadsetPriority.set(device, BluetoothHeadset.PRIORITY_ON); } break; case BluetoothDevice.BOND_NONE: - setPriority(device, BluetoothHeadset.PRIORITY_UNDEFINED); + mHeadsetPriority.set(device, BluetoothHeadset.PRIORITY_UNDEFINED); break; } } else if (action.equals(AudioManager.VOLUME_CHANGED_ACTION)) { @@ -302,23 +280,26 @@ public class BluetoothHeadsetService extends Service { } } else if (action.equals(BluetoothDevice.ACTION_UUID)) { - if (device.equals(mDeviceSdpQuery) && device.equals(currDevice)) { + if (device.equals(mDeviceSdpQuery)) { // We have got SDP records for the device we are interested in. - getSdpRecordsAndConnect(device); + getSdpRecordsAndConnect(); } } } }; - private static final int CONNECT_HEADSET_DELAYED = 1; + private static final int RECONNECT_LAST_HEADSET = 1; + private static final int CONNECT_HEADSET_DELAYED = 2; private Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { - case CONNECT_HEADSET_DELAYED: - BluetoothDevice device = (BluetoothDevice) msg.obj; - getSdpRecordsAndConnect(device); - break; + case RECONNECT_LAST_HEADSET: + autoConnectHeadset(); + break; + case CONNECT_HEADSET_DELAYED: + getSdpRecordsAndConnect(); + break; } } }; @@ -383,7 +364,7 @@ public class BluetoothHeadsetService extends Service { if (result == ECONNREFUSED && mDeviceSdpQuery == null) { // The rfcomm channel number might have changed, do SDP // query and try to connect again. - mDeviceSdpQuery = getCurrentDevice(); + mDeviceSdpQuery = mRemoteDevice; device.fetchUuidsWithSdp(); mConnectThread = null; return; @@ -395,6 +376,7 @@ public class BluetoothHeadsetService extends Service { } result = waitForConnect(headset); } + mDeviceSdpQuery = null; if (result == EINTERRUPT) return; @@ -424,9 +406,7 @@ public class BluetoothHeadsetService extends Service { private final Handler mConnectingStatusHandler = new Handler() { @Override public void handleMessage(Message msg) { - BluetoothDevice device = getCurrentDevice(); - if (device == null || - mRemoteHeadsets.get(device).mState != BluetoothHeadset.STATE_CONNECTING) { + if (mState != BluetoothHeadset.STATE_CONNECTING) { return; // stale events } @@ -434,19 +414,16 @@ public class BluetoothHeadsetService extends Service { case RFCOMM_ERROR: if (DBG) log("Rfcomm error"); mConnectThread = null; - setState(device, - BluetoothHeadset.STATE_DISCONNECTED, BluetoothHeadset.RESULT_FAILURE, + setState(BluetoothHeadset.STATE_DISCONNECTED, BluetoothHeadset.RESULT_FAILURE, BluetoothHeadset.LOCAL_DISCONNECT); break; case RFCOMM_CONNECTED: if (DBG) log("Rfcomm connected"); mConnectThread = null; - HeadsetBase headset = (HeadsetBase)msg.obj; - setState(device, - BluetoothHeadset.STATE_CONNECTED, BluetoothHeadset.RESULT_SUCCESS); + mHeadset = (HeadsetBase)msg.obj; + setState(BluetoothHeadset.STATE_CONNECTED, BluetoothHeadset.RESULT_SUCCESS); - mRemoteHeadsets.get(device).mHeadset = headset; - mBtHandsfree.connectHeadset(headset, mRemoteHeadsets.get(device).mHeadsetType); + mBtHandsfree.connectHeadset(mHeadset, mHeadsetType); break; } } @@ -460,183 +437,213 @@ public class BluetoothHeadsetService extends Service { public void handleMessage(Message msg) { switch (msg.what) { case HeadsetBase.RFCOMM_DISCONNECTED: - mBtHandsfree.resetAtState(); - BluetoothDevice device = getCurrentDevice(); - if (device != null) { - setState(device, - BluetoothHeadset.STATE_DISCONNECTED, BluetoothHeadset.RESULT_FAILURE, - BluetoothHeadset.REMOTE_DISCONNECT); - } + setState(BluetoothHeadset.STATE_DISCONNECTED, BluetoothHeadset.RESULT_FAILURE, + BluetoothHeadset.REMOTE_DISCONNECT); break; } } }; - private void setState(BluetoothDevice device, int state) { - setState(device, state, BluetoothHeadset.RESULT_SUCCESS); + private void setState(int state) { + setState(state, BluetoothHeadset.RESULT_SUCCESS); } - private void setState(BluetoothDevice device, int state, int result) { - setState(device, state, result, -1); + private void setState(int state, int result) { + setState(state, result, -1); } - private synchronized void setState(BluetoothDevice device, - int state, int result, int initiator) { - int prevState = mRemoteHeadsets.get(device).mState; - if (state != prevState) { - if (DBG) log("Device: " + device + - " Headset state" + prevState + " -> " + state + ", result = " + result); - if (prevState == BluetoothHeadset.STATE_CONNECTED) { + private synchronized void setState(int state, int result, int initiator) { + if (state != mState) { + if (DBG) log("Headset state " + mState + " -> " + state + ", result = " + result); + if (mState == BluetoothHeadset.STATE_CONNECTED) { mBtHandsfree.disconnectHeadset(); } Intent intent = new Intent(BluetoothHeadset.ACTION_STATE_CHANGED); - intent.putExtra(BluetoothHeadset.EXTRA_PREVIOUS_STATE, prevState); - intent.putExtra(BluetoothHeadset.EXTRA_STATE, state); - intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); + intent.putExtra(BluetoothHeadset.EXTRA_PREVIOUS_STATE, mState); + mState = state; + intent.putExtra(BluetoothHeadset.EXTRA_STATE, mState); + intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mRemoteDevice); // Add Extra EXTRA_DISCONNECT_INITIATOR for DISCONNECTED state - if (state == BluetoothHeadset.STATE_DISCONNECTED) { + if (mState == BluetoothHeadset.STATE_DISCONNECTED) { if (initiator == -1) { log("Headset Disconnected Intent without Disconnect Initiator extra"); } else { intent.putExtra(BluetoothHeadset.EXTRA_DISCONNECT_INITIATOR, initiator); } - mRemoteHeadsets.get(device).mHeadset = null; - mRemoteHeadsets.get(device).mHeadsetType = BluetoothHandsfree.TYPE_UNKNOWN; } - - mRemoteHeadsets.get(device).mState = state; - sendBroadcast(intent, BLUETOOTH_PERM); - if (state == BluetoothHeadset.STATE_CONNECTING) { + if (mState == BluetoothHeadset.STATE_DISCONNECTED) { + mHeadset = null; + mRemoteDevice = null; + mHeadsetType = BluetoothHandsfree.TYPE_UNKNOWN; + if (mAutoConnectQueue != null) { + doNextAutoConnect(); + } + } else if (mState == BluetoothHeadset.STATE_CONNECTING) { // Set the priority to AUTO_CONNECT - setPriority(device, BluetoothHeadset.PRIORITY_AUTO_CONNECT); - } - } - } - - private void setPriority(BluetoothDevice device, int priority) { - try { - mBinder.setPriority(device, priority); - } catch (RemoteException e) { - Log.e(TAG, "Error while setting priority for: " + device); - } - } - - private int getPriority(BluetoothDevice device) { - try { - return mBinder.getPriority(device); - } catch (RemoteException e) { - Log.e(TAG, "Error while getting priority for: " + device); - } - return BluetoothHeadset.PRIORITY_UNDEFINED; - } - - private void adjustPriorities() { - // This is to ensure backward compatibility. - // Only 1 device is set to AUTO_CONNECT - BluetoothDevice savedDevice = null; - int max_priority = BluetoothHeadset.PRIORITY_AUTO_CONNECT; - for (BluetoothDevice device : mAdapter.getBondedDevices()) { - int priority = getPriority(device); - if (priority >= BluetoothHeadset.PRIORITY_AUTO_CONNECT) { - setPriority(device, BluetoothHeadset.PRIORITY_ON); - } - if (priority >= max_priority) { - max_priority = priority; - savedDevice = device; + mHeadsetPriority.set(mRemoteDevice, BluetoothHeadset.PRIORITY_AUTO_CONNECT); + } else if (mState == BluetoothHeadset.STATE_CONNECTED) { + mAutoConnectQueue = null; // cancel further auto-connection + mHeadsetPriority.bump(mRemoteDevice); } } - if (savedDevice != null) { - setPriority(savedDevice, BluetoothHeadset.PRIORITY_AUTO_CONNECT); - } } - private synchronized void getSdpRecordsAndConnect(BluetoothDevice device) { - if (!device.equals(getCurrentDevice())) { - // stale - return; - } - ParcelUuid[] uuids = device.getUuids(); - int type = BluetoothHandsfree.TYPE_UNKNOWN; + private void getSdpRecordsAndConnect() { + ParcelUuid[] uuids = mRemoteDevice.getUuids(); if (uuids != null) { if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.Handsfree)) { log("SDP UUID: TYPE_HANDSFREE"); - type = BluetoothHandsfree.TYPE_HANDSFREE; - mRemoteHeadsets.get(device).mHeadsetType = type; - int channel = device.getServiceChannel(BluetoothUuid.Handsfree); - mConnectThread = new RfcommConnectThread(device, channel, type); + mHeadsetType = BluetoothHandsfree.TYPE_HANDSFREE; + int channel = mRemoteDevice.getServiceChannel(BluetoothUuid.Handsfree); + mConnectThread = new RfcommConnectThread(mRemoteDevice, channel, mHeadsetType); mConnectThread.start(); return; } else if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.HSP)) { log("SDP UUID: TYPE_HEADSET"); - type = BluetoothHandsfree.TYPE_HEADSET; - mRemoteHeadsets.get(device).mHeadsetType = type; - int channel = device.getServiceChannel(BluetoothUuid.HSP); - mConnectThread = new RfcommConnectThread(device, channel, type); + mHeadsetType = BluetoothHandsfree.TYPE_HEADSET; + int channel = mRemoteDevice.getServiceChannel(BluetoothUuid.HSP); + mConnectThread = new RfcommConnectThread(mRemoteDevice, channel, mHeadsetType); mConnectThread.start(); return; } } log("SDP UUID: TYPE_UNKNOWN"); - mRemoteHeadsets.get(device).mHeadsetType = type; - setState(device, BluetoothHeadset.STATE_DISCONNECTED, + mHeadsetType = BluetoothHandsfree.TYPE_UNKNOWN; + setState(BluetoothHeadset.STATE_DISCONNECTED, BluetoothHeadset.RESULT_FAILURE, BluetoothHeadset.LOCAL_DISCONNECT); return; } + private synchronized boolean doNextAutoConnect() { + if (mAutoConnectQueue == null || mAutoConnectQueue.size() == 0) { + mAutoConnectQueue = null; + return false; + } + mRemoteDevice = mAutoConnectQueue.removeFirst(); + // Don't auto connect with docks if we are docked with the dock. + if (isPhoneDocked(mRemoteDevice)) return doNextAutoConnect(); + + if (DBG) log("pulled " + mRemoteDevice + " off auto-connect queue"); + setState(BluetoothHeadset.STATE_CONNECTING); + getSdpRecordsAndConnect(); + + return true; + } + + private boolean isPhoneDocked(BluetoothDevice autoConnectDevice) { + // This works only because these broadcast intents are "sticky" + Intent i = registerReceiver(null, new IntentFilter(Intent.ACTION_DOCK_EVENT)); + if (i != null) { + int state = i.getIntExtra(Intent.EXTRA_DOCK_STATE, Intent.EXTRA_DOCK_STATE_UNDOCKED); + if (state != Intent.EXTRA_DOCK_STATE_UNDOCKED) { + BluetoothDevice device = i.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); + if (device != null && autoConnectDevice.equals(device)) { + return true; + } + } + } + return false; + } + /** * Handlers for incoming service calls */ private final IBluetoothHeadset.Stub mBinder = new IBluetoothHeadset.Stub() { - public int getState(BluetoothDevice device) { + public int getState() { enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); - BluetoothRemoteHeadset headset = mRemoteHeadsets.get(device); - if (headset == null) { - return BluetoothHeadset.STATE_DISCONNECTED; - } - return headset.mState; + return mState; } public BluetoothDevice getCurrentHeadset() { enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); - return getCurrentDevice(); + if (mState == BluetoothHeadset.STATE_DISCONNECTED) { + return null; + } + return mRemoteDevice; } public boolean connectHeadset(BluetoothDevice device) { enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission"); synchronized (BluetoothHeadsetService.this) { - try { - return mBluetoothService.connectHeadset(device.getAddress()); - } catch (RemoteException e) { - Log.e(TAG, "connectHeadset"); + if (mState == BluetoothHeadset.STATE_CONNECTED || + mState == BluetoothHeadset.STATE_CONNECTING) { + Log.w(TAG, "connectHeadset(" + device + "): failed: already in state " + + mState + " with headset " + mRemoteDevice); return false; } + if (device == null) { + mAutoConnectQueue = mHeadsetPriority.getSorted(); + return doNextAutoConnect(); + } + mRemoteDevice = device; + setState(BluetoothHeadset.STATE_CONNECTING); + if (mRemoteDevice.getUuids() == null) { + // We might not have got the UUID change notification from + // Bluez yet, if we have just paired. Try after 1.5 secs. + mHandler.sendMessageDelayed( + mHandler.obtainMessage(CONNECT_HEADSET_DELAYED), 1500); + } else { + getSdpRecordsAndConnect(); + } } + return true; } - public void disconnectHeadset(BluetoothDevice device) { + public boolean isConnected(BluetoothDevice device) { + enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); + return mState == BluetoothHeadset.STATE_CONNECTED && mRemoteDevice.equals(device); + } + public void disconnectHeadset() { enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission"); synchronized (BluetoothHeadsetService.this) { - try { - mBluetoothService.disconnectHeadset(device.getAddress()); - } catch (RemoteException e) { - Log.e(TAG, "disconnectHeadset"); + switch (mState) { + case BluetoothHeadset.STATE_CONNECTING: + if (mConnectThread != null) { + // cancel the connection thread + mConnectThread.interrupt(); + try { + mConnectThread.join(); + } catch (InterruptedException e) { + Log.e(TAG, "Connection cancelled twice?", e); + } + mConnectThread = null; + } + if (mHeadset != null) { + mHeadset.disconnect(); + mHeadset = null; + } + setState(BluetoothHeadset.STATE_DISCONNECTED, + BluetoothHeadset.RESULT_CANCELED, + BluetoothHeadset.LOCAL_DISCONNECT); + break; + case BluetoothHeadset.STATE_CONNECTED: + // Send a dummy battery level message to force headset + // out of sniff mode so that it will immediately notice + // the disconnection. We are currently sending it for + // handsfree only. + // TODO: Call hci_conn_enter_active_mode() from + // rfcomm_send_disc() in the kernel instead. + // See http://b/1716887 + if (mHeadsetType == BluetoothHandsfree.TYPE_HANDSFREE) { + mHeadset.sendURC("+CIEV: 7,3"); + } + + if (mHeadset != null) { + mHeadset.disconnect(); + mHeadset = null; + } + setState(BluetoothHeadset.STATE_DISCONNECTED, + BluetoothHeadset.RESULT_CANCELED, + BluetoothHeadset.LOCAL_DISCONNECT); + break; } } } - public boolean isConnected(BluetoothDevice device) { - enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); - - BluetoothRemoteHeadset headset = mRemoteHeadsets.get(device); - return headset != null && headset.mState == BluetoothHeadset.STATE_CONNECTED; - } public boolean startVoiceRecognition() { enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); synchronized (BluetoothHeadsetService.this) { - BluetoothDevice device = getCurrentDevice(); - - if (device == null || - mRemoteHeadsets.get(device).mState != BluetoothHeadset.STATE_CONNECTED) { + if (mState != BluetoothHeadset.STATE_CONNECTED) { return false; } return mBtHandsfree.startVoiceRecognition(); @@ -645,186 +652,162 @@ public class BluetoothHeadsetService extends Service { public boolean stopVoiceRecognition() { enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); synchronized (BluetoothHeadsetService.this) { - BluetoothDevice device = getCurrentDevice(); - - if (device == null || - mRemoteHeadsets.get(device).mState != BluetoothHeadset.STATE_CONNECTED) { + if (mState != BluetoothHeadset.STATE_CONNECTED) { return false; } - return mBtHandsfree.stopVoiceRecognition(); } } - public int getBatteryUsageHint() { - enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); - - return HeadsetBase.getAtInputCount(); - } - public int getPriority(BluetoothDevice device) { + public boolean setPriority(BluetoothDevice device, int priority) { enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, - "Need BLUETOOTH_ADMIN permission"); - synchronized (BluetoothHeadsetService.this) { - int priority = Settings.Secure.getInt(getContentResolver(), - Settings.Secure.getBluetoothHeadsetPriorityKey(device.getAddress()), - BluetoothHeadset.PRIORITY_UNDEFINED); - return priority; + "Need BLUETOOTH_ADMIN permission"); + if (priority < BluetoothHeadset.PRIORITY_OFF) { + return false; } + mHeadsetPriority.set(device, priority); + return true; } + public int getPriority(BluetoothDevice device) { + enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); - public boolean setPriority(BluetoothDevice device, int priority) { - enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, - "Need BLUETOOTH_ADMIN permission"); - synchronized (BluetoothHeadsetService.this) { - if (!BluetoothAdapter.checkBluetoothAddress(device.getAddress())) { - return false; - } - if (priority < BluetoothHeadset.PRIORITY_OFF) { - return false; - } - Settings.Secure.putInt(getContentResolver(), - Settings.Secure.getBluetoothHeadsetPriorityKey(device.getAddress()), - priority); - if (DBG) log("Saved priority " + device + " = " + priority); - return true; - } + return mHeadsetPriority.get(device); } - public boolean createIncomingConnect(BluetoothDevice device) { - synchronized (BluetoothHeadsetService.this) { - HeadsetBase headset; - setState(device, BluetoothHeadset.STATE_CONNECTING); + public int getBatteryUsageHint() { + enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); - IncomingConnectionInfo info = mRemoteHeadsets.get(device).mIncomingInfo; - headset = new HeadsetBase(mPowerManager, mAdapter, device, - info.mSocketFd, info.mRfcommChan, - mConnectedStatusHandler); + return HeadsetBase.getAtInputCount(); + } + }; - mRemoteHeadsets.get(device).mHeadset = headset; + @Override + public void onDestroy() { + super.onDestroy(); + if (DBG) log("Stopping BluetoothHeadsetService"); + unregisterReceiver(mBluetoothReceiver); + mBtHandsfree.onBluetoothDisabled(); + mAg.stop(); + sHasStarted = false; + setState(BluetoothHeadset.STATE_DISCONNECTED, + BluetoothHeadset.RESULT_CANCELED, + BluetoothHeadset.LOCAL_DISCONNECT); + mHeadsetType = BluetoothHandsfree.TYPE_UNKNOWN; + } - mConnectingStatusHandler.obtainMessage(RFCOMM_CONNECTED, headset).sendToTarget(); - return true; - } - } - public boolean acceptIncomingConnect(BluetoothDevice device) { - synchronized (BluetoothHeadsetService.this) { - HeadsetBase headset; - BluetoothRemoteHeadset cachedHeadset = mRemoteHeadsets.get(device); - if (cachedHeadset == null) { - Log.e(TAG, "Cached Headset is Null in acceptIncomingConnect"); - return false; - } - IncomingConnectionInfo info = cachedHeadset.mIncomingInfo; - headset = new HeadsetBase(mPowerManager, mAdapter, device, - info.mSocketFd, info.mRfcommChan, mConnectedStatusHandler); + private class HeadsetPriority { + private HashMap<BluetoothDevice, Integer> mPriority = + new HashMap<BluetoothDevice, Integer>(); - setState(device, BluetoothHeadset.STATE_CONNECTED, BluetoothHeadset.RESULT_SUCCESS); + public synchronized boolean load() { + Set<BluetoothDevice> devices = mAdapter.getBondedDevices(); + if (devices == null) { + return false; // for example, bluetooth is off + } + for (BluetoothDevice device : devices) { + load(device); + } + return true; + } - cachedHeadset.mHeadset = headset; - mBtHandsfree.connectHeadset(headset, cachedHeadset.mHeadsetType); + private synchronized int load(BluetoothDevice device) { + int priority = Settings.Secure.getInt(getContentResolver(), + Settings.Secure.getBluetoothHeadsetPriorityKey(device.getAddress()), + BluetoothHeadset.PRIORITY_UNDEFINED); + mPriority.put(device, new Integer(priority)); + if (DBG) log("Loaded priority " + device + " = " + priority); + return priority; + } - if (DBG) log("Successfully used incoming connection"); - return true; + public synchronized int get(BluetoothDevice device) { + Integer priority = mPriority.get(device); + if (priority == null) { + return load(device); } + return priority.intValue(); } - public boolean cancelConnectThread() { - synchronized (BluetoothHeadsetService.this) { - if (mConnectThread != null) { - // cancel the connection thread - mConnectThread.interrupt(); - try { - mConnectThread.join(); - } catch (InterruptedException e) { - Log.e(TAG, "Connection cancelled twice?", e); - } - mConnectThread = null; - } - return true; + public synchronized void set(BluetoothDevice device, int priority) { + int oldPriority = get(device); + if (oldPriority == priority) { + return; } + mPriority.put(device, new Integer(priority)); + Settings.Secure.putInt(getContentResolver(), + Settings.Secure.getBluetoothHeadsetPriorityKey(device.getAddress()), + priority); + if (DBG) log("Saved priority " + device + " = " + priority); } - public boolean connectHeadsetInternal(BluetoothDevice device) { - synchronized (BluetoothHeadsetService.this) { - BluetoothDevice currDevice = getCurrentDevice(); - if (currDevice == null) { - BluetoothRemoteHeadset headset = new BluetoothRemoteHeadset(); - mRemoteHeadsets.put(device, headset); - - setState(device, BluetoothHeadset.STATE_CONNECTING); - if (device.getUuids() == null) { - // We might not have got the UUID change notification from - // Bluez yet, if we have just paired. Try after 1.5 secs. - Message msg = new Message(); - msg.what = CONNECT_HEADSET_DELAYED; - msg.obj = device; - mHandler.sendMessageDelayed(msg, 1500); - } else { - getSdpRecordsAndConnect(device); - } - return true; - } else { - Log.w(TAG, "connectHeadset(" + device + "): failed: already in state " + - mRemoteHeadsets.get(currDevice).mState + - " with headset " + currDevice); + /** Mark this headset as highest priority */ + public synchronized void bump(BluetoothDevice device) { + int oldPriority = get(device); + int maxPriority = BluetoothHeadset.PRIORITY_AUTO_CONNECT; + + // Find max, not including given address + for (BluetoothDevice d : mPriority.keySet()) { + if (device.equals(d)) continue; + int p = mPriority.get(d).intValue(); + if (p > maxPriority) { + maxPriority = p; + } + } + if (maxPriority >= oldPriority) { + int p = maxPriority + 1; + set(device, p); + if (p >= Integer.MAX_VALUE) { + rebalance(); } - return false; } } - public boolean disconnectHeadsetInternal(BluetoothDevice device) { - synchronized (BluetoothHeadsetService.this) { - BluetoothRemoteHeadset remoteHeadset = mRemoteHeadsets.get(device); - if (remoteHeadset == null) return false; - - if (remoteHeadset.mState == BluetoothHeadset.STATE_CONNECTED) { - // Send a dummy battery level message to force headset - // out of sniff mode so that it will immediately notice - // the disconnection. We are currently sending it for - // handsfree only. - // TODO: Call hci_conn_enter_active_mode() from - // rfcomm_send_disc() in the kernel instead. - // See http://b/1716887 - HeadsetBase headset = remoteHeadset.mHeadset; - if (remoteHeadset.mHeadsetType == BluetoothHandsfree.TYPE_HANDSFREE) { - headset.sendURC("+CIEV: 7,3"); - } + /** shifts all non-zero priorities to be monotonically increasing from + * PRIORITY_AUTO_CONNECT */ + private synchronized void rebalance() { + LinkedList<BluetoothDevice> sorted = getSorted(); + if (DBG) log("Rebalancing " + sorted.size() + " headset priorities"); + + ListIterator<BluetoothDevice> li = sorted.listIterator(sorted.size()); + int priority = BluetoothHeadset.PRIORITY_AUTO_CONNECT; + while (li.hasPrevious()) { + BluetoothDevice device = li.previous(); + set(device, priority); + priority++; + } + } - if (headset != null) { - headset.disconnect(); - headset = null; + /** Get list of headsets sorted by decreasing priority. + * Headsets with priority less than AUTO_CONNECT are not included */ + public synchronized LinkedList<BluetoothDevice> getSorted() { + LinkedList<BluetoothDevice> sorted = new LinkedList<BluetoothDevice>(); + HashMap<BluetoothDevice, Integer> toSort = + new HashMap<BluetoothDevice, Integer>(mPriority); + + // add in sorted order. this could be more efficient. + while (true) { + BluetoothDevice maxDevice = null; + int maxPriority = BluetoothHeadset.PRIORITY_AUTO_CONNECT; + for (BluetoothDevice device : toSort.keySet()) { + int priority = toSort.get(device).intValue(); + if (priority >= maxPriority) { + maxDevice = device; + maxPriority = priority; } - setState(device, BluetoothHeadset.STATE_DISCONNECTED, - BluetoothHeadset.RESULT_CANCELED, - BluetoothHeadset.LOCAL_DISCONNECT); - return true; - } else if (remoteHeadset.mState == BluetoothHeadset.STATE_CONNECTING) { - // The state machine would have canceled the connect thread. - // Just set the state here. - setState(device, BluetoothHeadset.STATE_DISCONNECTED, - BluetoothHeadset.RESULT_CANCELED, - BluetoothHeadset.LOCAL_DISCONNECT); - return true; } - return false; + if (maxDevice == null) { + break; + } + sorted.addLast(maxDevice); + toSort.remove(maxDevice); } - } - }; - - @Override - public void onDestroy() { - super.onDestroy(); - if (DBG) log("Stopping BluetoothHeadsetService"); - unregisterReceiver(mBluetoothReceiver); - mBtHandsfree.onBluetoothDisabled(); - mAg.stop(); - sHasStarted = false; - if (getCurrentDevice() != null) { - setState(getCurrentDevice(), BluetoothHeadset.STATE_DISCONNECTED, - BluetoothHeadset.RESULT_CANCELED, - BluetoothHeadset.LOCAL_DISCONNECT); + return sorted; } } + /** If this property is false, then don't auto-reconnect BT headset */ + private static final String DEBUG_AUTO_RECONNECT = "debug.bt.hshfp.auto_reconnect"; + private boolean debugDontReconnect() { + return (!SystemProperties.getBoolean(DEBUG_AUTO_RECONNECT, true)); + } private static void log(String msg) { Log.d(TAG, msg); diff --git a/phone/src/com/android/phone2/CLIRListPreference.java b/phone/src/com/android/phone2/CLIRListPreference.java index 1b6dca7..5a92375 100644 --- a/phone/src/com/android/phone2/CLIRListPreference.java +++ b/phone/src/com/android/phone2/CLIRListPreference.java @@ -1,9 +1,11 @@ package com.android.phone2; +import static com.android.phone2.TimeConsumingPreferenceActivity.EXCEPTION_ERROR; import static com.android.phone2.TimeConsumingPreferenceActivity.RESPONSE_ERROR; -import com.android.internal.telephony.CommandException; + import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.Phone; +import com.android.internal.telephony.SipPhoneFactory; import android.content.Context; import android.os.AsyncResult; @@ -27,7 +29,7 @@ public class CLIRListPreference extends ListPreference { public CLIRListPreference(Context context, AttributeSet attrs) { super(context, attrs); - phone = PhoneApp.getPhone(); + phone = SipPhoneFactory.getDefaultPhone(); } public CLIRListPreference(Context context) { @@ -131,7 +133,8 @@ public class CLIRListPreference extends ListPreference { clirArray = null; if (ar.exception != null) { if (DBG) Log.d(LOG_TAG, "handleGetCLIRResponse: ar.exception="+ar.exception); - tcpListener.onException(CLIRListPreference.this, (CommandException) ar.exception); + setEnabled(false); + tcpListener.onError(CLIRListPreference.this, EXCEPTION_ERROR); } else if (ar.userObj instanceof Throwable) { tcpListener.onError(CLIRListPreference.this, RESPONSE_ERROR); } else { diff --git a/phone/src/com/android/phone2/CallCard.java b/phone/src/com/android/phone2/CallCard.java index 5c39c5d..47d640c 100755 --- a/phone/src/com/android/phone2/CallCard.java +++ b/phone/src/com/android/phone2/CallCard.java @@ -984,10 +984,6 @@ public class CallCard extends FrameLayout resID = R.string.callFailed_outOfService; break; - case UNOBTAINABLE_NUMBER: - resID = R.string.callFailed_unobtainable_number; - break; - default: resID = R.string.card_title_call_ended; break; diff --git a/phone/src/com/android/phone2/CallFeaturesSetting.java b/phone/src/com/android/phone2/CallFeaturesSetting.java index 9f9f2d8..b98b576 100644 --- a/phone/src/com/android/phone2/CallFeaturesSetting.java +++ b/phone/src/com/android/phone2/CallFeaturesSetting.java @@ -49,6 +49,7 @@ import android.widget.ListAdapter; import com.android.internal.telephony.CallForwardInfo; import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.Phone; +import com.android.internal.telephony.SipPhoneFactory; import com.android.internal.telephony.cdma.TtyIntent; import java.util.Collection; @@ -1303,7 +1304,7 @@ public class CallFeaturesSetting extends PreferenceActivity protected void onCreate(Bundle icicle) { super.onCreate(icicle); if (DBG) log("Creating activity"); - mPhone = PhoneApp.getPhone(); + mPhone = SipPhoneFactory.getDefaultPhone(); addPreferencesFromResource(R.xml.call_feature_setting); diff --git a/phone/src/com/android/phone2/CallForwardEditPreference.java b/phone/src/com/android/phone2/CallForwardEditPreference.java index 41688bf..b2768b8 100644 --- a/phone/src/com/android/phone2/CallForwardEditPreference.java +++ b/phone/src/com/android/phone2/CallForwardEditPreference.java @@ -1,9 +1,9 @@ package com.android.phone2; import com.android.internal.telephony.CallForwardInfo; -import com.android.internal.telephony.CommandException; import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.Phone; +import com.android.internal.telephony.SipPhoneFactory; import android.app.AlertDialog; import android.content.Context; @@ -16,6 +16,7 @@ import android.text.TextUtils; import android.util.AttributeSet; import android.util.Log; +import static com.android.phone2.TimeConsumingPreferenceActivity.EXCEPTION_ERROR; import static com.android.phone2.TimeConsumingPreferenceActivity.RESPONSE_ERROR; public class CallForwardEditPreference extends EditPhoneNumberPreference { @@ -35,7 +36,7 @@ public class CallForwardEditPreference extends EditPhoneNumberPreference { public CallForwardEditPreference(Context context, AttributeSet attrs) { super(context, attrs); - phone = PhoneApp.getPhone(); + phone = SipPhoneFactory.getDefaultPhone(); mSummaryOnTemplate = this.getSummaryOn(); TypedArray a = context.obtainStyledAttributes(attrs, @@ -177,8 +178,8 @@ public class CallForwardEditPreference extends EditPhoneNumberPreference { callForwardInfo = null; if (ar.exception != null) { if (DBG) Log.d(LOG_TAG, "handleGetCFResponse: ar.exception=" + ar.exception); - tcpListener.onException(CallForwardEditPreference.this, - (CommandException) ar.exception); + setEnabled(false); + tcpListener.onError(CallForwardEditPreference.this, EXCEPTION_ERROR); } else { if (ar.userObj instanceof Throwable) { tcpListener.onError(CallForwardEditPreference.this, RESPONSE_ERROR); diff --git a/phone/src/com/android/phone2/CallNotifier.java b/phone/src/com/android/phone2/CallNotifier.java index 5d20895..9df72ab 100755 --- a/phone/src/com/android/phone2/CallNotifier.java +++ b/phone/src/com/android/phone2/CallNotifier.java @@ -155,7 +155,7 @@ public class CallNotifier extends Handler private static final int TONE_RELATIVE_VOLUME_SIGNALINFO = 80; private Call.State mPreviousCdmaCallState; - private boolean mVoicePrivacyState = false; + private boolean mCdmaVoicePrivacyState = false; private boolean mIsCdmaRedialCall = false; // Emergency call tone and vibrate: @@ -180,19 +180,39 @@ public class CallNotifier extends Handler mAudioManager = (AudioManager) mPhone.getContext().getSystemService(Context.AUDIO_SERVICE); - registerForNotifications(); - - // Instantiate the ToneGenerator for SignalInfo and CallWaiting - // TODO: We probably don't need the mSignalInfoToneGenerator instance - // around forever. Need to change it so as to create a ToneGenerator instance only - // when a tone is being played and releases it after its done playing. - try { - mSignalInfoToneGenerator = new ToneGenerator(AudioManager.STREAM_VOICE_CALL, - TONE_RELATIVE_VOLUME_SIGNALINFO); - } catch (RuntimeException e) { - Log.w(LOG_TAG, "CallNotifier: Exception caught while creating " + - "mSignalInfoToneGenerator: " + e); - mSignalInfoToneGenerator = null; + mPhone.registerForNewRingingConnection(this, PHONE_NEW_RINGING_CONNECTION, null); + mPhone.registerForPreciseCallStateChanged(this, PHONE_STATE_CHANGED, null); + mPhone.registerForDisconnect(this, PHONE_DISCONNECT, null); + mPhone.registerForUnknownConnection(this, PHONE_UNKNOWN_CONNECTION_APPEARED, null); + mPhone.registerForIncomingRing(this, PHONE_INCOMING_RING, null); + + if (mPhone.getPhoneType() == Phone.PHONE_TYPE_CDMA) { + mPhone.registerForCdmaOtaStatusChange(this, EVENT_OTA_PROVISION_CHANGE, null); + + if (DBG) log("Registering for Call Waiting, Signal and Display Info."); + mPhone.registerForCallWaiting(this, PHONE_CDMA_CALL_WAITING, null); + mPhone.registerForDisplayInfo(this, PHONE_STATE_DISPLAYINFO, null); + mPhone.registerForSignalInfo(this, PHONE_STATE_SIGNALINFO, null); + mPhone.registerForInCallVoicePrivacyOn(this, PHONE_ENHANCED_VP_ON, null); + mPhone.registerForInCallVoicePrivacyOff(this, PHONE_ENHANCED_VP_OFF, null); + + // Instantiate the ToneGenerator for SignalInfo and CallWaiting + // TODO: We probably don't need the mSignalInfoToneGenerator instance + // around forever. Need to change it so as to create a ToneGenerator instance only + // when a tone is being played and releases it after its done playing. + try { + mSignalInfoToneGenerator = new ToneGenerator(AudioManager.STREAM_VOICE_CALL, + TONE_RELATIVE_VOLUME_SIGNALINFO); + } catch (RuntimeException e) { + Log.w(LOG_TAG, "CallNotifier: Exception caught while creating " + + "mSignalInfoToneGenerator: " + e); + mSignalInfoToneGenerator = null; + } + } + + if (mPhone.getPhoneType() == Phone.PHONE_TYPE_GSM) { + mPhone.registerForRingbackTone(this, PHONE_RINGBACK_TONE, null); + mPhone.registerForResendIncallMute(this, PHONE_RESEND_MUTE, null); } mRinger = ringer; @@ -308,10 +328,10 @@ public class CallNotifier extends Handler case PHONE_ENHANCED_VP_ON: if (DBG) log("PHONE_ENHANCED_VP_ON..."); - if (!mVoicePrivacyState) { + if (!mCdmaVoicePrivacyState) { int toneToPlay = InCallTonePlayer.TONE_VOICE_PRIVACY; new InCallTonePlayer(toneToPlay).start(); - mVoicePrivacyState = true; + mCdmaVoicePrivacyState = true; // Update the VP icon: NotificationMgr.getDefault().updateInCallNotification(); } @@ -319,10 +339,10 @@ public class CallNotifier extends Handler case PHONE_ENHANCED_VP_OFF: if (DBG) log("PHONE_ENHANCED_VP_OFF..."); - if (mVoicePrivacyState) { + if (mCdmaVoicePrivacyState) { int toneToPlay = InCallTonePlayer.TONE_VOICE_PRIVACY; new InCallTonePlayer(toneToPlay).start(); - mVoicePrivacyState = false; + mCdmaVoicePrivacyState = false; // Update the VP icon: NotificationMgr.getDefault().updateInCallNotification(); } @@ -369,7 +389,7 @@ public class CallNotifier extends Handler } // Incoming calls are totally ignored if OTA call is active - if (TelephonyCapabilities.supportsOtasp(mPhone)) { + if (mPhone.getPhoneType() == Phone.PHONE_TYPE_CDMA) { boolean activateState = (mApplication.cdmaOtaScreenState.otaScreenState == OtaUtils.CdmaOtaScreenState.OtaScreenState.OTA_STATUS_ACTIVATION); boolean dialogState = (mApplication.cdmaOtaScreenState.otaScreenState @@ -389,7 +409,9 @@ public class CallNotifier extends Handler if (c != null && c.isRinging()) { // Stop any signalInfo tone being played on receiving a Call - stopSignalInfoTone(); + if (mPhone.getPhoneType() == Phone.PHONE_TYPE_CDMA) { + stopSignalInfoTone(); + } Call.State state = c.getState(); // State will be either INCOMING or WAITING. @@ -719,26 +741,36 @@ public class CallNotifier extends Handler mPhone.unregisterForInCallVoicePrivacyOff(this); // Register all events new to the new active phone - registerForNotifications(); - } - - private void registerForNotifications() { mPhone.registerForNewRingingConnection(this, PHONE_NEW_RINGING_CONNECTION, null); mPhone.registerForPreciseCallStateChanged(this, PHONE_STATE_CHANGED, null); mPhone.registerForDisconnect(this, PHONE_DISCONNECT, null); mPhone.registerForUnknownConnection(this, PHONE_UNKNOWN_CONNECTION_APPEARED, null); mPhone.registerForIncomingRing(this, PHONE_INCOMING_RING, null); - - if (TelephonyCapabilities.supportsOtasp(mPhone)) { + if (mPhone.getPhoneType() == Phone.PHONE_TYPE_CDMA) { + if (DBG) log("Registering for Call Waiting, Signal and Display Info."); + mPhone.registerForCallWaiting(this, PHONE_CDMA_CALL_WAITING, null); + mPhone.registerForDisplayInfo(this, PHONE_STATE_DISPLAYINFO, null); + mPhone.registerForSignalInfo(this, PHONE_STATE_SIGNALINFO, null); mPhone.registerForCdmaOtaStatusChange(this, EVENT_OTA_PROVISION_CHANGE, null); + + // Instantiate the ToneGenerator for SignalInfo + try { + mSignalInfoToneGenerator = new ToneGenerator(AudioManager.STREAM_VOICE_CALL, + TONE_RELATIVE_VOLUME_SIGNALINFO); + } catch (RuntimeException e) { + Log.w(LOG_TAG, "CallNotifier: Exception caught while creating " + + "mSignalInfoToneGenerator: " + e); + mSignalInfoToneGenerator = null; + } + + mPhone.registerForInCallVoicePrivacyOn(this, PHONE_ENHANCED_VP_ON, null); + mPhone.registerForInCallVoicePrivacyOff(this, PHONE_ENHANCED_VP_OFF, null); + } + + if (mPhone.getPhoneType() == Phone.PHONE_TYPE_GSM) { + mPhone.registerForRingbackTone(this, PHONE_RINGBACK_TONE, null); + mPhone.registerForResendIncallMute(this, PHONE_RESEND_MUTE, null); } - mPhone.registerForCallWaiting(this, PHONE_CDMA_CALL_WAITING, null); - mPhone.registerForDisplayInfo(this, PHONE_STATE_DISPLAYINFO, null); - mPhone.registerForSignalInfo(this, PHONE_STATE_SIGNALINFO, null); - mPhone.registerForInCallVoicePrivacyOn(this, PHONE_ENHANCED_VP_ON, null); - mPhone.registerForInCallVoicePrivacyOff(this, PHONE_ENHANCED_VP_OFF, null); - mPhone.registerForRingbackTone(this, PHONE_RINGBACK_TONE, null); - mPhone.registerForResendIncallMute(this, PHONE_RESEND_MUTE, null); } /** @@ -791,7 +823,7 @@ public class CallNotifier extends Handler private void onDisconnect(AsyncResult r) { if (VDBG) log("onDisconnect()... phone state: " + mPhone.getState()); - mVoicePrivacyState = false; + mCdmaVoicePrivacyState = false; int autoretrySetting = 0; if (mPhone.getPhoneType() == Phone.PHONE_TYPE_CDMA) { autoretrySetting = android.provider.Settings.System.getInt(mPhone.getContext(). @@ -802,10 +834,10 @@ public class CallNotifier extends Handler PhoneUtils.setAudioControlState(PhoneUtils.AUDIO_IDLE); } - // Stop any signalInfo tone being played when a call gets ended - stopSignalInfoTone(); - if (mPhone.getPhoneType() == Phone.PHONE_TYPE_CDMA) { + // Stop any signalInfo tone being played when a call gets ended + stopSignalInfoTone(); + // Resetting the CdmaPhoneCallState members mApplication.cdmaPhoneCallState.resetCdmaPhoneCallState(); @@ -885,9 +917,6 @@ public class CallNotifier extends Handler } else if (cause == Connection.DisconnectCause.OUT_OF_SERVICE) { if (DBG) log("- need to play OUT OF SERVICE tone!"); toneToPlay = InCallTonePlayer.TONE_OUT_OF_SERVICE; - } else if (cause == Connection.DisconnectCause.UNOBTAINABLE_NUMBER) { - if (DBG) log("- need to play TONE_UNOBTAINABLE_NUMBER tone!"); - toneToPlay = InCallTonePlayer.TONE_UNOBTAINABLE_NUMBER; } else if (cause == Connection.DisconnectCause.ERROR_UNSPECIFIED) { if (DBG) log("- DisconnectCause is ERROR_UNSPECIFIED: play TONE_CALL_ENDED!"); toneToPlay = InCallTonePlayer.TONE_CALL_ENDED; @@ -972,30 +1001,26 @@ public class CallNotifier extends Handler } } - // On some devices, to avoid accidental redialing of - // emergency numbers, we *never* log emergency calls to - // the Call Log. (This behavior is set on a per-product - // basis, based on carrier requirements.) - final boolean okToLogEmergencyNumber = - mApplication.getResources().getBoolean( - R.bool.allow_emergency_numbers_in_call_log); + // To prevent accidental redial of emergency numbers + // (carrier requirement) the quickest solution is to + // not log the emergency number. We gate on CDMA + // (ugly) when we actually mean carrier X. + // TODO: Clean this up and come up with a unified strategy. + final boolean shouldNotlogEmergencyNumber = + (mPhone.getPhoneType() == Phone.PHONE_TYPE_CDMA); - // Don't call isOtaSpNumber() on phones that don't support OTASP. - final boolean isOtaspNumber = TelephonyCapabilities.supportsOtasp(mPhone) + // Don't call isOtaSpNumber on GSM phones. + final boolean isOtaNumber = (mPhone.getPhoneType() == Phone.PHONE_TYPE_CDMA) && mPhone.isOtaSpNumber(number); final boolean isEmergencyNumber = PhoneNumberUtils.isEmergencyNumber(number); - // Don't log emergency numbers if the device doesn't allow it, - // and never log OTASP calls. - final boolean okToLogThisCall = - (!isEmergencyNumber || okToLogEmergencyNumber) - && !isOtaspNumber; - - if (okToLogThisCall) { + // Don't put OTA or CDMA Emergency calls into call log + if (!(isOtaNumber || isEmergencyNumber && shouldNotlogEmergencyNumber)) { CallLogAsync.AddCallArgs args = new CallLogAsync.AddCallArgs( mPhone.getContext(), ci, logNumber, presentation, callLogType, date, duration); + mCallLog.addCall(args); } } @@ -1052,7 +1077,7 @@ public class CallNotifier extends Handler if (autoretrySetting == InCallScreen.AUTO_RETRY_ON) { // TODO: (Moto): The contact reference data may need to be stored and use // here when redialing a call. For now, pass in NULL as the URI parameter. - PhoneUtils.placeCall(mPhone.getContext(), mPhone, number, null, false, null); + PhoneUtils.placeCall(mPhone, number, null); mIsCdmaRedialCall = true; } else { mIsCdmaRedialCall = false; @@ -1169,7 +1194,6 @@ public class CallNotifier extends Handler public static final int TONE_REDIAL = 11; public static final int TONE_OTA_CALL_END = 12; public static final int TONE_RING_BACK = 13; - public static final int TONE_UNOBTAINABLE_NUMBER = 14; // The tone volume relative to other sounds in the stream private static final int TONE_RELATIVE_VOLUME_HIPRI = 80; @@ -1283,11 +1307,6 @@ public class CallNotifier extends Handler // Call ring back tone is stopped by stopTone() method toneLengthMillis = Integer.MAX_VALUE - TONE_TIMEOUT_BUFFER; break; - case TONE_UNOBTAINABLE_NUMBER: - toneType = ToneGenerator.TONE_SUP_ERROR; - toneVolume = TONE_RELATIVE_VOLUME_HIPRI; - toneLengthMillis = 4000; - break; default: throw new IllegalArgumentException("Bad toneId: " + mToneId); } @@ -1634,10 +1653,10 @@ public class CallNotifier extends Handler } /** - * Return the private variable mVoicePrivacyState. + * Return the private variable mCdmaVoicePrivacyState. */ - /* package */ boolean getVoicePrivacyState() { - return mVoicePrivacyState; + /* package */ boolean getCdmaVoicePrivacyState() { + return mCdmaVoicePrivacyState; } /** diff --git a/phone/src/com/android/phone2/CallWaitingCheckBoxPreference.java b/phone/src/com/android/phone2/CallWaitingCheckBoxPreference.java index f03d01e..7223ca4 100644 --- a/phone/src/com/android/phone2/CallWaitingCheckBoxPreference.java +++ b/phone/src/com/android/phone2/CallWaitingCheckBoxPreference.java @@ -1,10 +1,7 @@ package com.android.phone2; -import com.android.internal.telephony.CommandException; -import com.android.internal.telephony.Phone; - +import static com.android.phone2.TimeConsumingPreferenceActivity.EXCEPTION_ERROR; import static com.android.phone2.TimeConsumingPreferenceActivity.RESPONSE_ERROR; - import android.content.Context; import android.os.AsyncResult; import android.os.Handler; @@ -14,6 +11,7 @@ import android.util.AttributeSet; import android.util.Log; import com.android.internal.telephony.Phone; +import com.android.internal.telephony.SipPhoneFactory; public class CallWaitingCheckBoxPreference extends CheckBoxPreference { private static final String LOG_TAG = "CallWaitingCheckBoxPreference"; @@ -26,7 +24,7 @@ public class CallWaitingCheckBoxPreference extends CheckBoxPreference { public CallWaitingCheckBoxPreference(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); - phone = PhoneApp.getPhone(); + phone = SipPhoneFactory.getDefaultPhone(); } public CallWaitingCheckBoxPreference(Context context, AttributeSet attrs) { @@ -88,13 +86,9 @@ public class CallWaitingCheckBoxPreference extends CheckBoxPreference { } if (ar.exception != null) { - if (DBG) { - Log.d(LOG_TAG, "handleGetCallWaitingResponse: ar.exception=" + ar.exception); - } - if (tcpListener != null) { - tcpListener.onException(CallWaitingCheckBoxPreference.this, - (CommandException)ar.exception); - } + if (DBG) Log.d(LOG_TAG, "handleGetCallWaitingResponse: ar.exception=" + ar.exception); + setEnabled(false); + if (tcpListener != null) tcpListener.onError(CallWaitingCheckBoxPreference.this, EXCEPTION_ERROR); } else if (ar.userObj instanceof Throwable) { if (tcpListener != null) tcpListener.onError(CallWaitingCheckBoxPreference.this, RESPONSE_ERROR); } else { diff --git a/phone/src/com/android/phone2/CdmaCallOptions.java b/phone/src/com/android/phone2/CdmaCallOptions.java index 3cdf86b..d7de04f 100644 --- a/phone/src/com/android/phone2/CdmaCallOptions.java +++ b/phone/src/com/android/phone2/CdmaCallOptions.java @@ -1,6 +1,7 @@ package com.android.phone2; import com.android.internal.telephony.Phone; +import com.android.internal.telephony.SipPhoneFactory; import android.content.DialogInterface; import android.os.AsyncResult; @@ -27,7 +28,7 @@ public class CdmaCallOptions extends PreferenceActivity { addPreferencesFromResource(R.xml.cdma_call_options); mButtonVoicePrivacy = (CheckBoxPreference) findPreference(BUTTON_VP_KEY); - if (PhoneApp.getPhone().getPhoneType() != Phone.PHONE_TYPE_CDMA) { + if (SipPhoneFactory.getDefaultPhone().getPhoneType() != Phone.PHONE_TYPE_CDMA) { //disable the entire screen getPreferenceScreen().setEnabled(false); } diff --git a/phone/src/com/android/phone2/CdmaOptions.java b/phone/src/com/android/phone2/CdmaOptions.java index ec09133..c40b528 100644 --- a/phone/src/com/android/phone2/CdmaOptions.java +++ b/phone/src/com/android/phone2/CdmaOptions.java @@ -16,100 +16,42 @@ package com.android.phone2; -import android.os.SystemProperties; +import android.os.Bundle; import android.preference.Preference; import android.preference.PreferenceActivity; import android.preference.PreferenceScreen; -import android.text.TextUtils; + +import com.android.internal.telephony.Phone; +import com.android.internal.telephony.SipPhoneFactory; /** * List of Phone-specific settings screens. */ -public class CdmaOptions { - private static final String LOG_TAG = "CdmaOptions"; - - private CdmaSystemSelectListPreference mButtonCdmaSystemSelect; - private CdmaSubscriptionListPreference mButtonCdmaSubscription; - - private static final String BUTTON_CDMA_SYSTEM_SELECT_KEY = "cdma_system_select_key"; - private static final String BUTTON_CDMA_SUBSCRIPTION_KEY = "cdma_subscription_key"; +public class CdmaOptions extends PreferenceActivity { - private PreferenceActivity mPrefActivity; - private PreferenceScreen mPrefScreen; - - public CdmaOptions(PreferenceActivity prefActivity, PreferenceScreen prefScreen) { - mPrefActivity = prefActivity; - mPrefScreen = prefScreen; - create(); - } + private CdmaRoamingListPreference mButtonCdmaRoam; - protected void create() { - mPrefActivity.addPreferencesFromResource(R.xml.cdma_options); + private static final String BUTTON_CDMA_ROAMING_KEY = "cdma_roaming_mode_key"; - mButtonCdmaSystemSelect = (CdmaSystemSelectListPreference)mPrefScreen - .findPreference(BUTTON_CDMA_SYSTEM_SELECT_KEY); + @Override + protected void onCreate(Bundle icicle) { + super.onCreate(icicle); - mButtonCdmaSubscription = (CdmaSubscriptionListPreference)mPrefScreen - .findPreference(BUTTON_CDMA_SUBSCRIPTION_KEY); + addPreferencesFromResource(R.xml.cdma_options); - mButtonCdmaSystemSelect.setEnabled(true); - if(deviceSupportsNvAndRuim()) { - log("Both NV and Ruim supported, ENABLE subscription type selection"); - mButtonCdmaSubscription.setEnabled(true); - } else { - log("Both NV and Ruim NOT supported, REMOVE subscription type selection"); - mPrefScreen.removePreference(mPrefScreen - .findPreference(BUTTON_CDMA_SUBSCRIPTION_KEY)); + PreferenceScreen prefSet = getPreferenceScreen(); + mButtonCdmaRoam = + (CdmaRoamingListPreference) prefSet.findPreference(BUTTON_CDMA_ROAMING_KEY); + if (SipPhoneFactory.getDefaultPhone().getPhoneType() != Phone.PHONE_TYPE_CDMA) { + mButtonCdmaRoam.setEnabled(false); } } - private boolean deviceSupportsNvAndRuim() { - // retrieve the list of subscription types supported by device. - String subscriptionsSupported = SystemProperties.get("ril.subscription.types"); - boolean nvSupported = false; - boolean ruimSupported = false; - - log("deviceSupportsnvAnRum: prop=" + subscriptionsSupported); - if (!TextUtils.isEmpty(subscriptionsSupported)) { - // Searches through the comma-separated list for a match for "NV" - // and "RUIM" to update nvSupported and ruimSupported. - for (String subscriptionType : subscriptionsSupported.split(",")) { - subscriptionType = subscriptionType.trim(); - if (subscriptionType.equalsIgnoreCase("NV")) { - nvSupported = true; - } - if (subscriptionType.equalsIgnoreCase("RUIM")) { - ruimSupported = true; - } - } - } - - log("deviceSupportsnvAnRum: nvSupported=" + nvSupported + - " ruimSupported=" + ruimSupported); - return (nvSupported && ruimSupported); - } - - public boolean preferenceTreeClick(Preference preference) { - if (preference.getKey().equals(BUTTON_CDMA_SYSTEM_SELECT_KEY)) { - log("preferenceTreeClick: return BUTTON_CDMA_ROAMING_KEY true"); - return true; - } - if (preference.getKey().equals(BUTTON_CDMA_SUBSCRIPTION_KEY)) { - log("preferenceTreeClick: return CDMA_SUBSCRIPTION_KEY true"); + @Override + public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) { + if (preference.getKey().equals(BUTTON_CDMA_ROAMING_KEY)) { return true; } return false; } - - public void showDialog(Preference preference) { - if (preference.getKey().equals(BUTTON_CDMA_SYSTEM_SELECT_KEY)) { - mButtonCdmaSystemSelect.showDialog(null); - } else if (preference.getKey().equals(BUTTON_CDMA_SUBSCRIPTION_KEY)) { - mButtonCdmaSubscription.showDialog(null); - } - } - - protected void log(String s) { - android.util.Log.d(LOG_TAG, s); - } } diff --git a/phone/src/com/android/phone2/CdmaSystemSelectListPreference.java b/phone/src/com/android/phone2/CdmaRoamingListPreference.java index 055981c..c5e4cdd 100644 --- a/phone/src/com/android/phone2/CdmaSystemSelectListPreference.java +++ b/phone/src/com/android/phone2/CdmaRoamingListPreference.java @@ -28,9 +28,10 @@ import android.util.AttributeSet; import android.util.Log; import com.android.internal.telephony.Phone; +import com.android.internal.telephony.SipPhoneFactory; import com.android.internal.telephony.TelephonyProperties; -public class CdmaSystemSelectListPreference extends ListPreference { +public class CdmaRoamingListPreference extends ListPreference { private static final String LOG_TAG = "CdmaRoamingListPreference"; private static final boolean DBG = true; @@ -38,16 +39,16 @@ public class CdmaSystemSelectListPreference extends ListPreference { private Phone mPhone; private MyHandler mHandler = new MyHandler();; - public CdmaSystemSelectListPreference(Context context, AttributeSet attrs) { + public CdmaRoamingListPreference(Context context, AttributeSet attrs) { super(context, attrs); - mPhone = PhoneApp.getPhone(); + mPhone = SipPhoneFactory.getDefaultPhone(); mHandler = new MyHandler(); mPhone.queryCdmaRoamingPreference( mHandler.obtainMessage(MyHandler.MESSAGE_GET_ROAMING_PREFERENCE)); } - public CdmaSystemSelectListPreference(Context context) { + public CdmaRoamingListPreference(Context context) { this(context, null); } diff --git a/phone/src/com/android/phone2/CdmaSubscriptionListPreference.java b/phone/src/com/android/phone2/CdmaSubscriptionListPreference.java deleted file mode 100644 index c2ba664..0000000 --- a/phone/src/com/android/phone2/CdmaSubscriptionListPreference.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.phone2; - -import android.content.Context; -import android.os.AsyncResult; -import android.os.Bundle; -import android.os.Handler; -import android.os.Message; -import android.preference.ListPreference; -import android.provider.Settings.Secure; -import android.util.AttributeSet; -import android.util.Log; - -import com.android.internal.telephony.Phone; -import com.android.internal.telephony.PhoneFactory; - -public class CdmaSubscriptionListPreference extends ListPreference { - - private static final String LOG_TAG = "CdmaSubscriptionListPreference"; - - // Used for CDMA subscription mode - private static final int CDMA_SUBSCRIPTION_RUIM_SIM = 0; - private static final int CDMA_SUBSCRIPTION_NV = 1; - - //preferredSubscriptionMode 0 - RUIM/SIM, preferred - // 1 - NV - static final int preferredSubscriptionMode = CDMA_SUBSCRIPTION_NV; - - private Phone mPhone; - private CdmaSubscriptionButtonHandler mHandler; - - public CdmaSubscriptionListPreference(Context context, AttributeSet attrs) { - super(context, attrs); - - mPhone = PhoneFactory.getDefaultPhone(); - mHandler = new CdmaSubscriptionButtonHandler(); - setCurrentCdmaSubscriptionModeValue(); - } - - private void setCurrentCdmaSubscriptionModeValue() { - int cdmaSubscriptionMode = Secure.getInt(mPhone.getContext().getContentResolver(), - android.provider.Settings.Secure.CDMA_SUBSCRIPTION_MODE, preferredSubscriptionMode); - setValue(Integer.toString(cdmaSubscriptionMode)); - } - - public CdmaSubscriptionListPreference(Context context) { - this(context, null); - } - - @Override - protected void showDialog(Bundle state) { - setCurrentCdmaSubscriptionModeValue(); - - super.showDialog(state); - } - - @Override - protected void onDialogClosed(boolean positiveResult) { - super.onDialogClosed(positiveResult); - - if (!positiveResult) { - //The button was dismissed - no need to set new value - return; - } - - int buttonCdmaSubscriptionMode = Integer.valueOf(getValue()).intValue(); - Log.d(LOG_TAG, "Setting new value " + buttonCdmaSubscriptionMode); - int statusCdmaSubscriptionMode; - switch(buttonCdmaSubscriptionMode) { - case CDMA_SUBSCRIPTION_NV: - statusCdmaSubscriptionMode = Phone.CDMA_SUBSCRIPTION_NV; - break; - case CDMA_SUBSCRIPTION_RUIM_SIM: - statusCdmaSubscriptionMode = Phone.CDMA_SUBSCRIPTION_RUIM_SIM; - break; - default: - statusCdmaSubscriptionMode = Phone.PREFERRED_CDMA_SUBSCRIPTION; - } - - // Set the CDMA subscription mode, when mode has been successfully changed - // handleSetCdmaSubscriptionMode will be invoked and the value saved. - mPhone.setCdmaSubscription(statusCdmaSubscriptionMode, mHandler - .obtainMessage(CdmaSubscriptionButtonHandler.MESSAGE_SET_CDMA_SUBSCRIPTION, - getValue())); - - } - - private class CdmaSubscriptionButtonHandler extends Handler { - - private static final int MESSAGE_SET_CDMA_SUBSCRIPTION = 0; - - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case MESSAGE_SET_CDMA_SUBSCRIPTION: - handleSetCdmaSubscriptionMode(msg); - break; - } - } - - private void handleSetCdmaSubscriptionMode(Message msg) { - mPhone = PhoneFactory.getDefaultPhone(); - AsyncResult ar = (AsyncResult) msg.obj; - - if (ar.exception == null) { - // Get the original string entered by the user - int cdmaSubscriptionMode = Integer.valueOf((String) ar.userObj).intValue(); - Secure.putInt(mPhone.getContext().getContentResolver(), - Secure.CDMA_SUBSCRIPTION_MODE, - cdmaSubscriptionMode ); - } else { - Log.e(LOG_TAG, "Setting Cdma subscription source failed"); - } - } - } -} diff --git a/phone/src/com/android/phone2/CdmaVoicePrivacyCheckBoxPreference.java b/phone/src/com/android/phone2/CdmaVoicePrivacyCheckBoxPreference.java index 9714970..610c6dd 100644 --- a/phone/src/com/android/phone2/CdmaVoicePrivacyCheckBoxPreference.java +++ b/phone/src/com/android/phone2/CdmaVoicePrivacyCheckBoxPreference.java @@ -1,7 +1,7 @@ package com.android.phone2; import com.android.internal.telephony.Phone; - +import com.android.internal.telephony.SipPhoneFactory; import android.content.Context; import android.os.AsyncResult; import android.os.Handler; @@ -20,7 +20,7 @@ public class CdmaVoicePrivacyCheckBoxPreference extends CheckBoxPreference { public CdmaVoicePrivacyCheckBoxPreference(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); - phone = PhoneApp.getPhone(); + phone = SipPhoneFactory.getDefaultPhone(); phone.getEnhancedVoicePrivacy(mHandler.obtainMessage(MyHandler.MESSAGE_GET_VP)); } diff --git a/phone/src/com/android/phone2/CellBroadcastSms.java b/phone/src/com/android/phone2/CellBroadcastSms.java index 7114c78..ba7af14 100644 --- a/phone/src/com/android/phone2/CellBroadcastSms.java +++ b/phone/src/com/android/phone2/CellBroadcastSms.java @@ -24,6 +24,7 @@ import android.preference.Preference; import android.preference.PreferenceScreen; import android.preference.PreferenceActivity; import com.android.internal.telephony.Phone; +import com.android.internal.telephony.SipPhoneFactory; import com.android.internal.telephony.RILConstants; import android.os.AsyncResult; @@ -337,7 +338,7 @@ public class CellBroadcastSms extends PreferenceActivity addPreferencesFromResource(R.xml.cell_broadcast_sms); - mPhone = PhoneApp.getPhone(); + mPhone = SipPhoneFactory.getDefaultPhone(); mHandler = new MyHandler(); PreferenceScreen prefSet = getPreferenceScreen(); diff --git a/phone/src/com/android/phone2/ChangeIccPinScreen.java b/phone/src/com/android/phone2/ChangeIccPinScreen.java index e890321..cae3441 100644 --- a/phone/src/com/android/phone2/ChangeIccPinScreen.java +++ b/phone/src/com/android/phone2/ChangeIccPinScreen.java @@ -37,6 +37,7 @@ import android.widget.Toast; import com.android.internal.telephony.CommandException; import com.android.internal.telephony.IccCard; import com.android.internal.telephony.Phone; +import com.android.internal.telephony.SipPhoneFactory; /** * "Change ICC PIN" UI for the Phone app. @@ -91,7 +92,7 @@ public class ChangeIccPinScreen extends Activity { public void onCreate(Bundle icicle) { super.onCreate(icicle); - mPhone = PhoneApp.getPhone(); + mPhone = SipPhoneFactory.getDefaultPhone(); resolveIntent(); diff --git a/phone/src/com/android/phone2/DTMFTwelveKeyDialer.java b/phone/src/com/android/phone2/DTMFTwelveKeyDialer.java index 0947316..da2313b 100755 --- a/phone/src/com/android/phone2/DTMFTwelveKeyDialer.java +++ b/phone/src/com/android/phone2/DTMFTwelveKeyDialer.java @@ -20,6 +20,7 @@ import android.media.AudioManager; import android.media.ToneGenerator; import android.os.Handler; import android.os.Message; +import android.os.SystemProperties; import android.provider.Settings; import android.telephony.PhoneNumberUtils; import android.text.Editable; @@ -61,11 +62,11 @@ public class DTMFTwelveKeyDialer implements private ToneGenerator mToneGenerator; private Object mToneGeneratorLock = new Object(); - // indicate if we want to enable the local tone playback. - private boolean mLocalToneEnabled; + // indicate if we want to enable the DTMF tone playback. + private boolean mDTMFToneEnabled; - // indicates that we are using automatically shortened DTMF tones - boolean mShortTone; + // DTMF tone type + private int mDTMFToneType; // indicate if the confirmation from TelephonyFW is pending. private boolean mDTMFBurstCnfPending = false; @@ -404,7 +405,7 @@ public class DTMFTwelveKeyDialer implements if (DBG) log("DTMFTwelveKeyDialer constructor... this = " + this); mInCallScreen = parent; - mPhone = PhoneApp.getPhone(); + mPhone = PhoneApp.getInstance().phone; // The passed-in DTMFTwelveKeyDialerView *should* always be // non-null, now that the in-call UI uses only portrait mode. @@ -449,6 +450,7 @@ public class DTMFTwelveKeyDialer implements mDialerDrawer.setOnDrawerOpenListener(this); mDialerDrawer.setOnDrawerCloseListener(this); } + } /** @@ -465,10 +467,12 @@ public class DTMFTwelveKeyDialer implements mDialerDrawer.setOnDrawerOpenListener(null); mDialerDrawer.setOnDrawerCloseListener(null); } - mHandler.removeMessages(DTMF_SEND_CNF); - synchronized (mDTMFQueue) { - mDTMFBurstCnfPending = false; - mDTMFQueue.clear(); + if (mPhone.getPhoneType() == Phone.PHONE_TYPE_CDMA) { + mHandler.removeMessages(DTMF_SEND_CNF); + synchronized (mDTMFQueue) { + mDTMFBurstCnfPending = false; + mDTMFQueue.clear(); + } } closeDialer(false); } @@ -509,17 +513,17 @@ public class DTMFTwelveKeyDialer implements // see if we need to play local tones. if (mPhone.getContext().getResources().getBoolean(R.bool.allow_local_dtmf_tones)) { - mLocalToneEnabled = Settings.System.getInt(mInCallScreen.getContentResolver(), + mDTMFToneEnabled = Settings.System.getInt(mInCallScreen.getContentResolver(), Settings.System.DTMF_TONE_WHEN_DIALING, 1) == 1; } else { - mLocalToneEnabled = false; + mDTMFToneEnabled = false; } - if (DBG) log("- startDialerSession: mLocalToneEnabled = " + mLocalToneEnabled); + if (DBG) log("- startDialerSession: mDTMFToneEnabled = " + mDTMFToneEnabled); // create the tone generator // if the mToneGenerator creation fails, just continue without it. It is // a local audio signal, and is not as important as the dtmf tone itself. - if (mLocalToneEnabled) { + if (mDTMFToneEnabled) { synchronized (mToneGeneratorLock) { if (mToneGenerator == null) { try { @@ -859,49 +863,55 @@ public class DTMFTwelveKeyDialer implements } /** - * Plays the local tone based the phone type. + * Starts playing a DTMF tone. Also begins the local tone playback, + * if enabled. + * The access of this function is package rather than private + * since this is being referred from InCallScreen. + * InCallScreen calls this function to utilize the DTMF ToneGenerator properties + * defined here. + * @param tone a tone code from {@link ToneGenerator} */ - public void startTone(char c) { - // Only play the tone if it exists. - if (!mToneMap.containsKey(c)) { - return; - } - // Read the settings as it may be changed by the user during the call - mShortTone = TelephonyCapabilities.useShortDtmfTones(mPhone, mPhone.getContext()); - + /* package */ void startDtmfTone(char tone) { if (DBG) log("startDtmfTone()..."); + mPhone.startDtmf(tone); - // For Short DTMF we need to play the local tone for fixed duration - if (mShortTone) { - sendShortDtmfToNetwork(c); - } else { - // Pass as a char to be sent to network - Log.i(LOG_TAG, "send long dtmf for " + c); - mPhone.startDtmf(c); + // if local tone playback is enabled, start it. + if (mDTMFToneEnabled) { + synchronized (mToneGeneratorLock) { + if (mToneGenerator == null) { + if (DBG) log("startDtmfTone: mToneGenerator == null, tone: " + tone); + } else { + if (DBG) log("starting local tone " + tone); + mToneGenerator.startTone(mToneMap.get(tone)); + } + } } - startLocalToneIfNeeded(c); } /** - * Plays the local tone based the phone type. + * Stops playing the current DTMF tone. + * + * The ToneStopper class (similar to that in {@link TwelveKeyDialer#mToneStopper}) + * has been removed in favor of synchronous start / stop calls since tone duration + * is now a function of the input. + * The acess of this function is package rather than private + * since this is being referred from InCallScreen. + * InCallScreen calls this function to utilize the DTMF ToneGenerator properties + * defined here. */ - public void startLocalToneIfNeeded(char c) { - // if local tone playback is enabled, start it. - // Only play the tone if it exists. - if (!mToneMap.containsKey(c)) { - return; - } - if (mLocalToneEnabled) { + /* package */ void stopDtmfTone() { + if (DBG) log("stopDtmfTone()..."); + mPhone.stopDtmf(); + + // if local tone playback is enabled, stop it. + if (DBG) log("trying to stop local tone..."); + if (mDTMFToneEnabled) { synchronized (mToneGeneratorLock) { if (mToneGenerator == null) { - if (DBG) log("startDtmfTone: mToneGenerator == null, tone: " + c); + if (DBG) log("stopDtmfTone: mToneGenerator == null"); } else { - if (DBG) log("starting local tone " + c); - int toneDuration = -1; - if (mShortTone) { - toneDuration = DTMF_DURATION_MS; - } - mToneGenerator.startTone(mToneMap.get(c), toneDuration); + if (DBG) log("stopping local tone."); + mToneGenerator.stopTone(); } } } @@ -922,32 +932,79 @@ public class DTMFTwelveKeyDialer implements } /** - * Stops the local tone based on the phone type. + * Plays the local tone based the phone type. */ - public void stopTone() { - if (!mShortTone) { - if (DBG) log("stopping remote tone."); - mPhone.stopDtmf(); - stopLocalToneIfNeeded(); + private void startTone(char c) { + int phoneType = mPhone.getPhoneType(); + if (phoneType == Phone.PHONE_TYPE_GSM) { + startDtmfTone(c); + } else if (phoneType == Phone.PHONE_TYPE_CDMA) { + startToneCdma(c); + } else { + throw new IllegalStateException("Unexpected phone type: " + phoneType); } } /** * Stops the local tone based on the phone type. */ - public void stopLocalToneIfNeeded() { - if (!mShortTone) { - if (DBG) log("stopping remote tone."); - // if local tone playback is enabled, stop it. - if (DBG) log("trying to stop local tone..."); - if (mLocalToneEnabled) { - synchronized (mToneGeneratorLock) { - if (mToneGenerator == null) { - if (DBG) log("stopLocalTone: mToneGenerator == null"); - } else { - if (DBG) log("stopping local tone."); - mToneGenerator.stopTone(); + private void stopTone() { + int phoneType = mPhone.getPhoneType(); + if (phoneType == Phone.PHONE_TYPE_GSM) { + stopDtmfTone(); + } else if (phoneType == Phone.PHONE_TYPE_CDMA) { + // Cdma case we do stopTone only for Long DTMF Setting + if (mDTMFToneType == CallFeaturesSetting.DTMF_TONE_TYPE_LONG) { + stopToneCdma(); + } + } else { + throw new IllegalStateException("Unexpected phone type: " + phoneType); + } + } + + /** + * Plays tone when the DTMF setting is normal(Short). + */ + void startToneCdma(char tone) { + if (DBG) log("startToneCdma('" + tone + "')..."); + + // Read the settings as it may be changed by the user during the call + mDTMFToneType = Settings.System.getInt(mInCallScreen.getContentResolver(), + Settings.System.DTMF_TONE_TYPE_WHEN_DIALING, + CallFeaturesSetting.DTMF_TONE_TYPE_NORMAL); + // For Short DTMF we need to play the local tone for fixed duration + if (mDTMFToneType == CallFeaturesSetting.DTMF_TONE_TYPE_NORMAL) { + sendShortDtmfToNetwork (tone); + } else { + // Pass as a char to be sent to network + Log.i(LOG_TAG, "send long dtmf for " + tone); + mPhone.startDtmf(tone); + } + + startLocalToneCdma(tone); + } + + /** + * Plays local tone for CDMA. + */ + void startLocalToneCdma(char tone) { + if (DBG) log("startLocalToneCdma('" + tone + "')..." + + " mDTMFToneEnabled = " + mDTMFToneEnabled + " this = " + this); + + // if local tone playback is enabled, start it. + if (mDTMFToneEnabled) { + synchronized (mToneGeneratorLock) { + if (mToneGenerator == null) { + if (DBG) log("startToneCdma: mToneGenerator == null, tone: " + tone); + } else { + if (DBG) log("starting local tone " + tone); + + // Start the new tone. + int toneDuration = -1; + if (mDTMFToneType == CallFeaturesSetting.DTMF_TONE_TYPE_NORMAL) { + toneDuration = DTMF_DURATION_MS; } + mToneGenerator.startTone(mToneMap.get(tone), toneDuration); } } } @@ -974,6 +1031,35 @@ public class DTMFTwelveKeyDialer implements } /** + * Stops the dtmf from being sent over the network for Long DTMF case + * and stops local DTMF key feedback tone. + */ + private void stopToneCdma() { + if (DBG) log("stopping remote tone."); + + mPhone.stopDtmf(); + stopLocalToneCdma(); + } + + /** + * Stops the local dtmf tone. + */ + void stopLocalToneCdma() { + // if local tone playback is enabled, stop it. + if (DBG) log("trying to stop local tone..."); + if (mDTMFToneEnabled) { + synchronized (mToneGeneratorLock) { + if (mToneGenerator == null) { + if (DBG) log("stopLocalToneCdma: mToneGenerator == null"); + } else { + if (DBG) log("stopping local tone."); + mToneGenerator.stopTone(); + } + } + } + } + + /** * Handles Burst Dtmf Confirmation from the Framework. */ void handleBurstDtmfConfirmation() { diff --git a/phone/src/com/android/phone2/DeleteFdnContactScreen.java b/phone/src/com/android/phone2/DeleteFdnContactScreen.java index 74e0624..b8eb8dc 100644 --- a/phone/src/com/android/phone2/DeleteFdnContactScreen.java +++ b/phone/src/com/android/phone2/DeleteFdnContactScreen.java @@ -93,20 +93,16 @@ public class DeleteFdnContactScreen extends Activity { mName = intent.getStringExtra(INTENT_EXTRA_NAME); mNumber = intent.getStringExtra(INTENT_EXTRA_NUMBER); - if (TextUtils.isEmpty(mNumber)) { + if (TextUtils.isEmpty(mName)) { finish(); } } private void deleteContact() { StringBuilder buf = new StringBuilder(); - if (TextUtils.isEmpty(mName)) { - buf.append("number='"); - } else { - buf.append("tag='"); - buf.append(mName); - buf.append("' AND number='"); - } + buf.append("tag='"); + buf.append(mName); + buf.append("' AND number='"); buf.append(mNumber); buf.append("' AND pin2='"); buf.append(mPin2); diff --git a/phone/src/com/android/phone2/EditFdnContactScreen.java b/phone/src/com/android/phone2/EditFdnContactScreen.java index c17cc9a..6dcf596 100644 --- a/phone/src/com/android/phone2/EditFdnContactScreen.java +++ b/phone/src/com/android/phone2/EditFdnContactScreen.java @@ -205,7 +205,9 @@ public class EditFdnContactScreen extends Activity { mName = intent.getStringExtra(INTENT_EXTRA_NAME); mNumber = intent.getStringExtra(INTENT_EXTRA_NUMBER); - mAddContact = TextUtils.isEmpty(mNumber); + if (TextUtils.isEmpty(mName) && TextUtils.isEmpty(mNumber)) { + mAddContact = true; + } } /** diff --git a/phone/src/com/android/phone2/EditPhoneNumberPreference.java b/phone/src/com/android/phone2/EditPhoneNumberPreference.java index 92af9da..56d32a2 100644 --- a/phone/src/com/android/phone2/EditPhoneNumberPreference.java +++ b/phone/src/com/android/phone2/EditPhoneNumberPreference.java @@ -187,7 +187,7 @@ public class EditPhoneNumberPreference extends EditTextPreference { @Override protected void onBindDialogView(View view) { // default the button clicked to be the cancel button. - mButtonClicked = DialogInterface.BUTTON_NEGATIVE; + mButtonClicked = DialogInterface.BUTTON2; super.onBindDialogView(view); @@ -307,7 +307,7 @@ public class EditPhoneNumberPreference extends EditTextPreference { @Override public void onClick(DialogInterface dialog, int which) { // The neutral button (button3) is always the toggle. - if ((mConfirmationMode == CM_ACTIVATION) && (which == DialogInterface.BUTTON_NEUTRAL)) { + if ((mConfirmationMode == CM_ACTIVATION) && (which == DialogInterface.BUTTON3)) { //flip the toggle if we are in the correct mode. setToggled(!isToggled()); } @@ -321,8 +321,8 @@ public class EditPhoneNumberPreference extends EditTextPreference { // phone numbers and calling the close action listener. protected void onDialogClosed(boolean positiveResult) { // A positive result is technically either button1 or button3. - if ((mButtonClicked == DialogInterface.BUTTON_POSITIVE) || - (mButtonClicked == DialogInterface.BUTTON_NEUTRAL)){ + if ((mButtonClicked == DialogInterface.BUTTON1) || + (mButtonClicked == DialogInterface.BUTTON3)){ setPhoneNumber(getEditText().getText().toString()); super.onDialogClosed(positiveResult); setText(getStringValue()); diff --git a/phone/src/com/android/phone2/EmergencyCallHandler.java b/phone/src/com/android/phone2/EmergencyCallHandler.java index de2129a..e3e4495 100644 --- a/phone/src/com/android/phone2/EmergencyCallHandler.java +++ b/phone/src/com/android/phone2/EmergencyCallHandler.java @@ -26,6 +26,7 @@ import android.os.Handler; import android.os.Message; import android.provider.Settings; import com.android.internal.telephony.Phone; +import com.android.internal.telephony.SipPhoneFactory; import android.telephony.ServiceState; import android.view.WindowManager; @@ -106,7 +107,7 @@ public class EmergencyCallHandler extends Activity { super.onCreate(icicle); // setup the phone and get the retry count embedded in the intent. - Phone phone = PhoneApp.getPhone(); + Phone phone = SipPhoneFactory.getDefaultPhone(); int retryCount = getIntent().getIntExtra(EMERGENCY_CALL_RETRY_KEY, INITIAL_ATTEMPT); // create a new message object. diff --git a/phone/src/com/android/phone2/EmergencyCallbackModeExitDialog.java b/phone/src/com/android/phone2/EmergencyCallbackModeExitDialog.java index d36d5d8..98532fe 100644 --- a/phone/src/com/android/phone2/EmergencyCallbackModeExitDialog.java +++ b/phone/src/com/android/phone2/EmergencyCallbackModeExitDialog.java @@ -40,6 +40,7 @@ import android.os.SystemProperties; import android.util.Log; import com.android.internal.telephony.Phone; +import com.android.internal.telephony.SipPhoneFactory; import com.android.internal.telephony.TelephonyIntents; import com.android.internal.telephony.TelephonyProperties; @@ -91,7 +92,7 @@ public class EmergencyCallbackModeExitDialog extends Activity implements OnDismi waitForConnectionCompleteThread.start(); // Register ECM timer reset notfication - mPhone = PhoneApp.getPhone(); + mPhone = SipPhoneFactory.getDefaultPhone(); mPhone.registerForEcmTimerReset(mTimerResetHandler, ECM_TIMER_RESET, null); // Register receiver for intent closing the dialog diff --git a/phone/src/com/android/phone2/EmergencyCallbackModeService.java b/phone/src/com/android/phone2/EmergencyCallbackModeService.java index cc63519..4d9d714 100644 --- a/phone/src/com/android/phone2/EmergencyCallbackModeService.java +++ b/phone/src/com/android/phone2/EmergencyCallbackModeService.java @@ -36,7 +36,7 @@ import android.util.Log; import com.android.internal.telephony.cdma.CDMAPhone; import com.android.internal.telephony.Phone; -import com.android.internal.telephony.PhoneFactory; +import com.android.internal.telephony.SipPhoneFactory; import com.android.internal.telephony.TelephonyIntents; import com.android.internal.telephony.TelephonyProperties; @@ -73,9 +73,9 @@ public class EmergencyCallbackModeService extends Service { @Override public void onCreate() { // Check if it is CDMA phone - if (PhoneFactory.getDefaultPhone().getPhoneType() != Phone.PHONE_TYPE_CDMA) { + if (SipPhoneFactory.getDefaultPhone().getPhoneType() != Phone.PHONE_TYPE_CDMA) { Log.e(LOG_TAG, "Error! Emergency Callback Mode not supported for " + - PhoneFactory.getDefaultPhone().getPhoneName() + " phones"); + SipPhoneFactory.getDefaultPhone().getPhoneName() + " phones"); stopSelf(); } @@ -88,7 +88,7 @@ public class EmergencyCallbackModeService extends Service { mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); // Register ECM timer reset notfication - mPhone = PhoneFactory.getDefaultPhone(); + mPhone = SipPhoneFactory.getDefaultPhone(); mPhone.registerForEcmTimerReset(mHandler, ECM_TIMER_RESET, null); startTimerNotification(); diff --git a/phone/src/com/android/phone2/EmergencyDialer.java b/phone/src/com/android/phone2/EmergencyDialer.java index 92e5405..dd44799 100644 --- a/phone/src/com/android/phone2/EmergencyDialer.java +++ b/phone/src/com/android/phone2/EmergencyDialer.java @@ -198,19 +198,11 @@ public class EmergencyDialer extends Activity mVoicemailDialAndDeleteRow = null; } + if (icicle != null) { super.onRestoreInstanceState(icicle); } - // Extract phone number from intent - Uri data = getIntent().getData(); - if (data != null && ("tel".equals(data.getScheme()))) { - String number = PhoneNumberUtils.getNumberFromIntent(getIntent(), this); - if (number != null) { - mDigits.setText(number); - } - } - // if the mToneGenerator creation fails, just continue without it. It is // a local audio signal, and is not as important as the dtmf tone itself. synchronized (mToneGeneratorLock) { diff --git a/phone/src/com/android/phone2/EnableFdnScreen.java b/phone/src/com/android/phone2/EnableFdnScreen.java index bb3d2c7..8588396 100644 --- a/phone/src/com/android/phone2/EnableFdnScreen.java +++ b/phone/src/com/android/phone2/EnableFdnScreen.java @@ -31,6 +31,7 @@ import android.widget.TextView; import com.android.internal.telephony.CommandException; import com.android.internal.telephony.Phone; +import com.android.internal.telephony.SipPhoneFactory; /** * UI to enable/disable FDN. @@ -67,7 +68,7 @@ public class EnableFdnScreen extends Activity { setContentView(R.layout.enable_fdn_screen); setupView(); - mPhone = PhoneApp.getPhone(); + mPhone = SipPhoneFactory.getDefaultPhone(); mEnable = !mPhone.getIccCard().getIccFdnEnabled(); int id = mEnable ? R.string.enable_fdn : R.string.disable_fdn; @@ -77,7 +78,7 @@ public class EnableFdnScreen extends Activity { @Override protected void onResume() { super.onResume(); - mPhone = PhoneApp.getPhone(); + mPhone = SipPhoneFactory.getDefaultPhone(); } private void setupView() { diff --git a/phone/src/com/android/phone2/EnableIccPinScreen.java b/phone/src/com/android/phone2/EnableIccPinScreen.java index 9ad7b03..23722d3 100644 --- a/phone/src/com/android/phone2/EnableIccPinScreen.java +++ b/phone/src/com/android/phone2/EnableIccPinScreen.java @@ -31,6 +31,7 @@ import android.widget.TextView; import com.android.internal.telephony.CommandException; import com.android.internal.telephony.Phone; +import com.android.internal.telephony.SipPhoneFactory; /** * UI to enable/disable the ICC PIN. @@ -67,7 +68,7 @@ public class EnableIccPinScreen extends Activity { setContentView(R.layout.enable_sim_pin_screen); setupView(); - mPhone = PhoneApp.getPhone(); + mPhone = SipPhoneFactory.getDefaultPhone(); mEnable = !mPhone.getIccCard().getIccLockEnabled(); int id = mEnable ? R.string.enable_sim_pin : R.string.disable_sim_pin; diff --git a/phone/src/com/android/phone2/FakePhoneActivity.java b/phone/src/com/android/phone2/FakePhoneActivity.java index 141b54e..67d9350 100644 --- a/phone/src/com/android/phone2/FakePhoneActivity.java +++ b/phone/src/com/android/phone2/FakePhoneActivity.java @@ -54,10 +54,10 @@ public class FakePhoneActivity extends Activity { } }); - mRadioControl = PhoneApp.getPhone().getSimulatedRadioControl(); + mRadioControl = PhoneApp.getInstance().phone.getSimulatedRadioControl(); Log.i(TAG, "- PhoneApp.getInstance(): " + PhoneApp.getInstance()); - Log.i(TAG, "- PhoneApp.getPhone(): " + PhoneApp.getPhone()); + Log.i(TAG, "- PhoneApp.getInstance().phone: " + PhoneApp.getInstance().phone); Log.i(TAG, "- mRadioControl: " + mRadioControl); } diff --git a/phone/src/com/android/phone2/FdnSetting.java b/phone/src/com/android/phone2/FdnSetting.java index eeedc6f..1426b51 100644 --- a/phone/src/com/android/phone2/FdnSetting.java +++ b/phone/src/com/android/phone2/FdnSetting.java @@ -29,6 +29,7 @@ import android.widget.Toast; import com.android.internal.telephony.CommandException; import com.android.internal.telephony.Phone; +import com.android.internal.telephony.SipPhoneFactory; /** * FDN settings UI for the Phone app. @@ -383,7 +384,7 @@ public class FdnSetting extends PreferenceActivity addPreferencesFromResource(R.xml.fdn_setting); - mPhone = PhoneApp.getPhone(); + mPhone = SipPhoneFactory.getDefaultPhone(); //get UI object references PreferenceScreen prefSet = getPreferenceScreen(); @@ -412,7 +413,7 @@ public class FdnSetting extends PreferenceActivity @Override protected void onResume() { super.onResume(); - mPhone = PhoneApp.getPhone(); + mPhone = SipPhoneFactory.getDefaultPhone(); updateEnableFDN(); } diff --git a/phone/src/com/android/phone2/GsmUmtsCallOptions.java b/phone/src/com/android/phone2/GsmUmtsCallOptions.java index ec1b85a..b064926 100644 --- a/phone/src/com/android/phone2/GsmUmtsCallOptions.java +++ b/phone/src/com/android/phone2/GsmUmtsCallOptions.java @@ -23,6 +23,7 @@ import android.preference.PreferenceActivity; import android.preference.PreferenceScreen; import com.android.internal.telephony.Phone; +import com.android.internal.telephony.SipPhoneFactory; public class GsmUmtsCallOptions extends PreferenceActivity { private static final String LOG_TAG = "GsmUmtsCallOptions"; @@ -34,7 +35,7 @@ public class GsmUmtsCallOptions extends PreferenceActivity { addPreferencesFromResource(R.xml.gsm_umts_call_options); - if (PhoneApp.getPhone().getPhoneType() != Phone.PHONE_TYPE_GSM) { + if (SipPhoneFactory.getDefaultPhone().getPhoneType() != Phone.PHONE_TYPE_GSM) { //disable the entire screen getPreferenceScreen().setEnabled(false); } diff --git a/phone/src/com/android/phone2/GsmUmtsOptions.java b/phone/src/com/android/phone2/GsmUmtsOptions.java index 6593a52..525f01e 100644 --- a/phone/src/com/android/phone2/GsmUmtsOptions.java +++ b/phone/src/com/android/phone2/GsmUmtsOptions.java @@ -16,19 +16,19 @@ package com.android.phone2; +import android.os.Bundle; import android.preference.CheckBoxPreference; import android.preference.Preference; import android.preference.PreferenceActivity; import android.preference.PreferenceScreen; import com.android.internal.telephony.Phone; -import com.android.internal.telephony.PhoneFactory; +import com.android.internal.telephony.SipPhoneFactory; /** * List of Network-specific settings screens. */ -public class GsmUmtsOptions { - private static final String LOG_TAG = "GsmUmtsOptions"; +public class GsmUmtsOptions extends PreferenceActivity { private PreferenceScreen mButtonAPNExpand; private PreferenceScreen mButtonOperatorSelectionExpand; @@ -37,39 +37,30 @@ public class GsmUmtsOptions { private static final String BUTTON_APN_EXPAND_KEY = "button_apn_key"; private static final String BUTTON_OPERATOR_SELECTION_EXPAND_KEY = "button_carrier_sel_key"; private static final String BUTTON_PREFER_2G_KEY = "button_prefer_2g_key"; - private PreferenceActivity mPrefActivity; - private PreferenceScreen mPrefScreen; - public GsmUmtsOptions(PreferenceActivity prefActivity, PreferenceScreen prefScreen) { - mPrefActivity = prefActivity; - mPrefScreen = prefScreen; - create(); - } - protected void create() { - mPrefActivity.addPreferencesFromResource(R.xml.gsm_umts_options); - mButtonAPNExpand = (PreferenceScreen) mPrefScreen.findPreference(BUTTON_APN_EXPAND_KEY); + @Override + protected void onCreate(Bundle icicle) { + super.onCreate(icicle); + + addPreferencesFromResource(R.xml.gsm_umts_options); + PreferenceScreen prefSet = getPreferenceScreen(); + mButtonAPNExpand = (PreferenceScreen) prefSet.findPreference(BUTTON_APN_EXPAND_KEY); mButtonOperatorSelectionExpand = - (PreferenceScreen) mPrefScreen.findPreference(BUTTON_OPERATOR_SELECTION_EXPAND_KEY); - mButtonPrefer2g = (CheckBoxPreference) mPrefScreen.findPreference(BUTTON_PREFER_2G_KEY); - if (PhoneFactory.getDefaultPhone().getPhoneType() != Phone.PHONE_TYPE_GSM) { - log("Not a GSM phone"); + (PreferenceScreen) prefSet.findPreference(BUTTON_OPERATOR_SELECTION_EXPAND_KEY); + mButtonPrefer2g = (CheckBoxPreference) prefSet.findPreference(BUTTON_PREFER_2G_KEY); + if (SipPhoneFactory.getDefaultPhone().getPhoneType() != Phone.PHONE_TYPE_GSM) { mButtonAPNExpand.setEnabled(false); mButtonOperatorSelectionExpand.setEnabled(false); mButtonPrefer2g.setEnabled(false); } } - public boolean preferenceTreeClick(Preference preference) { + @Override + public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) { if (preference.getKey().equals(BUTTON_PREFER_2G_KEY)) { - log("preferenceTreeClick: return true"); return true; } - log("preferenceTreeClick: return false"); return false; } - - protected void log(String s) { - android.util.Log.d(LOG_TAG, s); - } } diff --git a/phone/src/com/android/phone2/IccMissingPanel.java b/phone/src/com/android/phone2/IccMissingPanel.java new file mode 100644 index 0000000..4be664e --- /dev/null +++ b/phone/src/com/android/phone2/IccMissingPanel.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.phone2; + +import android.content.Context; +import android.view.View; +import android.widget.Button; +import android.os.Bundle; + +/** + * Panel which displays the "ICC missing" message. + */ +public class IccMissingPanel extends IccPanel { + + public IccMissingPanel(Context context) { + super(context); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setContentView(R.layout.sim_missing); + ((Button) findViewById(R.id.continueView)).setOnClickListener(mButtonListener); + } + + View.OnClickListener mButtonListener = new View.OnClickListener() { + public void onClick(View v) { + dismiss(); + } + }; +} diff --git a/phone/src/com/android/phone2/IccNetworkDepersonalizationPanel.java b/phone/src/com/android/phone2/IccNetworkDepersonalizationPanel.java index 27cfce1..2f6cbae 100644 --- a/phone/src/com/android/phone2/IccNetworkDepersonalizationPanel.java +++ b/phone/src/com/android/phone2/IccNetworkDepersonalizationPanel.java @@ -35,6 +35,7 @@ import android.widget.LinearLayout; import android.widget.TextView; import com.android.internal.telephony.Phone; +import com.android.internal.telephony.SipPhoneFactory; /** * "SIM network unlock" PIN entry screen. @@ -148,7 +149,7 @@ public class IccNetworkDepersonalizationPanel extends IccPanel { mStatusPanel = (LinearLayout) findViewById(R.id.status_panel); mStatusText = (TextView) findViewById(R.id.status_text); - mPhone = PhoneApp.getPhone(); + mPhone = SipPhoneFactory.getDefaultPhone(); } @Override diff --git a/phone/src/com/android/phone2/IccPanel.java b/phone/src/com/android/phone2/IccPanel.java index 9fd021d..8a607cb 100644 --- a/phone/src/com/android/phone2/IccPanel.java +++ b/phone/src/com/android/phone2/IccPanel.java @@ -17,6 +17,7 @@ package com.android.phone2; import android.app.Dialog; +import android.app.KeyguardManager; import android.app.StatusBarManager; import android.content.Context; import android.view.Gravity; @@ -31,6 +32,7 @@ import android.os.Bundle; public class IccPanel extends Dialog { protected static final String TAG = PhoneApp.LOG_TAG; + private KeyguardManager.KeyguardLock mKeyguardLock; private StatusBarManager mStatusBarManager; public IccPanel(Context context) { @@ -46,26 +48,9 @@ public class IccPanel extends Dialog { WindowManager.LayoutParams.MATCH_PARENT); winP.setGravity(Gravity.CENTER); - // TODO: Ideally, we'd like this dialog to be visible in front of the - // keyguard, so the user will see it immediately after boot (without - // needing to enter the lock pattern or dismiss the keyguard first.) - // - // However that's not easy to do. It's not just a matter of setting - // the FLAG_SHOW_WHEN_LOCKED and FLAG_DISMISS_KEYGUARD flags on our - // window, since we're a Dialog (not an Activity), and the framework - // won't ever let a dialog hide the keyguard (because there could - // possibly be stuff behind it that shouldn't be seen.) - // - // So for now, we'll live with the fact that the user has to enter the - // lock pattern (or dismiss the keyguard) *before* being able to type - // a SIM network unlock PIN. That's not ideal, but still OK. - // (And eventually this will be a moot point once this UI moves - // from the phone app to the framework; see bug 1804111). - - // TODO: we shouldn't need the mStatusBarManager calls here either, - // once this dialog gets moved into the framework and becomes a truly - // full-screen UI. PhoneApp app = PhoneApp.getInstance(); + KeyguardManager km = (KeyguardManager) app.getSystemService(Context.KEYGUARD_SERVICE); + mKeyguardLock = km.newKeyguardLock(TAG); mStatusBarManager = (StatusBarManager) app.getSystemService(Context.STATUS_BAR_SERVICE); requestWindowFeature(Window.FEATURE_NO_TITLE); @@ -74,13 +59,26 @@ public class IccPanel extends Dialog { @Override protected void onStart() { super.onStart(); - mStatusBarManager.disable(StatusBarManager.DISABLE_EXPAND); + disableKeyguard(true); } @Override public void onStop() { super.onStop(); - mStatusBarManager.disable(StatusBarManager.DISABLE_NONE); + disableKeyguard(false); + } + + /** + * Acquires a wake lock and prevents keyguard from enabling. + */ + private void disableKeyguard(boolean disable) { + if (disable) { + mKeyguardLock.disableKeyguard(); + mStatusBarManager.disable(StatusBarManager.DISABLE_EXPAND); + } else { + mKeyguardLock.reenableKeyguard(); + mStatusBarManager.disable(StatusBarManager.DISABLE_NONE); + } } public boolean onKeyDown(int keyCode, KeyEvent event) { diff --git a/phone/src/com/android/phone2/IccPinUnlockPanel.java b/phone/src/com/android/phone2/IccPinUnlockPanel.java new file mode 100644 index 0000000..537d033 --- /dev/null +++ b/phone/src/com/android/phone2/IccPinUnlockPanel.java @@ -0,0 +1,372 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.phone2; + +import android.content.Context; +import android.os.AsyncResult; +import android.os.Handler; +import android.os.Message; +import android.os.Bundle; +import android.text.Editable; +import android.text.Spannable; +import android.text.TextUtils; +import android.text.TextWatcher; +import android.text.method.DialerKeyListener; +import android.util.Log; +import android.view.KeyEvent; +import android.view.View; +import android.widget.Button; +import android.widget.EditText; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.android.internal.telephony.CommandException; +import com.android.internal.telephony.IccCard; + +/** + * Panel where you enter your PIN to unlock the SIM card. + */ +public class IccPinUnlockPanel extends IccPanel { + private static final boolean DBG = false; + + private static final int EVENT_ICC_UNLOCKED_RESULT = 100; + + private enum IccLockState { + UNLOCKED, + REQUIRE_PIN, + REQUIRE_PUK, + REQUIRE_NEW_PIN, + VERIFY_NEW_PIN, + VERIFY_NEW_PIN_FAILED + }; + + private IccLockState mState; + private String mPUKCode; + private String mNewPinCode; + + private EditText mEntry; + private TextView mFailure; + private TextView mLabel; + private TextView mStatus; + private Button mUnlockButton; + private Button mDismissButton; + private LinearLayout mUnlockPane; + private LinearLayout mUnlockInProgressPane; + + private Handler mHandler = new Handler() { + public void handleMessage(Message msg) { + switch (msg.what) { + case EVENT_ICC_UNLOCKED_RESULT: + AsyncResult ar = (AsyncResult) msg.obj; + handleUnlockResult(ar); + break; + } + } + }; + + private class MyTextWatcher implements TextWatcher { + Context mContext; + + public MyTextWatcher(Context context) { + mContext = context; + } + + public void beforeTextChanged(CharSequence buffer, + int start, int olen, int nlen) { + } + + public void onTextChanged(CharSequence buffer, + int start, int olen, int nlen) { + } + + public void afterTextChanged(Editable buffer) { + if (SpecialCharSequenceMgr.handleChars( + mContext, buffer.toString())) { + mEntry.getText().clear(); + } + } + } + + public IccPinUnlockPanel(Context context) { + super(context); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.sim_unlock); + updateState(); + initView(); + updateView(); + } + + @Override + protected void onStart() { + super.onStart(); + if (updateState()) { + updateView(); // need to update the view only if state changed + } + } + + /** + * @return Whether the state changed. + */ + boolean updateState() { + PhoneApp app = PhoneApp.getInstance(); + IccCard iccCardInterface = app.phone.getIccCard(); + + try { + if (iccCardInterface.getState() == IccCard.State.PUK_REQUIRED) { + if (getState() != IccLockState.REQUIRE_PUK) { + setState(IccLockState.REQUIRE_PUK); + return true; + } + } else if (getState() != IccLockState.REQUIRE_PIN){ + setState(IccLockState.REQUIRE_PIN); + return true; + } + } catch (Exception ex) { + } + return false; + } + + void setState(IccLockState state) { + mState = state; + } + + IccLockState getState() { + return mState; + } + + void initView() { + mUnlockPane = (LinearLayout) findViewById(R.id.simPINPane); + mUnlockInProgressPane = (LinearLayout) findViewById(R.id.progress); + + mEntry = (EditText) findViewById(R.id.entry); + mEntry.setKeyListener(DialerKeyListener.getInstance()); + mEntry.setMovementMethod(null); + mEntry.setOnClickListener(mUnlockListener); + + // set up the text watcher + CharSequence text = mEntry.getText(); + Spannable span = (Spannable) text; + span.setSpan(new MyTextWatcher(this.getContext()), + 0, text.length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE); + + mFailure = (TextView) findViewById(R.id.failure); + mLabel = (TextView) findViewById(R.id.label); + mStatus = (TextView) findViewById(R.id.status); + + mUnlockButton = (Button) findViewById(R.id.unlock); + mUnlockButton.setOnClickListener(mUnlockListener); + + mDismissButton = (Button) findViewById(R.id.dismiss); + + // if we are using the ICC pin for keyguard password, force the + // user to enter the correct PIN to proceed. Otherwise, we won't + // know what the correct keyguard password is. + mDismissButton.setOnClickListener(mDismissListener); + } + + void updateView() { + Context context = getContext(); + + switch (mState) { + case REQUIRE_PIN: + mLabel.setText(context.getText(R.string.enterPin)); + break; + + case REQUIRE_PUK: + mLabel.setText(context.getText(R.string.enterPuk)); + mUnlockButton.setText( + context.getText(R.string.buttonTxtContinue)); + break; + + case REQUIRE_NEW_PIN: + hideIncorrectPinMessage(); + mLabel.setText(context.getText(R.string.enterNewPin)); + break; + + case VERIFY_NEW_PIN: + mLabel.setText(context.getText(R.string.verifyNewPin)); + break; + + case VERIFY_NEW_PIN_FAILED: + mLabel.setText(context.getText(R.string.verifyFailed)); + setState(IccLockState.REQUIRE_NEW_PIN); + break; + } + + mEntry.getText().clear(); + mEntry.requestFocus(View.FOCUS_FORWARD); + } + + public boolean onKeyDown(int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_BACK) { + return true; + } + + return super.onKeyDown(keyCode, event); + } + + void handleUnlockResult(AsyncResult ar) { + if (ar.exception == null) { + handleSuccess(); + return; + } + + // pin/puk unlock failed! + if (ar.exception instanceof com.android.internal.telephony.CommandException && + ((CommandException) ar.exception).getCommandError() == + CommandException.Error.PASSWORD_INCORRECT) { + hidePinUnlockInProgress(); + handleFailure(); + } + + // PENDING: any other failure types? + } + + void handleSuccess() { + if (DBG) log("unlock successful!"); + showUnlockSuccess(); + + // store the ICC pin in memory, to be used later for keyguard lock + // and radio reboots. + PhoneApp.getInstance().setCachedSimPin(mEntry.getText().toString()); + } + + void handleFailure() { + if (DBG) log("unlock failed"); + showIncorrectPinMessage(); + mEntry.getText().clear(); + updateState(); + updateView(); + } + + void showIncorrectPinMessage() { + CharSequence msg; + Context context = getContext(); + + if (getState() == IccLockState.REQUIRE_PIN) { + msg = context.getText(R.string.badPin); + } else { + msg = context.getText(R.string.badPuk); + } + + mFailure.setText(msg); + mFailure.setVisibility(View.VISIBLE); + } + + void hideIncorrectPinMessage() { + mFailure.setVisibility(View.GONE); + } + + void showUnlockInProgress() { + mUnlockInProgressPane.setVisibility(View.VISIBLE); + mUnlockPane.setVisibility(View.GONE); + } + + void hidePinUnlockInProgress() { + mUnlockInProgressPane.setVisibility(View.GONE); + mUnlockPane.setVisibility(View.VISIBLE); + } + + void showUnlockSuccess() { + mStatus.setText(getContext().getText(R.string.pinUnlocked)); + mHandler.postDelayed( + new Runnable() { + public void run() { + dismiss(); + } + }, 1000); + } + + private boolean verifyNewPin(String pin2) { + if (mNewPinCode.equals(pin2)) { + return true; + } + + return false; + } + + //***** Listeners + + View.OnClickListener mUnlockListener = new View.OnClickListener() { + public void onClick(View v) { + String code = mEntry.getText().toString(); + + if (TextUtils.isEmpty(code)) { + return; + } + + PhoneApp app = PhoneApp.getInstance(); + IccCard iccCardInterface = app.phone.getIccCard(); + if (iccCardInterface != null) { + Message callBack = Message.obtain(mHandler, + EVENT_ICC_UNLOCKED_RESULT); + + switch (mState) { + case REQUIRE_PIN: + if (DBG) log("unlock attempt: PIN code entered = " + + code); + showUnlockInProgress(); + iccCardInterface.supplyPin(code, callBack); + break; + + case REQUIRE_PUK: + if (DBG) log("puk code entered, request for new pin"); + mPUKCode = code; + setState(IccLockState.REQUIRE_NEW_PIN); + updateView(); + break; + + case REQUIRE_NEW_PIN: + if (DBG) log("new pin code entered, verify pin"); + mNewPinCode = code; + setState(IccLockState.VERIFY_NEW_PIN); + updateView(); + break; + + case VERIFY_NEW_PIN: + if (DBG) log("new pin code re-entered"); + + if (verifyNewPin(code)) { + // proceed + showUnlockInProgress(); + iccCardInterface.supplyPuk(mPUKCode, mNewPinCode, + callBack); + } else { + setState(IccLockState.VERIFY_NEW_PIN_FAILED); + updateView(); + } + + break; + } + } + } + }; + + View.OnClickListener mDismissListener = new View.OnClickListener() { + public void onClick(View v) { + dismiss(); + } + }; + + private void log(String msg) { + Log.v(TAG, "[SimPinUnlock] " + msg); + } +} diff --git a/phone/src/com/android/phone2/InCallControlState.java b/phone/src/com/android/phone2/InCallControlState.java index 17bc4c3..d154d55 100644 --- a/phone/src/com/android/phone2/InCallControlState.java +++ b/phone/src/com/android/phone2/InCallControlState.java @@ -102,17 +102,20 @@ public class InCallControlState { final boolean hasHoldingCall = !mPhone.getBackgroundCall().isIdle(); // Manage conference: - if (TelephonyCapabilities.supportsConferenceCallManagement(mPhone)) { + int phoneType = mPhone.getPhoneType(); + if (phoneType == Phone.PHONE_TYPE_GSM) { // This item is visible only if the foreground call is a // conference call, and it's enabled unless the "Manage // conference" UI is already up. manageConferenceVisible = PhoneUtils.isConferenceCall(fgCall); manageConferenceEnabled = manageConferenceVisible && !mInCallScreen.isManageConferenceMode(); - } else { - // This device has no concept of managing a conference call. + } else if (phoneType == Phone.PHONE_TYPE_CDMA) { + // CDMA has no concept of managing a conference call. manageConferenceVisible = false; manageConferenceEnabled = false; + } else { + throw new IllegalStateException("Unexpected phone type: " + phoneType); } // "Add call": @@ -138,14 +141,20 @@ public class InCallControlState { // "Mute": only enabled when the foreground call is ACTIVE. // (It's meaningless while on hold, or while DIALING/ALERTING.) - // It's also explicitly disabled during emergency calls. - Connection c = fgCall.getLatestConnection(); - boolean isEmergencyCall = false; - if (c != null) isEmergencyCall = PhoneNumberUtils.isEmergencyNumber(c.getAddress()); - if (isEmergencyCall) { // disable "Mute" item - canMute = false; - muteIndicatorOn = false; - } else { + // Also disabled (on CDMA devices) during emergency calls. + if (phoneType == Phone.PHONE_TYPE_CDMA) { + Connection c = fgCall.getLatestConnection(); + boolean isEmergencyCall = false; + if (c != null) isEmergencyCall = PhoneNumberUtils.isEmergencyNumber(c.getAddress()); + + if (isEmergencyCall) { // disable "Mute" item + canMute = false; + muteIndicatorOn = false; + } else { + canMute = hasActiveForegroundCall; + muteIndicatorOn = PhoneUtils.getMute(mPhone); + } + } else if (phoneType == Phone.PHONE_TYPE_GSM) { canMute = hasActiveForegroundCall; muteIndicatorOn = PhoneUtils.getMute(mPhone); } @@ -159,8 +168,8 @@ public class InCallControlState { dialpadVisible = mInCallScreen.isDialerOpened(); // "Hold: - if (TelephonyCapabilities.supportsHoldAndUnhold(mPhone)) { - // This phone has the concept of explicit "Hold" and "Unhold" actions. + if (phoneType == Phone.PHONE_TYPE_GSM) { + // GSM phones have the concept of "Hold" and "Unhold". supportsHold = true; // "On hold" means that there's a holding call and // *no* foreground call. (If there *is* a foreground call, @@ -171,8 +180,8 @@ public class InCallControlState { boolean okToHold = hasActiveForegroundCall && !hasHoldingCall; boolean okToUnhold = onHold; canHold = okToHold || okToUnhold; - } else { - // This device has no concept of "putting a call on hold." + } else if (phoneType == Phone.PHONE_TYPE_CDMA) { + // CDMA has no concept of "putting a call on hold." supportsHold = false; onHold = false; canHold = false; diff --git a/phone/src/com/android/phone2/InCallMenu.java b/phone/src/com/android/phone2/InCallMenu.java index 9b04b38..d6ad635 100755 --- a/phone/src/com/android/phone2/InCallMenu.java +++ b/phone/src/com/android/phone2/InCallMenu.java @@ -210,11 +210,12 @@ class InCallMenu { // // Row 0: - // This usually has "Show/Hide dialpad", but that might be replaced by - // "Manage conference" if a conference call is active (but only - // on phones that support "Manage conference" in the first place.) + // This usually has "Show/Hide dialpad", but that gets replaced by + // "Manage conference" if a conference call is active. PhoneApp app = PhoneApp.getInstance(); - if (TelephonyCapabilities.supportsConferenceCallManagement(app.phone)) { + // As managing conference is only valid for GSM and not for CDMA + int phoneType = app.phone.getPhoneType(); + if (phoneType == Phone.PHONE_TYPE_GSM) { mInCallMenuView.addItemView(mManageConference, 0); } mInCallMenuView.addItemView(mShowDialpad, 0); @@ -228,19 +229,16 @@ class InCallMenu { // Row 2: // In this row we see *either* bluetooth/speaker/mute/hold // *or* answerAndHold/answerAndEnd, but never all 6 together. - if (TelephonyCapabilities.supportsHoldAndUnhold(app.phone)) { + // For CDMA only Answer or Ignore option is valid for a Call Waiting scenario + if (phoneType == Phone.PHONE_TYPE_CDMA) { + mInCallMenuView.addItemView(mAnswer, 2); + mInCallMenuView.addItemView(mIgnore, 2); + } else if (phoneType == Phone.PHONE_TYPE_GSM) { mInCallMenuView.addItemView(mHold, 2); - } - // For phones that allow explicit "Answer & Hold" and "Answer & - // End" actions for a call-waiting call, provide menu items for - // those. Otherwise, just provide basic "Answer" and "Ignore" - // items. - if (TelephonyCapabilities.supportsAnswerAndHold(app.phone)) { mInCallMenuView.addItemView(mAnswerAndHold, 2); mInCallMenuView.addItemView(mAnswerAndEnd, 2); } else { - mInCallMenuView.addItemView(mAnswer, 2); - mInCallMenuView.addItemView(mIgnore, 2); + throw new IllegalStateException("Unexpected phone type: " + phoneType); } mInCallMenuView.addItemView(mMute, 2); mInCallMenuView.addItemView(mSpeaker, 2); @@ -277,8 +275,7 @@ class InCallMenu { final boolean hasHoldingCall = !phone.getBackgroundCall().isIdle(); // For OTA call, only show dialpad, endcall, speaker, and mute menu items - if (hasActiveCall && TelephonyCapabilities.supportsOtasp(phone) && - (PhoneApp.getInstance().isOtaCallInActiveState())) { + if (hasActiveCall && (PhoneApp.getInstance().isOtaCallInActiveState())) { mAnswerAndHold.setVisible(false); mAnswerAndHold.setEnabled(false); mAnswerAndEnd.setVisible(false); @@ -319,35 +316,37 @@ class InCallMenu { // Special cases when an incoming call is ringing. if (hasRingingCall) { + // In the "call waiting" state, show ONLY the "answer & end" + // and "answer & hold" buttons, and nothing else. + // TODO: be sure to test this for "only one line in use and it's + // active" AND for "only one line in use and it's on hold". if (hasActiveCall && !hasHoldingCall) { - // In the "call waiting" state, some devices allow separate - // "Answer & End" and "Answer & Hold" actions, and other - // devices just get basic "Answer" and "Ignore" actions. - if (TelephonyCapabilities.supportsAnswerAndHold(phone)) { + int phoneType = phone.getPhoneType(); + // For CDMA only make "Answer" and "Ignore" visible + if (phoneType == Phone.PHONE_TYPE_CDMA) { + mAnswer.setVisible(true); + mAnswer.setEnabled(true); + mIgnore.setVisible(true); + mIgnore.setEnabled(true); + + // Explicitly remove GSM menu items + mAnswerAndHold.setVisible(false); + mAnswerAndEnd.setVisible(false); + } else if (phoneType == Phone.PHONE_TYPE_GSM) { mAnswerAndHold.setVisible(true); mAnswerAndHold.setEnabled(true); mAnswerAndEnd.setVisible(true); mAnswerAndEnd.setEnabled(true); - // Explicitly remove unused items + // Explicitly remove CDMA menu items mAnswer.setVisible(false); mIgnore.setVisible(false); - } else { - // Just make the basic "Answer" and "Ignore" visible - mAnswer.setVisible(true); - mAnswer.setEnabled(true); - mIgnore.setVisible(true); - mIgnore.setEnabled(true); - // Explicitly remove unused items - mAnswerAndHold.setVisible(false); - mAnswerAndEnd.setVisible(false); + mManageConference.setVisible(false); + } else { + throw new IllegalStateException("Unexpected phone type: " + phoneType); } - // And regardless of the "Answer & Hold" capability of the - // current phone, disable everything else that's irrelevant to - // the call-waiting state. - mManageConference.setVisible(false); mShowDialpad.setVisible(false); mEndCall.setVisible(false); mAddCall.setVisible(false); diff --git a/phone/src/com/android/phone2/InCallScreen.java b/phone/src/com/android/phone2/InCallScreen.java index 908d7fa..9a74b88 100755 --- a/phone/src/com/android/phone2/InCallScreen.java +++ b/phone/src/com/android/phone2/InCallScreen.java @@ -52,14 +52,12 @@ import android.view.MotionEvent; import android.view.View; import android.view.ViewConfiguration; import android.view.ViewGroup; -import android.view.ViewStub; import android.view.Window; import android.view.WindowManager; import android.view.accessibility.AccessibilityEvent; import android.view.animation.Animation; import android.view.animation.AnimationUtils; import android.widget.EditText; -import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.SlidingDrawer; import android.widget.TextView; @@ -304,7 +302,7 @@ public class InCallScreen extends Activity private boolean mIsDestroyed = false; private boolean mIsForegroundActivity = false; - // For use with Pause/Wait dialogs + // For use with CDMA Pause/Wait dialogs private String mPostDialStrAfterPause; private boolean mPauseInProgress = false; @@ -569,6 +567,42 @@ public class InCallScreen extends Activity initInCallScreen(); + // Create the dtmf dialer. The dialer view we use depends on the + // current platform: + // + // - On non-prox-sensor devices, it's the dialpad contained inside + // a SlidingDrawer widget (see dtmf_twelve_key_dialer.xml). + // + // - On "full touch UI" devices, it's the compact non-sliding + // dialpad that appears on the upper half of the screen, + // above the main cluster of InCallTouchUi buttons + // (see non_drawer_dialpad.xml). + // + // TODO: These should both be ViewStubs, and right here we should + // inflate one or the other. (Also, while doing that, let's also + // move this block of code over to initInCallScreen().) + // + SlidingDrawer dialerDrawer; + if (isTouchUiEnabled()) { + // This is a "full touch" device. + mDialerView = (DTMFTwelveKeyDialerView) findViewById(R.id.non_drawer_dtmf_dialer); + if (DBG) log("- Full touch device! Found dialerView: " + mDialerView); + dialerDrawer = null; // No SlidingDrawer used on this device. + } else { + // Use the old-style dialpad contained within the SlidingDrawer. + mDialerView = (DTMFTwelveKeyDialerView) findViewById(R.id.dtmf_dialer); + if (DBG) log("- Using SlidingDrawer-based dialpad. Found dialerView: " + mDialerView); + dialerDrawer = (SlidingDrawer) findViewById(R.id.dialer_container); + if (DBG) log(" ...and the SlidingDrawer: " + dialerDrawer); + } + // Sanity-check that (regardless of the device) at least the + // dialer view is present: + if (mDialerView == null) { + Log.e(LOG_TAG, "onCreate: couldn't find dialerView", new IllegalStateException()); + } + // Finally, create the DTMFTwelveKeyDialer instance. + mDialer = new DTMFTwelveKeyDialer(this, mDialerView, dialerDrawer); + registerForPhoneStates(); // No need to change wake state here; that happens in onResume() when we @@ -650,7 +684,6 @@ public class InCallScreen extends Activity // Check for any failures that happened during onCreate() or onNewIntent(). if (DBG) log("- onResume: initial status = " + mInCallInitialStatus); - boolean handledStartupError = false; if (mInCallInitialStatus != InCallInitStatus.SUCCESS) { if (DBG) log("- onResume: failure during startup: " + mInCallInitialStatus); @@ -658,7 +691,6 @@ public class InCallScreen extends Activity // something more specific to let the user deal with the // problem. handleStartupError(mInCallInitialStatus); - handledStartupError = true; // But it *is* OK to continue with the rest of onResume(), // since any further setup steps (like updateScreen() and the @@ -678,8 +710,10 @@ public class InCallScreen extends Activity takeKeyEvents(true); + boolean phoneIsCdma = (mPhone.getPhoneType() == Phone.PHONE_TYPE_CDMA); + boolean inOtaCall = false; - if (TelephonyCapabilities.supportsOtasp(mPhone)) { + if (phoneIsCdma) { inOtaCall = initOtaState(); } if (!inOtaCall) { @@ -695,38 +729,13 @@ public class InCallScreen extends Activity InCallInitStatus status = syncWithPhoneState(); if (status != InCallInitStatus.SUCCESS) { - if (DBG) log("- onResume: syncWithPhoneState failed! status = " + status); + if (DBG) log("- syncWithPhoneState failed! status = " + status); // Couldn't update the UI, presumably because the phone is totally - // idle. - - if (handledStartupError) { - // Do NOT bail out of the in-call UI, since there's - // presumably a dialog visible right now (see the call to - // handleStartupError() above.) - // - // In this case, stay here for now, and we'll eventually - // leave the InCallScreen when the user presses the - // dialog's OK button (see bailOutAfterErrorDialog()). - Log.i(LOG_TAG, " ==> syncWithPhoneState failed, but staying here anyway."); - } else { - // The phone is idle, and we did NOT handle a - // startup error during this pass thru onResume. - // - // This basically means that we're being resumed because of - // some action *other* than a new intent. (For example, - // the user pressing POWER to wake up the device, causing - // the InCallScreen to come back to the foreground.) - // - // In this scenario we do NOT want to stay here on the - // InCallScreen: we're not showing any useful info to the - // user (like a dialog), and the in-call UI itself is - // useless if there's no active call. So bail out. - Log.i(LOG_TAG, " ==> syncWithPhoneState failed; bailing out!"); - dismissAllDialogs(); - endInCallScreenSession(); - return; - } - } else if (TelephonyCapabilities.supportsOtasp(mPhone)) { + // idle. But don't endInCallScreenSession immediately, since we might still + // have an error dialog up that the user needs to see. + // (And in that case, the error dialog is responsible for calling + // endInCallScreenSession when the user dismisses it.) + } else if (phoneIsCdma) { if (mInCallScreenMode == InCallScreenMode.OTA_NORMAL || mInCallScreenMode == InCallScreenMode.OTA_ENDED) { mDialer.setHandleVisible(false); @@ -1025,18 +1034,26 @@ public class InCallScreen extends Activity if (!mRegisteredForPhoneStates) { mPhone.registerForPreciseCallStateChanged(mHandler, PHONE_STATE_CHANGED, null); mPhone.registerForDisconnect(mHandler, PHONE_DISCONNECT, null); - mPhone.registerForMmiInitiate(mHandler, PhoneApp.MMI_INITIATE, null); - - // register for the MMI complete message. Upon completion, - // PhoneUtils will bring up a system dialog instead of the - // message display class in PhoneUtils.displayMMIComplete(). - // We'll listen for that message too, so that we can finish - // the activity at the same time. - mPhone.registerForMmiComplete(mHandler, PhoneApp.MMI_COMPLETE, null); - mPhone.registerForCallWaiting(mHandler, PHONE_CDMA_CALL_WAITING, null); + int phoneType = mPhone.getPhoneType(); + if (phoneType == Phone.PHONE_TYPE_GSM) { + mPhone.registerForMmiInitiate(mHandler, PhoneApp.MMI_INITIATE, null); + + // register for the MMI complete message. Upon completion, + // PhoneUtils will bring up a system dialog instead of the + // message display class in PhoneUtils.displayMMIComplete(). + // We'll listen for that message too, so that we can finish + // the activity at the same time. + mPhone.registerForMmiComplete(mHandler, PhoneApp.MMI_COMPLETE, null); + } else if (phoneType == Phone.PHONE_TYPE_CDMA) { + if (DBG) log("Registering for Call Waiting."); + mPhone.registerForCallWaiting(mHandler, PHONE_CDMA_CALL_WAITING, null); + } else { + throw new IllegalStateException("Unexpected phone type: " + phoneType); + } + mPhone.setOnPostDialCharacter(mHandler, POST_ON_DIAL_CHARS, null); mPhone.registerForSuppServiceFailed(mHandler, SUPP_SERVICE_FAILED, null); - if (TelephonyCapabilities.supportsOtasp(mPhone)) { + if (phoneType == Phone.PHONE_TYPE_CDMA) { mPhone.registerForCdmaOtaStatusChange(mHandler, EVENT_OTA_PROVISION_CHANGE, null); } mRegisteredForPhoneStates = true; @@ -1055,11 +1072,6 @@ public class InCallScreen extends Activity /* package */ void updateAfterRadioTechnologyChange() { if (DBG) Log.d(LOG_TAG, "updateAfterRadioTechnologyChange()..."); - - // Reset the call screen since the calls cannot be transferred - // across radio technologies. - resetInCallScreenMode(); - // Unregister for all events from the old obsolete phone unregisterForPhoneStates(); @@ -1120,7 +1132,7 @@ public class InCallScreen extends Activity // InCallScreen UI started with Intent of ACTION_SHOW_ACTIVATION // to show OTA Activation screen at power up. if ((action.equals(ACTION_SHOW_ACTIVATION)) - && (TelephonyCapabilities.supportsOtasp(mPhone))) { + && ((mPhone.getPhoneType() == Phone.PHONE_TYPE_CDMA))) { setInCallScreenMode(InCallScreenMode.OTA_NORMAL); if ((app.cdmaOtaProvisionData != null) && (!app.cdmaOtaProvisionData.isOtaCallIntentProcessed)) { @@ -1226,42 +1238,6 @@ public class InCallScreen extends Activity // Helper class to run the "Manage conference" UI mManageConferenceUtils = new ManageConferenceUtils(this, mPhone); - - // Create the dtmf dialer. The dialer view we use depends on the - // current platform: - // - // - On non-prox-sensor devices, it's the dialpad contained inside - // a SlidingDrawer widget (see dtmf_twelve_key_dialer.xml). - // - // - On "full touch UI" devices, it's the compact non-sliding - // dialpad that appears on the upper half of the screen, - // above the main cluster of InCallTouchUi buttons - // (see non_drawer_dialpad.xml). - // - SlidingDrawer dialerDrawer; - if (isTouchUiEnabled()) { - // This is a "full touch" device. - ViewStub stub = (ViewStub)findViewById(R.id.non_drawer_dialpad_stub); - stub.inflate(); - mDialerView = (DTMFTwelveKeyDialerView) findViewById(R.id.non_drawer_dtmf_dialer); - if (DBG) log("- Full touch device! Found dialerView: " + mDialerView); - dialerDrawer = null; // No SlidingDrawer used on this device. - } else { - // Use the old-style dialpad contained within the SlidingDrawer. - ViewStub stub = (ViewStub)findViewById(R.id.dtmf_dialer_stub); - stub.inflate(); - mDialerView = (DTMFTwelveKeyDialerView) findViewById(R.id.dtmf_dialer); - if (DBG) log("- Using SlidingDrawer-based dialpad. Found dialerView: " + mDialerView); - dialerDrawer = (SlidingDrawer) findViewById(R.id.dialer_container); - if (DBG) log(" ...and the SlidingDrawer: " + dialerDrawer); - } - // Sanity-check that (regardless of the device) at least the - // dialer view is present: - if (mDialerView == null) { - Log.e(LOG_TAG, "onCreate: couldn't find dialerView", new IllegalStateException()); - } - // Finally, create the DTMFTwelveKeyDialer instance. - mDialer = new DTMFTwelveKeyDialer(this, mDialerView, dialerDrawer); } /** @@ -2058,19 +2034,17 @@ public class InCallScreen extends Activity if (VDBG) log("handlePostOnDialChar: state = " + state + ", ch = " + ch); + int phoneType = mPhone.getPhoneType(); switch (state) { case STARTED: - mDialer.stopLocalToneIfNeeded(); - if (mPauseInProgress) { - /** - * Note that on some devices, this will never happen, - * because we will not ever enter the PAUSE state. - */ - showPausePromptDialog(c, mPostDialStrAfterPause); + if (phoneType == Phone.PHONE_TYPE_CDMA) { + mDialer.stopLocalToneCdma(); + if (mPauseInProgress) { + showPausePromptDialogCDMA(c, mPostDialStrAfterPause); + } + mPauseInProgress = false; + mDialer.startLocalToneCdma(ch); } - mPauseInProgress = false; - mDialer.startLocalToneIfNeeded(ch); - // TODO: is this needed, now that you can't actually // type DTMF chars or dial directly from here? // If so, we'd need to yank you out of the in-call screen @@ -2079,28 +2053,35 @@ public class InCallScreen extends Activity break; case WAIT: - // wait shows a prompt. if (DBG) log("handlePostOnDialChars: show WAIT prompt..."); - mDialer.stopLocalToneIfNeeded(); String postDialStr = c.getRemainingPostDialString(); - showWaitPromptDialog(c, postDialStr); + if (phoneType == Phone.PHONE_TYPE_CDMA) { + mDialer.stopLocalToneCdma(); + showWaitPromptDialogCDMA(c, postDialStr); + } else if (phoneType == Phone.PHONE_TYPE_GSM) { + showWaitPromptDialogGSM(c, postDialStr); + } else { + throw new IllegalStateException("Unexpected phone type: " + phoneType); + } break; case WILD: if (DBG) log("handlePostOnDialChars: show WILD prompt"); - mDialer.stopLocalToneIfNeeded(); showWildPromptDialog(c); break; case COMPLETE: - mDialer.stopLocalToneIfNeeded(); + if (phoneType == Phone.PHONE_TYPE_CDMA) { + mDialer.stopLocalToneCdma(); + } break; case PAUSE: - // pauses for a brief period of time then continue dialing. - mDialer.stopLocalToneIfNeeded(); - mPostDialStrAfterPause = c.getRemainingPostDialString(); - mPauseInProgress = true; + if (phoneType == Phone.PHONE_TYPE_CDMA) { + mPostDialStrAfterPause = c.getRemainingPostDialString(); + mDialer.stopLocalToneCdma(); + mPauseInProgress = true; + } break; default: @@ -2109,12 +2090,52 @@ public class InCallScreen extends Activity } } + private void showWaitPromptDialogGSM(final Connection c, String postDialStr) { + if (DBG) log("showWaitPromptDialogGSM: '" + postDialStr + "'..."); + + Resources r = getResources(); + StringBuilder buf = new StringBuilder(); + buf.append(r.getText(R.string.wait_prompt_str)); + buf.append(postDialStr); + + // if (DBG) log("- mWaitPromptDialog = " + mWaitPromptDialog); + if (mWaitPromptDialog != null) { + if (DBG) log("- DISMISSING mWaitPromptDialog."); + mWaitPromptDialog.dismiss(); // safe even if already dismissed + mWaitPromptDialog = null; + } + + mWaitPromptDialog = new AlertDialog.Builder(this) + .setMessage(buf.toString()) + .setPositiveButton(R.string.send_button, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int whichButton) { + if (DBG) log("handle WAIT_PROMPT_CONFIRMED, proceed..."); + c.proceedAfterWaitChar(); + PhoneApp.getInstance().pokeUserActivity(); + } + }) + .setOnCancelListener(new DialogInterface.OnCancelListener() { + public void onCancel(DialogInterface dialog) { + if (DBG) log("handle POST_DIAL_CANCELED!"); + c.cancelPostDial(); + PhoneApp.getInstance().pokeUserActivity(); + } + }) + .create(); + mWaitPromptDialog.getWindow().addFlags( + WindowManager.LayoutParams.FLAG_BLUR_BEHIND); + mWaitPromptDialog.show(); + } + /** + * Processes the CDMA specific requirements of a WAIT character in a + * dial string. + * * Pop up an alert dialog with OK and Cancel buttons to allow user to * Accept or Reject the WAIT inserted as part of the Dial string. */ - private void showWaitPromptDialog(final Connection c, String postDialStr) { - if (DBG) log("showWaitPromptDialogChoice: '" + postDialStr + "'..."); + private void showWaitPromptDialogCDMA(final Connection c, String postDialStr) { + if (DBG) log("showWaitPromptDialogCDMA: '" + postDialStr + "'..."); Resources r = getResources(); StringBuilder buf = new StringBuilder(); @@ -2146,7 +2167,6 @@ public class InCallScreen extends Activity .create(); mWaitPromptDialog.getWindow().addFlags( WindowManager.LayoutParams.FLAG_BLUR_BEHIND); - mWaitPromptDialog.show(); } @@ -2154,7 +2174,7 @@ public class InCallScreen extends Activity * Pop up an alert dialog which waits for 2 seconds for each P (Pause) Character entered * as part of the Dial String. */ - private void showPausePromptDialog(final Connection c, String postDialStrAfterPause) { + private void showPausePromptDialogCDMA(final Connection c, String postDialStrAfterPause) { Resources r = getResources(); StringBuilder buf = new StringBuilder(); buf.append(r.getText(R.string.pause_prompt_str)); @@ -2358,13 +2378,13 @@ public class InCallScreen extends Activity && (fgLatestConnection.getPostDialState() == Connection.PostDialState.WAIT)) { if(DBG) log("show the Wait dialog for CDMA"); postDialStr = fgLatestConnection.getRemainingPostDialString(); - showWaitPromptDialog(fgLatestConnection, postDialStr); + showWaitPromptDialogCDMA(fgLatestConnection, postDialStr); } } else if (phoneType == Phone.PHONE_TYPE_GSM) { for (Connection cn : fgConnections) { if ((cn != null) && (cn.getPostDialState() == Connection.PostDialState.WAIT)) { postDialStr = cn.getRemainingPostDialString(); - showWaitPromptDialog(cn, postDialStr); + showWaitPromptDialogGSM(cn, postDialStr); } } } else { @@ -2393,33 +2413,27 @@ public class InCallScreen extends Activity // Make sure the Phone is "in use". (If not, we shouldn't be on // this screen in the first place.) - // An active or just-ended OTA call counts as "in use". - if (TelephonyCapabilities.supportsOtasp(mPhone) + // Need to treat running MMI codes as a connection as well. + // Do not check for getPendingMmiCodes when phone is a CDMA phone + int phoneType = mPhone.getPhoneType(); + + if ((phoneType == Phone.PHONE_TYPE_CDMA) && ((mInCallScreenMode == InCallScreenMode.OTA_NORMAL) - || (mInCallScreenMode == InCallScreenMode.OTA_ENDED))) { + || (mInCallScreenMode == InCallScreenMode.OTA_ENDED))) { // Even when OTA Call ends, need to show OTA End UI, // so return Success to allow UI update. return InCallInitStatus.SUCCESS; } - // If an MMI code is running that also counts as "in use". - // - // TODO: We currently only call getPendingMmiCodes() for GSM - // phones. (The code's been that way all along.) But CDMAPhone - // does in fact implement getPendingMmiCodes(), so should we - // check that here regardless of the phone type? - boolean hasPendingMmiCodes = - (mPhone.getPhoneType() == Phone.PHONE_TYPE_GSM) - && !mPhone.getPendingMmiCodes().isEmpty(); - - if (!mForegroundCall.isIdle() || !mBackgroundCall.isIdle() || !mRingingCall.isIdle() - || hasPendingMmiCodes) { + if ((phoneType == Phone.PHONE_TYPE_CDMA) + || !mForegroundCall.isIdle() || !mBackgroundCall.isIdle() || !mRingingCall.isIdle() + || !mPhone.getPendingMmiCodes().isEmpty()) { if (VDBG) log("syncWithPhoneState: it's ok to be here; update the screen..."); updateScreen(); return InCallInitStatus.SUCCESS; } - Log.i(LOG_TAG, "syncWithPhoneState: phone is idle (shouldn't be here)"); + if (DBG) log("syncWithPhoneState: phone is idle; we shouldn't be here!"); return InCallInitStatus.PHONE_NOT_IN_USE; } @@ -2538,7 +2552,7 @@ public class InCallScreen extends Activity final PhoneApp app = PhoneApp.getInstance(); - if ((TelephonyCapabilities.supportsOtasp(mPhone)) && (mPhone.isOtaSpNumber(number))) { + if ((mPhone.getPhoneType() == Phone.PHONE_TYPE_CDMA) && (mPhone.isOtaSpNumber(number))) { if (DBG) log("placeCall: isOtaSpNumber() returns true"); setInCallScreenMode(InCallScreenMode.OTA_NORMAL); if (app.cdmaOtaProvisionData != null) { @@ -2555,8 +2569,15 @@ public class InCallScreen extends Activity int callStatus; Uri contactUri = intent.getData(); - callStatus = PhoneUtils.placeCall(this, mPhone, number, contactUri, - (isEmergencyNumber || isEmergencyIntent), mProviderGatewayUri); + if (null != mProviderGatewayUri && + !(isEmergencyNumber || isEmergencyIntent) && + PhoneUtils.isRoutableViaGateway(number)) { // Filter out MMI, OTA and other codes. + + callStatus = PhoneUtils.placeCallVia( + this, mPhone, number, contactUri, mProviderGatewayUri); + } else { + callStatus = PhoneUtils.placeCall(mPhone, number, contactUri); + } switch (callStatus) { case PhoneUtils.CALL_STATUS_DIALED: @@ -3169,11 +3190,9 @@ public class InCallScreen extends Activity mProviderAddress); TextView message = (TextView) findViewById(R.id.callingVia); + message.setCompoundDrawablesWithIntrinsicBounds(mProviderIcon, null, null, null); message.setText(text); - ImageView image = (ImageView) findViewById(R.id.callingViaIcon); - image.setImageDrawable(mProviderIcon); - overlay.setVisibility(View.VISIBLE); // Remove any zombie messages and then send a message to @@ -3546,7 +3565,7 @@ public class InCallScreen extends Activity * Hang up the current active call. */ /* package */ void internalHangup() { - if (DBG) log("internalHangup()..."); + if (DBG) log("internalHangup()..." + mPhone); PhoneUtils.hangup(mPhone); } @@ -4191,9 +4210,8 @@ public class InCallScreen extends Activity // Check if there's a connected headset, using the BluetoothHeadset API. boolean isConnected = false; if (mBluetoothHeadset != null) { + if (VDBG) log(" - headset state = " + mBluetoothHeadset.getState()); BluetoothDevice headset = mBluetoothHeadset.getCurrentHeadset(); - if (VDBG) log(" - headset state = " + - mBluetoothHeadset.getState(headset)); if (VDBG) log(" - headset address: " + headset); if (headset != null) { isConnected = mBluetoothHeadset.isConnected(headset); @@ -4664,7 +4682,7 @@ public class InCallScreen extends Activity return false; } - if (!TelephonyCapabilities.supportsOtasp(mPhone)) { + if (mPhone.getPhoneType() != Phone.PHONE_TYPE_CDMA) { return false; } @@ -4747,7 +4765,7 @@ public class InCallScreen extends Activity private boolean initOtaState() { boolean inOtaCall = false; - if (TelephonyCapabilities.supportsOtasp(mPhone)) { + if (mPhone.getPhoneType() == Phone.PHONE_TYPE_CDMA) { final PhoneApp app = PhoneApp.getInstance(); if ((app.cdmaOtaScreenState == null) || (app.cdmaOtaProvisionData == null)) { @@ -4785,7 +4803,7 @@ public class InCallScreen extends Activity public void updateMenuItems() { if (mInCallMenu != null) { - boolean okToShowMenu = mInCallMenu.updateItems(PhoneApp.getPhone()); + boolean okToShowMenu = mInCallMenu.updateItems(PhoneApp.getInstance().phone); if (!okToShowMenu) { dismissMenu(true); } diff --git a/phone/src/com/android/phone2/InCallTouchUi.java b/phone/src/com/android/phone2/InCallTouchUi.java index edec37b..a568b65 100644 --- a/phone/src/com/android/phone2/InCallTouchUi.java +++ b/phone/src/com/android/phone2/InCallTouchUi.java @@ -183,7 +183,7 @@ public class InCallTouchUi extends FrameLayout mSwapButton = (ImageButton) mInCallControls.findViewById(R.id.swapButton); mSwapButton.setOnClickListener(this); mSwapButtonLabel = (TextView) mInCallControls.findViewById(R.id.swapButtonLabel); - if (PhoneApp.getPhone().getPhoneType() == Phone.PHONE_TYPE_CDMA) { + if (PhoneApp.getInstance().phone.getPhoneType() == Phone.PHONE_TYPE_CDMA) { // In CDMA we use a generalized text - "Manage call", as behavior on selecting // this option depends entirely on what the current call state is. mSwapButtonLabel.setText(R.string.onscreenManageCallsText); diff --git a/phone/src/com/android/phone2/NetworkQueryService.java b/phone/src/com/android/phone2/NetworkQueryService.java index ff53fe9..2a44786 100644 --- a/phone/src/com/android/phone2/NetworkQueryService.java +++ b/phone/src/com/android/phone2/NetworkQueryService.java @@ -27,7 +27,7 @@ import android.os.Message; import android.os.RemoteCallbackList; import android.os.RemoteException; import com.android.internal.telephony.Phone; -import com.android.internal.telephony.PhoneFactory; +import com.android.internal.telephony.SipPhoneFactory; import android.util.Log; import java.util.ArrayList; @@ -157,7 +157,7 @@ public class NetworkQueryService extends Service { @Override public void onCreate() { mState = QUERY_READY; - mPhone = PhoneFactory.getDefaultPhone(); + mPhone = SipPhoneFactory.getDefaultPhone(); } /** diff --git a/phone/src/com/android/phone2/NetworkSetting.java b/phone/src/com/android/phone2/NetworkSetting.java index df893ba..7fcf75f 100644 --- a/phone/src/com/android/phone2/NetworkSetting.java +++ b/phone/src/com/android/phone2/NetworkSetting.java @@ -218,7 +218,7 @@ public class NetworkSetting extends PreferenceActivity addPreferencesFromResource(R.xml.carrier_select); - mPhone = PhoneApp.getPhone(); + mPhone = PhoneApp.getInstance().phone; mNetworkList = (PreferenceGroup) getPreferenceScreen().findPreference(LIST_NETWORKS_KEY); mNetworkMap = new HashMap<Preference, NetworkInfo>(); diff --git a/phone/src/com/android/phone2/NotificationMgr.java b/phone/src/com/android/phone2/NotificationMgr.java index 2e7503a..bfc16ce 100644 --- a/phone/src/com/android/phone2/NotificationMgr.java +++ b/phone/src/com/android/phone2/NotificationMgr.java @@ -84,8 +84,8 @@ public class NotificationMgr implements CallerInfoAsyncQuery.OnQueryCompleteList private StatusBarManager mStatusBar; private StatusBarMgr mStatusBarMgr; private Toast mToast; - private boolean mShowingSpeakerphoneIcon; - private boolean mShowingMuteIcon; + private IBinder mSpeakerphoneIcon; + private IBinder mMuteIcon; // used to track the missed call counter, default to 0. private int mNumberMissedCalls = 0; @@ -433,16 +433,16 @@ public class NotificationMgr implements CallerInfoAsyncQuery.OnQueryCompleteList } void notifySpeakerphone() { - if (!mShowingSpeakerphoneIcon) { - mStatusBar.setIcon("speakerphone", android.R.drawable.stat_sys_speakerphone, 0); - mShowingSpeakerphoneIcon = true; + if (mSpeakerphoneIcon == null) { + mSpeakerphoneIcon = mStatusBar.addIcon("speakerphone", + android.R.drawable.stat_sys_speakerphone, 0); } } void cancelSpeakerphone() { - if (mShowingSpeakerphoneIcon) { - mStatusBar.removeIcon("speakerphone"); - mShowingSpeakerphoneIcon = false; + if (mSpeakerphoneIcon != null) { + mStatusBar.removeIcon(mSpeakerphoneIcon); + mSpeakerphoneIcon = null; } } @@ -463,16 +463,15 @@ public class NotificationMgr implements CallerInfoAsyncQuery.OnQueryCompleteList } void notifyMute() { - if (mShowingMuteIcon) { - mStatusBar.setIcon("mute", android.R.drawable.stat_notify_call_mute, 0); - mShowingMuteIcon = true; + if (mMuteIcon == null) { + mMuteIcon = mStatusBar.addIcon("mute", android.R.drawable.stat_notify_call_mute, 0); } } void cancelMute() { - if (mShowingMuteIcon) { - mStatusBar.removeIcon("mute"); - mShowingMuteIcon = false; + if (mMuteIcon != null) { + mStatusBar.removeIcon(mMuteIcon); + mMuteIcon = null; } } @@ -503,7 +502,9 @@ public class NotificationMgr implements CallerInfoAsyncQuery.OnQueryCompleteList // Display the appropriate "in-call" icon in the status bar, // which depends on the current phone and/or bluetooth state. - boolean enhancedVoicePrivacy = PhoneApp.getInstance().notifier.getVoicePrivacyState(); + + + boolean enhancedVoicePrivacy = PhoneApp.getInstance().notifier.getCdmaVoicePrivacyState(); if (DBG) log("updateInCallNotification: enhancedVoicePrivacy = " + enhancedVoicePrivacy); if (!hasActiveCall && hasHoldingCall) { @@ -748,7 +749,7 @@ public class NotificationMgr implements CallerInfoAsyncQuery.OnQueryCompleteList } } - if (TelephonyCapabilities.supportsVoiceMessageCount(mPhone)) { + if (mPhone.getPhoneType() == Phone.PHONE_TYPE_CDMA) { int vmCount = mPhone.getVoiceMessageCount(); String titleFormat = mContext.getString(R.string.notification_voicemail_title_count); notificationTitle = String.format(titleFormat, vmCount); @@ -925,7 +926,7 @@ public class NotificationMgr implements CallerInfoAsyncQuery.OnQueryCompleteList * @param serviceState Phone service state */ void updateNetworkSelection(int serviceState) { - if (TelephonyCapabilities.supportsNetworkSelection(mPhone)) { + if (mPhone.getPhoneType() == Phone.PHONE_TYPE_GSM) { // get the shared preference of network_selection. // empty is auto mode, otherwise it is the operator alpha name // in case there is no operator name, check the operator numeric diff --git a/phone/src/com/android/phone2/OtaStartupReceiver.java b/phone/src/com/android/phone2/OtaStartupReceiver.java index d38976f..bd16435 100644 --- a/phone/src/com/android/phone2/OtaStartupReceiver.java +++ b/phone/src/com/android/phone2/OtaStartupReceiver.java @@ -53,13 +53,13 @@ public class OtaStartupReceiver extends BroadcastReceiver { public void onReceive(Context context, Intent intent) { mContext = context; - if (!TelephonyCapabilities.supportsOtasp(PhoneApp.getPhone())) { - if (DBG) Log.d(TAG, "OTASP not supported, nothing to do."); + if (!OtaUtils.isCdmaPhone()) { + if (DBG) Log.d(TAG, "Not a CDMA phone, no need to process OTA"); return; } if (shouldPostpone(context)) { - if (DBG) Log.d(TAG, "Postponing OTASP until wizard runs"); + if (DBG) Log.d(TAG, "Postponing CDMA provisioning until wizard runs"); return; } diff --git a/phone/src/com/android/phone2/OtaUtils.java b/phone/src/com/android/phone2/OtaUtils.java index 5a4ebc1..1632cb9 100644 --- a/phone/src/com/android/phone2/OtaUtils.java +++ b/phone/src/com/android/phone2/OtaUtils.java @@ -48,13 +48,6 @@ import android.widget.ProgressBar; import android.widget.TextView; /** - * TODO: This is Over The Air Service Provisioning (OTASP) - * A better name would be OtaspUtils.java. - * - * TODO: OTASP could UI may be substantially different on - * future devices, and may not necessarily be built-in - * to the InCallScreen. - * * Handles all OTA Call related logic and UI functionality. * The InCallScreen interacts with this class to perform an OTA Call. * @@ -65,6 +58,8 @@ import android.widget.TextView; */ public class OtaUtils { private static final String LOG_TAG = "OtaUtils"; + private static final String UNACTIVATED_MIN2_VALUE = "000000"; + private static final String UNACTIVATED_MIN_VALUE = "1111110111"; private static final boolean DBG = (PhoneApp.DBG_LEVEL >= 1); public static final int OTA_SHOW_ACTIVATION_SCREEN_OFF = 0; @@ -150,6 +145,22 @@ public class OtaUtils { } /** + * Returns true if the phone needs activation. + * + * @param minString the phone's MIN configuration string + * @return true if phone needs activation + * @throws OtaConfigurationException if the string is invalid + */ + public static boolean needsActivation(String minString) throws IllegalArgumentException { + if (minString == null || (minString.length() < 6)) { + throw new IllegalArgumentException(); + } + return (minString.equals(UNACTIVATED_MIN_VALUE) + || minString.substring(0,6).equals(UNACTIVATED_MIN2_VALUE)) + || SystemProperties.getBoolean("test_cdma_setup", false); + } + + /** * Starts the OTA provisioning call. If the MIN isn't available yet, it returns false and adds * an event to return the request to the calling app when it becomes available. * @@ -173,9 +184,20 @@ public class OtaUtils { phone.registerForSubscriptionInfoReady(handler, request, null); return false; } + phone.unregisterForSubscriptionInfoReady(handler); + String min = phone.getCdmaMin(); + + if (DBG) log("min_string: " + min); + + boolean phoneNeedsActivation = false; + try { + phoneNeedsActivation = needsActivation(min); + } catch (IllegalArgumentException e) { + if (DBG) log("invalid MIN string, exit"); + return true; // If the MIN string is wrong, there's nothing else we can do. + } - boolean phoneNeedsActivation = phone.needsOtaServiceProvisioning(); if (DBG) log("phoneNeedsActivation is set to " + phoneNeedsActivation); int otaShowActivationScreen = context.getResources().getInteger( @@ -407,7 +429,7 @@ public class OtaUtils { /** * Show either programming success dialog when OTA provisioning succeeds, or - * programming failure dialog when it fails. See {@link #otaShowProgramFailure} + * programming failure dialog when it fails. See {@link otaShowProgramFailure} * for more details. */ public void otaShowSuccessFailure() { @@ -991,7 +1013,7 @@ public class OtaUtils { Log.d(LOG_TAG, msg); } - private static boolean isCdmaPhone() { - return (PhoneApp.getPhone().getPhoneType() == Phone.PHONE_TYPE_CDMA); + public static boolean isCdmaPhone() { + return (PhoneApp.getInstance().phone.getPhoneType() == Phone.PHONE_TYPE_CDMA); } } diff --git a/phone/src/com/android/phone2/OutgoingCallBroadcaster.java b/phone/src/com/android/phone2/OutgoingCallBroadcaster.java index 2ad7e07..524f7b1 100644 --- a/phone/src/com/android/phone2/OutgoingCallBroadcaster.java +++ b/phone/src/com/android/phone2/OutgoingCallBroadcaster.java @@ -95,8 +95,8 @@ public class OutgoingCallBroadcaster extends Activity { number = getResultData(); final PhoneApp app = PhoneApp.getInstance(); - - if (TelephonyCapabilities.supportsOtasp(app.phone)) { + int phoneType = app.phone.getPhoneType(); + if (phoneType == Phone.PHONE_TYPE_CDMA) { boolean activateState = (app.cdmaOtaScreenState.otaScreenState == OtaUtils.CdmaOtaScreenState.OtaScreenState.OTA_STATUS_ACTIVATION); boolean dialogState = (app.cdmaOtaScreenState.otaScreenState @@ -124,9 +124,9 @@ public class OutgoingCallBroadcaster extends Activity { if (number == null) { if (DBG) Log.v(TAG, "CALL cancelled (null number), returning..."); return; - } else if (TelephonyCapabilities.supportsOtasp(app.phone) - && (app.phone.getState() != Phone.State.IDLE) - && (app.phone.isOtaSpNumber(number))) { + } else if ((phoneType == Phone.PHONE_TYPE_CDMA) + && ((app.phone.getState() != Phone.State.IDLE) + && (app.phone.isOtaSpNumber(number)))) { if (DBG) Log.v(TAG, "Call is active, a 2nd OTA call cancelled -- returning."); return; } else if (PhoneNumberUtils.isEmergencyNumber(number)) { @@ -198,10 +198,13 @@ public class OutgoingCallBroadcaster extends Activity { String action = intent.getAction(); String number = PhoneNumberUtils.getNumberFromIntent(intent, this); + Log.w(TAG, "getNumberFromIntent(): " + intent.getData() + " --> " + number); + /* if (number != null) { number = PhoneNumberUtils.convertKeypadLettersToDigits(number); number = PhoneNumberUtils.stripSeparators(number); } + */ final boolean emergencyNumber = (number != null) && PhoneNumberUtils.isEmergencyNumber(number); @@ -286,7 +289,7 @@ public class OutgoingCallBroadcaster extends Activity { if (number == null || TextUtils.isEmpty(number)) { if (intent.getBooleanExtra(EXTRA_SEND_EMPTY_FLASH, false)) { Log.i(TAG, "onCreate: SEND_EMPTY_FLASH..."); - PhoneUtils.sendEmptyFlash(PhoneApp.getPhone()); + PhoneUtils.sendEmptyFlash(PhoneApp.getInstance().phone); finish(); return; } else { diff --git a/phone/src/com/android/phone2/PhoneApp.java b/phone/src/com/android/phone2/PhoneApp.java index 69534e9..fef2f2b 100755 --- a/phone/src/com/android/phone2/PhoneApp.java +++ b/phone/src/com/android/phone2/PhoneApp.java @@ -55,7 +55,7 @@ import com.android.internal.telephony.Call; import com.android.internal.telephony.IccCard; import com.android.internal.telephony.MmiCode; import com.android.internal.telephony.Phone; -import com.android.internal.telephony.PhoneFactory; +import com.android.internal.telephony.SipPhoneFactory; import com.android.internal.telephony.TelephonyIntents; import com.android.internal.telephony.cdma.EriInfo; import com.android.phone2.OtaUtils.CdmaOtaScreenState; @@ -392,10 +392,10 @@ public class PhoneApp extends Application implements AccelerometerListener.Orien if (phone == null) { // Initialize the telephony framework - PhoneFactory.makeDefaultPhones(this); + SipPhoneFactory.makeDefaultPhones(this); // Get the default phone - phone = PhoneFactory.getDefaultPhone(); + phone = SipPhoneFactory.getDefaultPhone(); NotificationMgr.init(this); @@ -458,7 +458,9 @@ public class PhoneApp extends Application implements AccelerometerListener.Orien } // register for MMI/USSD - phone.registerForMmiComplete(mHandler, MMI_COMPLETE, null); + if (phoneType == Phone.PHONE_TYPE_GSM) { + phone.registerForMmiComplete(mHandler, MMI_COMPLETE, null); + } // register connection tracking to PhoneUtils PhoneUtils.initializeConnectionHandler(phone); @@ -525,7 +527,9 @@ public class PhoneApp extends Application implements AccelerometerListener.Orien } } - if (TelephonyCapabilities.supportsOtasp(phone)) { + boolean phoneIsCdma = (phone.getPhoneType() == Phone.PHONE_TYPE_CDMA); + + if (phoneIsCdma) { cdmaOtaProvisionData = new OtaUtils.CdmaOtaProvisionData(); cdmaOtaConfigData = new OtaUtils.CdmaOtaConfigData(); cdmaOtaScreenState = new OtaUtils.CdmaOtaScreenState(); @@ -584,13 +588,6 @@ public class PhoneApp extends Application implements AccelerometerListener.Orien return sMe; } - /** - * Returns the Phone associated with this instance - */ - static Phone getPhone() { - return getInstance().phone; - } - Ringer getRinger() { return ringer; } @@ -710,12 +707,11 @@ public class PhoneApp extends Application implements AccelerometerListener.Orien */ void dismissCallScreen() { if (mInCallScreen != null) { - if ((TelephonyCapabilities.supportsOtasp(phone)) && - (mInCallScreen.isOtaCallInActiveState() + if (mInCallScreen.isOtaCallInActiveState() || mInCallScreen.isOtaCallInEndState() || ((cdmaOtaScreenState != null) && (cdmaOtaScreenState.otaScreenState - != CdmaOtaScreenState.OtaScreenState.OTA_STATUS_UNDEFINED)))) { + != CdmaOtaScreenState.OtaScreenState.OTA_STATUS_UNDEFINED))) { // TODO: During OTA Call, display should not become dark to // allow user to see OTA UI update. Phone app needs to hold // a SCREEN_DIM_WAKE_LOCK wake lock during the entire OTA call. @@ -1170,13 +1166,10 @@ public class PhoneApp extends Application implements AccelerometerListener.Orien boolean screenOnImmediately = (isHeadsetPlugged() || PhoneUtils.isSpeakerOn(this) || ((mBtHandsfree != null) && mBtHandsfree.isAudioOn()) - || mIsHardKeyboardOpen); - // We do not keep the screen off when we are horizontal, but we do not force it - // on when we become horizontal until the proximity sensor goes negative. - boolean horizontal = (mOrientation == AccelerometerListener.ORIENTATION_HORIZONTAL); + || mIsHardKeyboardOpen + || mOrientation == AccelerometerListener.ORIENTATION_HORIZONTAL); - if (((state == Phone.State.OFFHOOK) || mBeginningCall) && - !screenOnImmediately && !horizontal) { + if (((state == Phone.State.OFFHOOK) || mBeginningCall) && !screenOnImmediately) { // Phone is in use! Arrange for the screen to turn off // automatically when the sensor detects a close object. if (!mProximityWakeLock.isHeld()) { @@ -1262,12 +1255,11 @@ public class PhoneApp extends Application implements AccelerometerListener.Orien private void initForNewRadioTechnology() { if (DBG) Log.d(LOG_TAG, "initForNewRadioTechnology..."); - if (phone.getPhoneType() == Phone.PHONE_TYPE_CDMA) { + if (phone.getPhoneType() == Phone.PHONE_TYPE_CDMA) { // Create an instance of CdmaPhoneCallState and initialize it to IDLE cdmaPhoneCallState = new CdmaPhoneCallState(); cdmaPhoneCallState.CdmaPhoneCallStateInit(); - } - if (TelephonyCapabilities.supportsOtasp(phone)) { + //create instances of CDMA OTA data classes if (cdmaOtaProvisionData == null) { cdmaOtaProvisionData = new OtaUtils.CdmaOtaProvisionData(); @@ -1281,9 +1273,6 @@ public class PhoneApp extends Application implements AccelerometerListener.Orien if (cdmaOtaInCallScreenUiState == null) { cdmaOtaInCallScreenUiState = new OtaUtils.CdmaOtaInCallScreenUiState(); } - } else { - //Clean up OTA data in GSM/UMTS. It is valid only for CDMA - clearOtaState(); } ringer.updateRingerContextAfterRadioTechnologyChange(this.phone); @@ -1470,7 +1459,7 @@ public class PhoneApp extends Application implements AccelerometerListener.Orien } else if (action.equals(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED)) { handleServiceStateChanged(intent); } else if (action.equals(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED)) { - if (TelephonyCapabilities.supportsEcm(phone)) { + if (phone.getPhoneType() == Phone.PHONE_TYPE_CDMA) { Log.d(LOG_TAG, "Emergency Callback Mode arrived in PhoneApp."); // Start Emergency Callback Mode service if (intent.getBooleanExtra("phoneinECMState", false)) { @@ -1478,10 +1467,8 @@ public class PhoneApp extends Application implements AccelerometerListener.Orien EmergencyCallbackModeService.class)); } } else { - // It doesn't make sense to get ACTION_EMERGENCY_CALLBACK_MODE_CHANGED - // on a device that doesn't support ECM in the first place. - Log.e(LOG_TAG, "Got ACTION_EMERGENCY_CALLBACK_MODE_CHANGED, " - + "but ECM isn't supported for phone: " + phone.getPhoneName()); + Log.e(LOG_TAG, "Error! Emergency Callback Mode not supported for " + + phone.getPhoneName() + " phones"); } } else if (action.equals(Intent.ACTION_DOCK_EVENT)) { mDockState = intent.getIntExtra(Intent.EXTRA_DOCK_STATE, @@ -1557,9 +1544,21 @@ public class PhoneApp extends Application implements AccelerometerListener.Orien // If service just returned, start sending out the queued messages ServiceState ss = ServiceState.newFromBundle(intent.getExtras()); + boolean hasService = true; + boolean isCdma = false; + String eriText = ""; + if (ss != null) { int state = ss.getState(); NotificationMgr.getDefault().updateNetworkSelection(state); + switch (state) { + case ServiceState.STATE_OUT_OF_SERVICE: + case ServiceState.STATE_POWER_OFF: + hasService = false; + break; + } + } else { + hasService = false; } } diff --git a/phone/src/com/android/phone2/PhoneInterfaceManager.java b/phone/src/com/android/phone2/PhoneInterfaceManager.java index f46ae52..e42f95b 100644 --- a/phone/src/com/android/phone2/PhoneInterfaceManager.java +++ b/phone/src/com/android/phone2/PhoneInterfaceManager.java @@ -135,7 +135,18 @@ public class PhoneInterfaceManager extends ITelephony.Stub { case CMD_END_CALL: request = (MainThreadRequest) msg.obj; - boolean hungUp = PhoneUtils.hangup(mPhone); + boolean hungUp = false; + int phoneType = mPhone.getPhoneType(); + if (phoneType == Phone.PHONE_TYPE_CDMA) { + // CDMA: If the user presses the Power button we treat it as + // ending the complete call session + hungUp = PhoneUtils.hangupRingingAndActive(mPhone); + } else if (phoneType == Phone.PHONE_TYPE_GSM) { + // GSM: End the call as per the Phone state + hungUp = PhoneUtils.hangup(mPhone); + } else { + throw new IllegalStateException("Unexpected phone type: " + phoneType); + } if (DBG) log("CMD_END_CALL: " + (hungUp ? "hung up!" : "no call to hang up")); request.result = hungUp; // Wake up the requesting thread @@ -198,7 +209,7 @@ public class PhoneInterfaceManager extends ITelephony.Stub { private void publish() { if (DBG) log("publish: " + this); - ServiceManager.addService("phone", this); + //ServiceManager.addService("phone", this); } // @@ -654,8 +665,20 @@ public class PhoneInterfaceManager extends ITelephony.Stub { /** * Returns true if CDMA provisioning needs to run. */ - public boolean needsOtaServiceProvisioning() { - return mPhone.needsOtaServiceProvisioning(); + public boolean getCdmaNeedsProvisioning() { + if (getActivePhoneType() == Phone.PHONE_TYPE_GSM) { + return false; + } + + boolean needsProvisioning = false; + String cdmaMin = mPhone.getCdmaMin(); + try { + needsProvisioning = OtaUtils.needsActivation(cdmaMin); + } catch (IllegalArgumentException e) { + // shouldn't get here unless hardware is misconfigured + Log.e(LOG_TAG, "CDMA MIN string " + ((cdmaMin == null) ? "was null" : "was too short")); + } + return needsProvisioning; } /** @@ -692,8 +715,6 @@ public class PhoneInterfaceManager extends ITelephony.Stub { return TelephonyManager.NETWORK_TYPE_EVDO_0; case ServiceState.RADIO_TECHNOLOGY_EVDO_A: return TelephonyManager.NETWORK_TYPE_EVDO_A; - case ServiceState.RADIO_TECHNOLOGY_EVDO_B: - return TelephonyManager.NETWORK_TYPE_EVDO_B; default: return TelephonyManager.NETWORK_TYPE_UNKNOWN; } diff --git a/phone/src/com/android/phone2/PhoneUtils.java b/phone/src/com/android/phone2/PhoneUtils.java index b064226..014d65d 100755 --- a/phone/src/com/android/phone2/PhoneUtils.java +++ b/phone/src/com/android/phone2/PhoneUtils.java @@ -67,7 +67,7 @@ import java.util.List; */ public class PhoneUtils { private static final String LOG_TAG = "PhoneUtils"; - private static final boolean DBG = (PhoneApp.DBG_LEVEL >= 2); + private static final boolean DBG = true; //(PhoneApp.DBG_LEVEL >= 2); /** Control stack trace for Audio Mode settings */ private static final boolean DBG_SETAUDIOMODE_STACK = false; @@ -276,10 +276,11 @@ public class PhoneUtils { //if (DBG) log("sPhone.acceptCall"); phone.acceptCall(); answered = true; - - // Always reset to "unmuted" for a freshly-answered call - setMute(phone, false); - + if (phoneIsCdma) { + // automatically reset mute state to unmuted for CDMA + // TODO: Would GSM want this also? + setMute(phone, false); + } setAudioMode(phone.getContext(), AudioManager.MODE_IN_CALL); // Check is phone in any dock, and turn on speaker accordingly @@ -335,43 +336,37 @@ public class PhoneUtils { } static boolean hangupRingingCall(Phone phone) { - if (DBG) log("hangupRingingCall()..."); + if (DBG) log("hangup ringing call"); Call ringing = phone.getRingingCall(); - Call.State state = ringing.getState(); + int phoneType = phone.getPhoneType(); - if (state == Call.State.INCOMING) { - // Regular incoming call (with no other active calls) - if (DBG) log("- regular incoming call: hangup()"); - return hangup(ringing); - } else if (state == Call.State.WAITING) { - // Call-waiting: there's an incoming call, but another call is - // already active. - // TODO: It would be better for the telephony layer to provide - // a "hangupWaitingCall()" API that works on all devices, - // rather than us having to check the phone type here and do - // the notifier.sendCdmaCallWaitingReject() hack for CDMA phones. - if (phone.getPhoneType() == Phone.PHONE_TYPE_CDMA) { - // CDMA: Ringing call and Call waiting hangup is handled differently. - // For Call waiting we DO NOT call the conventional hangup(call) function - // as in CDMA we just want to hangup the Call waiting connection. - if (DBG) log("- CDMA-specific call-waiting hangup"); + if (phoneType == Phone.PHONE_TYPE_CDMA) { + // CDMA: Ringing call and Call waiting hangup is handled differently. + // For Call waiting we DO NOT call the conventional hangup(call) function + // as in CDMA we just want to hungup the Call waiting connection. + Call.State state = ringing.getState(); + if (state == Call.State.INCOMING) { + if (DBG) log("hangup ringing call"); + return hangup(ringing); + } else if (state == Call.State.WAITING) { + if (DBG) log("hangup Call waiting call"); final CallNotifier notifier = PhoneApp.getInstance().notifier; notifier.sendCdmaCallWaitingReject(); return true; } else { - // Otherwise, the regular hangup() API works for - // call-waiting calls too. - if (DBG) log("- call-waiting call: hangup()"); - return hangup(ringing); + // This should never happen cause hangupRingingCall should always be called + // if the call.isRinging() returns TRUE, which basically means that the call + // should either be in INCOMING or WAITING state + if (DBG) log("No Ringing call to hangup"); + return false; } + } else if (phoneType == Phone.PHONE_TYPE_GSM) { + // GSM: Ringing Call and Call waiting, both are hungup by calling + // hangup(call) function. + if (DBG) log("hangup ringing call"); + return hangup(ringing); } else { - // Unexpected state: the ringing call isn't INCOMING or - // WAITING, so there's no reason to have called - // hangupRingingCall() in the first place. - // (Presumably the incoming call went away at the exact moment - // we got here, so just do nothing.) - Log.w(LOG_TAG, "hangupRingingCall: no INCOMING or WAITING call"); - return false; + throw new IllegalStateException("Unexpected phone type: " + phoneType); } } @@ -497,149 +492,173 @@ public class PhoneUtils { /** * Dial the number using the phone passed in. * - * If the connection is establised, this method issues a sync call - * that may block to query the caller info. - * TODO: Change the logic to use the async query. - * - * @param context To perform the CallerInfo query. * @param phone the Phone object. - * @param number to be dialed as requested by the user. This is - * NOT the phone number to connect to. It is used only to build the - * call card and to update the call log. See above for restrictions. - * @param contactRef that triggered the call. Typically a 'tel:' - * uri but can also be a 'content://contacts' one. - * @param isEmergencyCall indicates that whether or not this is an - * emergency call - * @param gatewayUri Is the address used to setup the connection, null - * if not using a gateway - * - * @return either CALL_STATUS_DIALED or CALL_STATUS_FAILED + * @param number to be dialed as requested by the user. + * @param contactRef that triggered the call. Either a 'tel:' or a + * 'content://contacts' uri depending on how the call was + * initiated (dialpad vs contact). + * @return either CALL_STATUS_DIALED, CALL_STATUS_DIALED_MMI, or CALL_STATUS_FAILED */ - public static int placeCall(Context context, Phone phone, - String number, Uri contactRef, boolean isEmergencyCall, - Uri gatewayUri) { - if (DBG) log("placeCall '" + number + "' GW:'" + gatewayUri + "'"); - boolean useGateway = false; - if (null != gatewayUri && - !isEmergencyCall && - PhoneUtils.isRoutableViaGateway(number)) { // Filter out MMI, OTA and other codes. - useGateway = true; - } - + static int placeCall(Phone phone, String number, Uri contactRef) { int status = CALL_STATUS_DIALED; - Connection connection; - String numberToDial; - if (useGateway) { - // TODO: 'tel' should be a constant defined in framework base - // somewhere (it is in webkit.) - if (null == gatewayUri || !"tel".equals(gatewayUri.getScheme())) { - Log.e(LOG_TAG, "Unsupported URL:" + gatewayUri); - return CALL_STATUS_FAILED; - } - - // We can use getSchemeSpecificPart because we don't allow # - // in the gateway numbers (treated a fragment delim.) However - // if we allow more complex gateway numbers sequence (with - // passwords or whatnot) that use #, this may break. - // TODO: Need to support MMI codes. - numberToDial = gatewayUri.getSchemeSpecificPart(); - } else { - numberToDial = number; - } - try { - connection = phone.dial(numberToDial); - } catch (CallStateException ex) { - Log.e(LOG_TAG, "Exception dialing ", ex); - connection = null; - } + if (DBG) log("placeCall: '" + number + "'..."); - int phoneType = phone.getPhoneType(); + Connection cn = phone.dial(number); + if (DBG) log("===> phone.dial() returned: " + cn); - // On GSM phones, null is returned for MMI codes - if (null == connection) { - if (phoneType == Phone.PHONE_TYPE_GSM && gatewayUri == null) { - if (DBG) log("dialed MMI code: " + number); - status = CALL_STATUS_DIALED_MMI; - // Set dialed MMI command to service - if (mNwService != null) { - try { - mNwService.setMmiString(number); - if (DBG) log("Extended NW bindService setUssdString (" + number + ")"); - } catch (RemoteException e) { - mNwService = null; + int phoneType = phone.getPhoneType(); + + // On GSM phones, null is returned for MMI codes + if (cn == null) { + if (phoneType == Phone.PHONE_TYPE_GSM) { + if (DBG) log("dialed MMI code: " + number); + status = CALL_STATUS_DIALED_MMI; + // Set dialed MMI command to service + if (mNwService != null) { + try { + mNwService.setMmiString(number); + if (DBG) log("Extended NW bindService setUssdString (" + number + ")"); + } catch (RemoteException e) { + mNwService = null; + } } + } else { + status = PhoneUtils.CALL_STATUS_FAILED; } } else { - status = CALL_STATUS_FAILED; - } - } else { - PhoneApp app = PhoneApp.getInstance(); - if (phoneType == Phone.PHONE_TYPE_CDMA) { - updateCdmaCallStateOnNewOutgoingCall(app); - } + PhoneApp app = PhoneApp.getInstance(); - PhoneUtils.setAudioControlState(PhoneUtils.AUDIO_OFFHOOK); + if (phoneType == Phone.PHONE_TYPE_CDMA) { + updateCdmaCallStateOnNewOutgoingCall(app); + } - // Clean up the number to be displayed. - if (phoneType == Phone.PHONE_TYPE_CDMA) { - number = CdmaConnection.formatDialString(number); - } - number = PhoneNumberUtils.extractNetworkPortion(number); - number = PhoneNumberUtils.convertKeypadLettersToDigits(number); - number = PhoneNumberUtils.formatNumber(number); + PhoneUtils.setAudioControlState(PhoneUtils.AUDIO_OFFHOOK); - if (gatewayUri == null) { // phone.dial() succeeded: we're now in a normal phone call. // attach the URI to the CallerInfo Object if it is there, // otherwise just attach the Uri Reference. // if the uri does not have a "content" scheme, then we treat // it as if it does NOT have a unique reference. - String content = context.getContentResolver().SCHEME_CONTENT; + String content = phone.getContext().getContentResolver().SCHEME_CONTENT; if ((contactRef != null) && (contactRef.getScheme().equals(content))) { - Object userDataObject = connection.getUserData(); + Object userDataObject = cn.getUserData(); if (userDataObject == null) { - connection.setUserData(contactRef); + cn.setUserData(contactRef); } else { // TODO: This branch is dead code, we have - // just created the connection which has + // just created the connection 'cn' which has // no user data (null) by default. if (userDataObject instanceof CallerInfo) { - ((CallerInfo) userDataObject).contactRefUri = contactRef; + ((CallerInfo) userDataObject).contactRefUri = contactRef; } else { - ((CallerInfoToken) userDataObject).currentInfo.contactRefUri = - contactRef; + ((CallerInfoToken) userDataObject).currentInfo.contactRefUri = + contactRef; } } } - } else { - // Get the caller info synchronously because we need the final - // CallerInfo object to update the dialed number with the one - // requested by the user (and not the provider's gateway number). - CallerInfo info = null; - String content = phone.getContext().getContentResolver().SCHEME_CONTENT; - if ((contactRef != null) && (contactRef.getScheme().equals(content))) { - info = CallerInfo.getCallerInfo(context, contactRef); - } + setAudioMode(phone.getContext(), AudioManager.MODE_IN_CALL); - // Fallback, lookup contact using the phone number if the - // contact's URI scheme was not content:// or if is was but - // the lookup failed. - if (null == info) { - info = CallerInfo.getCallerInfo(context, number); - } - info.phoneNumber = number; - connection.setUserData(info); + // Check is phone in any dock, and turn on speaker accordingly + activateSpeakerIfDocked(phone); } + } catch (CallStateException ex) { + Log.w(LOG_TAG, "Exception from phone.dial()", ex); + status = CALL_STATUS_FAILED; + } + + return status; + } + + /** + * Dial the number using a 3rd party provider gateway. Should + * *NOT* be called if the number is either: + * . An emergency one + * . A GSM MMI code + * . A CDMA feature code + * None of the above is checked in this method, it's the caller's + * responsability to make sure the number is 'valid'. + * + * If the connection is establised, this method issues a sync call + * that may block to query the caller info. + * TODO: Change the logic to use the async query. + * + * @param phone the Phone object. + * @param context To perform the CallerInfo query. + * @param number to be dialed as requested by the user. This is + * NOT the phone number to connect to. It is used only to build the + * call card and to update the call log. See above for restrictions. + * @param contactRef that triggered the call. Typically a 'tel:' + * uri but can also be a 'content://contacts' one. + * @param gatewayUri Is the address used to setup the connection. + * @return either CALL_STATUS_DIALED or CALL_STATUS_FAILED + */ + static int placeCallVia(Context context, Phone phone, + String number, Uri contactRef, Uri gatewayUri) { + if (DBG) log("placeCallVia: '" + number + "' GW:'" + gatewayUri + "'"); + + // TODO: 'tel' should be a contant defined in framework base + // somewhere (it is in webkit.) + if (null == gatewayUri || !"tel".equals(gatewayUri.getScheme())) { + Log.e(LOG_TAG, "Unsupported URL:" + gatewayUri); + return CALL_STATUS_FAILED; + } + + // We can use getSchemeSpecificPart because we don't allow # + // in the gateway numbers (treated a fragment delim.) However + // if we allow more complex gateway numbers sequence (with + // passwords or whatnot) that use #, this may break. + // TODO: Need to support MMI codes. + String gatewayNumber = gatewayUri.getSchemeSpecificPart(); + Connection connection; + try { + connection = phone.dial(gatewayNumber); + } catch (CallStateException ex) { + Log.e(LOG_TAG, "Exception dialing gateway", ex); + connection = null; + } - setAudioMode(phone.getContext(), AudioManager.MODE_IN_CALL); + if (null == connection) { + Log.e(LOG_TAG, "Got null connection."); + return CALL_STATUS_FAILED; + } - if (DBG) log("about to activate speaker"); - // Check is phone in any dock, and turn on speaker accordingly - activateSpeakerIfDocked(phone); + PhoneApp app = PhoneApp.getInstance(); + boolean phoneIsCdma = (phone.getPhoneType() == Phone.PHONE_TYPE_CDMA); + + if (phoneIsCdma) { + updateCdmaCallStateOnNewOutgoingCall(app); } + PhoneUtils.setAudioControlState(PhoneUtils.AUDIO_OFFHOOK); - return status; + // Clean up the number to be displayed. + if (phoneIsCdma) { + number = CdmaConnection.formatDialString(number); + } + number = PhoneNumberUtils.extractNetworkPortion(number); + number = PhoneNumberUtils.convertKeypadLettersToDigits(number); + number = PhoneNumberUtils.formatNumber(number); + + // Get the caller info synchronously because we need the final + // CallerInfo object to update the dialed number with the one + // requested by the user (and not the provider's gateway number). + CallerInfo info = null; + + if (ContentResolver.SCHEME_CONTENT.equals(contactRef.getScheme())) { + info = CallerInfo.getCallerInfo(context, contactRef); + } + + // Fallback, lookup contact using the phone number if the + // contact's URI scheme was not content:// or if is was but + // the lookup failed. + if (null == info) { + info = CallerInfo.getCallerInfo(context, number); + } + info.phoneNumber = number; + connection.setUserData(info); + + setAudioMode(phone.getContext(), AudioManager.MODE_IN_CALL); + return CALL_STATUS_DIALED; } /** @@ -1006,10 +1025,10 @@ public class PhoneUtils { new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { switch (whichButton) { - case DialogInterface.BUTTON_POSITIVE: + case DialogInterface.BUTTON1: phone.sendUssdResponse(inputText.getText().toString()); break; - case DialogInterface.BUTTON_NEGATIVE: + case DialogInterface.BUTTON2: if (mmiCode.isCancelable()) { mmiCode.cancel(); } @@ -2278,21 +2297,19 @@ public class PhoneUtils { /** * Returns whether the phone is in ECM ("Emergency Callback Mode") or not. + * (For non-CDMA phones, this will always return false. + * For CDMA Phones, return true iff PROPERTY_INECM_MODE == "true".) */ /* package */ static boolean isPhoneInEcm(Phone phone) { - if ((phone != null) && TelephonyCapabilities.supportsEcm(phone)) { - // For phones that support ECM, return true iff PROPERTY_INECM_MODE == "true". - // TODO: There ought to be a better API for this than just - // exposing a system property all the way up to the app layer, - // probably a method like "inEcm()" provided by the telephony - // layer. + boolean phoneInEcm = false; + if ((phone != null) && (phone.getPhoneType() == Phone.PHONE_TYPE_CDMA)) { String ecmMode = SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE); if (ecmMode != null) { - return ecmMode.equals("true"); + phoneInEcm = ecmMode.equals("true"); } } - return false; + return phoneInEcm; } diff --git a/phone/src/com/android/phone2/Settings.java b/phone/src/com/android/phone2/Settings.java index 50e4d0a..301ffc7 100644 --- a/phone/src/com/android/phone2/Settings.java +++ b/phone/src/com/android/phone2/Settings.java @@ -35,6 +35,7 @@ import android.preference.PreferenceScreen; import android.util.Log; import com.android.internal.telephony.Phone; +import com.android.internal.telephony.SipPhoneFactory; import com.android.internal.telephony.TelephonyIntents; import com.android.internal.telephony.TelephonyProperties; @@ -47,13 +48,17 @@ public class Settings extends PreferenceActivity implements DialogInterface.OnCl // debug data private static final String LOG_TAG = "NetworkSettings"; private static final boolean DBG = true; - public static final int REQUEST_CODE_EXIT_ECM = 17; + public static final int REQUEST_CODE_EXIT_ECM = 17; //String keys for preference lookup private static final String BUTTON_DATA_ENABLED_KEY = "button_data_enabled_key"; private static final String BUTTON_DATA_USAGE_KEY = "button_data_usage_key"; private static final String BUTTON_PREFERED_NETWORK_MODE = "preferred_network_mode_key"; private static final String BUTTON_ROAMING_KEY = "button_roaming_key"; + private static final String BUTTON_CDMA_ROAMING_KEY = "cdma_roaming_mode_key"; + + private static final String BUTTON_GSM_UMTS_OPTIONS = "gsm_umts_options_key"; + private static final String BUTTON_CDMA_OPTIONS = "cdma_options_key"; static final int preferredNetworkMode = Phone.PREFERRED_NT_MODE; @@ -61,6 +66,7 @@ public class Settings extends PreferenceActivity implements DialogInterface.OnCl private ListPreference mButtonPreferredNetworkMode; private CheckBoxPreference mButtonDataRoam; private CheckBoxPreference mButtonDataEnabled; + private CdmaRoamingListPreference mButtonCdmaRoam; private Preference mButtonDataUsage; private DataUsageListener mDataUsageListener; @@ -71,16 +77,14 @@ public class Settings extends PreferenceActivity implements DialogInterface.OnCl private boolean mOkClicked; //GsmUmts options and Cdma options - GsmUmtsOptions mGsmUmtsOptions; - CdmaOptions mCdmaOptions; - - private Preference mClickedPreference; + GsmUmtsOptions gsmumtsOptions; + CdmaOptions cdmaOptions; //This is a method implemented for DialogInterface.OnClickListener. // Used to dismiss the dialogs when they come up. public void onClick(DialogInterface dialog, int which) { - if (which == DialogInterface.BUTTON_POSITIVE) { + if (which == DialogInterface.BUTTON1) { mPhone.setDataRoamingEnabled(true); mOkClicked = true; } else { @@ -103,17 +107,13 @@ public class Settings extends PreferenceActivity implements DialogInterface.OnCl */ @Override public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) { - /** TODO: Refactor and get rid of the if's using subclasses */ - if (mGsmUmtsOptions != null && - mGsmUmtsOptions.preferenceTreeClick(preference) == true) { + if (gsmumtsOptions != null && + gsmumtsOptions.onPreferenceTreeClick(preferenceScreen, preference) == true) { return true; - } else if (mCdmaOptions != null && - mCdmaOptions.preferenceTreeClick(preference) == true) { + } else if (cdmaOptions != null && + cdmaOptions.onPreferenceTreeClick(preferenceScreen, preference) == true) { if (Boolean.parseBoolean( SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE))) { - - mClickedPreference = preference; - // In ECM mode launch ECM app dialog startActivityForResult( new Intent(TelephonyIntents.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS, null), @@ -127,7 +127,8 @@ public class Settings extends PreferenceActivity implements DialogInterface.OnCl preferredNetworkMode); mButtonPreferredNetworkMode.setValue(Integer.toString(settingsNetworkMode)); return true; - } else if (preference == mButtonDataRoam) { + } + else if (preference == mButtonDataRoam) { if (DBG) log("onPreferenceTreeClick: preference == mButtonDataRoam."); //normally called on the toggle click @@ -142,7 +143,8 @@ public class Settings extends PreferenceActivity implements DialogInterface.OnCl .setNegativeButton(android.R.string.no, this) .show() .setOnDismissListener(this); - } else { + } + else { mPhone.setDataRoamingEnabled(false); } return true; @@ -169,7 +171,7 @@ public class Settings extends PreferenceActivity implements DialogInterface.OnCl addPreferencesFromResource(R.xml.network_setting); - mPhone = PhoneApp.getPhone(); + mPhone = SipPhoneFactory.getDefaultPhone(); mHandler = new MyHandler(); //get UI object references @@ -191,15 +193,22 @@ public class Settings extends PreferenceActivity implements DialogInterface.OnCl getContentResolver(),android.provider.Settings.Secure.PREFERRED_NETWORK_MODE, preferredNetworkMode); mButtonPreferredNetworkMode.setValue(Integer.toString(settingsNetworkMode)); - mCdmaOptions = new CdmaOptions(this, prefSet); - mGsmUmtsOptions = new GsmUmtsOptions(this, prefSet); + // The intent code that resided here in the past has been moved into the + // more conventional location in network_setting.xml + } else { prefSet.removePreference(mButtonPreferredNetworkMode); + prefSet.removePreference(prefSet.findPreference(BUTTON_GSM_UMTS_OPTIONS)); + prefSet.removePreference(prefSet.findPreference(BUTTON_CDMA_OPTIONS)); int phoneType = mPhone.getPhoneType(); if (phoneType == Phone.PHONE_TYPE_CDMA) { - mCdmaOptions = new CdmaOptions(this, prefSet); + addPreferencesFromResource(R.xml.cdma_options); + mButtonCdmaRoam = + (CdmaRoamingListPreference) prefSet.findPreference(BUTTON_CDMA_ROAMING_KEY); + cdmaOptions = new CdmaOptions(); } else if (phoneType == Phone.PHONE_TYPE_GSM) { - mGsmUmtsOptions = new GsmUmtsOptions(this, prefSet); + addPreferencesFromResource(R.xml.gsm_umts_options); + gsmumtsOptions = new GsmUmtsOptions(); } else { throw new IllegalStateException("Unexpected phone type: " + phoneType); } @@ -448,8 +457,8 @@ public class Settings extends PreferenceActivity implements DialogInterface.OnCl Boolean isChoiceYes = data.getBooleanExtra(EmergencyCallbackModeExitDialog.EXTRA_EXIT_ECM_RESULT, false); if (isChoiceYes) { - // If the phone exits from ECM mode, show the CDMA Options - mCdmaOptions.showDialog(mClickedPreference); + // If the phone exits from ECM mode, show the system selection Options + mButtonCdmaRoam.showDialog(null); } else { // do nothing } diff --git a/phone/src/com/android/phone2/SimContacts.java b/phone/src/com/android/phone2/SimContacts.java index 7f9cb5e..fa15fa3 100644 --- a/phone/src/com/android/phone2/SimContacts.java +++ b/phone/src/com/android/phone2/SimContacts.java @@ -130,6 +130,11 @@ public class SimContacts extends ADNList { } } + // From HardCodedSources.java in Contacts app. + // TODO: fix this. + private static final String ACCOUNT_TYPE_GOOGLE = "com.google"; + private static final String GOOGLE_MY_CONTACTS_GROUP = "System Group: My Contacts"; + private static void actuallyImportOneSimContact( final Cursor cursor, final ContentResolver resolver, Account account) { final NamePhoneTypePair namePhoneTypePair = @@ -153,6 +158,23 @@ public class SimContacts extends ADNList { if (account != null) { builder.withValue(RawContacts.ACCOUNT_NAME, account.name); builder.withValue(RawContacts.ACCOUNT_TYPE, account.type); + + // TODO: temporal fix for "My Groups" issue. Need to be refactored. + if (ACCOUNT_TYPE_GOOGLE.equals(account.type)) { + final Cursor tmpCursor = resolver.query(Groups.CONTENT_URI, new String[] { + Groups.SOURCE_ID }, + Groups.TITLE + "=?", new String[] { + GOOGLE_MY_CONTACTS_GROUP }, null); + try { + if (tmpCursor != null && tmpCursor.moveToFirst()) { + myGroupsId = tmpCursor.getString(0); + } + } finally { + if (tmpCursor != null) { + tmpCursor.close(); + } + } + } } else { builder.withValues(sEmptyContentValues); } @@ -269,11 +291,6 @@ public class SimContacts extends ADNList { ImportAllSimContactsThread thread = new ImportAllSimContactsThread(); - // TODO: need to show some error dialog. - if (mCursor == null) { - Log.e(LOG_TAG, "cursor is null. Ignore silently."); - break; - } mProgressDialog = new ProgressDialog(this); mProgressDialog.setTitle(title); mProgressDialog.setMessage(message); @@ -281,7 +298,9 @@ public class SimContacts extends ADNList { mProgressDialog.setButton(DialogInterface.BUTTON_NEGATIVE, getString(R.string.cancel), thread); mProgressDialog.setProgress(0); - mProgressDialog.setMax(mCursor.getCount()); + if (mCursor != null) { + mProgressDialog.setMax(mCursor.getCount()); + } mProgressDialog.show(); thread.start(); diff --git a/phone/src/com/android/phone2/SpecialCharSequenceMgr.java b/phone/src/com/android/phone2/SpecialCharSequenceMgr.java index db31bbb..f81fe4b 100644 --- a/phone/src/com/android/phone2/SpecialCharSequenceMgr.java +++ b/phone/src/com/android/phone2/SpecialCharSequenceMgr.java @@ -22,6 +22,7 @@ import android.content.Context; import android.content.Intent; import android.net.Uri; import android.provider.Telephony.Intents; +import com.android.internal.telephony.SipPhoneFactory; import com.android.internal.telephony.Phone; import android.telephony.PhoneNumberUtils; import android.util.Log; @@ -198,23 +199,43 @@ public class SpecialCharSequenceMgr { static private boolean handleIMEIDisplay(Context context, String input) { if (input.equals(MMI_IMEI_DISPLAY)) { - showDeviceIdPanel(context); - return true; + int phoneType = PhoneApp.getInstance().phone.getPhoneType(); + if (phoneType == Phone.PHONE_TYPE_CDMA) { + showMEIDPanel(context); + return true; + } else if (phoneType == Phone.PHONE_TYPE_GSM) { + showIMEIPanel(context); + return true; + } } return false; } - static private void showDeviceIdPanel(Context context) { - if (DBG) log("showDeviceIdPanel()..."); + // TODO: showIMEIPanel and showMEIDPanel are almost cut and paste + // clones. Refactor. + static private void showIMEIPanel(Context context) { + if (DBG) log("showIMEIPanel"); + + String imeiStr = SipPhoneFactory.getDefaultPhone().getDeviceId(); + + AlertDialog alert = new AlertDialog.Builder(context) + .setTitle(R.string.imei) + .setMessage(imeiStr) + .setPositiveButton(R.string.ok, null) + .setCancelable(false) + .show(); + alert.getWindow().setType(WindowManager.LayoutParams.TYPE_PRIORITY_PHONE); + } + + static private void showMEIDPanel(Context context) { + if (DBG) log("showMEIDPanel"); - Phone phone = PhoneApp.getPhone(); - int labelId = TelephonyCapabilities.getDeviceIdLabel(phone); - String deviceId = phone.getDeviceId(); + String meidStr = SipPhoneFactory.getDefaultPhone().getDeviceId(); AlertDialog alert = new AlertDialog.Builder(context) - .setTitle(labelId) - .setMessage(deviceId) + .setTitle(R.string.meid) + .setMessage(meidStr) .setPositiveButton(R.string.ok, null) .setCancelable(false) .show(); diff --git a/phone/src/com/android/phone2/TelephonyCapabilities.java b/phone/src/com/android/phone2/TelephonyCapabilities.java deleted file mode 100644 index 527b813..0000000 --- a/phone/src/com/android/phone2/TelephonyCapabilities.java +++ /dev/null @@ -1,208 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.phone2; - -import android.content.Context; -import android.provider.Settings; -import android.util.Log; - -import com.android.internal.telephony.Phone; - -/** - * TODO: This is intended as a temporary repository for behavior policy - * functions that depend upon the type of phone or the carrier. Ultimately - * these sorts of questions should be answered by the telephony layer. - */ -public class TelephonyCapabilities { - private static final String LOG_TAG = "TelephonyCapabilities"; - - /** This class is never instantiated. */ - private TelephonyCapabilities() { - } - - /** - * On GSM devices, we never use short tones. - * On CDMA devices, it depends upon the settings. - * TODO: I don't think this has anything to do with GSM versus CDMA, - * should we be looking only at the setting? - */ - /* package */ static boolean useShortDtmfTones(Phone phone, Context context) { - int phoneType = phone.getPhoneType(); - if (phoneType == Phone.PHONE_TYPE_GSM) { - return false; - } else if (phoneType == Phone.PHONE_TYPE_CDMA) { - int toneType = android.provider.Settings.System.getInt( - context.getContentResolver(), - Settings.System.DTMF_TONE_TYPE_WHEN_DIALING, - CallFeaturesSetting.DTMF_TONE_TYPE_NORMAL); - if (toneType == CallFeaturesSetting.DTMF_TONE_TYPE_NORMAL) { - return true; - } else { - return false; - } - } else { - throw new IllegalStateException("Unexpected phone type: " + phoneType); - } - } - - /** - * Return true if the current phone supports ECM ("Emergency Callback - * Mode"), which is a feature where the device goes into a special - * state for a short period of time after making an outgoing emergency - * call. - * - * (On current devices, that state lasts 5 minutes. It prevents data - * usage by other apps, to avoid conflicts with any possible incoming - * calls. It also puts up a notification in the status bar, showing a - * countdown while ECM is active, and allowing the user to exit ECM.) - * - * Currently this is assumed to be true for CDMA phones, and false - * otherwise. - * - * TODO: This capability should really be exposed by the telephony - * layer, since it depends on the underlying telephony technology. - * (Or, is this actually carrier-specific? Is it VZW-only?) - */ - /* package */ static boolean supportsEcm(Phone phone) { - return (phone.getPhoneType() == Phone.PHONE_TYPE_CDMA); - } - - /** - * Return true if the current phone supports Over The Air Service - * Provisioning (OTASP) - * - * Currently this is assumed to be true for CDMA phones, and false - * otherwise. - * - * TODO: This capability should really be exposed by the telephony - * layer, since it depends on the underlying telephony technology. - * - * TODO: Watch out: this is also highly carrier-specific, since the - * OTA procedure is different from one carrier to the next, *and* the - * different carriers may want very different onscreen UI as well. - * The procedure may even be different for different devices with the - * same carrier. - * - * So we eventually will need a much more flexible, pluggable design. - * This method here is just a placeholder to reduce hardcoded - * "if (CDMA)" checks sprinkled throughout the rest of the phone app. - * - * TODO: consider using the term "OTASP" rather "OTA" everywhere in the - * phone app, since OTA can also mean over-the-air software updates. - */ - /* package */ static boolean supportsOtasp(Phone phone) { - return (phone.getPhoneType() == Phone.PHONE_TYPE_CDMA); - } - - /** - * Return true if the current phone can retrieve the voice message count. - * - * Currently this is assumed to be true on CDMA phones and false otherwise. - * - * TODO: This capability should really be exposed by the telephony - * layer, since it depends on the underlying telephony technology. - */ - /* package */ static boolean supportsVoiceMessageCount(Phone phone) { - return (phone.getPhoneType() == Phone.PHONE_TYPE_CDMA); - } - - /** - * Return true if this phone allows the user to select which - * network to use. - * - * Currently this is assumed to be true only on GSM phones. - * - * TODO: Should CDMA phones allow this as well? - */ - /* package */ static boolean supportsNetworkSelection(Phone phone) { - return (phone.getPhoneType() == Phone.PHONE_TYPE_GSM); - } - - /** - * Returns a resource ID for a label to use when displaying the - * "device id" of the current device. (This is currently used as the - * title of the "device id" dialog.) - * - * This is specific to the device's telephony technology: the device - * id is called "IMEI" on GSM phones and "MEID" on CDMA phones. - * TODO: ultimately this name should come directly from the - * telephony layer. - */ - /* package */ static int getDeviceIdLabel(Phone phone) { - if (phone.getPhoneType() == Phone.PHONE_TYPE_GSM) { - return R.string.imei; - } else if (phone.getPhoneType() == Phone.PHONE_TYPE_CDMA) { - return R.string.meid; - } else { - Log.w(LOG_TAG, "getDeviceIdLabel: no known label for phone " - + phone.getPhoneName()); - return 0; - } - } - - /** - * Return true if the current phone supports the ability to explicitly - * manage the state of a conference call (i.e. view the participants, - * and hangup or separate individual callers.) - * - * The in-call screen's "Manage conference" UI is available only on - * devices that support this feature. - * - * Currently this is assumed to be true on GSM phones and false otherwise. - * TODO: This capability should really be exposed by the telephony - * layer, since it depends on the underlying telephony technology. - */ - /* package */ static boolean supportsConferenceCallManagement(Phone phone) { - return (phone.getPhoneType() == Phone.PHONE_TYPE_GSM); - } - - /** - * Return true if the current phone supports explicit "Hold" and - * "Unhold" actions for an active call. (If so, the in-call UI will - * provide onscreen "Hold" / "Unhold" buttons.) - * - * Currently this is assumed to be true on GSM phones and false - * otherwise. (In particular, CDMA has no concept of "putting a call - * on hold.") - * TODO: This capability should really be exposed by the telephony - * layer, since it depends on the underlying telephony technology. - */ - /* package */ static boolean supportsHoldAndUnhold(Phone phone) { - return (phone.getPhoneType() == Phone.PHONE_TYPE_GSM); - } - - /** - * Return true if the current phone supports distinct "Answer & Hold" - * and "Answer & End" behaviors in the call-waiting scenario. If so, - * the in-call UI may provide separate buttons or menu items for these - * two actions. - * - * Currently this is assumed to be true on GSM phones and false - * otherwise. (In particular, CDMA has no concept of explicitly - * managing the background call, or "putting a call on hold.") - * - * TODO: This capability should really be exposed by the telephony - * layer, since it depends on the underlying telephony technology. - * - * TODO: It might be better to expose this capability in a more - * generic form, like maybe "supportsExplicitMultipleLineManagement()" - * rather than focusing specifically on call-waiting behavior. - */ - /* package */ static boolean supportsAnswerAndHold(Phone phone) { - return (phone.getPhoneType() == Phone.PHONE_TYPE_GSM); - } -} diff --git a/phone/src/com/android/phone2/TimeConsumingPreferenceActivity.java b/phone/src/com/android/phone2/TimeConsumingPreferenceActivity.java index c1abb13..2918f07 100644 --- a/phone/src/com/android/phone2/TimeConsumingPreferenceActivity.java +++ b/phone/src/com/android/phone2/TimeConsumingPreferenceActivity.java @@ -1,7 +1,5 @@ package com.android.phone2; -import com.android.internal.telephony.CommandException; - import android.app.AlertDialog; import android.app.Dialog; import android.app.ProgressDialog; @@ -17,7 +15,6 @@ interface TimeConsumingPreferenceListener { public void onStarted(Preference preference, boolean reading); public void onFinished(Preference preference, boolean reading); public void onError(Preference preference, int error); - public void onException(Preference preference, CommandException exception); } public class TimeConsumingPreferenceActivity extends PreferenceActivity @@ -32,7 +29,6 @@ public class TimeConsumingPreferenceActivity extends PreferenceActivity static final int EXCEPTION_ERROR = 300; static final int RESPONSE_ERROR = 400; static final int RADIO_OFF_ERROR = 500; - static final int FDN_CHECK_FAILURE = 600; private final ArrayList<String> mBusyList=new ArrayList<String> (); @@ -59,8 +55,7 @@ public class TimeConsumingPreferenceActivity extends PreferenceActivity return null; } - if (id == RESPONSE_ERROR || id == RADIO_OFF_ERROR || id == EXCEPTION_ERROR - || id == FDN_CHECK_FAILURE) { + if (id == RESPONSE_ERROR || id == RADIO_OFF_ERROR || id == EXCEPTION_ERROR) { AlertDialog.Builder b = new AlertDialog.Builder(this); int msgId; @@ -78,11 +73,6 @@ public class TimeConsumingPreferenceActivity extends PreferenceActivity // Set Button 3 b.setNeutralButton(R.string.close_dialog, this); break; - case FDN_CHECK_FAILURE: - msgId = R.string.fdn_only_error; - // Set Button 2 - b.setNegativeButton(R.string.close_dialog, this); - break; case EXCEPTION_ERROR: default: msgId = R.string.exception_error; @@ -161,14 +151,6 @@ public class TimeConsumingPreferenceActivity extends PreferenceActivity } } - public void onException(Preference preference, CommandException exception) { - if (exception.getCommandError() == CommandException.Error.FDN_CHECK_FAILURE) { - onError(preference, FDN_CHECK_FAILURE); - } else { - preference.setEnabled(false); - onError(preference, EXCEPTION_ERROR); - } - } public void onCancel(DialogInterface dialog) { if (DBG) dumpState(); finish(); diff --git a/phone/src/com/android/phone2/Use2GOnlyCheckBoxPreference.java b/phone/src/com/android/phone2/Use2GOnlyCheckBoxPreference.java index aae7410..e87fa7f 100644 --- a/phone/src/com/android/phone2/Use2GOnlyCheckBoxPreference.java +++ b/phone/src/com/android/phone2/Use2GOnlyCheckBoxPreference.java @@ -25,6 +25,7 @@ import android.util.AttributeSet; import android.util.Log; import com.android.internal.telephony.Phone; +import com.android.internal.telephony.SipPhoneFactory; public class Use2GOnlyCheckBoxPreference extends CheckBoxPreference { private static final String LOG_TAG = "Use2GOnlyCheckBoxPreference"; @@ -43,7 +44,7 @@ public class Use2GOnlyCheckBoxPreference extends CheckBoxPreference { public Use2GOnlyCheckBoxPreference(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); - mPhone = PhoneApp.getPhone(); + mPhone = SipPhoneFactory.getDefaultPhone(); mHandler = new MyHandler(); mPhone.getPreferredNetworkType( mHandler.obtainMessage(MyHandler.MESSAGE_GET_PREFERRED_NETWORK_TYPE)); diff --git a/phone/src2/com/android/internal/telephony/SipPhoneFactory.java b/phone/src2/com/android/internal/telephony/SipPhoneFactory.java new file mode 100644 index 0000000..6378922 --- /dev/null +++ b/phone/src2/com/android/internal/telephony/SipPhoneFactory.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony; + +import android.content.Context; +import android.util.Log; + +/** + * {@hide} + */ +public class SipPhoneFactory { + public static void makeDefaultPhones(Context context) { + makeDefaultPhone(context); + } + + public static void makeDefaultPhone(Context context) { + SipPhoneProxy.makePhoneProxy(context); + } + + public static Phone getDefaultPhone() { + return SipPhoneProxy.getPhoneProxy(); + } +} diff --git a/phone/src2/com/android/internal/telephony/SipPhoneNotifier.java b/phone/src2/com/android/internal/telephony/SipPhoneNotifier.java new file mode 100644 index 0000000..28f7618 --- /dev/null +++ b/phone/src2/com/android/internal/telephony/SipPhoneNotifier.java @@ -0,0 +1,234 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony; + +import android.os.Bundle; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.telephony.TelephonyManager; +import android.util.Log; + +import com.android.internal.telephony.ITelephonyRegistry; + +/** + * broadcast intents + */ +public class SipPhoneNotifier implements PhoneNotifier { + + static final String LOG_TAG = "GSM"; + private static final boolean DBG = true; + private ITelephonyRegistry mRegistry; + + /*package*/ + SipPhoneNotifier() { + mRegistry = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService( + "telephony.registry")); + } + + public void notifyPhoneState(Phone sender) { + Call ringingCall = sender.getRingingCall(); + String incomingNumber = ""; + if (ringingCall != null && ringingCall.getEarliestConnection() != null){ + incomingNumber = ringingCall.getEarliestConnection().getAddress(); + } + try { + mRegistry.notifyCallState(convertCallState(sender.getState()), incomingNumber); + } catch (RemoteException ex) { + // system process is dead + } + } + + public void notifyServiceState(Phone sender) { + try { + mRegistry.notifyServiceState(sender.getServiceState()); + } catch (RemoteException ex) { + // system process is dead + } + } + + public void notifySignalStrength(Phone sender) { + try { + mRegistry.notifySignalStrength(sender.getSignalStrength()); + } catch (RemoteException ex) { + // system process is dead + } + } + + public void notifyMessageWaitingChanged(Phone sender) { + try { + mRegistry.notifyMessageWaitingChanged(sender.getMessageWaitingIndicator()); + } catch (RemoteException ex) { + // system process is dead + } + } + + public void notifyCallForwardingChanged(Phone sender) { + try { + mRegistry.notifyCallForwardingChanged(sender.getCallForwardingIndicator()); + } catch (RemoteException ex) { + // system process is dead + } + } + + public void notifyDataActivity(Phone sender) { + try { + mRegistry.notifyDataActivity(convertDataActivityState(sender.getDataActivityState())); + } catch (RemoteException ex) { + // system process is dead + } + } + + public void notifyDataConnection(Phone sender, String reason) { + TelephonyManager telephony = TelephonyManager.getDefault(); + try { + mRegistry.notifyDataConnection( + convertDataState(sender.getDataConnectionState()), + sender.isDataConnectivityPossible(), reason, + sender.getActiveApn(), + sender.getActiveApnTypes(), + sender.getInterfaceName(null), + ((telephony!=null) ? telephony.getNetworkType() : + TelephonyManager.NETWORK_TYPE_UNKNOWN)); + } catch (RemoteException ex) { + // system process is dead + } + } + + public void notifyDataConnectionFailed(Phone sender, String reason) { + try { + mRegistry.notifyDataConnectionFailed(reason); + } catch (RemoteException ex) { + // system process is dead + } + } + + public void notifyCellLocation(Phone sender) { + Bundle data = new Bundle(); + sender.getCellLocation().fillInNotifierBundle(data); + try { + mRegistry.notifyCellLocation(data); + } catch (RemoteException ex) { + // system process is dead + } + } + + private void log(String s) { + Log.d(LOG_TAG, "[PhoneNotifier] " + s); + } + + /** + * Convert the {@link State} enum into the TelephonyManager.CALL_STATE_* constants + * for the public API. + */ + public static int convertCallState(Phone.State state) { + switch (state) { + case RINGING: + return TelephonyManager.CALL_STATE_RINGING; + case OFFHOOK: + return TelephonyManager.CALL_STATE_OFFHOOK; + default: + return TelephonyManager.CALL_STATE_IDLE; + } + } + + /** + * Convert the TelephonyManager.CALL_STATE_* constants into the {@link State} enum + * for the public API. + */ + public static Phone.State convertCallState(int state) { + switch (state) { + case TelephonyManager.CALL_STATE_RINGING: + return Phone.State.RINGING; + case TelephonyManager.CALL_STATE_OFFHOOK: + return Phone.State.OFFHOOK; + default: + return Phone.State.IDLE; + } + } + + /** + * Convert the {@link DataState} enum into the TelephonyManager.DATA_* constants + * for the public API. + */ + public static int convertDataState(Phone.DataState state) { + switch (state) { + case CONNECTING: + return TelephonyManager.DATA_CONNECTING; + case CONNECTED: + return TelephonyManager.DATA_CONNECTED; + case SUSPENDED: + return TelephonyManager.DATA_SUSPENDED; + default: + return TelephonyManager.DATA_DISCONNECTED; + } + } + + /** + * Convert the TelephonyManager.DATA_* constants into {@link DataState} enum + * for the public API. + */ + public static Phone.DataState convertDataState(int state) { + switch (state) { + case TelephonyManager.DATA_CONNECTING: + return Phone.DataState.CONNECTING; + case TelephonyManager.DATA_CONNECTED: + return Phone.DataState.CONNECTED; + case TelephonyManager.DATA_SUSPENDED: + return Phone.DataState.SUSPENDED; + default: + return Phone.DataState.DISCONNECTED; + } + } + + /** + * Convert the {@link DataState} enum into the TelephonyManager.DATA_* constants + * for the public API. + */ + public static int convertDataActivityState(Phone.DataActivityState state) { + switch (state) { + case DATAIN: + return TelephonyManager.DATA_ACTIVITY_IN; + case DATAOUT: + return TelephonyManager.DATA_ACTIVITY_OUT; + case DATAINANDOUT: + return TelephonyManager.DATA_ACTIVITY_INOUT; + case DORMANT: + return TelephonyManager.DATA_ACTIVITY_DORMANT; + default: + return TelephonyManager.DATA_ACTIVITY_NONE; + } + } + + /** + * Convert the TelephonyManager.DATA_* constants into the {@link DataState} enum + * for the public API. + */ + public static Phone.DataActivityState convertDataActivityState(int state) { + switch (state) { + case TelephonyManager.DATA_ACTIVITY_IN: + return Phone.DataActivityState.DATAIN; + case TelephonyManager.DATA_ACTIVITY_OUT: + return Phone.DataActivityState.DATAOUT; + case TelephonyManager.DATA_ACTIVITY_INOUT: + return Phone.DataActivityState.DATAINANDOUT; + case TelephonyManager.DATA_ACTIVITY_DORMANT: + return Phone.DataActivityState.DORMANT; + default: + return Phone.DataActivityState.NONE; + } + } +} diff --git a/phone/src2/com/android/internal/telephony/SipPhoneProxy.java b/phone/src2/com/android/internal/telephony/SipPhoneProxy.java new file mode 100644 index 0000000..a62deb2 --- /dev/null +++ b/phone/src2/com/android/internal/telephony/SipPhoneProxy.java @@ -0,0 +1,773 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony; + + +import android.app.ActivityManagerNative; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.net.sip.SipProfile; +import android.os.Handler; +import android.os.Message; +import android.os.SystemProperties; +import android.preference.PreferenceManager; +import android.telephony.CellLocation; +import android.telephony.PhoneStateListener; +import android.telephony.ServiceState; +import android.telephony.SignalStrength; +import android.util.Log; + +import com.android.internal.telephony.sip.SipPhone; +import com.android.internal.telephony.gsm.NetworkInfo; +import com.android.internal.telephony.test.SimulatedRadioControl; + +import java.text.ParseException; +import java.util.List; + +public class SipPhoneProxy implements Phone { + private static SipPhoneProxy sPhoneProxy = new SipPhoneProxy(); + private static PhoneNotifier sPhoneNotifier = makeDefaultPhoneNotifier(); + private static Context sContext; + + public static void makePhoneProxy(Context context) { + sContext = context; + setPhone("sip:fake@fake.domain"); + } + + public static SipPhoneProxy getPhoneProxy() { + return sPhoneProxy; + } + + public static void setPhone(String sipProfileUri) { + try { + SipProfile profile = new SipProfile.Builder(sipProfileUri).build(); + sPhoneProxy.mActivePhone = + new SipPhone(sContext, sPhoneNotifier, profile); + Log.v("SipPhoneProxy", "setPhone: " + sPhoneProxy + " proxes " + sPhoneProxy.mActivePhone); + } catch (ParseException e) { + Log.v("SipPhoneProxy", "setPhone", e); + } + } + + private static PhoneNotifier makeDefaultPhoneNotifier() { + try { + return new SipPhoneNotifier(); + } catch (Error e) { + Log.e("SipPhoneProxy", "makeDefaultPhoneNotifier", e); + throw e; + } + } + + private SipPhone mActivePhone; + + private static final String LOG_TAG = "PHONE"; + + private SipPhoneProxy() { + } + + private void logv(String msg) { + Log.v(LOG_TAG, "[PhoneProxy] " + msg); + } + + private void logd(String msg) { + Log.d(LOG_TAG, "[PhoneProxy] " + msg); + } + + private void logw(String msg) { + Log.w(LOG_TAG, "[PhoneProxy] " + msg); + } + + private void loge(String msg) { + Log.e(LOG_TAG, "[PhoneProxy] " + msg); + } + + + public ServiceState getServiceState() { + return mActivePhone.getServiceState(); + } + + public CellLocation getCellLocation() { + return mActivePhone.getCellLocation(); + } + + public DataState getDataConnectionState() { + return mActivePhone.getDataConnectionState(); + } + + public DataActivityState getDataActivityState() { + return mActivePhone.getDataActivityState(); + } + + public Context getContext() { + return mActivePhone.getContext(); + } + + public void disableDnsCheck(boolean b) { + mActivePhone.disableDnsCheck(b); + } + + public boolean isDnsCheckDisabled() { + return mActivePhone.isDnsCheckDisabled(); + } + + public State getState() { + return mActivePhone.getState(); + } + + public String getPhoneName() { + return mActivePhone.getPhoneName(); + } + + public int getPhoneType() { + return mActivePhone.getPhoneType(); + } + + public String[] getActiveApnTypes() { + return mActivePhone.getActiveApnTypes(); + } + + public String getActiveApn() { + return mActivePhone.getActiveApn(); + } + + public SignalStrength getSignalStrength() { + return mActivePhone.getSignalStrength(); + } + + public void registerForUnknownConnection(Handler h, int what, Object obj) { + mActivePhone.registerForUnknownConnection(h, what, obj); + } + + public void unregisterForUnknownConnection(Handler h) { + mActivePhone.unregisterForUnknownConnection(h); + } + + public void registerForPreciseCallStateChanged(Handler h, int what, Object obj) { + mActivePhone.registerForPreciseCallStateChanged(h, what, obj); + } + + public void unregisterForPreciseCallStateChanged(Handler h) { + mActivePhone.unregisterForPreciseCallStateChanged(h); + } + + public void registerForNewRingingConnection(Handler h, int what, Object obj) { + mActivePhone.registerForNewRingingConnection(h, what, obj); + } + + public void unregisterForNewRingingConnection(Handler h) { + mActivePhone.unregisterForNewRingingConnection(h); + } + + public void registerForIncomingRing(Handler h, int what, Object obj) { + mActivePhone.registerForIncomingRing(h, what, obj); + } + + public void unregisterForIncomingRing(Handler h) { + mActivePhone.unregisterForIncomingRing(h); + } + + public void registerForDisconnect(Handler h, int what, Object obj) { + mActivePhone.registerForDisconnect(h, what, obj); + } + + public void unregisterForDisconnect(Handler h) { + mActivePhone.unregisterForDisconnect(h); + } + + public void registerForMmiInitiate(Handler h, int what, Object obj) { + mActivePhone.registerForMmiInitiate(h, what, obj); + } + + public void unregisterForMmiInitiate(Handler h) { + mActivePhone.unregisterForMmiInitiate(h); + } + + public void registerForMmiComplete(Handler h, int what, Object obj) { + mActivePhone.registerForMmiComplete(h, what, obj); + } + + public void unregisterForMmiComplete(Handler h) { + mActivePhone.unregisterForMmiComplete(h); + } + + public List<? extends MmiCode> getPendingMmiCodes() { + return mActivePhone.getPendingMmiCodes(); + } + + public void sendUssdResponse(String ussdMessge) { + mActivePhone.sendUssdResponse(ussdMessge); + } + + public void registerForServiceStateChanged(Handler h, int what, Object obj) { + mActivePhone.registerForServiceStateChanged(h, what, obj); + } + + public void unregisterForServiceStateChanged(Handler h) { + mActivePhone.unregisterForServiceStateChanged(h); + } + + public void registerForSuppServiceNotification(Handler h, int what, Object obj) { + mActivePhone.registerForSuppServiceNotification(h, what, obj); + } + + public void unregisterForSuppServiceNotification(Handler h) { + mActivePhone.unregisterForSuppServiceNotification(h); + } + + public void registerForSuppServiceFailed(Handler h, int what, Object obj) { + mActivePhone.registerForSuppServiceFailed(h, what, obj); + } + + public void unregisterForSuppServiceFailed(Handler h) { + mActivePhone.unregisterForSuppServiceFailed(h); + } + + public void registerForInCallVoicePrivacyOn(Handler h, int what, Object obj){ + mActivePhone.registerForInCallVoicePrivacyOn(h,what,obj); + } + + public void unregisterForInCallVoicePrivacyOn(Handler h){ + mActivePhone.unregisterForInCallVoicePrivacyOn(h); + } + + public void registerForInCallVoicePrivacyOff(Handler h, int what, Object obj){ + mActivePhone.registerForInCallVoicePrivacyOff(h,what,obj); + } + + public void unregisterForInCallVoicePrivacyOff(Handler h){ + mActivePhone.unregisterForInCallVoicePrivacyOff(h); + } + + public void registerForCdmaOtaStatusChange(Handler h, int what, Object obj) { + mActivePhone.registerForCdmaOtaStatusChange(h,what,obj); + } + + public void unregisterForCdmaOtaStatusChange(Handler h) { + mActivePhone.unregisterForCdmaOtaStatusChange(h); + } + + public void registerForSubscriptionInfoReady(Handler h, int what, Object obj) { + mActivePhone.registerForSubscriptionInfoReady(h, what, obj); + } + + public void unregisterForSubscriptionInfoReady(Handler h) { + mActivePhone.unregisterForSubscriptionInfoReady(h); + } + + public void registerForEcmTimerReset(Handler h, int what, Object obj) { + mActivePhone.registerForEcmTimerReset(h,what,obj); + } + + public void unregisterForEcmTimerReset(Handler h) { + mActivePhone.unregisterForEcmTimerReset(h); + } + + public void registerForRingbackTone(Handler h, int what, Object obj) { + mActivePhone.registerForRingbackTone(h,what,obj); + } + + public void unregisterForRingbackTone(Handler h) { + mActivePhone.unregisterForRingbackTone(h); + } + + public void registerForResendIncallMute(Handler h, int what, Object obj) { + mActivePhone.registerForResendIncallMute(h,what,obj); + } + + public void unregisterForResendIncallMute(Handler h) { + mActivePhone.unregisterForResendIncallMute(h); + } + + public boolean getIccRecordsLoaded() { + return mActivePhone.getIccRecordsLoaded(); + } + + public IccCard getIccCard() { + return mActivePhone.getIccCard(); + } + + public void acceptCall() throws CallStateException { + mActivePhone.acceptCall(); + } + + public void rejectCall() throws CallStateException { + mActivePhone.rejectCall(); + } + + public void switchHoldingAndActive() throws CallStateException { + mActivePhone.switchHoldingAndActive(); + } + + public boolean canConference() { + return mActivePhone.canConference(); + } + + public void conference() throws CallStateException { + mActivePhone.conference(); + } + + public void enableEnhancedVoicePrivacy(boolean enable, Message onComplete) { + mActivePhone.enableEnhancedVoicePrivacy(enable, onComplete); + } + + public void getEnhancedVoicePrivacy(Message onComplete) { + mActivePhone.getEnhancedVoicePrivacy(onComplete); + } + + public boolean canTransfer() { + return mActivePhone.canTransfer(); + } + + public void explicitCallTransfer() throws CallStateException { + mActivePhone.explicitCallTransfer(); + } + + public void clearDisconnected() { + mActivePhone.clearDisconnected(); + } + + public Call getForegroundCall() { + Log.v("SipPhoneProxy", "getForegroundCall: " + sPhoneProxy + " proxes " + sPhoneProxy.mActivePhone); + return mActivePhone.getForegroundCall(); + } + + public Call getBackgroundCall() { + return mActivePhone.getBackgroundCall(); + } + + public Call getRingingCall() { + return mActivePhone.getRingingCall(); + } + + public Connection dial(String dialString) throws CallStateException { + return mActivePhone.dial(dialString); + } + + public boolean handlePinMmi(String dialString) { + return mActivePhone.handlePinMmi(dialString); + } + + public boolean handleInCallMmiCommands(String command) throws CallStateException { + return mActivePhone.handleInCallMmiCommands(command); + } + + public void sendDtmf(char c) { + mActivePhone.sendDtmf(c); + } + + public void startDtmf(char c) { + mActivePhone.startDtmf(c); + } + + public void stopDtmf() { + mActivePhone.stopDtmf(); + } + + public void setRadioPower(boolean power) { + mActivePhone.setRadioPower(power); + } + + public boolean getMessageWaitingIndicator() { + return mActivePhone.getMessageWaitingIndicator(); + } + + public boolean getCallForwardingIndicator() { + return mActivePhone.getCallForwardingIndicator(); + } + + public String getLine1Number() { + return mActivePhone.getLine1Number(); + } + + public String getCdmaMin() { + return mActivePhone.getCdmaMin(); + } + + public boolean isMinInfoReady() { + return mActivePhone.isMinInfoReady(); + } + + public String getCdmaPrlVersion() { + return mActivePhone.getCdmaPrlVersion(); + } + + public String getLine1AlphaTag() { + return mActivePhone.getLine1AlphaTag(); + } + + public void setLine1Number(String alphaTag, String number, Message onComplete) { + mActivePhone.setLine1Number(alphaTag, number, onComplete); + } + + public String getVoiceMailNumber() { + return mActivePhone.getVoiceMailNumber(); + } + + /** @hide */ + public int getVoiceMessageCount(){ + return mActivePhone.getVoiceMessageCount(); + } + + public String getVoiceMailAlphaTag() { + return mActivePhone.getVoiceMailAlphaTag(); + } + + public void setVoiceMailNumber(String alphaTag,String voiceMailNumber, + Message onComplete) { + mActivePhone.setVoiceMailNumber(alphaTag, voiceMailNumber, onComplete); + } + + public void getCallForwardingOption(int commandInterfaceCFReason, + Message onComplete) { + mActivePhone.getCallForwardingOption(commandInterfaceCFReason, + onComplete); + } + + public void setCallForwardingOption(int commandInterfaceCFReason, + int commandInterfaceCFAction, String dialingNumber, + int timerSeconds, Message onComplete) { + mActivePhone.setCallForwardingOption(commandInterfaceCFReason, + commandInterfaceCFAction, dialingNumber, timerSeconds, onComplete); + } + + public void getOutgoingCallerIdDisplay(Message onComplete) { + mActivePhone.getOutgoingCallerIdDisplay(onComplete); + } + + public void setOutgoingCallerIdDisplay(int commandInterfaceCLIRMode, + Message onComplete) { + mActivePhone.setOutgoingCallerIdDisplay(commandInterfaceCLIRMode, + onComplete); + } + + public void getCallWaiting(Message onComplete) { + mActivePhone.getCallWaiting(onComplete); + } + + public void setCallWaiting(boolean enable, Message onComplete) { + mActivePhone.setCallWaiting(enable, onComplete); + } + + public void getAvailableNetworks(Message response) { + mActivePhone.getAvailableNetworks(response); + } + + public void setNetworkSelectionModeAutomatic(Message response) { + mActivePhone.setNetworkSelectionModeAutomatic(response); + } + + public void selectNetworkManually(NetworkInfo network, Message response) { + mActivePhone.selectNetworkManually(network, response); + } + + public void setPreferredNetworkType(int networkType, Message response) { + mActivePhone.setPreferredNetworkType(networkType, response); + } + + public void getPreferredNetworkType(Message response) { + mActivePhone.getPreferredNetworkType(response); + } + + public void getNeighboringCids(Message response) { + mActivePhone.getNeighboringCids(response); + } + + public void setOnPostDialCharacter(Handler h, int what, Object obj) { + mActivePhone.setOnPostDialCharacter(h, what, obj); + } + + public void setMute(boolean muted) { + mActivePhone.setMute(muted); + } + + public boolean getMute() { + return mActivePhone.getMute(); + } + + public void invokeOemRilRequestRaw(byte[] data, Message response) { + mActivePhone.invokeOemRilRequestRaw(data, response); + } + + public void invokeOemRilRequestStrings(String[] strings, Message response) { + mActivePhone.invokeOemRilRequestStrings(strings, response); + } + + public void getDataCallList(Message response) { + mActivePhone.getDataCallList(response); + } + + public List<DataConnection> getCurrentDataConnectionList() { + return mActivePhone.getCurrentDataConnectionList(); + } + + public void updateServiceLocation() { + mActivePhone.updateServiceLocation(); + } + + public void enableLocationUpdates() { + mActivePhone.enableLocationUpdates(); + } + + public void disableLocationUpdates() { + mActivePhone.disableLocationUpdates(); + } + + public void setUnitTestMode(boolean f) { + mActivePhone.setUnitTestMode(f); + } + + public boolean getUnitTestMode() { + return mActivePhone.getUnitTestMode(); + } + + public void setBandMode(int bandMode, Message response) { + mActivePhone.setBandMode(bandMode, response); + } + + public void queryAvailableBandMode(Message response) { + mActivePhone.queryAvailableBandMode(response); + } + + public boolean getDataRoamingEnabled() { + return mActivePhone.getDataRoamingEnabled(); + } + + public void setDataRoamingEnabled(boolean enable) { + mActivePhone.setDataRoamingEnabled(enable); + } + + public void queryCdmaRoamingPreference(Message response) { + mActivePhone.queryCdmaRoamingPreference(response); + } + + public void setCdmaRoamingPreference(int cdmaRoamingType, Message response) { + mActivePhone.setCdmaRoamingPreference(cdmaRoamingType, response); + } + + public void setCdmaSubscription(int cdmaSubscriptionType, Message response) { + mActivePhone.setCdmaSubscription(cdmaSubscriptionType, response); + } + + public SimulatedRadioControl getSimulatedRadioControl() { + return mActivePhone.getSimulatedRadioControl(); + } + + public boolean enableDataConnectivity() { + return mActivePhone.enableDataConnectivity(); + } + + public boolean disableDataConnectivity() { + return mActivePhone.disableDataConnectivity(); + } + + public int enableApnType(String type) { + return mActivePhone.enableApnType(type); + } + + public int disableApnType(String type) { + return mActivePhone.disableApnType(type); + } + + public boolean isDataConnectivityEnabled() { + return mActivePhone.isDataConnectivityEnabled(); + } + + public boolean isDataConnectivityPossible() { + return mActivePhone.isDataConnectivityPossible(); + } + + public String getInterfaceName(String apnType) { + return mActivePhone.getInterfaceName(apnType); + } + + public String getIpAddress(String apnType) { + return mActivePhone.getIpAddress(apnType); + } + + public String getGateway(String apnType) { + return mActivePhone.getGateway(apnType); + } + + public String[] getDnsServers(String apnType) { + return mActivePhone.getDnsServers(apnType); + } + + public String getDeviceId() { + return mActivePhone.getDeviceId(); + } + + public String getDeviceSvn() { + return mActivePhone.getDeviceSvn(); + } + + public String getSubscriberId() { + return mActivePhone.getSubscriberId(); + } + + public String getIccSerialNumber() { + return mActivePhone.getIccSerialNumber(); + } + + public String getEsn() { + return mActivePhone.getEsn(); + } + + public String getMeid() { + return mActivePhone.getMeid(); + } + + public PhoneSubInfo getPhoneSubInfo(){ + return mActivePhone.getPhoneSubInfo(); + } + + public IccSmsInterfaceManager getIccSmsInterfaceManager(){ + return mActivePhone.getIccSmsInterfaceManager(); + } + + public IccPhoneBookInterfaceManager getIccPhoneBookInterfaceManager(){ + return mActivePhone.getIccPhoneBookInterfaceManager(); + } + + public void setTTYMode(int ttyMode, Message onComplete) { + mActivePhone.setTTYMode(ttyMode, onComplete); + } + + public void queryTTYMode(Message onComplete) { + mActivePhone.queryTTYMode(onComplete); + } + + public void activateCellBroadcastSms(int activate, Message response) { + mActivePhone.activateCellBroadcastSms(activate, response); + } + + public void getCellBroadcastSmsConfig(Message response) { + mActivePhone.getCellBroadcastSmsConfig(response); + } + + public void setCellBroadcastSmsConfig(int[] configValuesArray, Message response) { + mActivePhone.setCellBroadcastSmsConfig(configValuesArray, response); + } + + public void notifyDataActivity() { + mActivePhone.notifyDataActivity(); + } + + public void getSmscAddress(Message result) { + mActivePhone.getSmscAddress(result); + } + + public void setSmscAddress(String address, Message result) { + mActivePhone.setSmscAddress(address, result); + } + + public int getCdmaEriIconIndex() { + return mActivePhone.getCdmaEriIconIndex(); + } + + public String getCdmaEriText() { + return mActivePhone.getCdmaEriText(); + } + + public int getCdmaEriIconMode() { + return mActivePhone.getCdmaEriIconMode(); + } + + public void sendBurstDtmf(String dtmfString, int on, int off, Message onComplete){ + mActivePhone.sendBurstDtmf(dtmfString, on, off, onComplete); + } + + public void exitEmergencyCallbackMode(){ + mActivePhone.exitEmergencyCallbackMode(); + } + + public boolean isOtaSpNumber(String dialStr){ + return mActivePhone.isOtaSpNumber(dialStr); + } + + public void registerForCallWaiting(Handler h, int what, Object obj){ + mActivePhone.registerForCallWaiting(h,what,obj); + } + + public void unregisterForCallWaiting(Handler h){ + mActivePhone.unregisterForCallWaiting(h); + } + + public void registerForSignalInfo(Handler h, int what, Object obj) { + mActivePhone.registerForSignalInfo(h,what,obj); + } + + public void unregisterForSignalInfo(Handler h) { + mActivePhone.unregisterForSignalInfo(h); + } + + public void registerForDisplayInfo(Handler h, int what, Object obj) { + mActivePhone.registerForDisplayInfo(h,what,obj); + } + + public void unregisterForDisplayInfo(Handler h) { + mActivePhone.unregisterForDisplayInfo(h); + } + + public void registerForNumberInfo(Handler h, int what, Object obj) { + mActivePhone.registerForNumberInfo(h, what, obj); + } + + public void unregisterForNumberInfo(Handler h) { + mActivePhone.unregisterForNumberInfo(h); + } + + public void registerForRedirectedNumberInfo(Handler h, int what, Object obj) { + mActivePhone.registerForRedirectedNumberInfo(h, what, obj); + } + + public void unregisterForRedirectedNumberInfo(Handler h) { + mActivePhone.unregisterForRedirectedNumberInfo(h); + } + + public void registerForLineControlInfo(Handler h, int what, Object obj) { + mActivePhone.registerForLineControlInfo( h, what, obj); + } + + public void unregisterForLineControlInfo(Handler h) { + mActivePhone.unregisterForLineControlInfo(h); + } + + public void registerFoT53ClirlInfo(Handler h, int what, Object obj) { + mActivePhone.registerFoT53ClirlInfo(h, what, obj); + } + + public void unregisterForT53ClirInfo(Handler h) { + mActivePhone.unregisterForT53ClirInfo(h); + } + + public void registerForT53AudioControlInfo(Handler h, int what, Object obj) { + mActivePhone.registerForT53AudioControlInfo( h, what, obj); + } + + public void unregisterForT53AudioControlInfo(Handler h) { + mActivePhone.unregisterForT53AudioControlInfo(h); + } + + public void setOnEcbModeExitResponse(Handler h, int what, Object obj){ + mActivePhone.setOnEcbModeExitResponse(h,what,obj); + } + + public void unsetOnEcbModeExitResponse(Handler h){ + mActivePhone.unsetOnEcbModeExitResponse(h); + } +} diff --git a/phone/src2/com/android/internal/telephony/sip/SipCall.java b/phone/src2/com/android/internal/telephony/sip/SipCallBase.java index 3ed716b..447af7e 100644 --- a/phone/src2/com/android/internal/telephony/sip/SipCall.java +++ b/phone/src2/com/android/internal/telephony/sip/SipCallBase.java @@ -22,23 +22,19 @@ import com.android.internal.telephony.Connection; import com.android.internal.telephony.DriverCall; import com.android.internal.telephony.Phone; +import android.net.sip.SipManager; import java.util.ArrayList; +import java.util.Iterator; import java.util.List; +import javax.sip.SipException; -/** - * {@hide} - */ -class SipCall extends Call { - /*************************** Instance Variables **************************/ - - /*package*/ ArrayList<Connection> connections = new ArrayList<Connection>(); - /*package*/ SipCallTracker owner; - +abstract class SipCallBase extends Call { + private static final int MAX_CONNECTIONS_PER_CALL = 5; - /***************************** Class Methods *****************************/ + protected List<Connection> connections = new ArrayList<Connection>(); + /*package*/ //SipCallTracker owner; - static State - stateFromDCState (DriverCall.State dcState) { + private static State stateFromDCState (DriverCall.State dcState) { switch (dcState) { case ACTIVE: return State.ACTIVE; case HOLDING: return State.HOLDING; @@ -51,11 +47,9 @@ class SipCall extends Call { } - /****************************** Constructors *****************************/ - /*package*/ - SipCall (SipCallTracker owner) { - this.owner = owner; - } + //SipCall(SipPhone phone) { + //this.owner = owner; + //} public void dispose() { } @@ -67,23 +61,10 @@ class SipCall extends Call { return connections; } - public Phone getPhone() { - //TODO - return null; - } - public boolean isMultiparty() { return connections.size() > 1; } - /** Please note: if this is the foreground call and a - * background call exists, the background call will be resumed - * because an AT+CHLD=1 will be sent - */ - public void hangup() throws CallStateException { - owner.hangup(this); - } - public String toString() { return state.toString(); } @@ -105,7 +86,7 @@ class SipCall extends Call { /** * Called by SipConnection when it has disconnected */ - void connectionDisconnected(SipConnection conn) { + void connectionDisconnected(Connection conn) { if (state != State.DISCONNECTED) { /* If only disconnected connections remain, we are disconnected*/ @@ -127,7 +108,7 @@ class SipCall extends Call { } - /*package*/ void detach(SipConnection conn) { + /*package*/ void detach(Connection conn) { connections.remove(conn); if (connections.size() == 0) { @@ -135,7 +116,7 @@ class SipCall extends Call { } } - /*package*/ boolean update (SipConnection conn, DriverCall dc) { + /*package*/ boolean update (Connection conn, DriverCall dc) { State newState; boolean changed = false; @@ -154,7 +135,7 @@ class SipCall extends Call { * connections to be added via "conference" */ /*package*/ boolean isFull() { - return connections.size() == SipCallTracker.MAX_CONNECTIONS_PER_CALL; + return connections.size() == MAX_CONNECTIONS_PER_CALL; } //***** Called from SipCallTracker @@ -169,28 +150,19 @@ class SipCall extends Call { for (int i = 0, s = connections.size() ; i < s; i++ ) { - SipConnection cn = (SipConnection)connections.get(i); + SipConnectionBase cn = (SipConnectionBase)connections.get(i); cn.onHangupLocal(); } state = State.DISCONNECTING; } - /** - * Called when it's time to clean up disconnected Connection objects - */ void clearDisconnected() { - for (int i = connections.size() - 1 ; i >= 0 ; i--) { - SipConnection cn = (SipConnection)connections.get(i); - - if (cn.getState() == State.DISCONNECTED) { - connections.remove(i); - } + for (Iterator<Connection> it = connections.iterator(); it.hasNext(); ) { + Connection c = it.next(); + if (c.getState() == State.DISCONNECTED) it.remove(); } - if (connections.size() == 0) { - state = State.IDLE; - } + if (connections.isEmpty()) state = State.IDLE; } } - diff --git a/phone/src2/com/android/internal/telephony/sip/SipCallTracker.java b/phone/src2/com/android/internal/telephony/sip/SipCallTracker.java deleted file mode 100644 index 8fba43a..0000000 --- a/phone/src2/com/android/internal/telephony/sip/SipCallTracker.java +++ /dev/null @@ -1,515 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.internal.telephony.sip; - -import android.content.Context; -import android.net.sip.SipAudioCall; -import android.net.sip.SipManager; -import android.os.AsyncResult; -import android.os.Handler; -import android.os.Message; -import android.os.Registrant; -import android.os.SystemProperties; -import android.telephony.PhoneNumberUtils; -import android.telephony.ServiceState; -import android.telephony.TelephonyManager; -import android.util.EventLog; -import android.util.Log; - -import com.android.internal.telephony.CallStateException; -import com.android.internal.telephony.CallTracker; -import com.android.internal.telephony.CommandsInterface; -import com.android.internal.telephony.Connection; -import com.android.internal.telephony.DriverCall; -import com.android.internal.telephony.EventLogTags; -import com.android.internal.telephony.Phone; -import com.android.internal.telephony.TelephonyProperties; - -import java.util.List; -import java.util.ArrayList; - -/** - * {@hide} - */ -public final class SipCallTracker extends CallTracker { - static final int MAX_CONNECTIONS = 7; // only 7 connections allowed in GSM - static final int MAX_CONNECTIONS_PER_CALL = 5; // only 5 connections allowed per call - - private static final String LOG_TAG = "SIP_CT"; - private static final boolean DBG_POLL = false; - - SipConnection connections[] = new SipConnection[MAX_CONNECTIONS]; - - SipCall ringingCall = new SipCall(this); - // A call that is ringing or (call) waiting - SipCall foregroundCall = new SipCall(this); - SipCall backgroundCall = new SipCall(this); - - SipConnection pendingMO; - boolean hangupPendingMO; - - SipPhone phone; - - boolean desiredMute = false; // false = mute off - - Phone.State state = Phone.State.IDLE; - - SipCallTracker (SipPhone phone) { - this.phone = phone; - cm = phone.mCM; - } - - public void dispose() { - for(SipConnection c : connections) { - try { - if(c != null) hangup(c); - } catch (CallStateException ex) { - Log.e(LOG_TAG, "unexpected error on hangup during dispose"); - } - } - - try { - if(pendingMO != null) hangup(pendingMO); - } catch (CallStateException ex) { - Log.e(LOG_TAG, "unexpected error on hangup during dispose"); - } - - clearDisconnected(); - } - - protected void finalize() { - Log.d(LOG_TAG, "SipCallTracker finalized"); - } - - private void fakeHoldForegroundBeforeDial() { - List<Connection> connCopy; - - // We need to make a copy here, since fakeHoldBeforeDial() - // modifies the lists, and we don't want to reverse the order - connCopy = (List<Connection>) foregroundCall.connections.clone(); - - for (int i = 0, s = connCopy.size() ; i < s ; i++) { - SipConnection conn = (SipConnection)connCopy.get(i); - - conn.fakeHoldBeforeDial(); - } - } - - /** - * clirMode is one of the CLIR_ constants - */ - Connection dial(String dialString, int clirMode) throws CallStateException { - - // note that this triggers call state changed notif - clearDisconnected(); - - if (!canDial()) { - throw new CallStateException("cannot dial in current state"); - } - - // The new call must be assigned to the foreground call. - // That call must be idle, so place anything that's - // there on hold - if (foregroundCall.getState() == SipCall.State.ACTIVE) { - // this will probably be done by the radio anyway - // but the dial might fail before this happens - // and we need to make sure the foreground call is clear - // for the newly dialed connection - switchWaitingOrHoldingAndActive(); - - // Fake local state so that - // a) foregroundCall is empty for the newly dialed connection - // b) hasNonHangupStateChanged remains false in the - // next poll, so that we don't clear a failed dialing call - fakeHoldForegroundBeforeDial(); - } - - if (foregroundCall.getState() != SipCall.State.IDLE) { - //we should have failed in !canDial() above before we get here - throw new CallStateException("cannot dial in current state"); - } - - pendingMO = new SipConnection(phone.getContext(), dialString, this, foregroundCall); - hangupPendingMO = false; - - if (pendingMO.address == null || pendingMO.address.length() == 0 - || pendingMO.address.indexOf(PhoneNumberUtils.WILD) >= 0 - ) { - // Phone number is invalid - pendingMO.setDisconnectCause( - Connection.DisconnectCause.INVALID_NUMBER); - - // handlePollCalls() will notice this call not present - // and will mark it as dropped. - pollCallsWhenSafe(); - } else { - // Always unmute when initiating a new call - setMute(false); - - cm.dial(pendingMO.address, clirMode, obtainCompleteMessage()); - } - - updatePhoneState(); - phone.notifyPreciseCallStateChanged(); - - return pendingMO; - } - - - Connection dial(String dialString) throws CallStateException { - return dial(dialString, CommandsInterface.CLIR_DEFAULT); - } - - void acceptCall() throws CallStateException { - // FIXME if SWITCH fails, should retry with ANSWER - // in case the active/holding call disappeared and this - // is no longer call waiting - - if (ringingCall.getState() == SipCall.State.INCOMING) { - Log.i("phone", "acceptCall: incoming..."); - // Always unmute when answering a new call - setMute(false); - cm.acceptCall(obtainCompleteMessage()); - } else if (ringingCall.getState() == SipCall.State.WAITING) { - setMute(false); - switchWaitingOrHoldingAndActive(); - } else { - throw new CallStateException("phone not ringing"); - } - } - - void rejectCall() throws CallStateException { - // AT+CHLD=0 means "release held or UDUB" - // so if the phone isn't ringing, this could hang up held - if (ringingCall.getState().isRinging()) { - cm.rejectCall(obtainCompleteMessage()); - } else { - throw new CallStateException("phone not ringing"); - } - } - - void switchWaitingOrHoldingAndActive() throws CallStateException { - // Should we bother with this check? - if (ringingCall.getState() == SipCall.State.INCOMING) { - throw new CallStateException("cannot be in the incoming state"); - } else { - cm.switchWaitingOrHoldingAndActive( - obtainCompleteMessage(EVENT_SWITCH_RESULT)); - } - } - - void conference() throws CallStateException { - cm.conference(obtainCompleteMessage(EVENT_CONFERENCE_RESULT)); - } - - void explicitCallTransfer() throws CallStateException { - cm.explicitCallTransfer(obtainCompleteMessage(EVENT_ECT_RESULT)); - } - - void clearDisconnected() { - internalClearDisconnected(); - - updatePhoneState(); - phone.notifyPreciseCallStateChanged(); - } - - boolean canConference() { - return foregroundCall.getState() == SipCall.State.ACTIVE - && backgroundCall.getState() == SipCall.State.HOLDING - && !backgroundCall.isFull() - && !foregroundCall.isFull(); - } - - boolean canDial() { - boolean ret; - int serviceState = phone.getServiceState().getState(); - String disableCall = SystemProperties.get( - TelephonyProperties.PROPERTY_DISABLE_CALL, "false"); - - ret = (serviceState != ServiceState.STATE_POWER_OFF) - && pendingMO == null - && !ringingCall.isRinging() - && !disableCall.equals("true") - && (!foregroundCall.getState().isAlive() - || !backgroundCall.getState().isAlive()); - - return ret; - } - - boolean canTransfer() { - return foregroundCall.getState() == SipCall.State.ACTIVE - && backgroundCall.getState() == SipCall.State.HOLDING; - } - - //***** Private Instance Methods - - private void internalClearDisconnected() { - ringingCall.clearDisconnected(); - foregroundCall.clearDisconnected(); - backgroundCall.clearDisconnected(); - } - - /** - * Obtain a message to use for signalling "invoke getCurrentCalls() when - * this operation and all other pending operations are complete - */ - private Message obtainCompleteMessage() { - return obtainCompleteMessage(EVENT_OPERATION_COMPLETE); - } - - /** - * Obtain a message to use for signalling "invoke getCurrentCalls() when - * this operation and all other pending operations are complete - */ - private Message obtainCompleteMessage(int what) { - pendingOperations++; - lastRelevantPoll = null; - needsPoll = true; - - if (DBG_POLL) log("obtainCompleteMessage: pendingOperations=" + - pendingOperations + ", needsPoll=" + needsPoll); - - return obtainMessage(what); - } - - private void updatePhoneState() { - Phone.State oldState = state; - - if (ringingCall.isRinging()) { - state = Phone.State.RINGING; - } else if (pendingMO != null || - !(foregroundCall.isIdle() && backgroundCall.isIdle())) { - state = Phone.State.OFFHOOK; - } else { - state = Phone.State.IDLE; - } - - if (state != oldState) { - phone.notifyPhoneStateChanged(); - } - } - - protected void handlePollCalls(AsyncResult ar) { - } - - private void handleRadioNotAvailable() { - // handlePollCalls will clear out its - // call list when it gets the CommandException - // error result from this - pollCallsWhenSafe(); - } - - private void dumpState() { - List l; - - Log.i(LOG_TAG,"Phone State:" + state); - - Log.i(LOG_TAG,"Ringing call: " + ringingCall.toString()); - - l = ringingCall.getConnections(); - for (int i = 0, s = l.size(); i < s; i++) { - Log.i(LOG_TAG,l.get(i).toString()); - } - - Log.i(LOG_TAG,"Foreground call: " + foregroundCall.toString()); - - l = foregroundCall.getConnections(); - for (int i = 0, s = l.size(); i < s; i++) { - Log.i(LOG_TAG,l.get(i).toString()); - } - - Log.i(LOG_TAG,"Background call: " + backgroundCall.toString()); - - l = backgroundCall.getConnections(); - for (int i = 0, s = l.size(); i < s; i++) { - Log.i(LOG_TAG,l.get(i).toString()); - } - - } - - //***** Called from SipConnection - - /*package*/ void hangup (SipConnection conn) throws CallStateException { - if (conn.owner != this) { - throw new CallStateException ("SipConnection " + conn - + "does not belong to SipCallTracker " + this); - } - - if (conn == pendingMO) { - // We're hanging up an outgoing call that doesn't have it's - // Sip index assigned yet - - if (Phone.DEBUG_PHONE) log("hangup: set hangupPendingMO to true"); - hangupPendingMO = true; - } else { - try { - cm.hangupConnection (conn.getSipIndex(), obtainCompleteMessage()); - } catch (CallStateException ex) { - // Ignore "connection not found" - // Call may have hung up already - Log.w(LOG_TAG,"SipCallTracker WARN: hangup() on absent connection " - + conn); - } - } - - conn.onHangupLocal(); - } - - /*package*/ void separate (SipConnection conn) throws CallStateException { - if (conn.owner != this) { - throw new CallStateException ("SipConnection " + conn - + "does not belong to SipCallTracker " + this); - } - try { - cm.separateConnection (conn.getSipIndex(), - obtainCompleteMessage(EVENT_SEPARATE_RESULT)); - } catch (CallStateException ex) { - // Ignore "connection not found" - // Call may have hung up already - Log.w(LOG_TAG,"SipCallTracker WARN: separate() on absent connection " - + conn); - } - } - - //***** Called from SipPhone - - /*package*/ void setMute(boolean mute) { - desiredMute = mute; - cm.setMute(desiredMute, null); - } - - /*package*/ boolean getMute() { - return desiredMute; - } - - - //***** Called from SipCall - - /* package */ void hangup (SipCall call) throws CallStateException { - if (call.getConnections().size() == 0) { - throw new CallStateException("no connections in call"); - } - - if (call == ringingCall) { - if (Phone.DEBUG_PHONE) log("(ringing) hangup waiting or background"); - cm.hangupWaitingOrBackground(obtainCompleteMessage()); - } else if (call == foregroundCall) { - if (call.isDialingOrAlerting()) { - if (Phone.DEBUG_PHONE) { - log("(foregnd) hangup dialing or alerting..."); - } - hangup((SipConnection)(call.getConnections().get(0))); - } else { - hangupForegroundResumeBackground(); - } - } else if (call == backgroundCall) { - if (ringingCall.isRinging()) { - if (Phone.DEBUG_PHONE) { - log("hangup all conns in background call"); - } - hangupAllConnections(call); - } else { - hangupWaitingOrBackground(); - } - } else { - throw new RuntimeException ("SipCall " + call + - "does not belong to SipCallTracker " + this); - } - - call.onHangupLocal(); - phone.notifyPreciseCallStateChanged(); - } - - /* package */ - void hangupWaitingOrBackground() { - if (Phone.DEBUG_PHONE) log("hangupWaitingOrBackground"); - cm.hangupWaitingOrBackground(obtainCompleteMessage()); - } - - /* package */ - void hangupForegroundResumeBackground() { - if (Phone.DEBUG_PHONE) log("hangupForegroundResumeBackground"); - cm.hangupForegroundResumeBackground(obtainCompleteMessage()); - } - - void hangupAllConnections(SipCall call) throws CallStateException{ - try { - int count = call.connections.size(); - for (int i = 0; i < count; i++) { - SipConnection cn = (SipConnection)call.connections.get(i); - cm.hangupConnection(cn.getSipIndex(), obtainCompleteMessage()); - } - } catch (CallStateException ex) { - Log.e(LOG_TAG, "hangupConnectionByIndex caught " + ex); - } - } - - /* package */ - SipConnection getConnectionByIndex(SipCall call, int index) - throws CallStateException { - int count = call.connections.size(); - for (int i = 0; i < count; i++) { - SipConnection cn = (SipConnection)call.connections.get(i); - if (cn.getSipIndex() == index) { - return cn; - } - } - - return null; - } - - private Phone.SuppService getFailedService(int what) { - switch (what) { - case EVENT_SWITCH_RESULT: - return Phone.SuppService.SWITCH; - case EVENT_CONFERENCE_RESULT: - return Phone.SuppService.CONFERENCE; - case EVENT_SEPARATE_RESULT: - return Phone.SuppService.SEPARATE; - case EVENT_ECT_RESULT: - return Phone.SuppService.TRANSFER; - } - return Phone.SuppService.UNKNOWN; - } - - //****** Overridden from Handler - - public void handleMessage(Message msg) { - AsyncResult ar; - - switch (msg.what) { - case EVENT_POLL_CALLS_RESULT: - ar = (AsyncResult)msg.obj; - break; - - case EVENT_OPERATION_COMPLETE: - ar = (AsyncResult)msg.obj; - break; - - case EVENT_SWITCH_RESULT: - case EVENT_CONFERENCE_RESULT: - case EVENT_SEPARATE_RESULT: - case EVENT_ECT_RESULT: - ar = (AsyncResult)msg.obj; - break; - } - } - - protected void log(String msg) { - Log.d(LOG_TAG, "[SipCallTracker] " + msg); - } -} diff --git a/phone/src2/com/android/internal/telephony/sip/SipCommandInterface.java b/phone/src2/com/android/internal/telephony/sip/SipCommandInterface.java new file mode 100644 index 0000000..2c264c7 --- /dev/null +++ b/phone/src2/com/android/internal/telephony/sip/SipCommandInterface.java @@ -0,0 +1,373 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony.sip; + +import android.content.Context; +import android.os.Handler; +import android.os.Message; + +import com.android.internal.telephony.BaseCommands; +import com.android.internal.telephony.CommandsInterface; +//import com.android.internal.telephony.UUSInfo; +import com.android.internal.telephony.gsm.SmsBroadcastConfigInfo; + +/** + * SIP doesn't need CommandsInterface. The class does nothing but made to work + * with PhoneBase's constructor. + */ +class SipCommandInterface extends BaseCommands implements CommandsInterface { + SipCommandInterface(Context context) { + super(context); + } + + @Override public void setOnNITZTime(Handler h, int what, Object obj) { + } + + public void getIccCardStatus(Message result) { + } + + public void supplyIccPin(String pin, Message result) { + } + + public void supplyIccPuk(String puk, String newPin, Message result) { + } + + public void supplyIccPin2(String pin, Message result) { + } + + public void supplyIccPuk2(String puk, String newPin2, Message result) { + } + + public void changeIccPin(String oldPin, String newPin, Message result) { + } + + public void changeIccPin2(String oldPin2, String newPin2, Message result) { + } + + public void changeBarringPassword(String facility, String oldPwd, + String newPwd, Message result) { + } + + public void supplyNetworkDepersonalization(String netpin, Message result) { + } + + public void getCurrentCalls(Message result) { + } + + @Deprecated public void getPDPContextList(Message result) { + } + + public void getDataCallList(Message result) { + } + + public void dial(String address, int clirMode, Message result) { + } + + //public void dial(String address, int clirMode, UUSInfo uusInfo, + // Message result) { + //} + + public void getIMSI(Message result) { + } + + public void getIMEI(Message result) { + } + + public void getIMEISV(Message result) { + } + + + public void hangupConnection (int gsmIndex, Message result) { + } + + public void hangupWaitingOrBackground (Message result) { + } + + public void hangupForegroundResumeBackground (Message result) { + } + + public void switchWaitingOrHoldingAndActive (Message result) { + } + + public void conference (Message result) { + } + + + public void setPreferredVoicePrivacy(boolean enable, Message result) { + } + + public void getPreferredVoicePrivacy(Message result) { + } + + public void separateConnection (int gsmIndex, Message result) { + } + + public void acceptCall (Message result) { + } + + public void rejectCall (Message result) { + } + + public void explicitCallTransfer (Message result) { + } + + public void getLastCallFailCause (Message result) { + } + + /** @deprecated */ + public void getLastPdpFailCause (Message result) { + } + + public void getLastDataCallFailCause (Message result) { + } + + public void setMute (boolean enableMute, Message response) { + } + + public void getMute (Message response) { + } + + public void getSignalStrength (Message result) { + } + + public void getRegistrationState (Message result) { + } + + public void getGPRSRegistrationState (Message result) { + } + + public void getOperator(Message result) { + } + + public void sendDtmf(char c, Message result) { + } + + public void startDtmf(char c, Message result) { + } + + public void stopDtmf(Message result) { + } + + public void sendBurstDtmf(String dtmfString, int on, int off, + Message result) { + } + + public void sendSMS (String smscPDU, String pdu, Message result) { + } + + public void sendCdmaSms(byte[] pdu, Message result) { + } + + public void deleteSmsOnSim(int index, Message response) { + } + + public void deleteSmsOnRuim(int index, Message response) { + } + + public void writeSmsToSim(int status, String smsc, String pdu, Message response) { + } + + public void writeSmsToRuim(int status, String pdu, Message response) { + } + + public void setupDefaultPDP(String apn, String user, String password, + Message result) { + } + + public void deactivateDefaultPDP(int cid, Message result) { + } + + public void setupDataCall(String radioTechnology, String profile, + String apn, String user, String password, String authType, + Message result) { + } + + public void deactivateDataCall(int cid, Message result) { + } + + public void setRadioPower(boolean on, Message result) { + } + + public void setSuppServiceNotifications(boolean enable, Message result) { + } + + public void acknowledgeLastIncomingGsmSms(boolean success, int cause, + Message result) { + } + + public void acknowledgeLastIncomingCdmaSms(boolean success, int cause, + Message result) { + } + + + public void iccIO (int command, int fileid, String path, int p1, int p2, + int p3, String data, String pin2, Message result) { + } + + public void getCLIR(Message result) { + } + + public void setCLIR(int clirMode, Message result) { + } + + public void queryCallWaiting(int serviceClass, Message response) { + } + + public void setCallWaiting(boolean enable, int serviceClass, + Message response) { + } + + public void setNetworkSelectionModeAutomatic(Message response) { + } + + public void setNetworkSelectionModeManual( + String operatorNumeric, Message response) { + } + + public void getNetworkSelectionMode(Message response) { + } + + public void getAvailableNetworks(Message response) { + } + + public void setCallForward(int action, int cfReason, int serviceClass, + String number, int timeSeconds, Message response) { + } + + public void queryCallForwardStatus(int cfReason, int serviceClass, + String number, Message response) { + } + + public void queryCLIP(Message response) { + } + + public void getBasebandVersion (Message response) { + } + + public void queryFacilityLock (String facility, String password, + int serviceClass, Message response) { + } + + public void setFacilityLock (String facility, boolean lockState, + String password, int serviceClass, Message response) { + } + + public void sendUSSD (String ussdString, Message response) { + } + + public void cancelPendingUssd (Message response) { + } + + public void resetRadio(Message result) { + } + + public void invokeOemRilRequestRaw(byte[] data, Message response) { + } + + public void invokeOemRilRequestStrings(String[] strings, Message response) { + } + + public void setBandMode (int bandMode, Message response) { + } + + public void queryAvailableBandMode (Message response) { + } + + public void sendTerminalResponse(String contents, Message response) { + } + + public void sendEnvelope(String contents, Message response) { + } + + public void handleCallSetupRequestFromSim( + boolean accept, Message response) { + } + + public void setPreferredNetworkType(int networkType , Message response) { + } + + public void getPreferredNetworkType(Message response) { + } + + public void getNeighboringCids(Message response) { + } + + public void setLocationUpdates(boolean enable, Message response) { + } + + public void getSmscAddress(Message result) { + } + + public void setSmscAddress(String address, Message result) { + } + + public void reportSmsMemoryStatus(boolean available, Message result) { + } + + public void reportStkServiceIsRunning(Message result) { + } + + public void getGsmBroadcastConfig(Message response) { + } + + public void setGsmBroadcastConfig(SmsBroadcastConfigInfo[] config, Message response) { + } + + public void setGsmBroadcastActivation(boolean activate, Message response) { + } + + + // ***** Methods for CDMA support + public void getDeviceIdentity(Message response) { + } + + public void getCDMASubscription(Message response) { + } + + public void setPhoneType(int phoneType) { //Set by CDMAPhone and GSMPhone constructor + } + + public void queryCdmaRoamingPreference(Message response) { + } + + public void setCdmaRoamingPreference(int cdmaRoamingType, Message response) { + } + + public void setCdmaSubscription(int cdmaSubscription , Message response) { + } + + public void queryTTYMode(Message response) { + } + + public void setTTYMode(int ttyMode, Message response) { + } + + public void sendCDMAFeatureCode(String FeatureCode, Message response) { + } + + public void getCdmaBroadcastConfig(Message response) { + } + + public void setCdmaBroadcastConfig(int[] configValuesArray, Message response) { + } + + public void setCdmaBroadcastActivation(boolean activate, Message response) { + } + + public void exitEmergencyCallbackMode(Message response) { + } +} diff --git a/phone/src2/com/android/internal/telephony/sip/SipConnection.java b/phone/src2/com/android/internal/telephony/sip/SipConnectionBase.java index b99f501..75a9dad 100644 --- a/phone/src2/com/android/internal/telephony/sip/SipConnection.java +++ b/phone/src2/com/android/internal/telephony/sip/SipConnectionBase.java @@ -31,10 +31,7 @@ import android.telephony.ServiceState; import com.android.internal.telephony.*; -/** - * {@hide} - */ -public class SipConnection extends Connection { +abstract class SipConnectionBase extends Connection { //***** Event Constants private static final int EVENT_DTMF_DONE = 1; private static final int EVENT_PAUSE_DONE = 2; @@ -48,14 +45,10 @@ public class SipConnection extends Connection { private static final String LOG_TAG = "SIP_CONN"; - //***** Instance Variables - - SipCallTracker owner; - SipCall parent; - private SipAudioCall mSipAudioCall; - final String address; // MAY BE NULL!!! + // TODO + private String mAddress = null; // MAY BE NULL!!! private String dialString; // outgoing calls only private String postDialString; // outgoing calls only private int nextPostDialChar; // index into postDialString @@ -88,11 +81,23 @@ public class SipConnection extends Connection { private Handler h; - /** This is probably an MT call that we first saw in a CLCC response */ - SipConnection (Context context, DriverCall dc, SipCallTracker ct, int index) { + SipConnectionBase(String address, String calleeSipUri) { + mAddress = address; + dialString = calleeSipUri; + + postDialString = PhoneNumberUtils.extractPostDialPortion(dialString); + + isIncoming = false; + createTime = System.currentTimeMillis(); + } + + // TODO + // This is probably an MT call that we first saw in a CLCC response + /* + SipConnectionBase(Context context, DriverCall dc, SipCallTracker ct, int index) { owner = ct; - address = dc.number; + mAddress = dc.number; isIncoming = dc.isMT; createTime = System.currentTimeMillis(); @@ -100,17 +105,18 @@ public class SipConnection extends Connection { this.index = index; - parent = parentFromDCState (dc.state); + //parent = parentFromDCState (dc.state); parent.attach(this, dc); } - /** This is an MO call, created when dialing */ - SipConnection (Context context, String dialString, SipCallTracker ct, SipCall parent) { + // TODO + // This is an MO call, created when dialing + SipConnectionBase(Context context, String dialString, SipCallTracker ct, SipCall parent) { owner = ct; this.dialString = dialString; - this.address = PhoneNumberUtils.extractNetworkPortionAlt(dialString); + this.mAddress = PhoneNumberUtils.extractNetworkPortionAlt(dialString); this.postDialString = PhoneNumberUtils.extractPostDialPortion(dialString); index = -1; @@ -121,6 +127,7 @@ public class SipConnection extends Connection { this.parent = parent; parent.attachFake(this, SipCall.State.DIALING); } + */ public void dispose() { } @@ -141,15 +148,11 @@ public class SipConnection extends Connection { // no control over when they begin, so we might as well String cAddress = PhoneNumberUtils.stringFromStringAndTOA(c.number, c.TOA); - return isIncoming == c.isMT && equalsHandlesNulls(address, cAddress); + return isIncoming == c.isMT && equalsHandlesNulls(mAddress, cAddress); } public String getAddress() { - return address; - } - - public SipCall getCall() { - return parent; + return mAddress; } public long getCreateTime() { @@ -175,7 +178,7 @@ public class SipConnection extends Connection { } public long getHoldDurationMillis() { - if (getState() != SipCall.State.HOLDING) { + if (getState() != Call.State.HOLDING) { // If not holding, return 0 return 0; } else { @@ -195,30 +198,14 @@ public class SipConnection extends Connection { return isIncoming; } - public SipCall.State getState() { + public Call.State getState() { if (disconnected) { - return SipCall.State.DISCONNECTED; + return Call.State.DISCONNECTED; } else { return super.getState(); } } - public void hangup() throws CallStateException { - if (!disconnected) { - owner.hangup(this); - } else { - throw new CallStateException ("disconnected"); - } - } - - public void separate() throws CallStateException { - if (!disconnected) { - owner.separate(this); - } else { - throw new CallStateException ("disconnected"); - } - } - public PostDialState getPostDialState() { return postDialState; } @@ -295,6 +282,8 @@ public class SipConnection extends Connection { mCause = DisconnectCause.LOCAL; } + protected abstract Phone getPhone(); + DisconnectCause disconnectCauseFromCode(int causeCode) { /** * See 22.001 Annex F.4 for mapping of cause codes @@ -325,7 +314,7 @@ public class SipConnection extends Connection { case CallFailCause.ERROR_UNSPECIFIED: case CallFailCause.NORMAL_CLEARING: default: - SipPhone phone = owner.phone; + Phone phone = getPhone(); int serviceState = phone.getServiceState().getState(); if (serviceState == ServiceState.STATE_POWER_OFF) { return DisconnectCause.POWER_OFF; @@ -350,6 +339,7 @@ public class SipConnection extends Connection { /** Called when the radio indicates the connection has been disconnected */ void onDisconnect(DisconnectCause cause) { + /* mCause = cause; if (!disconnected) { @@ -368,6 +358,7 @@ public class SipConnection extends Connection { parent.connectionDisconnected(this); } } + */ } // Returns true if state has changed, false if nothing changed @@ -380,9 +371,9 @@ public class SipConnection extends Connection { newParent = parentFromDCState(dc.state); - if (!equalsHandlesNulls(address, dc.number)) { + if (!equalsHandlesNulls(mAddress, dc.number)) { if (Phone.DEBUG_PHONE) log("update: phone # changed!"); - address = dc.number; + mAddress = dc.number; changed = true; } @@ -430,6 +421,7 @@ public class SipConnection extends Connection { * HOLDING in the backgroundCall */ void fakeHoldBeforeDial() { + /* if (parent != null) { parent.detach(this); } @@ -438,6 +430,7 @@ public class SipConnection extends Connection { parent.attachFake(this, SipCall.State.HOLDING); onStartedHolding(); + */ } int getSipIndex() throws CallStateException { @@ -557,6 +550,8 @@ public class SipConnection extends Connection { } } + // TODO + /* postDialHandler = owner.phone.mPostDialHandler; Message notifyMessage; @@ -575,6 +570,7 @@ public class SipConnection extends Connection { //Log.v("Sip", "##### processNextPostDialChar: send msg to postDialHandler, arg1=" + c); notifyMessage.sendToTarget(); } + */ } @@ -582,11 +578,16 @@ public class SipConnection extends Connection { * and outgoing calls */ private boolean isConnectingInOrOut() { + // TODO + return false; + /* return parent == null || parent == owner.ringingCall || parent.state == SipCall.State.DIALING || parent.state == SipCall.State.ALERTING; + */ } +/* private SipCall parentFromDCState (DriverCall.State state) { switch (state) { case ACTIVE: @@ -608,6 +609,7 @@ public class SipConnection extends Connection { throw new RuntimeException("illegal call state: " + state); } } + */ /** * Set post dial state and acquire wake lock while switching to "started" @@ -637,11 +639,13 @@ public class SipConnection extends Connection { return Connection.PRESENTATION_ALLOWED; } + /* @Override public UUSInfo getUUSInfo() { // FIXME: what's this for SIP? return null; } + */ private class MyHandler extends Handler { MyHandler(Looper l) { diff --git a/phone/src2/com/android/internal/telephony/sip/SipPhone.java b/phone/src2/com/android/internal/telephony/sip/SipPhone.java index e9e8275..2c440b3 100755 --- a/phone/src2/com/android/internal/telephony/sip/SipPhone.java +++ b/phone/src2/com/android/internal/telephony/sip/SipPhone.java @@ -20,8 +20,13 @@ import android.content.ContentValues; import android.content.Context; import android.content.SharedPreferences; import android.net.Uri; +import android.net.sip.SipAudioCall; +import android.net.sip.SipManager; +import android.net.sip.SipProfile; +import android.net.sip.SipSessionState; import android.os.AsyncResult; import android.os.Handler; +import android.os.Looper; import android.os.Message; import android.os.Registrant; import android.os.RegistrantList; @@ -66,214 +71,127 @@ import com.android.internal.telephony.PhoneSubInfo; import com.android.internal.telephony.TelephonyProperties; import java.io.IOException; +import java.text.ParseException; import java.util.ArrayList; import java.util.List; +import javax.sip.SipException; + /** * {@hide} */ -public class SipPhone extends PhoneBase { - // NOTE that LOG_TAG here is "Sip", which means that log messages - // from this file will go into the radio log rather than the main - // log. (Use "adb logcat -b radio" to see them.) - static final String LOG_TAG = "SipPhone"; +public class SipPhone extends SipPhoneBase { + private static final String LOG_TAG = "SipPhone"; private static final boolean LOCAL_DEBUG = true; - // Instance Variables - SipCallTracker mCT; - PhoneSubInfo mSubInfo; - - Registrant mPostDialHandler; + private List<SipCall.SipConnection> connections = + new ArrayList<SipCall.SipConnection>(); - // Constructors + // A call that is ringing or (call) waiting + private SipCall ringingCall = new SipCall(); + private SipCall foregroundCall = new SipCall(); + private SipCall backgroundCall = new SipCall(); - public - SipPhone (Context context, CommandsInterface ci, PhoneNotifier notifier) { - this(context,ci,notifier, false); - } + private SipManager mSipManager; + private SipProfile mProfile; - public - SipPhone (Context context, CommandsInterface ci, PhoneNotifier notifier, boolean unitTestMode) { - super(notifier, context, ci, unitTestMode); + public SipPhone (Context context, PhoneNotifier notifier, + SipProfile profile) { + super(context, notifier); - // TODO: add a new phone type for SIP - mCM.setPhoneType(Phone.PHONE_TYPE_GSM); - mCT = new SipCallTracker(this); - if (!unitTestMode) { - mSubInfo = new PhoneSubInfo(this); - } + Log.v(LOG_TAG, " +++++++++++++++++++++ new SipPhone: " + profile.getUriString()); + ringingCall = new SipCall(); + foregroundCall = new SipCall(); + backgroundCall = new SipCall(); + mProfile = profile; + mSipManager = SipManager.getInstance(context); + // FIXME: what's this for SIP? //Change the system property - SystemProperties.set(TelephonyProperties.CURRENT_ACTIVE_PHONE, - new Integer(Phone.PHONE_TYPE_GSM).toString()); - } - - public void dispose() { - synchronized(PhoneProxy.lockForRadioTechnologyChange) { - super.dispose(); - - //Force all referenced classes to unregister their former registered events - mCT.dispose(); - mSubInfo.dispose(); - } - } - - public void removeReferences() { - this.mSubInfo = null; - this.mCT = null; + //SystemProperties.set(TelephonyProperties.CURRENT_ACTIVE_PHONE, + // new Integer(Phone.PHONE_TYPE_GSM).toString()); } public ServiceState getServiceState() { - return null; //mSST.ss; - } - - public CellLocation getCellLocation() { - return null; //mSST.cellLoc; - } - - public Phone.State getState() { - return mCT.state; + // FIXME: we may need to provide this when data connectivity is lost + // or when server is down + return super.getServiceState(); } public String getPhoneName() { + // FIXME: profile's name? return "SIP"; } - public int getPhoneType() { - return Phone.PHONE_TYPE_GSM; - } - - public SignalStrength getSignalStrength() { - return null; - } - - public boolean getMessageWaitingIndicator() { - return false; - } - - public boolean getCallForwardingIndicator() { - return false; - } - - public List<? extends MmiCode> getPendingMmiCodes() { - return null; - } - - public DataState getDataConnectionState() { - return null; - } - - public DataActivityState getDataActivityState() { - return null; - } - - /** - * Notify any interested party of a Phone state change {@link Phone.State} - */ - void notifyPhoneStateChanged() { - mNotifier.notifyPhoneState(this); - } - - /** - * Notify registrants of a change in the call state. This notifies changes in {@link Call.State} - * Use this when changes in the precise call state are needed, else use notifyPhoneStateChanged. - */ - void notifyPreciseCallStateChanged() { - /* we'd love it if this was package-scoped*/ - super.notifyPreciseCallStateChangedP(); - } - - void notifyNewRingingConnection(Connection c) { - /* we'd love it if this was package-scoped*/ - super.notifyNewRingingConnectionP(c); - } - - void notifyDisconnect(Connection cn) { - mDisconnectRegistrants.notifyResult(cn); - } - - void notifyUnknownConnection() { - mUnknownConnectionRegistrants.notifyResult(this); - } - - void notifySuppServiceFailed(SuppService code) { - mSuppServiceFailedRegistrants.notifyResult(code); - } - - void notifyServiceStateChanged(ServiceState ss) { - super.notifyServiceStateChangedP(ss); - } - - public void notifyCallForwardingIndicator() { - mNotifier.notifyCallForwardingChanged(this); - } - public void acceptCall() throws CallStateException { - mCT.acceptCall(); + //mCT.acceptCall(); } public void rejectCall() throws CallStateException { - mCT.rejectCall(); + //mCT.rejectCall(); } public void switchHoldingAndActive() throws CallStateException { - mCT.switchWaitingOrHoldingAndActive(); + // TODO } public boolean canConference() { - return mCT.canConference(); - } - - public boolean canDial() { - return mCT.canDial(); + //TODO + //return mCT.canConference(); + return false; } public void conference() throws CallStateException { - mCT.conference(); + // TODO } public void clearDisconnected() { - mCT.clearDisconnected(); + ringingCall.clearDisconnected(); + foregroundCall.clearDisconnected(); + backgroundCall.clearDisconnected(); + + updatePhoneState(); + notifyPreciseCallStateChanged(); } public boolean canTransfer() { - return mCT.canTransfer(); + // TODO + //return mCT.canTransfer(); + return false; } public void explicitCallTransfer() throws CallStateException { - mCT.explicitCallTransfer(); - } - - public SipCall getForegroundCall() { - return mCT.foregroundCall; - } - - public SipCall getBackgroundCall() { - return mCT.backgroundCall; - } - - public SipCall getRingingCall() { - return mCT.ringingCall; + //mCT.explicitCallTransfer(); } - public boolean handleInCallMmiCommands(String dialString) - throws CallStateException { - return false; - } - - boolean isInCall() { - SipCall.State foregroundCallState = getForegroundCall().getState(); - SipCall.State backgroundCallState = getBackgroundCall().getState(); - SipCall.State ringingCallState = getRingingCall().getState(); + public Connection dial(String dialString) throws CallStateException { + // TODO: parse SIP URL? + // Need to make sure dialString gets parsed properly + //String newDialString = PhoneNumberUtils.stripSeparators(dialString); + //return mCT.dial(newDialString); + clearDisconnected(); - return (foregroundCallState.isAlive() || backgroundCallState.isAlive() - || ringingCallState.isAlive()); - } + if (!canDial()) { + throw new CallStateException("cannot dial in current state"); + } + if (foregroundCall.getState() == SipCall.State.ACTIVE) { + switchHoldingAndActive(); + } + if (foregroundCall.getState() != SipCall.State.IDLE) { + //we should have failed in !canDial() above before we get here + throw new CallStateException("cannot dial in current state"); + } - public Connection dial (String dialString) throws CallStateException { - // Need to make sure dialString gets parsed properly - String newDialString = PhoneNumberUtils.stripSeparators(dialString); - return mCT.dial(newDialString); + setMute(false); + //cm.dial(pendingMO.address, clirMode, obtainCompleteMessage()); + try { + Connection c = foregroundCall.dial(dialString); + updatePhoneState(); + notifyPreciseCallStateChanged(); + return c; + } catch (SipException e) { + throw new CallStateException("dial error: " + e); + } } public void sendDtmf(char c) { @@ -281,7 +199,7 @@ public class SipPhone extends PhoneBase { Log.e(LOG_TAG, "sendDtmf called with invalid character '" + c + "'"); } else { - if (mCT.state == Phone.State.OFFHOOK) { + if (getState() == State.OFFHOOK) { // FIXME: use mCT instead of mCM //mCM.sendDtmf(c, null); } @@ -307,127 +225,6 @@ public class SipPhone extends PhoneBase { Log.e(LOG_TAG, "[SipPhone] sendBurstDtmf() is a CDMA method"); } - public boolean handlePinMmi(String dialString) { - return false; - } - - public void sendUssdResponse(String ussdMessge) { - } - - public void registerForSuppServiceNotification( - Handler h, int what, Object obj) { - } - - public void unregisterForSuppServiceNotification(Handler h) { - } - - public void setRadioPower(boolean power) { - } - - public String getVoiceMailNumber() { - return null; - } - - public String getVoiceMailAlphaTag() { - return null; - } - - public String getDeviceId() { - return null; - } - - public String getDeviceSvn() { - return null; - } - - public String getEsn() { - Log.e(LOG_TAG, "[SipPhone] getEsn() is a CDMA method"); - return "0"; - } - - public String getMeid() { - Log.e(LOG_TAG, "[SipPhone] getMeid() is a CDMA method"); - return "0"; - } - - public String getSubscriberId() { - return null; - } - - public String getIccSerialNumber() { - return null; - } - - public String getLine1Number() { - return null; - } - - public String getLine1AlphaTag() { - return null; - } - - public void setLine1Number(String alphaTag, String number, Message onComplete) { - // FIXME: what to reply? - AsyncResult.forMessage(onComplete, null, null); - onComplete.sendToTarget(); - } - - public void setVoiceMailNumber(String alphaTag, String voiceMailNumber, - Message onComplete) { - // FIXME: what to reply? - AsyncResult.forMessage(onComplete, null, null); - onComplete.sendToTarget(); - } - - private boolean isValidCommandInterfaceCFReason(int commandInterfaceCFReason) { - switch (commandInterfaceCFReason) { - case CF_REASON_UNCONDITIONAL: - case CF_REASON_BUSY: - case CF_REASON_NO_REPLY: - case CF_REASON_NOT_REACHABLE: - case CF_REASON_ALL: - case CF_REASON_ALL_CONDITIONAL: - return true; - default: - return false; - } - } - - private boolean isValidCommandInterfaceCFAction (int commandInterfaceCFAction) { - switch (commandInterfaceCFAction) { - case CF_ACTION_DISABLE: - case CF_ACTION_ENABLE: - case CF_ACTION_REGISTRATION: - case CF_ACTION_ERASURE: - return true; - default: - return false; - } - } - - protected boolean isCfEnable(int action) { - return (action == CF_ACTION_ENABLE) || (action == CF_ACTION_REGISTRATION); - } - - public void getCallForwardingOption(int commandInterfaceCFReason, Message onComplete) { - if (isValidCommandInterfaceCFReason(commandInterfaceCFReason)) { - // FIXME: what to reply? - AsyncResult.forMessage(onComplete, null, null); - onComplete.sendToTarget(); - } - } - - public void setCallForwardingOption(int commandInterfaceCFAction, - int commandInterfaceCFReason, String dialingNumber, - int timerSeconds, Message onComplete) { - if (isValidCommandInterfaceCFAction(commandInterfaceCFAction) - && isValidCommandInterfaceCFReason(commandInterfaceCFReason)) { - // FIXME: what to reply? - AsyncResult.forMessage(onComplete, null, null); - onComplete.sendToTarget(); - } - } - public void getOutgoingCallerIdDisplay(Message onComplete) { // FIXME: what to reply? AsyncResult.forMessage(onComplete, null, null); @@ -452,120 +249,184 @@ public class SipPhone extends PhoneBase { Log.e(LOG_TAG, "call waiting not supported"); } - public boolean getIccRecordsLoaded() { - return false; - } - - public IccCard getIccCard() { - return null; - } - - public void getAvailableNetworks(Message response) { - // FIXME: what to reply? - } - - public void setNetworkSelectionModeAutomatic(Message response) { - // FIXME: what to reply? - } - - public void selectNetworkManually( - com.android.internal.telephony.gsm.NetworkInfo network, - Message response) { - // FIXME: what to reply? + public void setMute(boolean muted) { + // TODO + //mCT.setMute(muted); } - public void getNeighboringCids(Message response) { - // FIXME: what to reply? + public boolean getMute() { + // TODO + //return mCT.getMute(); + return false; } - public void setOnPostDialCharacter(Handler h, int what, Object obj) { - mPostDialHandler = new Registrant(h, what, obj); + public Call getForegroundCall() { + return foregroundCall; } - public void setMute(boolean muted) { - mCT.setMute(muted); + public Call getBackgroundCall() { + return backgroundCall; } - public boolean getMute() { - return mCT.getMute(); + public Call getRingingCall() { + return ringingCall; } - public void getDataCallList(Message response) { - // FIXME: what to reply? - } + private class SipCall extends SipCallBase { + public Phone getPhone() { + return SipPhone.this; + } - public List<DataConnection> getCurrentDataConnectionList () { - return null; - } + public Connection dial(String calleeSipUri) throws SipException { + try { + SipProfile callee = + new SipProfile.Builder(calleeSipUri).build(); + SipConnection c = new SipConnection(callee); + c.dial(); + connections.add(c); + state = Call.State.DIALING; + return c; + } catch (ParseException e) { + throw new SipException("dial", e); + } + } - public void updateServiceLocation() { - } + // TODO: if this is the foreground call and a background call exists, + // resume the background call + public void hangup() throws CallStateException { + Log.v(LOG_TAG, "hang up call: " + getState() + ": " + this + + " on phone " + getPhone()); + CallStateException excp = null; + for (Connection c : connections) { + try { + c.hangup(); + } catch (CallStateException e) { + excp = e; + } + } + if (excp != null) throw excp; + } - public void enableLocationUpdates() { - } + private void onConnectionStateChanged(SipConnection conn) { + // this can be called back when a conf call is formed + // TODO: how to synchronize this? + // TODO: who to notify? + state = conn.getState(); + Log.v(LOG_TAG, "++******++ call state changed: " + getState() + ": " + + this + ": on phone " + getPhone() + " " + + connections.size()); + notifyPreciseCallStateChangedP(); + } - public void disableLocationUpdates() { - } + private void onConnectionEnded(SipConnection conn) { + // this can be called back when a conf call is formed + // TODO: how to synchronize this? + // TODO: who to notify? + state = conn.getState(); + Log.v(LOG_TAG, "-------- call ended: " + getState() + ": " + this + + ": on phone " + getPhone() + " " + connections.size()); + notifyDisconnectP(conn); + } - public boolean getDataRoamingEnabled() { - return false; - } + class SipConnection extends SipConnectionBase { + private SipCall mOwner = SipCall.this; + // could be different in a conf call + private SipAudioCall mSipAudioCall; + private Call.State mState = Call.State.IDLE; + private SipProfile mPeer; + private SipAudioCallAdapter mAdapter = new SipAudioCallAdapter() { + protected void onCallEnded() { + mState = Call.State.DISCONNECTED; + mOwner.onConnectionEnded(SipConnection.this); + Log.v(LOG_TAG, "-------- connection ended: " + mPeer.getUriString() + ": " + mSipAudioCall.getState() + ": on phone " + getPhone()); + } + + public void onChanged(SipAudioCall call) { + mState = getCallStateFrom(call); + mOwner.onConnectionStateChanged(SipConnection.this); + Log.v(LOG_TAG, "++******++ connection state changed: " + mPeer.getUriString() + ": " + call.getState() + ": on phone " + getPhone()); + } + }; + + public SipConnection(SipProfile callee) { + super(callee.getSipDomain(), callee.getUriString()); + mPeer = callee; + } - public void setDataRoamingEnabled(boolean enable) { - } + public Call.State getState() { + return mState; + } - public boolean enableDataConnectivity() { - return false; - } + public void dial() throws SipException { + mState = Call.State.DIALING; + mSipAudioCall = mSipManager.makeAudioCall(mContext, mProfile, + mPeer, mAdapter); + } - public boolean disableDataConnectivity() { - return false; - } + public SipCall getCall() { + return mOwner; + } - public boolean isDataConnectivityPossible() { - return false; - } + protected Phone getPhone() { + return mOwner.getPhone(); + } - boolean updateCurrentCarrierInProvider() { - return false; - } + public void hangup() throws CallStateException { + Log.v(LOG_TAG, "hangup conn: " + mPeer.getUriString() + ": " + + ": on phone " + getPhone()); + try { + mSipAudioCall.endCall(); + } catch (SipException e) { + throw new CallStateException("hangup(): " + e); + } + } - public void saveClirSetting(int commandInterfaceCLIRMode) { - // FIXME: what's this for SIP? - } + public void separate() throws CallStateException { + // TODO: what's this for SIP? + /* + if (!disconnected) { + owner.separate(this); + } else { + throw new CallStateException ("disconnected"); + } + */ + } - /** - * Retrieves the PhoneSubInfo of the SipPhone - */ - public PhoneSubInfo getPhoneSubInfo(){ - return mSubInfo; + } } - /** {@inheritDoc} */ - public IccSmsInterfaceManager getIccSmsInterfaceManager(){ - return null; + private static Call.State getCallStateFrom(SipAudioCall sipAudioCall) { + SipSessionState sessionState = sipAudioCall.getState(); + switch (sessionState) { + case READY_TO_CALL: return Call.State.IDLE; + case INCOMING_CALL: + case INCOMING_CALL_ANSWERING: return Call.State.INCOMING; + case OUTGOING_CALL: return Call.State.DIALING; + case OUTGOING_CALL_RING_BACK: return Call.State.ALERTING; + case OUTGOING_CALL_CANCELING: return Call.State.DISCONNECTING; + case IN_CALL: return Call.State.ACTIVE; + default: + Log.w(LOG_TAG, "illegal connection state: " + sessionState); + return Call.State.DISCONNECTED; + } } - /** {@inheritDoc} */ - public IccPhoneBookInterfaceManager getIccPhoneBookInterfaceManager(){ - return null; - } + private abstract class SipAudioCallAdapter extends SipAudioCall.Adapter { + private SipException mError; - /** {@inheritDoc} */ - public IccFileHandler getIccFileHandler(){ - return null; - } + protected abstract void onCallEnded(); - public void activateCellBroadcastSms(int activate, Message response) { - Log.e(LOG_TAG, "Error! This functionality is not implemented for SIP."); - } + public void onCallEnded(SipAudioCall call) { + onCallEnded(); + } - public void getCellBroadcastSmsConfig(Message response) { - Log.e(LOG_TAG, "Error! This functionality is not implemented for SIP."); - } + public void onError(SipAudioCall call, String errorMessage) { + mError = new SipException(errorMessage); + onCallEnded(); + } - public void setCellBroadcastSmsConfig(int[] configValuesArray, Message response){ - Log.e(LOG_TAG, "Error! This functionality is not implemented for SIP."); + public SipException getError() { + return mError; + } } - } diff --git a/phone/src2/com/android/internal/telephony/sip/SipPhoneBase.java b/phone/src2/com/android/internal/telephony/sip/SipPhoneBase.java new file mode 100755 index 0000000..cafcc0e --- /dev/null +++ b/phone/src2/com/android/internal/telephony/sip/SipPhoneBase.java @@ -0,0 +1,515 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony.sip; + +import android.content.ContentValues; +import android.content.Context; +import android.content.SharedPreferences; +import android.net.Uri; +import android.os.AsyncResult; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.os.Registrant; +import android.os.RegistrantList; +import android.os.SystemProperties; +import android.preference.PreferenceManager; +import android.provider.Telephony; +import android.telephony.CellLocation; +import android.telephony.PhoneNumberUtils; +import android.telephony.ServiceState; +import android.telephony.SignalStrength; +import android.text.TextUtils; +import android.util.Log; + +import static com.android.internal.telephony.CommandsInterface.CF_ACTION_DISABLE; +import static com.android.internal.telephony.CommandsInterface.CF_ACTION_ENABLE; +import static com.android.internal.telephony.CommandsInterface.CF_ACTION_ERASURE; +import static com.android.internal.telephony.CommandsInterface.CF_ACTION_REGISTRATION; +import static com.android.internal.telephony.CommandsInterface.CF_REASON_ALL; +import static com.android.internal.telephony.CommandsInterface.CF_REASON_ALL_CONDITIONAL; +import static com.android.internal.telephony.CommandsInterface.CF_REASON_NO_REPLY; +import static com.android.internal.telephony.CommandsInterface.CF_REASON_NOT_REACHABLE; +import static com.android.internal.telephony.CommandsInterface.CF_REASON_BUSY; +import static com.android.internal.telephony.CommandsInterface.CF_REASON_UNCONDITIONAL; +import static com.android.internal.telephony.CommandsInterface.SERVICE_CLASS_VOICE; +import static com.android.internal.telephony.TelephonyProperties.PROPERTY_BASEBAND_VERSION; + +import com.android.internal.telephony.Call; +import com.android.internal.telephony.CallStateException; +import com.android.internal.telephony.CommandsInterface; +import com.android.internal.telephony.Connection; +import com.android.internal.telephony.DataConnection; +import com.android.internal.telephony.IccCard; +import com.android.internal.telephony.IccFileHandler; +import com.android.internal.telephony.IccPhoneBookInterfaceManager; +import com.android.internal.telephony.IccSmsInterfaceManager; +import com.android.internal.telephony.MmiCode; +import com.android.internal.telephony.Phone; +import com.android.internal.telephony.PhoneBase; +import com.android.internal.telephony.PhoneNotifier; +import com.android.internal.telephony.PhoneProxy; +import com.android.internal.telephony.PhoneSubInfo; +import com.android.internal.telephony.TelephonyProperties; +//import com.android.internal.telephony.UUSInfo; + +import java.io.IOException; +import java.util.List; + +abstract class SipPhoneBase extends PhoneBase { + // NOTE that LOG_TAG here is "Sip", which means that log messages + // from this file will go into the radio log rather than the main + // log. (Use "adb logcat -b radio" to see them.) + static final String LOG_TAG = "SipPhone"; + private static final boolean LOCAL_DEBUG = true; + + //SipCallTracker mCT; + PhoneSubInfo mSubInfo; + + Registrant mPostDialHandler; + + private State state = State.IDLE; + + public SipPhoneBase(Context context, PhoneNotifier notifier) { + super(notifier, context, new SipCommandInterface(context), false); + + // FIXME: what's this for SIP? + //Change the system property + //SystemProperties.set(TelephonyProperties.CURRENT_ACTIVE_PHONE, + // new Integer(Phone.PHONE_TYPE_GSM).toString()); + } + + public abstract Call getForegroundCall(); + + public abstract Call getBackgroundCall(); + + public abstract Call getRingingCall(); + + /* + public Connection dial(String dialString, UUSInfo uusInfo) + throws CallStateException { + // ignore UUSInfo + return dial(dialString); + } + */ + + public void dispose() { + mIsTheCurrentActivePhone = false; + mSubInfo.dispose(); + } + + public void removeReferences() { + mSubInfo = null; + } + + public ServiceState getServiceState() { + // FIXME: we may need to provide this when data connectivity is lost + // or when server is down + ServiceState s = new ServiceState(); + s.setState(ServiceState.STATE_IN_SERVICE); + return s; + } + + public CellLocation getCellLocation() { + return null; //mSST.cellLoc; + } + + public State getState() { + return state; + } + + public String getPhoneName() { + return "SIP"; + } + + public int getPhoneType() { + // FIXME: add SIP phone type + return Phone.PHONE_TYPE_GSM; + } + + public SignalStrength getSignalStrength() { + return new SignalStrength(); + } + + public boolean getMessageWaitingIndicator() { + return false; + } + + public boolean getCallForwardingIndicator() { + return false; + } + + public List<? extends MmiCode> getPendingMmiCodes() { + return null; + } + + public DataState getDataConnectionState() { + return DataState.DISCONNECTED; + } + + public DataState getDataConnectionState(String apnType) { + return DataState.DISCONNECTED; + } + + public DataActivityState getDataActivityState() { + return DataActivityState.NONE; + } + + /** + * Notify any interested party of a Phone state change {@link Phone.State} + */ + void notifyPhoneStateChanged() { + mNotifier.notifyPhoneState(this); + } + + /** + * Notify registrants of a change in the call state. This notifies changes in {@link Call.State} + * Use this when changes in the precise call state are needed, else use notifyPhoneStateChanged. + */ + void notifyPreciseCallStateChanged() { + /* we'd love it if this was package-scoped*/ + super.notifyPreciseCallStateChangedP(); + } + + void notifyNewRingingConnection(Connection c) { + /* we'd love it if this was package-scoped*/ + super.notifyNewRingingConnectionP(c); + } + + void notifyDisconnect(Connection cn) { + mDisconnectRegistrants.notifyResult(cn); + } + + void notifyUnknownConnection() { + mUnknownConnectionRegistrants.notifyResult(this); + } + + void notifySuppServiceFailed(SuppService code) { + mSuppServiceFailedRegistrants.notifyResult(code); + } + + void notifyServiceStateChanged(ServiceState ss) { + super.notifyServiceStateChangedP(ss); + } + + public void notifyCallForwardingIndicator() { + mNotifier.notifyCallForwardingChanged(this); + } + + public boolean canDial() { + int serviceState = getServiceState().getState(); + Log.v(LOG_TAG, "canDial(): serviceState = " + serviceState); + if (serviceState == ServiceState.STATE_POWER_OFF) return false; + + String disableCall = SystemProperties.get( + TelephonyProperties.PROPERTY_DISABLE_CALL, "false"); + Log.v(LOG_TAG, "canDial(): disableCall = " + disableCall); + if (disableCall.equals("true")) return false; + + Log.v(LOG_TAG, "canDial(): ringingCall: " + getRingingCall().getState()); + Log.v(LOG_TAG, "canDial(): foregndCall: " + getForegroundCall().getState()); + Log.v(LOG_TAG, "canDial(): backgndCall: " + getBackgroundCall().getState()); + return !getRingingCall().isRinging() + && (!getForegroundCall().getState().isAlive() + || !getBackgroundCall().getState().isAlive()); + } + + public boolean handleInCallMmiCommands(String dialString) + throws CallStateException { + return false; + } + + boolean isInCall() { + Call.State foregroundCallState = getForegroundCall().getState(); + Call.State backgroundCallState = getBackgroundCall().getState(); + Call.State ringingCallState = getRingingCall().getState(); + + return (foregroundCallState.isAlive() || backgroundCallState.isAlive() + || ringingCallState.isAlive()); + } + + public boolean handlePinMmi(String dialString) { + return false; + } + + public void sendUssdResponse(String ussdMessge) { + } + + public void registerForSuppServiceNotification( + Handler h, int what, Object obj) { + } + + public void unregisterForSuppServiceNotification(Handler h) { + } + + public void setRadioPower(boolean power) { + } + + public String getVoiceMailNumber() { + return null; + } + + public String getVoiceMailAlphaTag() { + return null; + } + + public String getDeviceId() { + return null; + } + + public String getDeviceSvn() { + return null; + } + + public String getEsn() { + Log.e(LOG_TAG, "[SipPhone] getEsn() is a CDMA method"); + return "0"; + } + + public String getMeid() { + Log.e(LOG_TAG, "[SipPhone] getMeid() is a CDMA method"); + return "0"; + } + + public String getSubscriberId() { + return null; + } + + public String getIccSerialNumber() { + return null; + } + + public String getLine1Number() { + return null; + } + + public String getLine1AlphaTag() { + return null; + } + + public void setLine1Number(String alphaTag, String number, Message onComplete) { + // FIXME: what to reply for SIP? + AsyncResult.forMessage(onComplete, null, null); + onComplete.sendToTarget(); + } + + public void setVoiceMailNumber(String alphaTag, String voiceMailNumber, + Message onComplete) { + // FIXME: what to reply for SIP? + AsyncResult.forMessage(onComplete, null, null); + onComplete.sendToTarget(); + } + + private boolean isValidCommandInterfaceCFReason(int commandInterfaceCFReason) { + switch (commandInterfaceCFReason) { + case CF_REASON_UNCONDITIONAL: + case CF_REASON_BUSY: + case CF_REASON_NO_REPLY: + case CF_REASON_NOT_REACHABLE: + case CF_REASON_ALL: + case CF_REASON_ALL_CONDITIONAL: + return true; + default: + return false; + } + } + + private boolean isValidCommandInterfaceCFAction (int commandInterfaceCFAction) { + switch (commandInterfaceCFAction) { + case CF_ACTION_DISABLE: + case CF_ACTION_ENABLE: + case CF_ACTION_REGISTRATION: + case CF_ACTION_ERASURE: + return true; + default: + return false; + } + } + + protected boolean isCfEnable(int action) { + return (action == CF_ACTION_ENABLE) || (action == CF_ACTION_REGISTRATION); + } + + public void getCallForwardingOption(int commandInterfaceCFReason, Message onComplete) { + if (isValidCommandInterfaceCFReason(commandInterfaceCFReason)) { + // FIXME: what to reply? + AsyncResult.forMessage(onComplete, null, null); + onComplete.sendToTarget(); + } + } + + public void setCallForwardingOption(int commandInterfaceCFAction, + int commandInterfaceCFReason, String dialingNumber, + int timerSeconds, Message onComplete) { + if (isValidCommandInterfaceCFAction(commandInterfaceCFAction) + && isValidCommandInterfaceCFReason(commandInterfaceCFReason)) { + // FIXME: what to reply? + AsyncResult.forMessage(onComplete, null, null); + onComplete.sendToTarget(); + } + } + + public void getOutgoingCallerIdDisplay(Message onComplete) { + // FIXME: what to reply? + AsyncResult.forMessage(onComplete, null, null); + onComplete.sendToTarget(); + } + + public void setOutgoingCallerIdDisplay(int commandInterfaceCLIRMode, + Message onComplete) { + // FIXME: what's this for SIP? + AsyncResult.forMessage(onComplete, null, null); + onComplete.sendToTarget(); + } + + public void getCallWaiting(Message onComplete) { + // FIXME: what to reply? + AsyncResult.forMessage(onComplete, null, null); + onComplete.sendToTarget(); + } + + public void setCallWaiting(boolean enable, Message onComplete) { + // FIXME: what to reply? + Log.e(LOG_TAG, "call waiting not supported"); + } + + public boolean getIccRecordsLoaded() { + return false; + } + + public IccCard getIccCard() { + return null; + } + + public void getAvailableNetworks(Message response) { + // FIXME: what to reply? + } + + public void setNetworkSelectionModeAutomatic(Message response) { + // FIXME: what to reply? + } + + public void selectNetworkManually( + com.android.internal.telephony.gsm.NetworkInfo network, + Message response) { + // FIXME: what to reply? + } + + public void getNeighboringCids(Message response) { + // FIXME: what to reply? + } + + public void setOnPostDialCharacter(Handler h, int what, Object obj) { + mPostDialHandler = new Registrant(h, what, obj); + } + + public void getDataCallList(Message response) { + // FIXME: what to reply? + } + + public List<DataConnection> getCurrentDataConnectionList () { + return null; + } + + public void updateServiceLocation() { + } + + public void enableLocationUpdates() { + } + + public void disableLocationUpdates() { + } + + public boolean getDataRoamingEnabled() { + return false; + } + + public void setDataRoamingEnabled(boolean enable) { + } + + public boolean enableDataConnectivity() { + return false; + } + + public boolean disableDataConnectivity() { + return false; + } + + public boolean isDataConnectivityPossible() { + return false; + } + + boolean updateCurrentCarrierInProvider() { + return false; + } + + public void saveClirSetting(int commandInterfaceCLIRMode) { + // FIXME: what's this for SIP? + } + + /** + * Retrieves the PhoneSubInfo of the SipPhone + */ + public PhoneSubInfo getPhoneSubInfo(){ + return mSubInfo; + } + + /** {@inheritDoc} */ + public IccSmsInterfaceManager getIccSmsInterfaceManager(){ + return null; + } + + /** {@inheritDoc} */ + public IccPhoneBookInterfaceManager getIccPhoneBookInterfaceManager(){ + return null; + } + + /** {@inheritDoc} */ + public IccFileHandler getIccFileHandler(){ + return null; + } + + public void activateCellBroadcastSms(int activate, Message response) { + Log.e(LOG_TAG, "Error! This functionality is not implemented for SIP."); + } + + public void getCellBroadcastSmsConfig(Message response) { + Log.e(LOG_TAG, "Error! This functionality is not implemented for SIP."); + } + + public void setCellBroadcastSmsConfig(int[] configValuesArray, Message response){ + Log.e(LOG_TAG, "Error! This functionality is not implemented for SIP."); + } + + void updatePhoneState() { + State oldState = state; + + if (getRingingCall().isRinging()) { + state = State.RINGING; + } else if (getForegroundCall().isIdle() + && getBackgroundCall().isIdle()) { + state = State.IDLE; + } else { + state = State.OFFHOOK; + } + Log.e(LOG_TAG, " ^^^^^^ new phone state: " + state); + + if (state != oldState) { + notifyPhoneStateChanged(); + } + } +} diff --git a/phone/src2/com/android/phone2/SipBroadcastReceiver.java b/phone/src2/com/android/phone2/SipBroadcastReceiver.java new file mode 100644 index 0000000..34ccae8 --- /dev/null +++ b/phone/src2/com/android/phone2/SipBroadcastReceiver.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.phone2; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.net.sip.SipManager; +import android.util.Log; + +/** + * Broadcast receiver that handles SIP-related intents. + */ +public class SipBroadcastReceiver extends BroadcastReceiver { + private static final String TAG = SipBroadcastReceiver.class.getSimpleName(); + + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + + if (action.equals(SipManager.SIP_INCOMING_CALL_ACTION)) { + // TODO: bring up InCallScreen + + /* + intent.setClass(context, SipCallUi.class); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + context.startActivity(intent); + */ + } else if (action.equals(SipManager.SIP_ADD_PHONE_ACTION)) { + String localSipUri = intent.getStringExtra(SipManager.LOCAL_URI_KEY); + Log.v(TAG, "new profile: " + localSipUri); + // TODO: should call CallManager.addPhone() + com.android.internal.telephony.SipPhoneProxy.setPhone(localSipUri); + } else { + Log.v(TAG, "action not processed: " + action); + return; + } + } +} |