summaryrefslogtreecommitdiffstats
path: root/telephony/java/com/android/internal/telephony/CallManager.java
diff options
context:
space:
mode:
Diffstat (limited to 'telephony/java/com/android/internal/telephony/CallManager.java')
-rw-r--r--telephony/java/com/android/internal/telephony/CallManager.java1855
1 files changed, 0 insertions, 1855 deletions
diff --git a/telephony/java/com/android/internal/telephony/CallManager.java b/telephony/java/com/android/internal/telephony/CallManager.java
deleted file mode 100644
index f825f31..0000000
--- a/telephony/java/com/android/internal/telephony/CallManager.java
+++ /dev/null
@@ -1,1855 +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;
-
-import com.android.internal.telephony.sip.SipPhone;
-
-import android.content.Context;
-import android.media.AudioManager;
-import android.os.AsyncResult;
-import android.os.Handler;
-import android.os.Message;
-import android.os.RegistrantList;
-import android.os.Registrant;
-import android.telephony.PhoneStateListener;
-import android.telephony.ServiceState;
-import android.util.Log;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-
-
-/**
- * @hide
- *
- * CallManager class provides an abstract layer for PhoneApp to access
- * and control calls. It implements Phone interface.
- *
- * CallManager provides call and connection control as well as
- * channel capability.
- *
- * There are three categories of APIs CallManager provided
- *
- * 1. Call control and operation, such as dial() and hangup()
- * 2. Channel capabilities, such as CanConference()
- * 3. Register notification
- *
- *
- */
-public final class CallManager {
-
- private static final String LOG_TAG ="CallManager";
- private static final boolean DBG = true;
- private static final boolean VDBG = false;
-
- private static final int EVENT_DISCONNECT = 100;
- private static final int EVENT_PRECISE_CALL_STATE_CHANGED = 101;
- private static final int EVENT_NEW_RINGING_CONNECTION = 102;
- private static final int EVENT_UNKNOWN_CONNECTION = 103;
- private static final int EVENT_INCOMING_RING = 104;
- private static final int EVENT_RINGBACK_TONE = 105;
- private static final int EVENT_IN_CALL_VOICE_PRIVACY_ON = 106;
- private static final int EVENT_IN_CALL_VOICE_PRIVACY_OFF = 107;
- private static final int EVENT_CALL_WAITING = 108;
- private static final int EVENT_DISPLAY_INFO = 109;
- private static final int EVENT_SIGNAL_INFO = 110;
- private static final int EVENT_CDMA_OTA_STATUS_CHANGE = 111;
- private static final int EVENT_RESEND_INCALL_MUTE = 112;
- private static final int EVENT_MMI_INITIATE = 113;
- private static final int EVENT_MMI_COMPLETE = 114;
- private static final int EVENT_ECM_TIMER_RESET = 115;
- private static final int EVENT_SUBSCRIPTION_INFO_READY = 116;
- private static final int EVENT_SUPP_SERVICE_FAILED = 117;
- private static final int EVENT_SERVICE_STATE_CHANGED = 118;
- private static final int EVENT_POST_DIAL_CHARACTER = 119;
-
- // Singleton instance
- private static final CallManager INSTANCE = new CallManager();
-
- // list of registered phones, which are PhoneBase objs
- private final ArrayList<Phone> mPhones;
-
- // list of supported ringing calls
- private final ArrayList<Call> mRingingCalls;
-
- // list of supported background calls
- private final ArrayList<Call> mBackgroundCalls;
-
- // list of supported foreground calls
- private final ArrayList<Call> mForegroundCalls;
-
- // empty connection list
- private final ArrayList<Connection> emptyConnections = new ArrayList<Connection>();
-
- // default phone as the first phone registered, which is PhoneBase obj
- private Phone mDefaultPhone;
-
- // state registrants
- protected final RegistrantList mPreciseCallStateRegistrants
- = new RegistrantList();
-
- protected final RegistrantList mNewRingingConnectionRegistrants
- = new RegistrantList();
-
- protected final RegistrantList mIncomingRingRegistrants
- = new RegistrantList();
-
- protected final RegistrantList mDisconnectRegistrants
- = new RegistrantList();
-
- protected final RegistrantList mMmiRegistrants
- = new RegistrantList();
-
- protected final RegistrantList mUnknownConnectionRegistrants
- = new RegistrantList();
-
- protected final RegistrantList mRingbackToneRegistrants
- = new RegistrantList();
-
- protected final RegistrantList mInCallVoicePrivacyOnRegistrants
- = new RegistrantList();
-
- protected final RegistrantList mInCallVoicePrivacyOffRegistrants
- = new RegistrantList();
-
- protected final RegistrantList mCallWaitingRegistrants
- = new RegistrantList();
-
- protected final RegistrantList mDisplayInfoRegistrants
- = new RegistrantList();
-
- protected final RegistrantList mSignalInfoRegistrants
- = new RegistrantList();
-
- protected final RegistrantList mCdmaOtaStatusChangeRegistrants
- = new RegistrantList();
-
- protected final RegistrantList mResendIncallMuteRegistrants
- = new RegistrantList();
-
- protected final RegistrantList mMmiInitiateRegistrants
- = new RegistrantList();
-
- protected final RegistrantList mMmiCompleteRegistrants
- = new RegistrantList();
-
- protected final RegistrantList mEcmTimerResetRegistrants
- = new RegistrantList();
-
- protected final RegistrantList mSubscriptionInfoReadyRegistrants
- = new RegistrantList();
-
- protected final RegistrantList mSuppServiceFailedRegistrants
- = new RegistrantList();
-
- protected final RegistrantList mServiceStateChangedRegistrants
- = new RegistrantList();
-
- protected final RegistrantList mPostDialCharacterRegistrants
- = new RegistrantList();
-
- private CallManager() {
- mPhones = new ArrayList<Phone>();
- mRingingCalls = new ArrayList<Call>();
- mBackgroundCalls = new ArrayList<Call>();
- mForegroundCalls = new ArrayList<Call>();
- mDefaultPhone = null;
- }
-
- /**
- * get singleton instance of CallManager
- * @return CallManager
- */
- public static CallManager getInstance() {
- return INSTANCE;
- }
-
- /**
- * Get the corresponding PhoneBase obj
- *
- * @param phone a Phone object
- * @return the corresponding PhoneBase obj in Phone if Phone
- * is a PhoneProxy obj
- * or the Phone itself if Phone is not a PhoneProxy obj
- */
- private static Phone getPhoneBase(Phone phone) {
- if (phone instanceof PhoneProxy) {
- return phone.getForegroundCall().getPhone();
- }
- return phone;
- }
-
- /**
- * Check if two phones refer to the same PhoneBase obj
- *
- * Note: PhoneBase, not PhoneProxy, is to be used inside of CallManager
- *
- * Both PhoneBase and PhoneProxy implement Phone interface, so
- * they have same phone APIs, such as dial(). The real implementation, for
- * example in GSM, is in GSMPhone as extend from PhoneBase, so that
- * foregroundCall.getPhone() returns GSMPhone obj. On the other hand,
- * PhoneFactory.getDefaultPhone() returns PhoneProxy obj, which has a class
- * member of GSMPhone.
- *
- * So for phone returned by PhoneFacotry, which is used by PhoneApp,
- * phone.getForegroundCall().getPhone() != phone
- * but
- * isSamePhone(phone, phone.getForegroundCall().getPhone()) == true
- *
- * @param p1 is the first Phone obj
- * @param p2 is the second Phone obj
- * @return true if p1 and p2 refer to the same phone
- */
- public static boolean isSamePhone(Phone p1, Phone p2) {
- return (getPhoneBase(p1) == getPhoneBase(p2));
- }
-
- /**
- * Returns all the registered phone objects.
- * @return all the registered phone objects.
- */
- public List<Phone> getAllPhones() {
- return Collections.unmodifiableList(mPhones);
- }
-
- /**
- * Get current coarse-grained voice call state.
- * If the Call Manager has an active call and call waiting occurs,
- * then the phone state is RINGING not OFFHOOK
- *
- */
- public Phone.State getState() {
- Phone.State s = Phone.State.IDLE;
-
- for (Phone phone : mPhones) {
- if (phone.getState() == Phone.State.RINGING) {
- s = Phone.State.RINGING;
- } else if (phone.getState() == Phone.State.OFFHOOK) {
- if (s == Phone.State.IDLE) s = Phone.State.OFFHOOK;
- }
- }
- return s;
- }
-
- /**
- * @return the service state of CallManager, which represents the
- * highest priority state of all the service states of phones
- *
- * The priority is defined as
- *
- * STATE_IN_SERIVCE > STATE_OUT_OF_SERIVCE > STATE_EMERGENCY > STATE_POWER_OFF
- *
- */
-
- public int getServiceState() {
- int resultState = ServiceState.STATE_OUT_OF_SERVICE;
-
- for (Phone phone : mPhones) {
- int serviceState = phone.getServiceState().getState();
- if (serviceState == ServiceState.STATE_IN_SERVICE) {
- // IN_SERVICE has the highest priority
- resultState = serviceState;
- break;
- } else if (serviceState == ServiceState.STATE_OUT_OF_SERVICE) {
- // OUT_OF_SERVICE replaces EMERGENCY_ONLY and POWER_OFF
- // Note: EMERGENCY_ONLY is not in use at this moment
- if ( resultState == ServiceState.STATE_EMERGENCY_ONLY ||
- resultState == ServiceState.STATE_POWER_OFF) {
- resultState = serviceState;
- }
- } else if (serviceState == ServiceState.STATE_EMERGENCY_ONLY) {
- if (resultState == ServiceState.STATE_POWER_OFF) {
- resultState = serviceState;
- }
- }
- }
- return resultState;
- }
-
- /**
- * Register phone to CallManager
- * @param phone to be registered
- * @return true if register successfully
- */
- public boolean registerPhone(Phone phone) {
- Phone basePhone = getPhoneBase(phone);
-
- if (basePhone != null && !mPhones.contains(basePhone)) {
-
- if (DBG) {
- Log.d(LOG_TAG, "registerPhone(" +
- phone.getPhoneName() + " " + phone + ")");
- }
-
- if (mPhones.isEmpty()) {
- mDefaultPhone = basePhone;
- }
- mPhones.add(basePhone);
- mRingingCalls.add(basePhone.getRingingCall());
- mBackgroundCalls.add(basePhone.getBackgroundCall());
- mForegroundCalls.add(basePhone.getForegroundCall());
- registerForPhoneStates(basePhone);
- return true;
- }
- return false;
- }
-
- /**
- * unregister phone from CallManager
- * @param phone to be unregistered
- */
- public void unregisterPhone(Phone phone) {
- Phone basePhone = getPhoneBase(phone);
-
- if (basePhone != null && mPhones.contains(basePhone)) {
-
- if (DBG) {
- Log.d(LOG_TAG, "unregisterPhone(" +
- phone.getPhoneName() + " " + phone + ")");
- }
-
- mPhones.remove(basePhone);
- mRingingCalls.remove(basePhone.getRingingCall());
- mBackgroundCalls.remove(basePhone.getBackgroundCall());
- mForegroundCalls.remove(basePhone.getForegroundCall());
- unregisterForPhoneStates(basePhone);
- if (basePhone == mDefaultPhone) {
- if (mPhones.isEmpty()) {
- mDefaultPhone = null;
- } else {
- mDefaultPhone = mPhones.get(0);
- }
- }
- }
- }
-
- /**
- * return the default phone or null if no phone available
- */
- public Phone getDefaultPhone() {
- return mDefaultPhone;
- }
-
- /**
- * @return the phone associated with the foreground call
- */
- public Phone getFgPhone() {
- return getActiveFgCall().getPhone();
- }
-
- /**
- * @return the phone associated with the background call
- */
- public Phone getBgPhone() {
- return getFirstActiveBgCall().getPhone();
- }
-
- /**
- * @return the phone associated with the ringing call
- */
- public Phone getRingingPhone() {
- return getFirstActiveRingingCall().getPhone();
- }
-
- public void setAudioMode() {
- Context context = getContext();
- if (context == null) return;
- AudioManager audioManager = (AudioManager)
- context.getSystemService(Context.AUDIO_SERVICE);
-
- // change the audio mode and request/abandon audio focus according to phone state,
- // but only on audio mode transitions
- switch (getState()) {
- case RINGING:
- if (audioManager.getMode() != AudioManager.MODE_RINGTONE) {
- // only request audio focus if the ringtone is going to be heard
- if (audioManager.getStreamVolume(AudioManager.STREAM_RING) > 0) {
- if (VDBG) Log.d(LOG_TAG, "requestAudioFocus on STREAM_RING");
- audioManager.requestAudioFocusForCall(AudioManager.STREAM_RING,
- AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
- }
- audioManager.setMode(AudioManager.MODE_RINGTONE);
- }
- break;
- case OFFHOOK:
- Phone offhookPhone = getFgPhone();
- if (getActiveFgCallState() == Call.State.IDLE) {
- // There is no active Fg calls, the OFFHOOK state
- // is set by the Bg call. So set the phone to bgPhone.
- offhookPhone = getBgPhone();
- }
-
- int newAudioMode = AudioManager.MODE_IN_CALL;
- if (offhookPhone instanceof SipPhone) {
- // enable IN_COMMUNICATION audio mode instead for sipPhone
- newAudioMode = AudioManager.MODE_IN_COMMUNICATION;
- }
- if (audioManager.getMode() != newAudioMode) {
- // request audio focus before setting the new mode
- if (VDBG) Log.d(LOG_TAG, "requestAudioFocus on STREAM_VOICE_CALL");
- audioManager.requestAudioFocusForCall(AudioManager.STREAM_VOICE_CALL,
- AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
- audioManager.setMode(newAudioMode);
- }
- break;
- case IDLE:
- if (audioManager.getMode() != AudioManager.MODE_NORMAL) {
- audioManager.setMode(AudioManager.MODE_NORMAL);
- if (VDBG) Log.d(LOG_TAG, "abandonAudioFocus");
- // abandon audio focus after the mode has been set back to normal
- audioManager.abandonAudioFocusForCall();
- }
- break;
- }
- }
-
- private Context getContext() {
- Phone defaultPhone = getDefaultPhone();
- return ((defaultPhone == null) ? null : defaultPhone.getContext());
- }
-
- private void registerForPhoneStates(Phone phone) {
- // for common events supported by all phones
- phone.registerForPreciseCallStateChanged(mHandler, EVENT_PRECISE_CALL_STATE_CHANGED, null);
- phone.registerForDisconnect(mHandler, EVENT_DISCONNECT, null);
- phone.registerForNewRingingConnection(mHandler, EVENT_NEW_RINGING_CONNECTION, null);
- phone.registerForUnknownConnection(mHandler, EVENT_UNKNOWN_CONNECTION, null);
- phone.registerForIncomingRing(mHandler, EVENT_INCOMING_RING, null);
- phone.registerForRingbackTone(mHandler, EVENT_RINGBACK_TONE, null);
- phone.registerForInCallVoicePrivacyOn(mHandler, EVENT_IN_CALL_VOICE_PRIVACY_ON, null);
- phone.registerForInCallVoicePrivacyOff(mHandler, EVENT_IN_CALL_VOICE_PRIVACY_OFF, null);
- phone.registerForDisplayInfo(mHandler, EVENT_DISPLAY_INFO, null);
- phone.registerForSignalInfo(mHandler, EVENT_SIGNAL_INFO, null);
- phone.registerForResendIncallMute(mHandler, EVENT_RESEND_INCALL_MUTE, null);
- phone.registerForMmiInitiate(mHandler, EVENT_MMI_INITIATE, null);
- phone.registerForMmiComplete(mHandler, EVENT_MMI_COMPLETE, null);
- phone.registerForSuppServiceFailed(mHandler, EVENT_SUPP_SERVICE_FAILED, null);
- phone.registerForServiceStateChanged(mHandler, EVENT_SERVICE_STATE_CHANGED, null);
-
- // for events supported only by GSM and CDMA phone
- if (phone.getPhoneType() == Phone.PHONE_TYPE_GSM ||
- phone.getPhoneType() == Phone.PHONE_TYPE_CDMA) {
- phone.setOnPostDialCharacter(mHandler, EVENT_POST_DIAL_CHARACTER, null);
- }
-
- // for events supported only by CDMA phone
- if (phone.getPhoneType() == Phone.PHONE_TYPE_CDMA ){
- phone.registerForCdmaOtaStatusChange(mHandler, EVENT_CDMA_OTA_STATUS_CHANGE, null);
- phone.registerForSubscriptionInfoReady(mHandler, EVENT_SUBSCRIPTION_INFO_READY, null);
- phone.registerForCallWaiting(mHandler, EVENT_CALL_WAITING, null);
- phone.registerForEcmTimerReset(mHandler, EVENT_ECM_TIMER_RESET, null);
- }
- }
-
- private void unregisterForPhoneStates(Phone phone) {
- // for common events supported by all phones
- phone.unregisterForPreciseCallStateChanged(mHandler);
- phone.unregisterForDisconnect(mHandler);
- phone.unregisterForNewRingingConnection(mHandler);
- phone.unregisterForUnknownConnection(mHandler);
- phone.unregisterForIncomingRing(mHandler);
- phone.unregisterForRingbackTone(mHandler);
- phone.unregisterForInCallVoicePrivacyOn(mHandler);
- phone.unregisterForInCallVoicePrivacyOff(mHandler);
- phone.unregisterForDisplayInfo(mHandler);
- phone.unregisterForSignalInfo(mHandler);
- phone.unregisterForResendIncallMute(mHandler);
- phone.unregisterForMmiInitiate(mHandler);
- phone.unregisterForMmiComplete(mHandler);
- phone.unregisterForSuppServiceFailed(mHandler);
- phone.unregisterForServiceStateChanged(mHandler);
-
- // for events supported only by GSM and CDMA phone
- if (phone.getPhoneType() == Phone.PHONE_TYPE_GSM ||
- phone.getPhoneType() == Phone.PHONE_TYPE_CDMA) {
- phone.setOnPostDialCharacter(null, EVENT_POST_DIAL_CHARACTER, null);
- }
-
- // for events supported only by CDMA phone
- if (phone.getPhoneType() == Phone.PHONE_TYPE_CDMA ){
- phone.unregisterForCdmaOtaStatusChange(mHandler);
- phone.unregisterForSubscriptionInfoReady(mHandler);
- phone.unregisterForCallWaiting(mHandler);
- phone.unregisterForEcmTimerReset(mHandler);
- }
- }
-
- /**
- * Answers a ringing or waiting call.
- *
- * Active call, if any, go on hold.
- * If active call can't be held, i.e., a background call of the same channel exists,
- * the active call will be hang up.
- *
- * Answering occurs asynchronously, and final notification occurs via
- * {@link #registerForPreciseCallStateChanged(android.os.Handler, int,
- * java.lang.Object) registerForPreciseCallStateChanged()}.
- *
- * @exception CallStateException when call is not ringing or waiting
- */
- public void acceptCall(Call ringingCall) throws CallStateException {
- Phone ringingPhone = ringingCall.getPhone();
-
- if (VDBG) {
- Log.d(LOG_TAG, "acceptCall(" +ringingCall + " from " + ringingCall.getPhone() + ")");
- Log.d(LOG_TAG, this.toString());
- }
-
- if ( hasActiveFgCall() ) {
- Phone activePhone = getActiveFgCall().getPhone();
- boolean hasBgCall = ! (activePhone.getBackgroundCall().isIdle());
- boolean sameChannel = (activePhone == ringingPhone);
-
- if (VDBG) {
- Log.d(LOG_TAG, "hasBgCall: "+ hasBgCall + "sameChannel:" + sameChannel);
- }
-
- if (sameChannel && hasBgCall) {
- getActiveFgCall().hangup();
- } else if (!sameChannel && !hasBgCall) {
- activePhone.switchHoldingAndActive();
- } else if (!sameChannel && hasBgCall) {
- getActiveFgCall().hangup();
- }
- }
-
- ringingPhone.acceptCall();
-
- if (VDBG) {
- Log.d(LOG_TAG, "End acceptCall(" +ringingCall + ")");
- Log.d(LOG_TAG, this.toString());
- }
- }
-
- /**
- * Reject (ignore) a ringing call. In GSM, this means UDUB
- * (User Determined User Busy). Reject occurs asynchronously,
- * and final notification occurs via
- * {@link #registerForPreciseCallStateChanged(android.os.Handler, int,
- * java.lang.Object) registerForPreciseCallStateChanged()}.
- *
- * @exception CallStateException when no call is ringing or waiting
- */
- public void rejectCall(Call ringingCall) throws CallStateException {
- if (VDBG) {
- Log.d(LOG_TAG, "rejectCall(" +ringingCall + ")");
- Log.d(LOG_TAG, this.toString());
- }
-
- Phone ringingPhone = ringingCall.getPhone();
-
- ringingPhone.rejectCall();
-
- if (VDBG) {
- Log.d(LOG_TAG, "End rejectCall(" +ringingCall + ")");
- Log.d(LOG_TAG, this.toString());
- }
- }
-
- /**
- * Places active call on hold, and makes held call active.
- * Switch occurs asynchronously and may fail.
- *
- * There are 4 scenarios
- * 1. only active call but no held call, aka, hold
- * 2. no active call but only held call, aka, unhold
- * 3. both active and held calls from same phone, aka, swap
- * 4. active and held calls from different phones, aka, phone swap
- *
- * Final notification occurs via
- * {@link #registerForPreciseCallStateChanged(android.os.Handler, int,
- * java.lang.Object) registerForPreciseCallStateChanged()}.
- *
- * @exception CallStateException if active call is ringing, waiting, or
- * dialing/alerting, or heldCall can't be active.
- * In these cases, this operation may not be performed.
- */
- public void switchHoldingAndActive(Call heldCall) throws CallStateException {
- Phone activePhone = null;
- Phone heldPhone = null;
-
- if (VDBG) {
- Log.d(LOG_TAG, "switchHoldingAndActive(" +heldCall + ")");
- Log.d(LOG_TAG, this.toString());
- }
-
- if (hasActiveFgCall()) {
- activePhone = getActiveFgCall().getPhone();
- }
-
- if (heldCall != null) {
- heldPhone = heldCall.getPhone();
- }
-
- if (activePhone != null) {
- activePhone.switchHoldingAndActive();
- }
-
- if (heldPhone != null && heldPhone != activePhone) {
- heldPhone.switchHoldingAndActive();
- }
-
- if (VDBG) {
- Log.d(LOG_TAG, "End switchHoldingAndActive(" +heldCall + ")");
- Log.d(LOG_TAG, this.toString());
- }
- }
-
- /**
- * Hangup foreground call and resume the specific background call
- *
- * Note: this is noop if there is no foreground call or the heldCall is null
- *
- * @param heldCall to become foreground
- * @throws CallStateException
- */
- public void hangupForegroundResumeBackground(Call heldCall) throws CallStateException {
- Phone foregroundPhone = null;
- Phone backgroundPhone = null;
-
- if (VDBG) {
- Log.d(LOG_TAG, "hangupForegroundResumeBackground(" +heldCall + ")");
- Log.d(LOG_TAG, this.toString());
- }
-
- if (hasActiveFgCall()) {
- foregroundPhone = getFgPhone();
- if (heldCall != null) {
- backgroundPhone = heldCall.getPhone();
- if (foregroundPhone == backgroundPhone) {
- getActiveFgCall().hangup();
- } else {
- // the call to be hangup and resumed belongs to different phones
- getActiveFgCall().hangup();
- switchHoldingAndActive(heldCall);
- }
- }
- }
-
- if (VDBG) {
- Log.d(LOG_TAG, "End hangupForegroundResumeBackground(" +heldCall + ")");
- Log.d(LOG_TAG, this.toString());
- }
- }
-
- /**
- * Whether or not the phone can conference in the current phone
- * state--that is, one call holding and one call active.
- * @return true if the phone can conference; false otherwise.
- */
- public boolean canConference(Call heldCall) {
- Phone activePhone = null;
- Phone heldPhone = null;
-
- if (hasActiveFgCall()) {
- activePhone = getActiveFgCall().getPhone();
- }
-
- if (heldCall != null) {
- heldPhone = heldCall.getPhone();
- }
-
- return heldPhone.getClass().equals(activePhone.getClass());
- }
-
- /**
- * Conferences holding and active. Conference occurs asynchronously
- * and may fail. Final notification occurs via
- * {@link #registerForPreciseCallStateChanged(android.os.Handler, int,
- * java.lang.Object) registerForPreciseCallStateChanged()}.
- *
- * @exception CallStateException if canConference() would return false.
- * In these cases, this operation may not be performed.
- */
- public void conference(Call heldCall) throws CallStateException {
-
- if (VDBG) {
- Log.d(LOG_TAG, "conference(" +heldCall + ")");
- Log.d(LOG_TAG, this.toString());
- }
-
-
- Phone fgPhone = getFgPhone();
- if (fgPhone instanceof SipPhone) {
- ((SipPhone) fgPhone).conference(heldCall);
- } else if (canConference(heldCall)) {
- fgPhone.conference();
- } else {
- throw(new CallStateException("Can't conference foreground and selected background call"));
- }
-
- if (VDBG) {
- Log.d(LOG_TAG, "End conference(" +heldCall + ")");
- Log.d(LOG_TAG, this.toString());
- }
-
- }
-
- /**
- * Initiate a new voice connection. This happens asynchronously, so you
- * cannot assume the audio path is connected (or a call index has been
- * assigned) until PhoneStateChanged notification has occurred.
- *
- * @exception CallStateException if a new outgoing call is not currently
- * possible because no more call slots exist or a call exists that is
- * dialing, alerting, ringing, or waiting. Other errors are
- * handled asynchronously.
- */
- public Connection dial(Phone phone, String dialString) throws CallStateException {
- Phone basePhone = getPhoneBase(phone);
- Connection result;
-
- if (VDBG) {
- Log.d(LOG_TAG, " dial(" + basePhone + ", "+ dialString + ")");
- Log.d(LOG_TAG, this.toString());
- }
-
- if (!canDial(phone)) {
- throw new CallStateException("cannot dial in current state");
- }
-
- if ( hasActiveFgCall() ) {
- Phone activePhone = getActiveFgCall().getPhone();
- boolean hasBgCall = !(activePhone.getBackgroundCall().isIdle());
-
- if (DBG) {
- Log.d(LOG_TAG, "hasBgCall: "+ hasBgCall + " sameChannel:" + (activePhone == basePhone));
- }
-
- if (activePhone != basePhone) {
- if (hasBgCall) {
- Log.d(LOG_TAG, "Hangup");
- getActiveFgCall().hangup();
- } else {
- Log.d(LOG_TAG, "Switch");
- activePhone.switchHoldingAndActive();
- }
- }
- }
-
- result = basePhone.dial(dialString);
-
- if (VDBG) {
- Log.d(LOG_TAG, "End dial(" + basePhone + ", "+ dialString + ")");
- Log.d(LOG_TAG, this.toString());
- }
-
- return result;
- }
-
- /**
- * Initiate a new voice connection. This happens asynchronously, so you
- * cannot assume the audio path is connected (or a call index has been
- * assigned) until PhoneStateChanged notification has occurred.
- *
- * @exception CallStateException if a new outgoing call is not currently
- * possible because no more call slots exist or a call exists that is
- * dialing, alerting, ringing, or waiting. Other errors are
- * handled asynchronously.
- */
- public Connection dial(Phone phone, String dialString, UUSInfo uusInfo) throws CallStateException {
- return phone.dial(dialString, uusInfo);
- }
-
- /**
- * clear disconnect connection for each phone
- */
- public void clearDisconnected() {
- for(Phone phone : mPhones) {
- phone.clearDisconnected();
- }
- }
-
- /**
- * Phone can make a call only if ALL of the following are true:
- * - Phone is not powered off
- * - There's no incoming or waiting call
- * - There's available call slot in either foreground or background
- * - The foreground call is ACTIVE or IDLE or DISCONNECTED.
- * (We mainly need to make sure it *isn't* DIALING or ALERTING.)
- * @param phone
- * @return true if the phone can make a new call
- */
- private boolean canDial(Phone phone) {
- int serviceState = phone.getServiceState().getState();
- boolean hasRingingCall = hasActiveRingingCall();
- boolean hasActiveCall = hasActiveFgCall();
- boolean hasHoldingCall = hasActiveBgCall();
- boolean allLinesTaken = hasActiveCall && hasHoldingCall;
- Call.State fgCallState = getActiveFgCallState();
-
- boolean result = (serviceState != ServiceState.STATE_POWER_OFF
- && !hasRingingCall
- && !allLinesTaken
- && ((fgCallState == Call.State.ACTIVE)
- || (fgCallState == Call.State.IDLE)
- || (fgCallState == Call.State.DISCONNECTED)));
-
- if (result == false) {
- Log.d(LOG_TAG, "canDial serviceState=" + serviceState
- + " hasRingingCall=" + hasRingingCall
- + " hasActiveCall=" + hasActiveCall
- + " hasHoldingCall=" + hasHoldingCall
- + " allLinesTaken=" + allLinesTaken
- + " fgCallState=" + fgCallState);
- }
- return result;
- }
-
- /**
- * Whether or not the phone can do explicit call transfer in the current
- * phone state--that is, one call holding and one call active.
- * @return true if the phone can do explicit call transfer; false otherwise.
- */
- public boolean canTransfer(Call heldCall) {
- Phone activePhone = null;
- Phone heldPhone = null;
-
- if (hasActiveFgCall()) {
- activePhone = getActiveFgCall().getPhone();
- }
-
- if (heldCall != null) {
- heldPhone = heldCall.getPhone();
- }
-
- return (heldPhone == activePhone && activePhone.canTransfer());
- }
-
- /**
- * Connects the held call and active call
- * Disconnects the subscriber from both calls
- *
- * Explicit Call Transfer occurs asynchronously
- * and may fail. Final notification occurs via
- * {@link #registerForPreciseCallStateChanged(android.os.Handler, int,
- * java.lang.Object) registerForPreciseCallStateChanged()}.
- *
- * @exception CallStateException if canTransfer() would return false.
- * In these cases, this operation may not be performed.
- */
- public void explicitCallTransfer(Call heldCall) throws CallStateException {
- if (VDBG) {
- Log.d(LOG_TAG, " explicitCallTransfer(" + heldCall + ")");
- Log.d(LOG_TAG, this.toString());
- }
-
- if (canTransfer(heldCall)) {
- heldCall.getPhone().explicitCallTransfer();
- }
-
- if (VDBG) {
- Log.d(LOG_TAG, "End explicitCallTransfer(" + heldCall + ")");
- Log.d(LOG_TAG, this.toString());
- }
-
- }
-
- /**
- * Returns a list of MMI codes that are pending for a phone. (They have initiated
- * but have not yet completed).
- * Presently there is only ever one.
- *
- * Use <code>registerForMmiInitiate</code>
- * and <code>registerForMmiComplete</code> for change notification.
- * @return null if phone doesn't have or support mmi code
- */
- public List<? extends MmiCode> getPendingMmiCodes(Phone phone) {
- Log.e(LOG_TAG, "getPendingMmiCodes not implemented");
- return null;
- }
-
- /**
- * Sends user response to a USSD REQUEST message. An MmiCode instance
- * representing this response is sent to handlers registered with
- * registerForMmiInitiate.
- *
- * @param ussdMessge Message to send in the response.
- * @return false if phone doesn't support ussd service
- */
- public boolean sendUssdResponse(Phone phone, String ussdMessge) {
- Log.e(LOG_TAG, "sendUssdResponse not implemented");
- return false;
- }
-
- /**
- * Mutes or unmutes the microphone for the active call. The microphone
- * is automatically unmuted if a call is answered, dialed, or resumed
- * from a holding state.
- *
- * @param muted true to mute the microphone,
- * false to activate the microphone.
- */
-
- public void setMute(boolean muted) {
- if (VDBG) {
- Log.d(LOG_TAG, " setMute(" + muted + ")");
- Log.d(LOG_TAG, this.toString());
- }
-
- if (hasActiveFgCall()) {
- getActiveFgCall().getPhone().setMute(muted);
- }
-
- if (VDBG) {
- Log.d(LOG_TAG, "End setMute(" + muted + ")");
- Log.d(LOG_TAG, this.toString());
- }
- }
-
- /**
- * Gets current mute status. Use
- * {@link #registerForPreciseCallStateChanged(android.os.Handler, int,
- * java.lang.Object) registerForPreciseCallStateChanged()}
- * as a change notifcation, although presently phone state changed is not
- * fired when setMute() is called.
- *
- * @return true is muting, false is unmuting
- */
- public boolean getMute() {
- if (hasActiveFgCall()) {
- return getActiveFgCall().getPhone().getMute();
- } else if (hasActiveBgCall()) {
- return getFirstActiveBgCall().getPhone().getMute();
- }
- return false;
- }
-
- /**
- * Enables or disables echo suppression.
- */
- public void setEchoSuppressionEnabled(boolean enabled) {
- if (VDBG) {
- Log.d(LOG_TAG, " setEchoSuppression(" + enabled + ")");
- Log.d(LOG_TAG, this.toString());
- }
-
- if (hasActiveFgCall()) {
- getActiveFgCall().getPhone().setEchoSuppressionEnabled(enabled);
- }
-
- if (VDBG) {
- Log.d(LOG_TAG, "End setEchoSuppression(" + enabled + ")");
- Log.d(LOG_TAG, this.toString());
- }
- }
-
- /**
- * Play a DTMF tone on the active call.
- *
- * @param c should be one of 0-9, '*' or '#'. Other values will be
- * silently ignored.
- * @return false if no active call or the active call doesn't support
- * dtmf tone
- */
- public boolean sendDtmf(char c) {
- boolean result = false;
-
- if (VDBG) {
- Log.d(LOG_TAG, " sendDtmf(" + c + ")");
- Log.d(LOG_TAG, this.toString());
- }
-
- if (hasActiveFgCall()) {
- getActiveFgCall().getPhone().sendDtmf(c);
- result = true;
- }
-
- if (VDBG) {
- Log.d(LOG_TAG, "End sendDtmf(" + c + ")");
- Log.d(LOG_TAG, this.toString());
- }
- return result;
- }
-
- /**
- * Start to paly a DTMF tone on the active call.
- * or there is a playing DTMF tone.
- * @param c should be one of 0-9, '*' or '#'. Other values will be
- * silently ignored.
- *
- * @return false if no active call or the active call doesn't support
- * dtmf tone
- */
- public boolean startDtmf(char c) {
- boolean result = false;
-
- if (VDBG) {
- Log.d(LOG_TAG, " startDtmf(" + c + ")");
- Log.d(LOG_TAG, this.toString());
- }
-
- if (hasActiveFgCall()) {
- getActiveFgCall().getPhone().startDtmf(c);
- result = true;
- }
-
- if (VDBG) {
- Log.d(LOG_TAG, "End startDtmf(" + c + ")");
- Log.d(LOG_TAG, this.toString());
- }
-
- return result;
- }
-
- /**
- * Stop the playing DTMF tone. Ignored if there is no playing DTMF
- * tone or no active call.
- */
- public void stopDtmf() {
- if (VDBG) {
- Log.d(LOG_TAG, " stopDtmf()" );
- Log.d(LOG_TAG, this.toString());
- }
-
- if (hasActiveFgCall()) getFgPhone().stopDtmf();
-
- if (VDBG) {
- Log.d(LOG_TAG, "End stopDtmf()");
- Log.d(LOG_TAG, this.toString());
- }
- }
-
- /**
- * send burst DTMF tone, it can send the string as single character or multiple character
- * ignore if there is no active call or not valid digits string.
- * Valid digit means only includes characters ISO-LATIN characters 0-9, *, #
- * The difference between sendDtmf and sendBurstDtmf is sendDtmf only sends one character,
- * this api can send single character and multiple character, also, this api has response
- * back to caller.
- *
- * @param dtmfString is string representing the dialing digit(s) in the active call
- * @param on the DTMF ON length in milliseconds, or 0 for default
- * @param off the DTMF OFF length in milliseconds, or 0 for default
- * @param onComplete is the callback message when the action is processed by BP
- *
- */
- public boolean sendBurstDtmf(String dtmfString, int on, int off, Message onComplete) {
- if (hasActiveFgCall()) {
- getActiveFgCall().getPhone().sendBurstDtmf(dtmfString, on, off, onComplete);
- return true;
- }
- return false;
- }
-
- /**
- * Notifies when a voice connection has disconnected, either due to local
- * or remote hangup or error.
- *
- * Messages received from this will have the following members:<p>
- * <ul><li>Message.obj will be an AsyncResult</li>
- * <li>AsyncResult.userObj = obj</li>
- * <li>AsyncResult.result = a Connection object that is
- * no longer connected.</li></ul>
- */
- public void registerForDisconnect(Handler h, int what, Object obj) {
- mDisconnectRegistrants.addUnique(h, what, obj);
- }
-
- /**
- * Unregisters for voice disconnection notification.
- * Extraneous calls are tolerated silently
- */
- public void unregisterForDisconnect(Handler h){
- mDisconnectRegistrants.remove(h);
- }
-
- /**
- * Register for getting notifications for change in the Call State {@link Call.State}
- * This is called PreciseCallState because the call state is more precise than the
- * {@link Phone.State} which can be obtained using the {@link PhoneStateListener}
- *
- * Resulting events will have an AsyncResult in <code>Message.obj</code>.
- * AsyncResult.userData will be set to the obj argument here.
- * The <em>h</em> parameter is held only by a weak reference.
- */
- public void registerForPreciseCallStateChanged(Handler h, int what, Object obj){
- mPreciseCallStateRegistrants.addUnique(h, what, obj);
- }
-
- /**
- * Unregisters for voice call state change notifications.
- * Extraneous calls are tolerated silently.
- */
- public void unregisterForPreciseCallStateChanged(Handler h){
- mPreciseCallStateRegistrants.remove(h);
- }
-
- /**
- * Notifies when a previously untracked non-ringing/waiting connection has appeared.
- * This is likely due to some other entity (eg, SIM card application) initiating a call.
- */
- public void registerForUnknownConnection(Handler h, int what, Object obj){
- mUnknownConnectionRegistrants.addUnique(h, what, obj);
- }
-
- /**
- * Unregisters for unknown connection notifications.
- */
- public void unregisterForUnknownConnection(Handler h){
- mUnknownConnectionRegistrants.remove(h);
- }
-
-
- /**
- * Notifies when a new ringing or waiting connection has appeared.<p>
- *
- * Messages received from this:
- * Message.obj will be an AsyncResult
- * AsyncResult.userObj = obj
- * AsyncResult.result = a Connection. <p>
- * Please check Connection.isRinging() to make sure the Connection
- * has not dropped since this message was posted.
- * If Connection.isRinging() is true, then
- * Connection.getCall() == Phone.getRingingCall()
- */
- public void registerForNewRingingConnection(Handler h, int what, Object obj){
- mNewRingingConnectionRegistrants.addUnique(h, what, obj);
- }
-
- /**
- * Unregisters for new ringing connection notification.
- * Extraneous calls are tolerated silently
- */
-
- public void unregisterForNewRingingConnection(Handler h){
- mNewRingingConnectionRegistrants.remove(h);
- }
-
- /**
- * Notifies when an incoming call rings.<p>
- *
- * Messages received from this:
- * Message.obj will be an AsyncResult
- * AsyncResult.userObj = obj
- * AsyncResult.result = a Connection. <p>
- */
- public void registerForIncomingRing(Handler h, int what, Object obj){
- mIncomingRingRegistrants.addUnique(h, what, obj);
- }
-
- /**
- * Unregisters for ring notification.
- * Extraneous calls are tolerated silently
- */
-
- public void unregisterForIncomingRing(Handler h){
- mIncomingRingRegistrants.remove(h);
- }
-
- /**
- * Notifies when out-band ringback tone is needed.<p>
- *
- * Messages received from this:
- * Message.obj will be an AsyncResult
- * AsyncResult.userObj = obj
- * AsyncResult.result = boolean, true to start play ringback tone
- * and false to stop. <p>
- */
- public void registerForRingbackTone(Handler h, int what, Object obj){
- mRingbackToneRegistrants.addUnique(h, what, obj);
- }
-
- /**
- * Unregisters for ringback tone notification.
- */
-
- public void unregisterForRingbackTone(Handler h){
- mRingbackToneRegistrants.remove(h);
- }
-
- /**
- * Registers the handler to reset the uplink mute state to get
- * uplink audio.
- */
- public void registerForResendIncallMute(Handler h, int what, Object obj){
- mResendIncallMuteRegistrants.addUnique(h, what, obj);
- }
-
- /**
- * Unregisters for resend incall mute notifications.
- */
- public void unregisterForResendIncallMute(Handler h){
- mResendIncallMuteRegistrants.remove(h);
- }
-
- /**
- * Register for notifications of initiation of a new MMI code request.
- * MMI codes for GSM are discussed in 3GPP TS 22.030.<p>
- *
- * Example: If Phone.dial is called with "*#31#", then the app will
- * be notified here.<p>
- *
- * The returned <code>Message.obj</code> will contain an AsyncResult.
- *
- * <code>obj.result</code> will be an "MmiCode" object.
- */
- public void registerForMmiInitiate(Handler h, int what, Object obj){
- mMmiInitiateRegistrants.addUnique(h, what, obj);
- }
-
- /**
- * Unregisters for new MMI initiate notification.
- * Extraneous calls are tolerated silently
- */
- public void unregisterForMmiInitiate(Handler h){
- mMmiInitiateRegistrants.remove(h);
- }
-
- /**
- * Register for notifications that an MMI request has completed
- * its network activity and is in its final state. This may mean a state
- * of COMPLETE, FAILED, or CANCELLED.
- *
- * <code>Message.obj</code> will contain an AsyncResult.
- * <code>obj.result</code> will be an "MmiCode" object
- */
- public void registerForMmiComplete(Handler h, int what, Object obj){
- mMmiCompleteRegistrants.addUnique(h, what, obj);
- }
-
- /**
- * Unregisters for MMI complete notification.
- * Extraneous calls are tolerated silently
- */
- public void unregisterForMmiComplete(Handler h){
- mMmiCompleteRegistrants.remove(h);
- }
-
- /**
- * Registration point for Ecm timer reset
- * @param h handler to notify
- * @param what user-defined message code
- * @param obj placed in Message.obj
- */
- public void registerForEcmTimerReset(Handler h, int what, Object obj){
- mEcmTimerResetRegistrants.addUnique(h, what, obj);
- }
-
- /**
- * Unregister for notification for Ecm timer reset
- * @param h Handler to be removed from the registrant list.
- */
- public void unregisterForEcmTimerReset(Handler h){
- mEcmTimerResetRegistrants.remove(h);
- }
-
- /**
- * Register for ServiceState changed.
- * Message.obj will contain an AsyncResult.
- * AsyncResult.result will be a ServiceState instance
- */
- public void registerForServiceStateChanged(Handler h, int what, Object obj){
- mServiceStateChangedRegistrants.addUnique(h, what, obj);
- }
-
- /**
- * Unregisters for ServiceStateChange notification.
- * Extraneous calls are tolerated silently
- */
- public void unregisterForServiceStateChanged(Handler h){
- mServiceStateChangedRegistrants.remove(h);
- }
-
- /**
- * Register for notifications when a supplementary service attempt fails.
- * Message.obj will contain an AsyncResult.
- *
- * @param h Handler that receives the notification message.
- * @param what User-defined message code.
- * @param obj User object.
- */
- public void registerForSuppServiceFailed(Handler h, int what, Object obj){
- mSuppServiceFailedRegistrants.addUnique(h, what, obj);
- }
-
- /**
- * Unregister for notifications when a supplementary service attempt fails.
- * Extraneous calls are tolerated silently
- *
- * @param h Handler to be removed from the registrant list.
- */
- public void unregisterForSuppServiceFailed(Handler h){
- mSuppServiceFailedRegistrants.remove(h);
- }
-
- /**
- * Register for notifications when a sInCall VoicePrivacy is enabled
- *
- * @param h Handler that receives the notification message.
- * @param what User-defined message code.
- * @param obj User object.
- */
- public void registerForInCallVoicePrivacyOn(Handler h, int what, Object obj){
- mInCallVoicePrivacyOnRegistrants.addUnique(h, what, obj);
- }
-
- /**
- * Unregister for notifications when a sInCall VoicePrivacy is enabled
- *
- * @param h Handler to be removed from the registrant list.
- */
- public void unregisterForInCallVoicePrivacyOn(Handler h){
- mInCallVoicePrivacyOnRegistrants.remove(h);
- }
-
- /**
- * Register for notifications when a sInCall VoicePrivacy is disabled
- *
- * @param h Handler that receives the notification message.
- * @param what User-defined message code.
- * @param obj User object.
- */
- public void registerForInCallVoicePrivacyOff(Handler h, int what, Object obj){
- mInCallVoicePrivacyOffRegistrants.addUnique(h, what, obj);
- }
-
- /**
- * Unregister for notifications when a sInCall VoicePrivacy is disabled
- *
- * @param h Handler to be removed from the registrant list.
- */
- public void unregisterForInCallVoicePrivacyOff(Handler h){
- mInCallVoicePrivacyOffRegistrants.remove(h);
- }
-
- /**
- * Register for notifications when CDMA call waiting comes
- *
- * @param h Handler that receives the notification message.
- * @param what User-defined message code.
- * @param obj User object.
- */
- public void registerForCallWaiting(Handler h, int what, Object obj){
- mCallWaitingRegistrants.addUnique(h, what, obj);
- }
-
- /**
- * Unregister for notifications when CDMA Call waiting comes
- * @param h Handler to be removed from the registrant list.
- */
- public void unregisterForCallWaiting(Handler h){
- mCallWaitingRegistrants.remove(h);
- }
-
-
- /**
- * Register for signal information notifications from the network.
- * Message.obj will contain an AsyncResult.
- * AsyncResult.result will be a SuppServiceNotification instance.
- *
- * @param h Handler that receives the notification message.
- * @param what User-defined message code.
- * @param obj User object.
- */
-
- public void registerForSignalInfo(Handler h, int what, Object obj){
- mSignalInfoRegistrants.addUnique(h, what, obj);
- }
-
- /**
- * Unregisters for signal information notifications.
- * Extraneous calls are tolerated silently
- *
- * @param h Handler to be removed from the registrant list.
- */
- public void unregisterForSignalInfo(Handler h){
- mSignalInfoRegistrants.remove(h);
- }
-
- /**
- * Register for display information notifications from the network.
- * Message.obj will contain an AsyncResult.
- * AsyncResult.result will be a SuppServiceNotification instance.
- *
- * @param h Handler that receives the notification message.
- * @param what User-defined message code.
- * @param obj User object.
- */
- public void registerForDisplayInfo(Handler h, int what, Object obj){
- mDisplayInfoRegistrants.addUnique(h, what, obj);
- }
-
- /**
- * Unregisters for display information notifications.
- * Extraneous calls are tolerated silently
- *
- * @param h Handler to be removed from the registrant list.
- */
- public void unregisterForDisplayInfo(Handler h) {
- mDisplayInfoRegistrants.remove(h);
- }
-
- /**
- * Register for notifications when CDMA OTA Provision status change
- *
- * @param h Handler that receives the notification message.
- * @param what User-defined message code.
- * @param obj User object.
- */
- public void registerForCdmaOtaStatusChange(Handler h, int what, Object obj){
- mCdmaOtaStatusChangeRegistrants.addUnique(h, what, obj);
- }
-
- /**
- * Unregister for notifications when CDMA OTA Provision status change
- * @param h Handler to be removed from the registrant list.
- */
- public void unregisterForCdmaOtaStatusChange(Handler h){
- mCdmaOtaStatusChangeRegistrants.remove(h);
- }
-
- /**
- * Registration point for subscription info ready
- * @param h handler to notify
- * @param what what code of message when delivered
- * @param obj placed in Message.obj
- */
- public void registerForSubscriptionInfoReady(Handler h, int what, Object obj){
- mSubscriptionInfoReadyRegistrants.addUnique(h, what, obj);
- }
-
- /**
- * Unregister for notifications for subscription info
- * @param h Handler to be removed from the registrant list.
- */
- public void unregisterForSubscriptionInfoReady(Handler h){
- mSubscriptionInfoReadyRegistrants.remove(h);
- }
-
- /**
- * Sets an event to be fired when the telephony system processes
- * a post-dial character on an outgoing call.<p>
- *
- * Messages of type <code>what</code> will be sent to <code>h</code>.
- * The <code>obj</code> field of these Message's will be instances of
- * <code>AsyncResult</code>. <code>Message.obj.result</code> will be
- * a Connection object.<p>
- *
- * Message.arg1 will be the post dial character being processed,
- * or 0 ('\0') if end of string.<p>
- *
- * If Connection.getPostDialState() == WAIT,
- * the application must call
- * {@link com.android.internal.telephony.Connection#proceedAfterWaitChar()
- * Connection.proceedAfterWaitChar()} or
- * {@link com.android.internal.telephony.Connection#cancelPostDial()
- * Connection.cancelPostDial()}
- * for the telephony system to continue playing the post-dial
- * DTMF sequence.<p>
- *
- * If Connection.getPostDialState() == WILD,
- * the application must call
- * {@link com.android.internal.telephony.Connection#proceedAfterWildChar
- * Connection.proceedAfterWildChar()}
- * or
- * {@link com.android.internal.telephony.Connection#cancelPostDial()
- * Connection.cancelPostDial()}
- * for the telephony system to continue playing the
- * post-dial DTMF sequence.<p>
- *
- */
- public void registerForPostDialCharacter(Handler h, int what, Object obj){
- mPostDialCharacterRegistrants.addUnique(h, what, obj);
- }
-
- public void unregisterForPostDialCharacter(Handler h){
- mPostDialCharacterRegistrants.remove(h);
- }
-
- /* APIs to access foregroudCalls, backgroudCalls, and ringingCalls
- * 1. APIs to access list of calls
- * 2. APIs to check if any active call, which has connection other than
- * disconnected ones, pleaser refer to Call.isIdle()
- * 3. APIs to return first active call
- * 4. APIs to return the connections of first active call
- * 5. APIs to return other property of first active call
- */
-
- /**
- * @return list of all ringing calls
- */
- public List<Call> getRingingCalls() {
- return Collections.unmodifiableList(mRingingCalls);
- }
-
- /**
- * @return list of all foreground calls
- */
- public List<Call> getForegroundCalls() {
- return Collections.unmodifiableList(mForegroundCalls);
- }
-
- /**
- * @return list of all background calls
- */
- public List<Call> getBackgroundCalls() {
- return Collections.unmodifiableList(mBackgroundCalls);
- }
-
- /**
- * Return true if there is at least one active foreground call
- */
- public boolean hasActiveFgCall() {
- return (getFirstActiveCall(mForegroundCalls) != null);
- }
-
- /**
- * Return true if there is at least one active background call
- */
- public boolean hasActiveBgCall() {
- // TODO since hasActiveBgCall may get called often
- // better to cache it to improve performance
- return (getFirstActiveCall(mBackgroundCalls) != null);
- }
-
- /**
- * Return true if there is at least one active ringing call
- *
- */
- public boolean hasActiveRingingCall() {
- return (getFirstActiveCall(mRingingCalls) != null);
- }
-
- /**
- * return the active foreground call from foreground calls
- *
- * Active call means the call is NOT in Call.State.IDLE
- *
- * 1. If there is active foreground call, return it
- * 2. If there is no active foreground call, return the
- * foreground call associated with default phone, which state is IDLE.
- * 3. If there is no phone registered at all, return null.
- *
- */
- public Call getActiveFgCall() {
- Call call = getFirstNonIdleCall(mForegroundCalls);
- if (call == null) {
- call = (mDefaultPhone == null)
- ? null
- : mDefaultPhone.getForegroundCall();
- }
- return call;
- }
-
- // Returns the first call that is not in IDLE state. If both active calls
- // and disconnecting/disconnected calls exist, return the first active call.
- private Call getFirstNonIdleCall(List<Call> calls) {
- Call result = null;
- for (Call call : calls) {
- if (!call.isIdle()) {
- return call;
- } else if (call.getState() != Call.State.IDLE) {
- if (result == null) result = call;
- }
- }
- return result;
- }
-
- /**
- * return one active background call from background calls
- *
- * Active call means the call is NOT idle defined by Call.isIdle()
- *
- * 1. If there is only one active background call, return it
- * 2. If there is more than one active background call, return the first one
- * 3. If there is no active background call, return the background call
- * associated with default phone, which state is IDLE.
- * 4. If there is no background call at all, return null.
- *
- * Complete background calls list can be get by getBackgroundCalls()
- */
- public Call getFirstActiveBgCall() {
- Call call = getFirstNonIdleCall(mBackgroundCalls);
- if (call == null) {
- call = (mDefaultPhone == null)
- ? null
- : mDefaultPhone.getBackgroundCall();
- }
- return call;
- }
-
- /**
- * return one active ringing call from ringing calls
- *
- * Active call means the call is NOT idle defined by Call.isIdle()
- *
- * 1. If there is only one active ringing call, return it
- * 2. If there is more than one active ringing call, return the first one
- * 3. If there is no active ringing call, return the ringing call
- * associated with default phone, which state is IDLE.
- * 4. If there is no ringing call at all, return null.
- *
- * Complete ringing calls list can be get by getRingingCalls()
- */
- public Call getFirstActiveRingingCall() {
- Call call = getFirstNonIdleCall(mRingingCalls);
- if (call == null) {
- call = (mDefaultPhone == null)
- ? null
- : mDefaultPhone.getRingingCall();
- }
- return call;
- }
-
- /**
- * @return the state of active foreground call
- * return IDLE if there is no active foreground call
- */
- public Call.State getActiveFgCallState() {
- Call fgCall = getActiveFgCall();
-
- if (fgCall != null) {
- return fgCall.getState();
- }
-
- return Call.State.IDLE;
- }
-
- /**
- * @return the connections of active foreground call
- * return empty list if there is no active foreground call
- */
- public List<Connection> getFgCallConnections() {
- Call fgCall = getActiveFgCall();
- if ( fgCall != null) {
- return fgCall.getConnections();
- }
- return emptyConnections;
- }
-
- /**
- * @return the connections of active background call
- * return empty list if there is no active background call
- */
- public List<Connection> getBgCallConnections() {
- Call bgCall = getFirstActiveBgCall();
- if ( bgCall != null) {
- return bgCall.getConnections();
- }
- return emptyConnections;
- }
-
- /**
- * @return the latest connection of active foreground call
- * return null if there is no active foreground call
- */
- public Connection getFgCallLatestConnection() {
- Call fgCall = getActiveFgCall();
- if ( fgCall != null) {
- return fgCall.getLatestConnection();
- }
- return null;
- }
-
- /**
- * @return true if there is at least one Foreground call in disconnected state
- */
- public boolean hasDisconnectedFgCall() {
- return (getFirstCallOfState(mForegroundCalls, Call.State.DISCONNECTED) != null);
- }
-
- /**
- * @return true if there is at least one background call in disconnected state
- */
- public boolean hasDisconnectedBgCall() {
- return (getFirstCallOfState(mBackgroundCalls, Call.State.DISCONNECTED) != null);
- }
-
- /**
- * @return the first active call from a call list
- */
- private Call getFirstActiveCall(ArrayList<Call> calls) {
- for (Call call : calls) {
- if (!call.isIdle()) {
- return call;
- }
- }
- return null;
- }
-
- /**
- * @return the first call in a the Call.state from a call list
- */
- private Call getFirstCallOfState(ArrayList<Call> calls, Call.State state) {
- for (Call call : calls) {
- if (call.getState() == state) {
- return call;
- }
- }
- return null;
- }
-
-
- private boolean hasMoreThanOneRingingCall() {
- int count = 0;
- for (Call call : mRingingCalls) {
- if (call.getState().isRinging()) {
- if (++count > 1) return true;
- }
- }
- return false;
- }
-
- private Handler mHandler = new Handler() {
-
- @Override
- public void handleMessage(Message msg) {
-
- switch (msg.what) {
- case EVENT_DISCONNECT:
- if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_DISCONNECT)");
- mDisconnectRegistrants.notifyRegistrants((AsyncResult) msg.obj);
- break;
- case EVENT_PRECISE_CALL_STATE_CHANGED:
- if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_PRECISE_CALL_STATE_CHANGED)");
- mPreciseCallStateRegistrants.notifyRegistrants((AsyncResult) msg.obj);
- break;
- case EVENT_NEW_RINGING_CONNECTION:
- if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_NEW_RINGING_CONNECTION)");
- if (getActiveFgCallState().isDialing() || hasMoreThanOneRingingCall()) {
- Connection c = (Connection) ((AsyncResult) msg.obj).result;
- try {
- Log.d(LOG_TAG, "silently drop incoming call: " + c.getCall());
- c.getCall().hangup();
- } catch (CallStateException e) {
- Log.w(LOG_TAG, "new ringing connection", e);
- }
- } else {
- mNewRingingConnectionRegistrants.notifyRegistrants((AsyncResult) msg.obj);
- }
- break;
- case EVENT_UNKNOWN_CONNECTION:
- if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_UNKNOWN_CONNECTION)");
- mUnknownConnectionRegistrants.notifyRegistrants((AsyncResult) msg.obj);
- break;
- case EVENT_INCOMING_RING:
- if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_INCOMING_RING)");
- // The event may come from RIL who's not aware of an ongoing fg call
- if (!hasActiveFgCall()) {
- mIncomingRingRegistrants.notifyRegistrants((AsyncResult) msg.obj);
- }
- break;
- case EVENT_RINGBACK_TONE:
- if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_RINGBACK_TONE)");
- mRingbackToneRegistrants.notifyRegistrants((AsyncResult) msg.obj);
- break;
- case EVENT_IN_CALL_VOICE_PRIVACY_ON:
- if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_IN_CALL_VOICE_PRIVACY_ON)");
- mInCallVoicePrivacyOnRegistrants.notifyRegistrants((AsyncResult) msg.obj);
- break;
- case EVENT_IN_CALL_VOICE_PRIVACY_OFF:
- if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_IN_CALL_VOICE_PRIVACY_OFF)");
- mInCallVoicePrivacyOffRegistrants.notifyRegistrants((AsyncResult) msg.obj);
- break;
- case EVENT_CALL_WAITING:
- if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_CALL_WAITING)");
- mCallWaitingRegistrants.notifyRegistrants((AsyncResult) msg.obj);
- break;
- case EVENT_DISPLAY_INFO:
- if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_DISPLAY_INFO)");
- mDisplayInfoRegistrants.notifyRegistrants((AsyncResult) msg.obj);
- break;
- case EVENT_SIGNAL_INFO:
- if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_SIGNAL_INFO)");
- mSignalInfoRegistrants.notifyRegistrants((AsyncResult) msg.obj);
- break;
- case EVENT_CDMA_OTA_STATUS_CHANGE:
- if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_CDMA_OTA_STATUS_CHANGE)");
- mCdmaOtaStatusChangeRegistrants.notifyRegistrants((AsyncResult) msg.obj);
- break;
- case EVENT_RESEND_INCALL_MUTE:
- if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_RESEND_INCALL_MUTE)");
- mResendIncallMuteRegistrants.notifyRegistrants((AsyncResult) msg.obj);
- break;
- case EVENT_MMI_INITIATE:
- if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_MMI_INITIATE)");
- mMmiInitiateRegistrants.notifyRegistrants((AsyncResult) msg.obj);
- break;
- case EVENT_MMI_COMPLETE:
- if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_MMI_COMPLETE)");
- mMmiCompleteRegistrants.notifyRegistrants((AsyncResult) msg.obj);
- break;
- case EVENT_ECM_TIMER_RESET:
- if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_ECM_TIMER_RESET)");
- mEcmTimerResetRegistrants.notifyRegistrants((AsyncResult) msg.obj);
- break;
- case EVENT_SUBSCRIPTION_INFO_READY:
- if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_SUBSCRIPTION_INFO_READY)");
- mSubscriptionInfoReadyRegistrants.notifyRegistrants((AsyncResult) msg.obj);
- break;
- case EVENT_SUPP_SERVICE_FAILED:
- if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_SUPP_SERVICE_FAILED)");
- mSuppServiceFailedRegistrants.notifyRegistrants((AsyncResult) msg.obj);
- break;
- case EVENT_SERVICE_STATE_CHANGED:
- if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_SERVICE_STATE_CHANGED)");
- mServiceStateChangedRegistrants.notifyRegistrants((AsyncResult) msg.obj);
- break;
- case EVENT_POST_DIAL_CHARACTER:
- // we need send the character that is being processed in msg.arg1
- // so can't use notifyRegistrants()
- if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_POST_DIAL_CHARACTER)");
- for(int i=0; i < mPostDialCharacterRegistrants.size(); i++) {
- Message notifyMsg;
- notifyMsg = ((Registrant)mPostDialCharacterRegistrants.get(i)).messageForRegistrant();
- notifyMsg.obj = msg.obj;
- notifyMsg.arg1 = msg.arg1;
- notifyMsg.sendToTarget();
- }
- break;
- }
- }
- };
-
- @Override
- public String toString() {
- Call call;
- StringBuilder b = new StringBuilder();
-
- b.append("CallManager {");
- b.append("\nstate = " + getState());
- call = getActiveFgCall();
- b.append("\n- Foreground: " + getActiveFgCallState());
- b.append(" from " + call.getPhone());
- b.append("\n Conn: ").append(getFgCallConnections());
- call = getFirstActiveBgCall();
- b.append("\n- Background: " + call.getState());
- b.append(" from " + call.getPhone());
- b.append("\n Conn: ").append(getBgCallConnections());
- call = getFirstActiveRingingCall();
- b.append("\n- Ringing: " +call.getState());
- b.append(" from " + call.getPhone());
-
- for (Phone phone : getAllPhones()) {
- if (phone != null) {
- b.append("\nPhone: " + phone + ", name = " + phone.getPhoneName()
- + ", state = " + phone.getState());
- call = phone.getForegroundCall();
- b.append("\n- Foreground: ").append(call);
- call = phone.getBackgroundCall();
- b.append(" Background: ").append(call);
- call = phone.getRingingCall();
- b.append(" Ringing: ").append(call);
- }
- }
- b.append("\n}");
- return b.toString();
- }
-}