/* * 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.Context; import android.content.SharedPreferences; import android.net.LinkCapabilities; import android.net.LinkProperties; 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.RegistrantList; import android.os.SystemProperties; import android.preference.PreferenceManager; import android.provider.Settings; import android.telephony.CellInfo; import android.telephony.ServiceState; import android.telephony.SignalStrength; import android.text.TextUtils; import android.telephony.Rlog; import com.android.internal.R; import com.android.internal.telephony.dataconnection.DcTrackerBase; 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.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.List; import java.util.concurrent.atomic.AtomicReference; /** * (Not for SDK use) * 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"; // 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_NEW_ICC_SMS = 29; protected static final int EVENT_ICC_RECORD_EVENTS = 30; protected static final int EVENT_ICC_CHANGED = 31; // 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"; /* 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 mIccRecords = new AtomicReference(); public SmsStorageMonitor mSmsStorageMonitor; public SmsUsageMonitor mSmsUsageMonitor; protected AtomicReference mUiccApplication = new AtomicReference(); public SMSDispatcher mSMS; private TelephonyTester mTelephonyTester; private final String mName; private final String mActionDetached; private final String mActionAttached; @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 */ public void setSystemProperty(String property, String value) { if(getUnitTestMode()) { return; } SystemProperties.set(property, value); } 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 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 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) { 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); } setPropertiesByCarrier(); 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); // 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); } @Override public void dispose() { synchronized(PhoneProxy.lockForRadioTechnologyChange) { 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); if (mTelephonyTester != null) { mTelephonyTester.dispose(); } } } @Override public void removeReferences() { mSmsStorageMonitor = null; mSmsUsageMonitor = null; mSMS = null; mIccRecords.set(null); mUiccApplication.set(null); mDcTracker = null; mUiccController = 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; 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; default: throw new RuntimeException("unexpected event not handled"); } } // 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); } // 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); } /** * 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 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(boolean enabled) { // 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)) { String l = carrierLocales[i+1].toString(); String language = l.substring(0, 2); String country = ""; if (l.length() >=5) { country = l.substring(3, 5); } MccTable.setSystemLocale(mContext, language, 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(); if (uiccApplication == null) return null; return uiccApplication.getIccFileHandler(); } /* * Retrieves the Handler of the Phone instance */ public Handler getHandler() { return this; } /** * 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 getAllCellInfo() { return getServiceStateTracker().getAllCellInfo(); } /** * {@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 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) { mNotifier.notifyCellInfo(this, cellInfo); } /** * @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 LinkCapabilities getLinkCapabilities(String apnType) { return mDcTracker.getLinkCapabilities(apnType); } @Override public int enableApnType(String type) { return mDcTracker.enableApnType(type); } @Override public int disableApnType(String type) { return mDcTracker.disableApnType(type); } @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 */ protected 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 void requestIsimAuthentication(String nonce, Message result) { Rlog.e(LOG_TAG, "requestIsimAuthentication() is only supported on LTE devices"); } @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); } /** * {@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; } 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.println(" mSMS=" + mSMS); 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()); } }