| /* |
| * Copyright (C) 2007 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.BroadcastReceiver; |
| import android.content.Context; |
| import android.content.Intent; |
| import android.content.IntentFilter; |
| import android.content.SharedPreferences; |
| import android.net.LinkProperties; |
| import android.net.NetworkCapabilities; |
| import android.net.wifi.WifiManager; |
| import android.os.AsyncResult; |
| import android.os.Build; |
| 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.Settings; |
| import android.telecom.VideoProfile; |
| import android.telephony.CellIdentityCdma; |
| import android.telephony.CellInfo; |
| import android.telephony.CellInfoCdma; |
| import android.telephony.DataConnectionRealTimeInfo; |
| import android.telephony.VoLteServiceState; |
| import android.telephony.Rlog; |
| import android.telephony.ServiceState; |
| import android.telephony.SignalStrength; |
| import android.telephony.SubscriptionManager; |
| import android.text.TextUtils; |
| |
| import com.android.ims.ImsManager; |
| import com.android.internal.R; |
| import com.android.internal.telephony.dataconnection.DcTrackerBase; |
| import com.android.internal.telephony.imsphone.ImsPhone; |
| import com.android.internal.telephony.test.SimulatedRadioControl; |
| import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppType; |
| import com.android.internal.telephony.uicc.IccFileHandler; |
| import com.android.internal.telephony.uicc.IccRecords; |
| import com.android.internal.telephony.uicc.IsimRecords; |
| import com.android.internal.telephony.uicc.UiccCard; |
| import com.android.internal.telephony.uicc.UiccCardApplication; |
| import com.android.internal.telephony.uicc.UiccController; |
| import com.android.internal.telephony.uicc.UsimServiceTable; |
| |
| import java.io.FileDescriptor; |
| import java.io.PrintWriter; |
| import java.util.ArrayList; |
| import java.util.List; |
| import java.util.Locale; |
| import java.util.concurrent.atomic.AtomicReference; |
| |
| /** |
| * (<em>Not for SDK use</em>) |
| * A base implementation for the com.android.internal.telephony.Phone interface. |
| * |
| * Note that implementations of Phone.java are expected to be used |
| * from a single application thread. This should be the same thread that |
| * originally called PhoneFactory to obtain the interface. |
| * |
| * {@hide} |
| * |
| */ |
| |
| public abstract class PhoneBase extends Handler implements Phone { |
| private static final String LOG_TAG = "PhoneBase"; |
| |
| private BroadcastReceiver mImsIntentReceiver = new BroadcastReceiver() { |
| @Override |
| public void onReceive(Context context, Intent intent) { |
| // TODO: MSIM potentially replace SUBID with information available to external |
| // service, e.g. slot ID |
| if (intent.hasExtra(ImsManager.EXTRA_SUBID)) { |
| if (intent.getLongExtra(ImsManager.EXTRA_SUBID, -1) != getSubId()) |
| return; |
| } |
| |
| if (intent.getAction().equals(ImsManager.ACTION_IMS_SERVICE_UP)) { |
| mImsServiceReady = true; |
| updateImsPhone(); |
| } else if (intent.getAction().equals(ImsManager.ACTION_IMS_SERVICE_DOWN)) { |
| mImsServiceReady = false; |
| updateImsPhone(); |
| } |
| } |
| }; |
| |
| // Key used to read and write the saved network selection numeric value |
| public static final String NETWORK_SELECTION_KEY = "network_selection_key"; |
| // Key used to read and write the saved network selection operator name |
| public static final String NETWORK_SELECTION_NAME_KEY = "network_selection_name_key"; |
| |
| |
| // Key used to read/write "disable data connection on boot" pref (used for testing) |
| public static final String DATA_DISABLED_ON_BOOT_KEY = "disabled_on_boot_key"; |
| |
| /* Event Constants */ |
| protected static final int EVENT_RADIO_AVAILABLE = 1; |
| /** Supplementary Service Notification received. */ |
| protected static final int EVENT_SSN = 2; |
| protected static final int EVENT_SIM_RECORDS_LOADED = 3; |
| protected static final int EVENT_MMI_DONE = 4; |
| protected static final int EVENT_RADIO_ON = 5; |
| protected static final int EVENT_GET_BASEBAND_VERSION_DONE = 6; |
| protected static final int EVENT_USSD = 7; |
| protected static final int EVENT_RADIO_OFF_OR_NOT_AVAILABLE = 8; |
| protected static final int EVENT_GET_IMEI_DONE = 9; |
| protected static final int EVENT_GET_IMEISV_DONE = 10; |
| protected static final int EVENT_GET_SIM_STATUS_DONE = 11; |
| protected static final int EVENT_SET_CALL_FORWARD_DONE = 12; |
| protected static final int EVENT_GET_CALL_FORWARD_DONE = 13; |
| protected static final int EVENT_CALL_RING = 14; |
| protected static final int EVENT_CALL_RING_CONTINUE = 15; |
| |
| // Used to intercept the carrier selection calls so that |
| // we can save the values. |
| protected static final int EVENT_SET_NETWORK_MANUAL_COMPLETE = 16; |
| protected static final int EVENT_SET_NETWORK_AUTOMATIC_COMPLETE = 17; |
| protected static final int EVENT_SET_CLIR_COMPLETE = 18; |
| protected static final int EVENT_REGISTERED_TO_NETWORK = 19; |
| protected static final int EVENT_SET_VM_NUMBER_DONE = 20; |
| // Events for CDMA support |
| protected static final int EVENT_GET_DEVICE_IDENTITY_DONE = 21; |
| protected static final int EVENT_RUIM_RECORDS_LOADED = 22; |
| protected static final int EVENT_NV_READY = 23; |
| protected static final int EVENT_SET_ENHANCED_VP = 24; |
| protected static final int EVENT_EMERGENCY_CALLBACK_MODE_ENTER = 25; |
| protected static final int EVENT_EXIT_EMERGENCY_CALLBACK_RESPONSE = 26; |
| protected static final int EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED = 27; |
| // other |
| protected static final int EVENT_SET_NETWORK_AUTOMATIC = 28; |
| protected static final int EVENT_ICC_RECORD_EVENTS = 29; |
| protected static final int EVENT_ICC_CHANGED = 30; |
| // Single Radio Voice Call Continuity |
| protected static final int EVENT_SRVCC_STATE_CHANGED = 31; |
| protected static final int EVENT_INITIATE_SILENT_REDIAL = 32; |
| protected static final int EVENT_UNSOL_OEM_HOOK_RAW = 33; |
| protected static final int EVENT_LAST = EVENT_UNSOL_OEM_HOOK_RAW; |
| |
| // Key used to read/write current CLIR setting |
| public static final String CLIR_KEY = "clir_key"; |
| |
| // Key used to read/write "disable DNS server check" pref (used for testing) |
| public static final String DNS_SERVER_CHECK_DISABLED_KEY = "dns_server_check_disabled_key"; |
| |
| /** |
| * Small container class used to hold information relevant to |
| * the carrier selection process. operatorNumeric can be "" |
| * if we are looking for automatic selection. operatorAlphaLong is the |
| * corresponding operator name. |
| */ |
| protected static class NetworkSelectMessage { |
| public Message message; |
| public String operatorNumeric; |
| public String operatorAlphaLong; |
| } |
| |
| /* Instance Variables */ |
| public CommandsInterface mCi; |
| boolean mDnsCheckDisabled; |
| public DcTrackerBase mDcTracker; |
| boolean mDoesRilSendMultipleCallRing; |
| int mCallRingContinueToken; |
| int mCallRingDelay; |
| public boolean mIsTheCurrentActivePhone = true; |
| boolean mIsVoiceCapable = true; |
| protected UiccController mUiccController = null; |
| public AtomicReference<IccRecords> mIccRecords = new AtomicReference<IccRecords>(); |
| public SmsStorageMonitor mSmsStorageMonitor; |
| public SmsUsageMonitor mSmsUsageMonitor; |
| protected AtomicReference<UiccCardApplication> mUiccApplication = |
| new AtomicReference<UiccCardApplication>(); |
| |
| private TelephonyTester mTelephonyTester; |
| private final String mName; |
| private final String mActionDetached; |
| private final String mActionAttached; |
| |
| // Holds the subscription information |
| protected Subscription mSubscriptionData = null; |
| protected int mPhoneId; |
| |
| private final Object mImsLock = new Object(); |
| private boolean mImsServiceReady = false; |
| protected ImsPhone mImsPhone = null; |
| |
| @Override |
| public String getPhoneName() { |
| return mName; |
| } |
| |
| /** |
| * Return the ActionDetached string. When this action is received by components |
| * they are to simulate detaching from the network. |
| * |
| * @return com.android.internal.telephony.{mName}.action_detached |
| * {mName} is GSM, CDMA ... |
| */ |
| public String getActionDetached() { |
| return mActionDetached; |
| } |
| |
| /** |
| * Return the ActionAttached string. When this action is received by components |
| * they are to simulate attaching to the network. |
| * |
| * @return com.android.internal.telephony.{mName}.action_detached |
| * {mName} is GSM, CDMA ... |
| */ |
| public String getActionAttached() { |
| return mActionAttached; |
| } |
| |
| /** |
| * Set a system property, unless we're in unit test mode |
| */ |
| // CAF_MSIM TODO this need to be replated with TelephonyManager API ? |
| public void setSystemProperty(String property, String value) { |
| if(getUnitTestMode()) { |
| return; |
| } |
| SystemProperties.set(property, value); |
| } |
| |
| /** |
| * Set a system property, unless we're in unit test mode |
| */ |
| // CAF_MSIM TODO this need to be replated with TelephonyManager API ? |
| public String getSystemProperty(String property, String defValue) { |
| if(getUnitTestMode()) { |
| return null; |
| } |
| return SystemProperties.get(property, defValue); |
| } |
| |
| |
| protected final RegistrantList mPreciseCallStateRegistrants |
| = new RegistrantList(); |
| |
| protected final RegistrantList mHandoverRegistrants |
| = new RegistrantList(); |
| |
| protected final RegistrantList mNewRingingConnectionRegistrants |
| = new RegistrantList(); |
| |
| protected final RegistrantList mIncomingRingRegistrants |
| = new RegistrantList(); |
| |
| protected final RegistrantList mDisconnectRegistrants |
| = new RegistrantList(); |
| |
| protected final RegistrantList mServiceStateRegistrants |
| = new RegistrantList(); |
| |
| protected final RegistrantList mMmiCompleteRegistrants |
| = new RegistrantList(); |
| |
| protected final RegistrantList mMmiRegistrants |
| = new RegistrantList(); |
| |
| protected final RegistrantList mUnknownConnectionRegistrants |
| = new RegistrantList(); |
| |
| protected final RegistrantList mSuppServiceFailedRegistrants |
| = new RegistrantList(); |
| |
| protected final RegistrantList mSimRecordsLoadedRegistrants |
| = new RegistrantList(); |
| |
| protected Looper mLooper; /* to insure registrants are in correct thread*/ |
| |
| protected final Context mContext; |
| |
| /** |
| * PhoneNotifier is an abstraction for all system-wide |
| * state change notification. DefaultPhoneNotifier is |
| * used here unless running we're inside a unit test. |
| */ |
| protected PhoneNotifier mNotifier; |
| |
| protected SimulatedRadioControl mSimulatedRadioControl; |
| |
| boolean mUnitTestMode; |
| |
| /** |
| * Constructs a PhoneBase in normal (non-unit test) mode. |
| * |
| * @param notifier An instance of DefaultPhoneNotifier, |
| * @param context Context object from hosting application |
| * unless unit testing. |
| * @param ci the CommandsInterface |
| */ |
| protected PhoneBase(String name, PhoneNotifier notifier, Context context, CommandsInterface ci) { |
| this(name, notifier, context, ci, false); |
| } |
| |
| /** |
| * Constructs a PhoneBase in normal (non-unit test) mode. |
| * |
| * @param notifier An instance of DefaultPhoneNotifier, |
| * @param context Context object from hosting application |
| * unless unit testing. |
| * @param ci is CommandsInterface |
| * @param unitTestMode when true, prevents notifications |
| * of state change events |
| */ |
| protected PhoneBase(String name, PhoneNotifier notifier, Context context, CommandsInterface ci, |
| boolean unitTestMode) { |
| this(name, notifier, context, ci, unitTestMode, SubscriptionManager.DEFAULT_PHONE_ID); |
| } |
| |
| /** |
| * Constructs a PhoneBase in normal (non-unit test) mode. |
| * |
| * @param notifier An instance of DefaultPhoneNotifier, |
| * @param context Context object from hosting application |
| * unless unit testing. |
| * @param ci is CommandsInterface |
| * @param unitTestMode when true, prevents notifications |
| * of state change events |
| * @param subscription is current phone subscription |
| */ |
| protected PhoneBase(String name, PhoneNotifier notifier, Context context, CommandsInterface ci, |
| boolean unitTestMode, int phoneId) { |
| mPhoneId = phoneId; |
| mName = name; |
| mNotifier = notifier; |
| mContext = context; |
| mLooper = Looper.myLooper(); |
| mCi = ci; |
| mActionDetached = this.getClass().getPackage().getName() + ".action_detached"; |
| mActionAttached = this.getClass().getPackage().getName() + ".action_attached"; |
| |
| if (Build.IS_DEBUGGABLE) { |
| mTelephonyTester = new TelephonyTester(this); |
| } |
| |
| setUnitTestMode(unitTestMode); |
| |
| SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context); |
| mDnsCheckDisabled = sp.getBoolean(DNS_SERVER_CHECK_DISABLED_KEY, false); |
| mCi.setOnCallRing(this, EVENT_CALL_RING, null); |
| |
| /* "Voice capable" means that this device supports circuit-switched |
| * (i.e. voice) phone calls over the telephony network, and is allowed |
| * to display the in-call UI while a cellular voice call is active. |
| * This will be false on "data only" devices which can't make voice |
| * calls and don't support any in-call UI. |
| */ |
| mIsVoiceCapable = mContext.getResources().getBoolean( |
| com.android.internal.R.bool.config_voice_capable); |
| |
| /** |
| * Some RIL's don't always send RIL_UNSOL_CALL_RING so it needs |
| * to be generated locally. Ideally all ring tones should be loops |
| * and this wouldn't be necessary. But to minimize changes to upper |
| * layers it is requested that it be generated by lower layers. |
| * |
| * By default old phones won't have the property set but do generate |
| * the RIL_UNSOL_CALL_RING so the default if there is no property is |
| * true. |
| */ |
| mDoesRilSendMultipleCallRing = SystemProperties.getBoolean( |
| TelephonyProperties.PROPERTY_RIL_SENDS_MULTIPLE_CALL_RING, true); |
| Rlog.d(LOG_TAG, "mDoesRilSendMultipleCallRing=" + mDoesRilSendMultipleCallRing); |
| |
| mCallRingDelay = SystemProperties.getInt( |
| TelephonyProperties.PROPERTY_CALL_RING_DELAY, 3000); |
| Rlog.d(LOG_TAG, "mCallRingDelay=" + mCallRingDelay); |
| |
| if (getPhoneType() == PhoneConstants.PHONE_TYPE_IMS) return; |
| |
| setPropertiesByCarrier(); |
| |
| // Initialize device storage and outgoing SMS usage monitors for SMSDispatchers. |
| mSmsStorageMonitor = new SmsStorageMonitor(this); |
| mSmsUsageMonitor = new SmsUsageMonitor(context); |
| mUiccController = UiccController.getInstance(); |
| mUiccController.registerForIccChanged(this, EVENT_ICC_CHANGED, null); |
| |
| // Monitor IMS service |
| IntentFilter filter = new IntentFilter(); |
| filter.addAction(ImsManager.ACTION_IMS_SERVICE_UP); |
| filter.addAction(ImsManager.ACTION_IMS_SERVICE_DOWN); |
| mContext.registerReceiver(mImsIntentReceiver, filter); |
| |
| mCi.registerForSrvccStateChanged(this, EVENT_SRVCC_STATE_CHANGED, null); |
| mCi.setOnUnsolOemHookRaw(this, EVENT_UNSOL_OEM_HOOK_RAW, null); |
| } |
| |
| @Override |
| public void dispose() { |
| synchronized(PhoneProxy.lockForRadioTechnologyChange) { |
| mContext.unregisterReceiver(mImsIntentReceiver); |
| mCi.unSetOnCallRing(this); |
| // Must cleanup all connectionS and needs to use sendMessage! |
| mDcTracker.cleanUpAllConnections(null); |
| mIsTheCurrentActivePhone = false; |
| // Dispose the SMS usage and storage monitors |
| mSmsStorageMonitor.dispose(); |
| mSmsUsageMonitor.dispose(); |
| mUiccController.unregisterForIccChanged(this); |
| mCi.unregisterForSrvccStateChanged(this); |
| mCi.unSetOnUnsolOemHookRaw(this); |
| |
| if (mTelephonyTester != null) { |
| mTelephonyTester.dispose(); |
| } |
| |
| ImsPhone imsPhone = mImsPhone; |
| if (imsPhone != null) { |
| imsPhone.unregisterForSilentRedial(this); |
| imsPhone.dispose(); |
| } |
| } |
| } |
| |
| @Override |
| public void removeReferences() { |
| mSmsStorageMonitor = null; |
| mSmsUsageMonitor = null; |
| mIccRecords.set(null); |
| mUiccApplication.set(null); |
| mDcTracker = null; |
| mUiccController = null; |
| |
| ImsPhone imsPhone = mImsPhone; |
| if (imsPhone != null) { |
| imsPhone.removeReferences(); |
| mImsPhone = null; |
| } |
| } |
| |
| /** |
| * When overridden the derived class needs to call |
| * super.handleMessage(msg) so this method has a |
| * a chance to process the message. |
| * |
| * @param msg |
| */ |
| @Override |
| public void handleMessage(Message msg) { |
| AsyncResult ar; |
| |
| if (!mIsTheCurrentActivePhone) { |
| Rlog.e(LOG_TAG, "Received message " + msg + |
| "[" + msg.what + "] while being destroyed. Ignoring."); |
| return; |
| } |
| switch(msg.what) { |
| case EVENT_CALL_RING: |
| Rlog.d(LOG_TAG, "Event EVENT_CALL_RING Received state=" + getState()); |
| ar = (AsyncResult)msg.obj; |
| if (ar.exception == null) { |
| PhoneConstants.State state = getState(); |
| if ((!mDoesRilSendMultipleCallRing) |
| && ((state == PhoneConstants.State.RINGING) || |
| (state == PhoneConstants.State.IDLE))) { |
| mCallRingContinueToken += 1; |
| sendIncomingCallRingNotification(mCallRingContinueToken); |
| } else { |
| notifyIncomingRing(); |
| } |
| } |
| break; |
| |
| case EVENT_CALL_RING_CONTINUE: |
| Rlog.d(LOG_TAG, "Event EVENT_CALL_RING_CONTINUE Received stat=" + getState()); |
| if (getState() == PhoneConstants.State.RINGING) { |
| sendIncomingCallRingNotification(msg.arg1); |
| } |
| break; |
| |
| case EVENT_ICC_CHANGED: |
| onUpdateIccAvailability(); |
| break; |
| |
| // handle the select network completion callbacks. |
| case EVENT_SET_NETWORK_MANUAL_COMPLETE: |
| case EVENT_SET_NETWORK_AUTOMATIC_COMPLETE: |
| handleSetSelectNetwork((AsyncResult) msg.obj); |
| break; |
| |
| case EVENT_INITIATE_SILENT_REDIAL: |
| Rlog.d(LOG_TAG, "Event EVENT_INITIATE_SILENT_REDIAL Received"); |
| ar = (AsyncResult) msg.obj; |
| if ((ar.exception == null) && (ar.result != null)) { |
| String dialString = (String) ar.result; |
| if (TextUtils.isEmpty(dialString)) return; |
| try { |
| dialInternal(dialString, null, VideoProfile.VideoState.AUDIO_ONLY); |
| } catch (CallStateException e) { |
| Rlog.e(LOG_TAG, "silent redial failed: " + e); |
| } |
| } |
| break; |
| |
| case EVENT_SRVCC_STATE_CHANGED: |
| ar = (AsyncResult)msg.obj; |
| if (ar.exception == null) { |
| handleSrvccStateChanged((int[]) ar.result); |
| } else { |
| Rlog.e(LOG_TAG, "Srvcc exception: " + ar.exception); |
| } |
| break; |
| |
| case EVENT_UNSOL_OEM_HOOK_RAW: |
| ar = (AsyncResult)msg.obj; |
| if (ar.exception == null) { |
| byte[] data = (byte[])ar.result; |
| Rlog.d(LOG_TAG, "EVENT_UNSOL_OEM_HOOK_RAW data=" |
| + IccUtils.bytesToHexString(data)); |
| mNotifier.notifyOemHookRawEventForSubscriber(getSubId(), data); |
| } else { |
| Rlog.e(LOG_TAG, "OEM hook raw exception: " + ar.exception); |
| } |
| break; |
| |
| default: |
| throw new RuntimeException("unexpected event not handled"); |
| } |
| } |
| |
| private void handleSrvccStateChanged(int[] ret) { |
| Rlog.d(LOG_TAG, "handleSrvccStateChanged"); |
| |
| Connection conn = null; |
| ImsPhone imsPhone = mImsPhone; |
| Call.SrvccState srvccState = Call.SrvccState.NONE; |
| if (ret != null && ret.length != 0) { |
| int state = ret[0]; |
| switch(state) { |
| case VoLteServiceState.HANDOVER_STARTED: |
| srvccState = Call.SrvccState.STARTED; |
| if (imsPhone != null) { |
| conn = imsPhone.getHandoverConnection(); |
| } else { |
| Rlog.d(LOG_TAG, "HANDOVER_STARTED: mImsPhone null"); |
| } |
| break; |
| case VoLteServiceState.HANDOVER_COMPLETED: |
| srvccState = Call.SrvccState.COMPLETED; |
| if (imsPhone != null) { |
| imsPhone.notifySrvccState(srvccState); |
| } else { |
| Rlog.d(LOG_TAG, "HANDOVER_COMPLETED: mImsPhone null"); |
| } |
| break; |
| case VoLteServiceState.HANDOVER_FAILED: |
| case VoLteServiceState.HANDOVER_CANCELED: |
| srvccState = Call.SrvccState.FAILED; |
| break; |
| |
| default: |
| //ignore invalid state |
| return; |
| } |
| |
| getCallTracker().notifySrvccState(srvccState, conn); |
| |
| VoLteServiceState lteState = new VoLteServiceState(state); |
| notifyVoLteServiceStateChanged(lteState); |
| } |
| } |
| |
| // Inherited documentation suffices. |
| @Override |
| public Context getContext() { |
| return mContext; |
| } |
| |
| // Will be called when icc changed |
| protected abstract void onUpdateIccAvailability(); |
| |
| /** |
| * Disables the DNS check (i.e., allows "0.0.0.0"). |
| * Useful for lab testing environment. |
| * @param b true disables the check, false enables. |
| */ |
| @Override |
| public void disableDnsCheck(boolean b) { |
| mDnsCheckDisabled = b; |
| SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext()); |
| SharedPreferences.Editor editor = sp.edit(); |
| editor.putBoolean(DNS_SERVER_CHECK_DISABLED_KEY, b); |
| editor.apply(); |
| } |
| |
| /** |
| * Returns true if the DNS check is currently disabled. |
| */ |
| @Override |
| public boolean isDnsCheckDisabled() { |
| return mDnsCheckDisabled; |
| } |
| |
| // Inherited documentation suffices. |
| @Override |
| public void registerForPreciseCallStateChanged(Handler h, int what, Object obj) { |
| checkCorrectThread(h); |
| |
| mPreciseCallStateRegistrants.addUnique(h, what, obj); |
| } |
| |
| // Inherited documentation suffices. |
| @Override |
| public void unregisterForPreciseCallStateChanged(Handler h) { |
| mPreciseCallStateRegistrants.remove(h); |
| } |
| |
| /** |
| * Subclasses of Phone probably want to replace this with a |
| * version scoped to their packages |
| */ |
| protected void notifyPreciseCallStateChangedP() { |
| AsyncResult ar = new AsyncResult(null, this, null); |
| mPreciseCallStateRegistrants.notifyRegistrants(ar); |
| |
| mNotifier.notifyPreciseCallState(this); |
| } |
| |
| @Override |
| public void registerForHandoverStateChanged(Handler h, int what, Object obj) { |
| checkCorrectThread(h); |
| mHandoverRegistrants.addUnique(h, what, obj); |
| } |
| |
| @Override |
| public void unregisterForHandoverStateChanged(Handler h) { |
| mHandoverRegistrants.remove(h); |
| } |
| |
| /** |
| * Subclasses of Phone probably want to replace this with a |
| * version scoped to their packages |
| */ |
| public void notifyHandoverStateChanged(Connection cn) { |
| AsyncResult ar = new AsyncResult(null, cn, null); |
| mHandoverRegistrants.notifyRegistrants(ar); |
| } |
| |
| public void migrateFrom(PhoneBase from) { |
| migrate(mHandoverRegistrants, from.mHandoverRegistrants); |
| migrate(mPreciseCallStateRegistrants, from.mPreciseCallStateRegistrants); |
| migrate(mNewRingingConnectionRegistrants, from.mNewRingingConnectionRegistrants); |
| migrate(mIncomingRingRegistrants, from.mIncomingRingRegistrants); |
| migrate(mDisconnectRegistrants, from.mDisconnectRegistrants); |
| migrate(mServiceStateRegistrants, from.mServiceStateRegistrants); |
| migrate(mMmiCompleteRegistrants, from.mMmiCompleteRegistrants); |
| migrate(mMmiRegistrants, from.mMmiRegistrants); |
| migrate(mUnknownConnectionRegistrants, from.mUnknownConnectionRegistrants); |
| migrate(mSuppServiceFailedRegistrants, from.mSuppServiceFailedRegistrants); |
| } |
| |
| public void migrate(RegistrantList to, RegistrantList from) { |
| from.removeCleared(); |
| for (int i = 0, n = from.size(); i < n; i++) { |
| to.add((Registrant) from.get(i)); |
| } |
| } |
| |
| // Inherited documentation suffices. |
| @Override |
| public void registerForUnknownConnection(Handler h, int what, Object obj) { |
| checkCorrectThread(h); |
| |
| mUnknownConnectionRegistrants.addUnique(h, what, obj); |
| } |
| |
| // Inherited documentation suffices. |
| @Override |
| public void unregisterForUnknownConnection(Handler h) { |
| mUnknownConnectionRegistrants.remove(h); |
| } |
| |
| // Inherited documentation suffices. |
| @Override |
| public void registerForNewRingingConnection( |
| Handler h, int what, Object obj) { |
| checkCorrectThread(h); |
| |
| mNewRingingConnectionRegistrants.addUnique(h, what, obj); |
| } |
| |
| // Inherited documentation suffices. |
| @Override |
| public void unregisterForNewRingingConnection(Handler h) { |
| mNewRingingConnectionRegistrants.remove(h); |
| } |
| |
| // Inherited documentation suffices. |
| @Override |
| public void registerForInCallVoicePrivacyOn(Handler h, int what, Object obj){ |
| mCi.registerForInCallVoicePrivacyOn(h, what, obj); |
| } |
| |
| // Inherited documentation suffices. |
| @Override |
| public void unregisterForInCallVoicePrivacyOn(Handler h){ |
| mCi.unregisterForInCallVoicePrivacyOn(h); |
| } |
| |
| // Inherited documentation suffices. |
| @Override |
| public void registerForInCallVoicePrivacyOff(Handler h, int what, Object obj){ |
| mCi.registerForInCallVoicePrivacyOff(h, what, obj); |
| } |
| |
| // Inherited documentation suffices. |
| @Override |
| public void unregisterForInCallVoicePrivacyOff(Handler h){ |
| mCi.unregisterForInCallVoicePrivacyOff(h); |
| } |
| |
| // Inherited documentation suffices. |
| @Override |
| public void registerForIncomingRing( |
| Handler h, int what, Object obj) { |
| checkCorrectThread(h); |
| |
| mIncomingRingRegistrants.addUnique(h, what, obj); |
| } |
| |
| // Inherited documentation suffices. |
| @Override |
| public void unregisterForIncomingRing(Handler h) { |
| mIncomingRingRegistrants.remove(h); |
| } |
| |
| // Inherited documentation suffices. |
| @Override |
| public void registerForDisconnect(Handler h, int what, Object obj) { |
| checkCorrectThread(h); |
| |
| mDisconnectRegistrants.addUnique(h, what, obj); |
| } |
| |
| // Inherited documentation suffices. |
| @Override |
| public void unregisterForDisconnect(Handler h) { |
| mDisconnectRegistrants.remove(h); |
| } |
| |
| // Inherited documentation suffices. |
| @Override |
| public void registerForSuppServiceFailed(Handler h, int what, Object obj) { |
| checkCorrectThread(h); |
| |
| mSuppServiceFailedRegistrants.addUnique(h, what, obj); |
| } |
| |
| // Inherited documentation suffices. |
| @Override |
| public void unregisterForSuppServiceFailed(Handler h) { |
| mSuppServiceFailedRegistrants.remove(h); |
| } |
| |
| // Inherited documentation suffices. |
| @Override |
| public void registerForMmiInitiate(Handler h, int what, Object obj) { |
| checkCorrectThread(h); |
| |
| mMmiRegistrants.addUnique(h, what, obj); |
| } |
| |
| // Inherited documentation suffices. |
| @Override |
| public void unregisterForMmiInitiate(Handler h) { |
| mMmiRegistrants.remove(h); |
| } |
| |
| // Inherited documentation suffices. |
| @Override |
| public void registerForMmiComplete(Handler h, int what, Object obj) { |
| checkCorrectThread(h); |
| |
| mMmiCompleteRegistrants.addUnique(h, what, obj); |
| } |
| |
| // Inherited documentation suffices. |
| @Override |
| public void unregisterForMmiComplete(Handler h) { |
| checkCorrectThread(h); |
| |
| mMmiCompleteRegistrants.remove(h); |
| } |
| |
| public void registerForSimRecordsLoaded(Handler h, int what, Object obj) { |
| logUnexpectedCdmaMethodCall("registerForSimRecordsLoaded"); |
| } |
| |
| public void unregisterForSimRecordsLoaded(Handler h) { |
| logUnexpectedCdmaMethodCall("unregisterForSimRecordsLoaded"); |
| } |
| |
| @Override |
| public void setNetworkSelectionModeAutomatic(Message response) { |
| // wrap the response message in our own message along with |
| // an empty string (to indicate automatic selection) for the |
| // operator's id. |
| NetworkSelectMessage nsm = new NetworkSelectMessage(); |
| nsm.message = response; |
| nsm.operatorNumeric = ""; |
| nsm.operatorAlphaLong = ""; |
| |
| Message msg = obtainMessage(EVENT_SET_NETWORK_AUTOMATIC_COMPLETE, nsm); |
| mCi.setNetworkSelectionModeAutomatic(msg); |
| } |
| |
| @Override |
| public void selectNetworkManually(OperatorInfo network, Message response) { |
| // wrap the response message in our own message along with |
| // the operator's id. |
| NetworkSelectMessage nsm = new NetworkSelectMessage(); |
| nsm.message = response; |
| nsm.operatorNumeric = network.getOperatorNumeric(); |
| nsm.operatorAlphaLong = network.getOperatorAlphaLong(); |
| |
| Message msg = obtainMessage(EVENT_SET_NETWORK_MANUAL_COMPLETE, nsm); |
| mCi.setNetworkSelectionModeManual(network.getOperatorNumeric(), msg); |
| } |
| |
| /** |
| * Used to track the settings upon completion of the network change. |
| */ |
| private void handleSetSelectNetwork(AsyncResult ar) { |
| // look for our wrapper within the asyncresult, skip the rest if it |
| // is null. |
| if (!(ar.userObj instanceof NetworkSelectMessage)) { |
| Rlog.e(LOG_TAG, "unexpected result from user object."); |
| return; |
| } |
| |
| NetworkSelectMessage nsm = (NetworkSelectMessage) ar.userObj; |
| |
| // found the object, now we send off the message we had originally |
| // attached to the request. |
| if (nsm.message != null) { |
| AsyncResult.forMessage(nsm.message, ar.result, ar.exception); |
| nsm.message.sendToTarget(); |
| } |
| |
| // open the shared preferences editor, and write the value. |
| // nsm.operatorNumeric is "" if we're in automatic.selection. |
| SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext()); |
| SharedPreferences.Editor editor = sp.edit(); |
| editor.putString(NETWORK_SELECTION_KEY, nsm.operatorNumeric); |
| editor.putString(NETWORK_SELECTION_NAME_KEY, nsm.operatorAlphaLong); |
| |
| // commit and log the result. |
| if (!editor.commit()) { |
| Rlog.e(LOG_TAG, "failed to commit network selection preference"); |
| } |
| } |
| |
| /** |
| * Method to retrieve the saved operator id from the Shared Preferences |
| */ |
| private String getSavedNetworkSelection() { |
| // open the shared preferences and search with our key. |
| SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext()); |
| return sp.getString(NETWORK_SELECTION_KEY, ""); |
| } |
| |
| /** |
| * Method to restore the previously saved operator id, or reset to |
| * automatic selection, all depending upon the value in the shared |
| * preferences. |
| */ |
| public void restoreSavedNetworkSelection(Message response) { |
| // retrieve the operator id |
| String networkSelection = getSavedNetworkSelection(); |
| |
| // set to auto if the id is empty, otherwise select the network. |
| if (TextUtils.isEmpty(networkSelection)) { |
| mCi.setNetworkSelectionModeAutomatic(response); |
| } else { |
| mCi.setNetworkSelectionModeManual(networkSelection, response); |
| } |
| } |
| |
| // Inherited documentation suffices. |
| @Override |
| public void setUnitTestMode(boolean f) { |
| mUnitTestMode = f; |
| } |
| |
| // Inherited documentation suffices. |
| @Override |
| public boolean getUnitTestMode() { |
| return mUnitTestMode; |
| } |
| |
| /** |
| * To be invoked when a voice call Connection disconnects. |
| * |
| * Subclasses of Phone probably want to replace this with a |
| * version scoped to their packages |
| */ |
| protected void notifyDisconnectP(Connection cn) { |
| AsyncResult ar = new AsyncResult(null, cn, null); |
| mDisconnectRegistrants.notifyRegistrants(ar); |
| } |
| |
| // Inherited documentation suffices. |
| @Override |
| public void registerForServiceStateChanged( |
| Handler h, int what, Object obj) { |
| checkCorrectThread(h); |
| |
| mServiceStateRegistrants.add(h, what, obj); |
| } |
| |
| // Inherited documentation suffices. |
| @Override |
| public void unregisterForServiceStateChanged(Handler h) { |
| mServiceStateRegistrants.remove(h); |
| } |
| |
| // Inherited documentation suffices. |
| @Override |
| public void registerForRingbackTone(Handler h, int what, Object obj) { |
| mCi.registerForRingbackTone(h, what, obj); |
| } |
| |
| // Inherited documentation suffices. |
| @Override |
| public void unregisterForRingbackTone(Handler h) { |
| mCi.unregisterForRingbackTone(h); |
| } |
| |
| // Inherited documentation suffices. |
| @Override |
| public void registerForOnHoldTone(Handler h, int what, Object obj) { |
| } |
| |
| // Inherited documentation suffices. |
| @Override |
| public void unregisterForOnHoldTone(Handler h) { |
| } |
| |
| // Inherited documentation suffices. |
| @Override |
| public void registerForResendIncallMute(Handler h, int what, Object obj) { |
| mCi.registerForResendIncallMute(h, what, obj); |
| } |
| |
| // Inherited documentation suffices. |
| @Override |
| public void unregisterForResendIncallMute(Handler h) { |
| mCi.unregisterForResendIncallMute(h); |
| } |
| |
| @Override |
| public void setEchoSuppressionEnabled() { |
| // no need for regular phone |
| } |
| |
| /** |
| * Subclasses of Phone probably want to replace this with a |
| * version scoped to their packages |
| */ |
| protected void notifyServiceStateChangedP(ServiceState ss) { |
| AsyncResult ar = new AsyncResult(null, ss, null); |
| mServiceStateRegistrants.notifyRegistrants(ar); |
| |
| mNotifier.notifyServiceState(this); |
| } |
| |
| // Inherited documentation suffices. |
| @Override |
| public SimulatedRadioControl getSimulatedRadioControl() { |
| return mSimulatedRadioControl; |
| } |
| |
| /** |
| * Verifies the current thread is the same as the thread originally |
| * used in the initialization of this instance. Throws RuntimeException |
| * if not. |
| * |
| * @exception RuntimeException if the current thread is not |
| * the thread that originally obtained this PhoneBase instance. |
| */ |
| private void checkCorrectThread(Handler h) { |
| if (h.getLooper() != mLooper) { |
| throw new RuntimeException( |
| "com.android.internal.telephony.Phone must be used from within one thread"); |
| } |
| } |
| |
| /** |
| * Set the properties by matching the carrier string in |
| * a string-array resource |
| */ |
| private void setPropertiesByCarrier() { |
| String carrier = SystemProperties.get("ro.carrier"); |
| |
| if (null == carrier || 0 == carrier.length() || "unknown".equals(carrier)) { |
| return; |
| } |
| |
| CharSequence[] carrierLocales = mContext. |
| getResources().getTextArray(R.array.carrier_properties); |
| |
| for (int i = 0; i < carrierLocales.length; i+=3) { |
| String c = carrierLocales[i].toString(); |
| if (carrier.equals(c)) { |
| final Locale l = Locale.forLanguageTag(carrierLocales[i + 1].toString().replace('_', '-')); |
| final String country = l.getCountry(); |
| MccTable.setSystemLocale(mContext, l.getLanguage(), country); |
| |
| if (!country.isEmpty()) { |
| try { |
| Settings.Global.getInt(mContext.getContentResolver(), |
| Settings.Global.WIFI_COUNTRY_CODE); |
| } catch (Settings.SettingNotFoundException e) { |
| // note this is not persisting |
| WifiManager wM = (WifiManager) |
| mContext.getSystemService(Context.WIFI_SERVICE); |
| wM.setCountryCode(country, false); |
| } |
| } |
| return; |
| } |
| } |
| } |
| |
| /** |
| * Get state |
| */ |
| @Override |
| public abstract PhoneConstants.State getState(); |
| |
| /** |
| * Retrieves the IccFileHandler of the Phone instance |
| */ |
| public IccFileHandler getIccFileHandler(){ |
| UiccCardApplication uiccApplication = mUiccApplication.get(); |
| IccFileHandler fh; |
| |
| if (uiccApplication == null) { |
| Rlog.d(LOG_TAG, "getIccFileHandler: uiccApplication == null, return null"); |
| fh = null; |
| } else { |
| fh = uiccApplication.getIccFileHandler(); |
| } |
| |
| Rlog.d(LOG_TAG, "getIccFileHandler: fh=" + fh); |
| return fh; |
| } |
| |
| /* |
| * Retrieves the Handler of the Phone instance |
| */ |
| public Handler getHandler() { |
| return this; |
| } |
| |
| @Override |
| public void updatePhoneObject(int voiceRadioTech) { |
| // Only the PhoneProxy can update the phone object. |
| PhoneFactory.getDefaultPhone().updatePhoneObject(voiceRadioTech); |
| } |
| |
| /** |
| * Retrieves the ServiceStateTracker of the phone instance. |
| */ |
| public ServiceStateTracker getServiceStateTracker() { |
| return null; |
| } |
| |
| /** |
| * Get call tracker |
| */ |
| public CallTracker getCallTracker() { |
| return null; |
| } |
| |
| public AppType getCurrentUiccAppType() { |
| UiccCardApplication currentApp = mUiccApplication.get(); |
| if (currentApp != null) { |
| return currentApp.getType(); |
| } |
| return AppType.APPTYPE_UNKNOWN; |
| } |
| |
| @Override |
| public IccCard getIccCard() { |
| return null; |
| //throw new Exception("getIccCard Shouldn't be called from PhoneBase"); |
| } |
| |
| @Override |
| public String getIccSerialNumber() { |
| IccRecords r = mIccRecords.get(); |
| return (r != null) ? r.getIccId() : null; |
| } |
| |
| @Override |
| public boolean getIccRecordsLoaded() { |
| IccRecords r = mIccRecords.get(); |
| return (r != null) ? r.getRecordsLoaded() : false; |
| } |
| |
| /** |
| * @return all available cell information or null if none. |
| */ |
| @Override |
| public List<CellInfo> getAllCellInfo() { |
| List<CellInfo> cellInfoList = getServiceStateTracker().getAllCellInfo(); |
| return privatizeCellInfoList(cellInfoList); |
| } |
| |
| /** |
| * Clear CDMA base station lat/long values if location setting is disabled. |
| * @param cellInfoList the original cell info list from the RIL |
| * @return the original list with CDMA lat/long cleared if necessary |
| */ |
| private List<CellInfo> privatizeCellInfoList(List<CellInfo> cellInfoList) { |
| int mode = Settings.Secure.getInt(getContext().getContentResolver(), |
| Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF); |
| if (mode == Settings.Secure.LOCATION_MODE_OFF) { |
| ArrayList<CellInfo> privateCellInfoList = new ArrayList<CellInfo>(cellInfoList.size()); |
| // clear lat/lon values for location privacy |
| for (CellInfo c : cellInfoList) { |
| if (c instanceof CellInfoCdma) { |
| CellInfoCdma cellInfoCdma = (CellInfoCdma) c; |
| CellIdentityCdma cellIdentity = cellInfoCdma.getCellIdentity(); |
| CellIdentityCdma maskedCellIdentity = new CellIdentityCdma( |
| cellIdentity.getNetworkId(), |
| cellIdentity.getSystemId(), |
| cellIdentity.getBasestationId(), |
| Integer.MAX_VALUE, Integer.MAX_VALUE); |
| CellInfoCdma privateCellInfoCdma = new CellInfoCdma(cellInfoCdma); |
| privateCellInfoCdma.setCellIdentity(maskedCellIdentity); |
| privateCellInfoList.add(privateCellInfoCdma); |
| } else { |
| privateCellInfoList.add(c); |
| } |
| } |
| cellInfoList = privateCellInfoList; |
| } |
| return cellInfoList; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public void setCellInfoListRate(int rateInMillis) { |
| mCi.setCellInfoListRate(rateInMillis, null); |
| } |
| |
| @Override |
| public boolean getMessageWaitingIndicator() { |
| IccRecords r = mIccRecords.get(); |
| return (r != null) ? r.getVoiceMessageWaiting() : false; |
| } |
| |
| @Override |
| public boolean getCallForwardingIndicator() { |
| IccRecords r = mIccRecords.get(); |
| return (r != null) ? r.getVoiceCallForwardingFlag() : false; |
| } |
| |
| /** |
| * Query the status of the CDMA roaming preference |
| */ |
| @Override |
| public void queryCdmaRoamingPreference(Message response) { |
| mCi.queryCdmaRoamingPreference(response); |
| } |
| |
| /** |
| * Get the signal strength |
| */ |
| @Override |
| public SignalStrength getSignalStrength() { |
| ServiceStateTracker sst = getServiceStateTracker(); |
| if (sst == null) { |
| return new SignalStrength(); |
| } else { |
| return sst.getSignalStrength(); |
| } |
| } |
| |
| /** |
| * Set the status of the CDMA roaming preference |
| */ |
| @Override |
| public void setCdmaRoamingPreference(int cdmaRoamingType, Message response) { |
| mCi.setCdmaRoamingPreference(cdmaRoamingType, response); |
| } |
| |
| /** |
| * Set the status of the CDMA subscription mode |
| */ |
| @Override |
| public void setCdmaSubscription(int cdmaSubscriptionType, Message response) { |
| mCi.setCdmaSubscriptionSource(cdmaSubscriptionType, response); |
| } |
| |
| /** |
| * Set the preferred Network Type: Global, CDMA only or GSM/UMTS only |
| */ |
| @Override |
| public void setPreferredNetworkType(int networkType, Message response) { |
| mCi.setPreferredNetworkType(networkType, response); |
| } |
| |
| @Override |
| public void getPreferredNetworkType(Message response) { |
| mCi.getPreferredNetworkType(response); |
| } |
| |
| @Override |
| public void getSmscAddress(Message result) { |
| mCi.getSmscAddress(result); |
| } |
| |
| @Override |
| public void setSmscAddress(String address, Message result) { |
| mCi.setSmscAddress(address, result); |
| } |
| |
| @Override |
| public void setTTYMode(int ttyMode, Message onComplete) { |
| mCi.setTTYMode(ttyMode, onComplete); |
| } |
| |
| @Override |
| public void queryTTYMode(Message onComplete) { |
| mCi.queryTTYMode(onComplete); |
| } |
| |
| @Override |
| public void enableEnhancedVoicePrivacy(boolean enable, Message onComplete) { |
| // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone. |
| logUnexpectedCdmaMethodCall("enableEnhancedVoicePrivacy"); |
| } |
| |
| @Override |
| public void getEnhancedVoicePrivacy(Message onComplete) { |
| // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone. |
| logUnexpectedCdmaMethodCall("getEnhancedVoicePrivacy"); |
| } |
| |
| @Override |
| public void setBandMode(int bandMode, Message response) { |
| mCi.setBandMode(bandMode, response); |
| } |
| |
| @Override |
| public void queryAvailableBandMode(Message response) { |
| mCi.queryAvailableBandMode(response); |
| } |
| |
| @Override |
| public void invokeOemRilRequestRaw(byte[] data, Message response) { |
| mCi.invokeOemRilRequestRaw(data, response); |
| } |
| |
| @Override |
| public void invokeOemRilRequestStrings(String[] strings, Message response) { |
| mCi.invokeOemRilRequestStrings(strings, response); |
| } |
| |
| @Override |
| public void nvReadItem(int itemID, Message response) { |
| mCi.nvReadItem(itemID, response); |
| } |
| |
| @Override |
| public void nvWriteItem(int itemID, String itemValue, Message response) { |
| mCi.nvWriteItem(itemID, itemValue, response); |
| } |
| |
| @Override |
| public void nvWriteCdmaPrl(byte[] preferredRoamingList, Message response) { |
| mCi.nvWriteCdmaPrl(preferredRoamingList, response); |
| } |
| |
| @Override |
| public void nvResetConfig(int resetType, Message response) { |
| mCi.nvResetConfig(resetType, response); |
| } |
| |
| @Override |
| public void notifyDataActivity() { |
| mNotifier.notifyDataActivity(this); |
| } |
| |
| public void notifyMessageWaitingIndicator() { |
| // Do not notify voice mail waiting if device doesn't support voice |
| if (!mIsVoiceCapable) |
| return; |
| |
| // This function is added to send the notification to DefaultPhoneNotifier. |
| mNotifier.notifyMessageWaitingChanged(this); |
| } |
| |
| public void notifyDataConnection(String reason, String apnType, |
| PhoneConstants.DataState state) { |
| mNotifier.notifyDataConnection(this, reason, apnType, state); |
| } |
| |
| public void notifyDataConnection(String reason, String apnType) { |
| mNotifier.notifyDataConnection(this, reason, apnType, getDataConnectionState(apnType)); |
| } |
| |
| public void notifyDataConnection(String reason) { |
| String types[] = getActiveApnTypes(); |
| for (String apnType : types) { |
| mNotifier.notifyDataConnection(this, reason, apnType, getDataConnectionState(apnType)); |
| } |
| } |
| |
| public void notifyOtaspChanged(int otaspMode) { |
| mNotifier.notifyOtaspChanged(this, otaspMode); |
| } |
| |
| public void notifySignalStrength() { |
| mNotifier.notifySignalStrength(this); |
| } |
| |
| public void notifyCellInfo(List<CellInfo> cellInfo) { |
| mNotifier.notifyCellInfo(this, privatizeCellInfoList(cellInfo)); |
| } |
| |
| public void notifyDataConnectionRealTimeInfo(DataConnectionRealTimeInfo dcRtInfo) { |
| mNotifier.notifyDataConnectionRealTimeInfo(this, dcRtInfo); |
| } |
| |
| public void notifyVoLteServiceStateChanged(VoLteServiceState lteState) { |
| mNotifier.notifyVoLteServiceStateChanged(this, lteState); |
| } |
| |
| /** |
| * @return true if a mobile originating emergency call is active |
| */ |
| public boolean isInEmergencyCall() { |
| return false; |
| } |
| |
| /** |
| * @return true if we are in the emergency call back mode. This is a period where |
| * the phone should be using as little power as possible and be ready to receive an |
| * incoming call from the emergency operator. |
| */ |
| public boolean isInEcm() { |
| return false; |
| } |
| |
| @Override |
| public abstract int getPhoneType(); |
| |
| /** @hide */ |
| @Override |
| public int getVoiceMessageCount(){ |
| return 0; |
| } |
| |
| /** |
| * Returns the CDMA ERI icon index to display |
| */ |
| @Override |
| public int getCdmaEriIconIndex() { |
| logUnexpectedCdmaMethodCall("getCdmaEriIconIndex"); |
| return -1; |
| } |
| |
| /** |
| * Returns the CDMA ERI icon mode, |
| * 0 - ON |
| * 1 - FLASHING |
| */ |
| @Override |
| public int getCdmaEriIconMode() { |
| logUnexpectedCdmaMethodCall("getCdmaEriIconMode"); |
| return -1; |
| } |
| |
| /** |
| * Returns the CDMA ERI text, |
| */ |
| @Override |
| public String getCdmaEriText() { |
| logUnexpectedCdmaMethodCall("getCdmaEriText"); |
| return "GSM nw, no ERI"; |
| } |
| |
| @Override |
| public String getCdmaMin() { |
| // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone. |
| logUnexpectedCdmaMethodCall("getCdmaMin"); |
| return null; |
| } |
| |
| @Override |
| public boolean isMinInfoReady() { |
| // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone. |
| logUnexpectedCdmaMethodCall("isMinInfoReady"); |
| return false; |
| } |
| |
| @Override |
| public String getCdmaPrlVersion(){ |
| // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone. |
| logUnexpectedCdmaMethodCall("getCdmaPrlVersion"); |
| return null; |
| } |
| |
| @Override |
| public void sendBurstDtmf(String dtmfString, int on, int off, Message onComplete) { |
| // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone. |
| logUnexpectedCdmaMethodCall("sendBurstDtmf"); |
| } |
| |
| @Override |
| public void exitEmergencyCallbackMode() { |
| // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone. |
| logUnexpectedCdmaMethodCall("exitEmergencyCallbackMode"); |
| } |
| |
| @Override |
| public void registerForCdmaOtaStatusChange(Handler h, int what, Object obj) { |
| // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone. |
| logUnexpectedCdmaMethodCall("registerForCdmaOtaStatusChange"); |
| } |
| |
| @Override |
| public void unregisterForCdmaOtaStatusChange(Handler h) { |
| // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone. |
| logUnexpectedCdmaMethodCall("unregisterForCdmaOtaStatusChange"); |
| } |
| |
| @Override |
| public void registerForSubscriptionInfoReady(Handler h, int what, Object obj) { |
| // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone. |
| logUnexpectedCdmaMethodCall("registerForSubscriptionInfoReady"); |
| } |
| |
| @Override |
| public void unregisterForSubscriptionInfoReady(Handler h) { |
| // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone. |
| logUnexpectedCdmaMethodCall("unregisterForSubscriptionInfoReady"); |
| } |
| |
| /** |
| * Returns true if OTA Service Provisioning needs to be performed. |
| * If not overridden return false. |
| */ |
| @Override |
| public boolean needsOtaServiceProvisioning() { |
| return false; |
| } |
| |
| /** |
| * Return true if number is an OTASP number. |
| * If not overridden return false. |
| */ |
| @Override |
| public boolean isOtaSpNumber(String dialStr) { |
| return false; |
| } |
| |
| @Override |
| public void registerForCallWaiting(Handler h, int what, Object obj){ |
| // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone. |
| logUnexpectedCdmaMethodCall("registerForCallWaiting"); |
| } |
| |
| @Override |
| public void unregisterForCallWaiting(Handler h){ |
| // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone. |
| logUnexpectedCdmaMethodCall("unregisterForCallWaiting"); |
| } |
| |
| @Override |
| public void registerForEcmTimerReset(Handler h, int what, Object obj) { |
| // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone. |
| logUnexpectedCdmaMethodCall("registerForEcmTimerReset"); |
| } |
| |
| @Override |
| public void unregisterForEcmTimerReset(Handler h) { |
| // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone. |
| logUnexpectedCdmaMethodCall("unregisterForEcmTimerReset"); |
| } |
| |
| @Override |
| public void registerForSignalInfo(Handler h, int what, Object obj) { |
| mCi.registerForSignalInfo(h, what, obj); |
| } |
| |
| @Override |
| public void unregisterForSignalInfo(Handler h) { |
| mCi.unregisterForSignalInfo(h); |
| } |
| |
| @Override |
| public void registerForDisplayInfo(Handler h, int what, Object obj) { |
| mCi.registerForDisplayInfo(h, what, obj); |
| } |
| |
| @Override |
| public void unregisterForDisplayInfo(Handler h) { |
| mCi.unregisterForDisplayInfo(h); |
| } |
| |
| @Override |
| public void registerForNumberInfo(Handler h, int what, Object obj) { |
| mCi.registerForNumberInfo(h, what, obj); |
| } |
| |
| @Override |
| public void unregisterForNumberInfo(Handler h) { |
| mCi.unregisterForNumberInfo(h); |
| } |
| |
| @Override |
| public void registerForRedirectedNumberInfo(Handler h, int what, Object obj) { |
| mCi.registerForRedirectedNumberInfo(h, what, obj); |
| } |
| |
| @Override |
| public void unregisterForRedirectedNumberInfo(Handler h) { |
| mCi.unregisterForRedirectedNumberInfo(h); |
| } |
| |
| @Override |
| public void registerForLineControlInfo(Handler h, int what, Object obj) { |
| mCi.registerForLineControlInfo( h, what, obj); |
| } |
| |
| @Override |
| public void unregisterForLineControlInfo(Handler h) { |
| mCi.unregisterForLineControlInfo(h); |
| } |
| |
| @Override |
| public void registerFoT53ClirlInfo(Handler h, int what, Object obj) { |
| mCi.registerFoT53ClirlInfo(h, what, obj); |
| } |
| |
| @Override |
| public void unregisterForT53ClirInfo(Handler h) { |
| mCi.unregisterForT53ClirInfo(h); |
| } |
| |
| @Override |
| public void registerForT53AudioControlInfo(Handler h, int what, Object obj) { |
| mCi.registerForT53AudioControlInfo( h, what, obj); |
| } |
| |
| @Override |
| public void unregisterForT53AudioControlInfo(Handler h) { |
| mCi.unregisterForT53AudioControlInfo(h); |
| } |
| |
| @Override |
| public void setOnEcbModeExitResponse(Handler h, int what, Object obj){ |
| // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone. |
| logUnexpectedCdmaMethodCall("setOnEcbModeExitResponse"); |
| } |
| |
| @Override |
| public void unsetOnEcbModeExitResponse(Handler h){ |
| // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone. |
| logUnexpectedCdmaMethodCall("unsetOnEcbModeExitResponse"); |
| } |
| |
| @Override |
| public String[] getActiveApnTypes() { |
| return mDcTracker.getActiveApnTypes(); |
| } |
| |
| @Override |
| public String getActiveApnHost(String apnType) { |
| return mDcTracker.getActiveApnString(apnType); |
| } |
| |
| @Override |
| public LinkProperties getLinkProperties(String apnType) { |
| return mDcTracker.getLinkProperties(apnType); |
| } |
| |
| @Override |
| public NetworkCapabilities getNetworkCapabilities(String apnType) { |
| return mDcTracker.getNetworkCapabilities(apnType); |
| } |
| |
| @Override |
| public boolean isDataConnectivityPossible() { |
| return isDataConnectivityPossible(PhoneConstants.APN_TYPE_DEFAULT); |
| } |
| |
| @Override |
| public boolean isDataConnectivityPossible(String apnType) { |
| return ((mDcTracker != null) && |
| (mDcTracker.isDataPossible(apnType))); |
| } |
| |
| /** |
| * Notify registrants of a new ringing Connection. |
| * Subclasses of Phone probably want to replace this with a |
| * version scoped to their packages |
| */ |
| public void notifyNewRingingConnectionP(Connection cn) { |
| if (!mIsVoiceCapable) |
| return; |
| AsyncResult ar = new AsyncResult(null, cn, null); |
| mNewRingingConnectionRegistrants.notifyRegistrants(ar); |
| } |
| |
| /** |
| * Notify registrants of a RING event. |
| */ |
| private void notifyIncomingRing() { |
| if (!mIsVoiceCapable) |
| return; |
| AsyncResult ar = new AsyncResult(null, this, null); |
| mIncomingRingRegistrants.notifyRegistrants(ar); |
| } |
| |
| /** |
| * Send the incoming call Ring notification if conditions are right. |
| */ |
| private void sendIncomingCallRingNotification(int token) { |
| if (mIsVoiceCapable && !mDoesRilSendMultipleCallRing && |
| (token == mCallRingContinueToken)) { |
| Rlog.d(LOG_TAG, "Sending notifyIncomingRing"); |
| notifyIncomingRing(); |
| sendMessageDelayed( |
| obtainMessage(EVENT_CALL_RING_CONTINUE, token, 0), mCallRingDelay); |
| } else { |
| Rlog.d(LOG_TAG, "Ignoring ring notification request," |
| + " mDoesRilSendMultipleCallRing=" + mDoesRilSendMultipleCallRing |
| + " token=" + token |
| + " mCallRingContinueToken=" + mCallRingContinueToken |
| + " mIsVoiceCapable=" + mIsVoiceCapable); |
| } |
| } |
| |
| @Override |
| public boolean isCspPlmnEnabled() { |
| // This function should be overridden by the class GSMPhone. |
| // Not implemented in CDMAPhone. |
| logUnexpectedGsmMethodCall("isCspPlmnEnabled"); |
| return false; |
| } |
| |
| @Override |
| public IsimRecords getIsimRecords() { |
| Rlog.e(LOG_TAG, "getIsimRecords() is only supported on LTE devices"); |
| return null; |
| } |
| |
| @Override |
| public String getMsisdn() { |
| logUnexpectedGsmMethodCall("getMsisdn"); |
| return null; |
| } |
| |
| /** |
| * Common error logger method for unexpected calls to CDMA-only methods. |
| */ |
| private static void logUnexpectedCdmaMethodCall(String name) |
| { |
| Rlog.e(LOG_TAG, "Error! " + name + "() in PhoneBase should not be " + |
| "called, CDMAPhone inactive."); |
| } |
| |
| @Override |
| public PhoneConstants.DataState getDataConnectionState() { |
| return getDataConnectionState(PhoneConstants.APN_TYPE_DEFAULT); |
| } |
| |
| /** |
| * Common error logger method for unexpected calls to GSM/WCDMA-only methods. |
| */ |
| private static void logUnexpectedGsmMethodCall(String name) { |
| Rlog.e(LOG_TAG, "Error! " + name + "() in PhoneBase should not be " + |
| "called, GSMPhone inactive."); |
| } |
| |
| // Called by SimRecords which is constructed with a PhoneBase instead of a GSMPhone. |
| public void notifyCallForwardingIndicator() { |
| // This function should be overridden by the class GSMPhone. Not implemented in CDMAPhone. |
| Rlog.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone."); |
| } |
| |
| public void notifyDataConnectionFailed(String reason, String apnType) { |
| mNotifier.notifyDataConnectionFailed(this, reason, apnType); |
| } |
| |
| public void notifyPreciseDataConnectionFailed(String reason, String apnType, String apn, |
| String failCause) { |
| mNotifier.notifyPreciseDataConnectionFailed(this, reason, apnType, apn, failCause); |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public int getLteOnCdmaMode() { |
| return mCi.getLteOnCdmaMode(); |
| } |
| |
| /** |
| * Sets the SIM voice message waiting indicator records. |
| * @param line GSM Subscriber Profile Number, one-based. Only '1' is supported |
| * @param countWaiting The number of messages waiting, if known. Use |
| * -1 to indicate that an unknown number of |
| * messages are waiting |
| */ |
| @Override |
| public void setVoiceMessageWaiting(int line, int countWaiting) { |
| IccRecords r = mIccRecords.get(); |
| if (r != null) { |
| r.setVoiceMessageWaiting(line, countWaiting); |
| } |
| } |
| |
| /** |
| * Gets the USIM service table from the UICC, if present and available. |
| * @return an interface to the UsimServiceTable record, or null if not available |
| */ |
| @Override |
| public UsimServiceTable getUsimServiceTable() { |
| IccRecords r = mIccRecords.get(); |
| return (r != null) ? r.getUsimServiceTable() : null; |
| } |
| |
| /** |
| * Gets the Uicc card corresponding to this phone. |
| * @return the UiccCard object corresponding to the phone ID. |
| */ |
| @Override |
| public UiccCard getUiccCard() { |
| return mUiccController.getUiccCard(mPhoneId); |
| } |
| |
| /** |
| * Get P-CSCF address from PCO after data connection is established or modified. |
| * @param apnType the apnType, "ims" for IMS APN, "emergency" for EMERGENCY APN |
| */ |
| @Override |
| public String[] getPcscfAddress(String apnType) { |
| return mDcTracker.getPcscfAddress(apnType); |
| } |
| |
| /** |
| * Set IMS registration state |
| */ |
| @Override |
| public void setImsRegistrationState(boolean registered) { |
| mDcTracker.setImsRegistrationState(registered); |
| } |
| |
| /** |
| * Return an instance of a IMS phone |
| */ |
| @Override |
| public Phone getImsPhone() { |
| return mImsPhone; |
| } |
| |
| @Override |
| public ImsPhone relinquishOwnershipOfImsPhone() { |
| synchronized (mImsLock) { |
| if (mImsPhone == null) |
| return null; |
| |
| ImsPhone imsPhone = mImsPhone; |
| mImsPhone = null; |
| |
| CallManager.getInstance().unregisterPhone(imsPhone); |
| imsPhone.unregisterForSilentRedial(this); |
| |
| return imsPhone; |
| } |
| } |
| |
| @Override |
| public void acquireOwnershipOfImsPhone(ImsPhone imsPhone) { |
| synchronized (mImsLock) { |
| if (imsPhone == null) |
| return; |
| |
| if (mImsPhone != null) { |
| Rlog.e(LOG_TAG, "acquireOwnershipOfImsPhone: non-null mImsPhone." + |
| " Shouldn't happen - but disposing"); |
| mImsPhone.dispose(); |
| // Potential GC issue if someone keeps a reference to ImsPhone. |
| // However: this change will make sure that such a reference does |
| // not access functions through NULL pointer. |
| //mImsPhone.removeReferences(); |
| } |
| |
| mImsPhone = imsPhone; |
| |
| mImsServiceReady = true; |
| mImsPhone.updateParentPhone(this); |
| CallManager.getInstance().registerPhone(mImsPhone); |
| mImsPhone.registerForSilentRedial( |
| this, EVENT_INITIATE_SILENT_REDIAL, null); |
| } |
| } |
| |
| protected void updateImsPhone() { |
| synchronized (mImsLock) { |
| Rlog.d(LOG_TAG, "updateImsPhone" |
| + " mImsServiceReady=" + mImsServiceReady); |
| |
| if (mImsServiceReady && (mImsPhone == null)) { |
| mImsPhone = PhoneFactory.makeImsPhone(mNotifier, this); |
| CallManager.getInstance().registerPhone(mImsPhone); |
| mImsPhone.registerForSilentRedial( |
| this, EVENT_INITIATE_SILENT_REDIAL, null); |
| } else if (!mImsServiceReady && (mImsPhone != null)) { |
| CallManager.getInstance().unregisterPhone(mImsPhone); |
| mImsPhone.unregisterForSilentRedial(this); |
| |
| mImsPhone.dispose(); |
| // Potential GC issue if someone keeps a reference to ImsPhone. |
| // However: this change will make sure that such a reference does |
| // not access functions through NULL pointer. |
| //mImsPhone.removeReferences(); |
| mImsPhone = null; |
| } |
| } |
| } |
| |
| /** |
| * Dials a number. |
| * |
| * @param dialString The number to dial. |
| * @param uusInfo The UUSInfo. |
| * @param videoState The video state for the call. |
| * @return The Connection. |
| * @throws CallStateException |
| */ |
| protected Connection dialInternal(String dialString, UUSInfo uusInfo, int videoState) |
| throws CallStateException { |
| // dialInternal shall be overriden by GSMPhone and CDMAPhone |
| return null; |
| } |
| |
| public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { |
| pw.println("PhoneBase:"); |
| pw.println(" mCi=" + mCi); |
| pw.println(" mDnsCheckDisabled=" + mDnsCheckDisabled); |
| pw.println(" mDcTracker=" + mDcTracker); |
| pw.println(" mDoesRilSendMultipleCallRing=" + mDoesRilSendMultipleCallRing); |
| pw.println(" mCallRingContinueToken=" + mCallRingContinueToken); |
| pw.println(" mCallRingDelay=" + mCallRingDelay); |
| pw.println(" mIsTheCurrentActivePhone=" + mIsTheCurrentActivePhone); |
| pw.println(" mIsVoiceCapable=" + mIsVoiceCapable); |
| pw.println(" mIccRecords=" + mIccRecords.get()); |
| pw.println(" mUiccApplication=" + mUiccApplication.get()); |
| pw.println(" mSmsStorageMonitor=" + mSmsStorageMonitor); |
| pw.println(" mSmsUsageMonitor=" + mSmsUsageMonitor); |
| pw.flush(); |
| pw.println(" mLooper=" + mLooper); |
| pw.println(" mContext=" + mContext); |
| pw.println(" mNotifier=" + mNotifier); |
| pw.println(" mSimulatedRadioControl=" + mSimulatedRadioControl); |
| pw.println(" mUnitTestMode=" + mUnitTestMode); |
| pw.println(" isDnsCheckDisabled()=" + isDnsCheckDisabled()); |
| pw.println(" getUnitTestMode()=" + getUnitTestMode()); |
| pw.println(" getState()=" + getState()); |
| pw.println(" getIccSerialNumber()=" + getIccSerialNumber()); |
| pw.println(" getIccRecordsLoaded()=" + getIccRecordsLoaded()); |
| pw.println(" getMessageWaitingIndicator()=" + getMessageWaitingIndicator()); |
| pw.println(" getCallForwardingIndicator()=" + getCallForwardingIndicator()); |
| pw.println(" isInEmergencyCall()=" + isInEmergencyCall()); |
| pw.flush(); |
| pw.println(" isInEcm()=" + isInEcm()); |
| pw.println(" getPhoneName()=" + getPhoneName()); |
| pw.println(" getPhoneType()=" + getPhoneType()); |
| pw.println(" getVoiceMessageCount()=" + getVoiceMessageCount()); |
| pw.println(" getActiveApnTypes()=" + getActiveApnTypes()); |
| pw.println(" isDataConnectivityPossible()=" + isDataConnectivityPossible()); |
| pw.println(" needsOtaServiceProvisioning=" + needsOtaServiceProvisioning()); |
| } |
| |
| /** |
| * Returns the subscription id. |
| */ |
| public long getSubId() { |
| return SubscriptionController.getInstance().getSubIdUsingPhoneId(mPhoneId); |
| } |
| |
| /** |
| * Returns the phone id. |
| */ |
| public int getPhoneId() { |
| return mPhoneId; |
| } |
| |
| //Gets Subscription information in the Phone Object |
| public Subscription getSubscriptionInfo() { |
| return mSubscriptionData; |
| } |
| |
| /** |
| * Return the service state of mImsPhone if it is STATE_IN_SERVICE |
| * otherwise return the current voice service state |
| */ |
| @Override |
| public int getVoicePhoneServiceState() { |
| ImsPhone imsPhone = mImsPhone; |
| if (imsPhone != null |
| && imsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE) { |
| return ServiceState.STATE_IN_SERVICE; |
| } |
| return getServiceState().getState(); |
| } |
| |
| @Override |
| public boolean setOperatorBrandOverride(String brand) { |
| return false; |
| } |
| |
| @Override |
| public boolean isRadioAvailable() { |
| return mCi.getRadioState().isAvailable(); |
| } |
| |
| @Override |
| public void shutdownRadio() { |
| getServiceStateTracker().requestShutdown(); |
| } |
| } |