When there is a radio technology change in a multimode modem, resetting the radio is not necessary always. Reset radio only when a property is set. Notify applications that data connection is lost and ignore notifications coming on the old radio technology. Minor optimizations and bug fixes in CdmaDataConnectionTracker. - Stop netstat polling when data connection is not active - check all the elements of the data call list array to figure out if the data connection is active. Change-Id: I36785a9d1bf8ee135b574b61e9ba371faa04ffc7
1021 lines
36 KiB
Java
1021 lines
36 KiB
Java
/*
|
|
* 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.app.ActivityManagerNative;
|
|
import android.app.IActivityManager;
|
|
import android.content.Context;
|
|
import android.content.res.Configuration;
|
|
import android.content.SharedPreferences;
|
|
import android.net.wifi.WifiManager;
|
|
import android.os.AsyncResult;
|
|
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.ServiceState;
|
|
import android.text.TextUtils;
|
|
import android.util.Log;
|
|
|
|
import com.android.internal.R;
|
|
import com.android.internal.telephony.gsm.PdpConnection;
|
|
import com.android.internal.telephony.test.SimulatedRadioControl;
|
|
|
|
import java.util.List;
|
|
import java.util.Locale;
|
|
|
|
|
|
/**
|
|
* (<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 = "PHONE";
|
|
private static final boolean LOCAL_DEBUG = true;
|
|
|
|
// 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;
|
|
|
|
// 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 mCM;
|
|
protected IccFileHandler mIccFileHandler;
|
|
boolean mDnsCheckDisabled = false;
|
|
public DataConnectionTracker mDataConnection;
|
|
boolean mDoesRilSendMultipleCallRing;
|
|
int mCallRingContinueToken = 0;
|
|
int mCallRingDelay;
|
|
public boolean mIsTheCurrentActivePhone = true;
|
|
|
|
/**
|
|
* 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 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 context Context object from hosting application
|
|
* @param notifier An instance of DefaultPhoneNotifier,
|
|
* unless unit testing.
|
|
*/
|
|
protected PhoneBase(PhoneNotifier notifier, Context context, CommandsInterface ci) {
|
|
this(notifier, context, ci, false);
|
|
}
|
|
|
|
/**
|
|
* Constructs a PhoneBase in normal (non-unit test) mode.
|
|
*
|
|
* @param context Context object from hosting application
|
|
* @param notifier An instance of DefaultPhoneNotifier,
|
|
* unless unit testing.
|
|
* @param unitTestMode when true, prevents notifications
|
|
* of state change events
|
|
*/
|
|
protected PhoneBase(PhoneNotifier notifier, Context context, CommandsInterface ci,
|
|
boolean unitTestMode) {
|
|
this.mNotifier = notifier;
|
|
this.mContext = context;
|
|
mLooper = Looper.myLooper();
|
|
mCM = ci;
|
|
|
|
setPropertiesByCarrier();
|
|
|
|
setUnitTestMode(unitTestMode);
|
|
|
|
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
|
|
mDnsCheckDisabled = sp.getBoolean(DNS_SERVER_CHECK_DISABLED_KEY, false);
|
|
mCM.setOnCallRing(this, EVENT_CALL_RING, null);
|
|
|
|
/**
|
|
* 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);
|
|
Log.d(LOG_TAG, "mDoesRilSendMultipleCallRing=" + mDoesRilSendMultipleCallRing);
|
|
|
|
mCallRingDelay = SystemProperties.getInt(
|
|
TelephonyProperties.PROPERTY_CALL_RING_DELAY, 3000);
|
|
Log.d(LOG_TAG, "mCallRingDelay=" + mCallRingDelay);
|
|
}
|
|
|
|
public void dispose() {
|
|
synchronized(PhoneProxy.lockForRadioTechnologyChange) {
|
|
mCM.unSetOnCallRing(this);
|
|
mDataConnection.onCleanUpConnection(false, REASON_RADIO_TURNED_OFF);
|
|
mIsTheCurrentActivePhone = false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 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:
|
|
Log.d(LOG_TAG, "Event EVENT_CALL_RING Received state=" + getState());
|
|
ar = (AsyncResult)msg.obj;
|
|
if (ar.exception == null) {
|
|
Phone.State state = getState();
|
|
if ((!mDoesRilSendMultipleCallRing)
|
|
&& ((state == Phone.State.RINGING) || (state == Phone.State.IDLE))) {
|
|
mCallRingContinueToken += 1;
|
|
sendIncomingCallRingNotification(mCallRingContinueToken);
|
|
} else {
|
|
notifyIncomingRing();
|
|
}
|
|
}
|
|
break;
|
|
|
|
case EVENT_CALL_RING_CONTINUE:
|
|
Log.d(LOG_TAG, "Event EVENT_CALL_RING_CONTINUE Received stat=" + getState());
|
|
if (getState() == Phone.State.RINGING) {
|
|
sendIncomingCallRingNotification(msg.arg1);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
throw new RuntimeException("unexpected event not handled");
|
|
}
|
|
}
|
|
|
|
// Inherited documentation suffices.
|
|
public Context getContext() {
|
|
return mContext;
|
|
}
|
|
|
|
/**
|
|
* Disables the DNS check (i.e., allows "0.0.0.0").
|
|
* Useful for lab testing environment.
|
|
* @param b true disables the check, false enables.
|
|
*/
|
|
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.commit();
|
|
}
|
|
|
|
/**
|
|
* Returns true if the DNS check is currently disabled.
|
|
*/
|
|
public boolean isDnsCheckDisabled() {
|
|
return mDnsCheckDisabled;
|
|
}
|
|
|
|
// Inherited documentation suffices.
|
|
public void registerForPreciseCallStateChanged(Handler h, int what, Object obj) {
|
|
checkCorrectThread(h);
|
|
|
|
mPreciseCallStateRegistrants.addUnique(h, what, obj);
|
|
}
|
|
|
|
// Inherited documentation suffices.
|
|
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.
|
|
public void registerForUnknownConnection(Handler h, int what, Object obj) {
|
|
checkCorrectThread(h);
|
|
|
|
mUnknownConnectionRegistrants.addUnique(h, what, obj);
|
|
}
|
|
|
|
// Inherited documentation suffices.
|
|
public void unregisterForUnknownConnection(Handler h) {
|
|
mUnknownConnectionRegistrants.remove(h);
|
|
}
|
|
|
|
// Inherited documentation suffices.
|
|
public void registerForNewRingingConnection(
|
|
Handler h, int what, Object obj) {
|
|
checkCorrectThread(h);
|
|
|
|
mNewRingingConnectionRegistrants.addUnique(h, what, obj);
|
|
}
|
|
|
|
// Inherited documentation suffices.
|
|
public void unregisterForNewRingingConnection(Handler h) {
|
|
mNewRingingConnectionRegistrants.remove(h);
|
|
}
|
|
|
|
// Inherited documentation suffices.
|
|
public void registerForInCallVoicePrivacyOn(Handler h, int what, Object obj){
|
|
mCM.registerForInCallVoicePrivacyOn(h,what,obj);
|
|
}
|
|
|
|
// Inherited documentation suffices.
|
|
public void unregisterForInCallVoicePrivacyOn(Handler h){
|
|
mCM.unregisterForInCallVoicePrivacyOn(h);
|
|
}
|
|
|
|
// Inherited documentation suffices.
|
|
public void registerForInCallVoicePrivacyOff(Handler h, int what, Object obj){
|
|
mCM.registerForInCallVoicePrivacyOff(h,what,obj);
|
|
}
|
|
|
|
// Inherited documentation suffices.
|
|
public void unregisterForInCallVoicePrivacyOff(Handler h){
|
|
mCM.unregisterForInCallVoicePrivacyOff(h);
|
|
}
|
|
|
|
// Inherited documentation suffices.
|
|
public void registerForIncomingRing(
|
|
Handler h, int what, Object obj) {
|
|
checkCorrectThread(h);
|
|
|
|
mIncomingRingRegistrants.addUnique(h, what, obj);
|
|
}
|
|
|
|
// Inherited documentation suffices.
|
|
public void unregisterForIncomingRing(Handler h) {
|
|
mIncomingRingRegistrants.remove(h);
|
|
}
|
|
|
|
// Inherited documentation suffices.
|
|
public void registerForDisconnect(Handler h, int what, Object obj) {
|
|
checkCorrectThread(h);
|
|
|
|
mDisconnectRegistrants.addUnique(h, what, obj);
|
|
}
|
|
|
|
// Inherited documentation suffices.
|
|
public void unregisterForDisconnect(Handler h) {
|
|
mDisconnectRegistrants.remove(h);
|
|
}
|
|
|
|
// Inherited documentation suffices.
|
|
public void registerForSuppServiceFailed(Handler h, int what, Object obj) {
|
|
checkCorrectThread(h);
|
|
|
|
mSuppServiceFailedRegistrants.addUnique(h, what, obj);
|
|
}
|
|
|
|
// Inherited documentation suffices.
|
|
public void unregisterForSuppServiceFailed(Handler h) {
|
|
mSuppServiceFailedRegistrants.remove(h);
|
|
}
|
|
|
|
// Inherited documentation suffices.
|
|
public void registerForMmiInitiate(Handler h, int what, Object obj) {
|
|
checkCorrectThread(h);
|
|
|
|
mMmiRegistrants.addUnique(h, what, obj);
|
|
}
|
|
|
|
// Inherited documentation suffices.
|
|
public void unregisterForMmiInitiate(Handler h) {
|
|
mMmiRegistrants.remove(h);
|
|
}
|
|
|
|
// Inherited documentation suffices.
|
|
public void registerForMmiComplete(Handler h, int what, Object obj) {
|
|
checkCorrectThread(h);
|
|
|
|
mMmiCompleteRegistrants.addUnique(h, what, obj);
|
|
}
|
|
|
|
// Inherited documentation suffices.
|
|
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)) {
|
|
mCM.setNetworkSelectionModeAutomatic(response);
|
|
} else {
|
|
mCM.setNetworkSelectionModeManual(networkSelection, response);
|
|
}
|
|
}
|
|
|
|
// Inherited documentation suffices.
|
|
public void setUnitTestMode(boolean f) {
|
|
mUnitTestMode = f;
|
|
}
|
|
|
|
// Inherited documentation suffices.
|
|
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.
|
|
public void registerForServiceStateChanged(
|
|
Handler h, int what, Object obj) {
|
|
checkCorrectThread(h);
|
|
|
|
mServiceStateRegistrants.add(h, what, obj);
|
|
}
|
|
|
|
// Inherited documentation suffices.
|
|
public void unregisterForServiceStateChanged(Handler h) {
|
|
mServiceStateRegistrants.remove(h);
|
|
}
|
|
|
|
// Inherited documentation suffices.
|
|
public void registerForRingbackTone(Handler h, int what, Object obj) {
|
|
mCM.registerForRingbackTone(h,what,obj);
|
|
}
|
|
|
|
// Inherited documentation suffices.
|
|
public void unregisterForRingbackTone(Handler h) {
|
|
mCM.unregisterForRingbackTone(h);
|
|
}
|
|
|
|
/**
|
|
* 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.
|
|
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()) {
|
|
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();
|
|
int wifiChannels = 0;
|
|
try {
|
|
wifiChannels = Integer.parseInt(
|
|
carrierLocales[i+2].toString());
|
|
} catch (NumberFormatException e) { }
|
|
|
|
String language = l.substring(0, 2);
|
|
String country = "";
|
|
if (l.length() >=5) {
|
|
country = l.substring(3, 5);
|
|
}
|
|
setSystemLocale(language, country);
|
|
|
|
if (wifiChannels != 0) {
|
|
try {
|
|
Settings.Secure.getInt(mContext.getContentResolver(),
|
|
Settings.Secure.WIFI_NUM_ALLOWED_CHANNELS);
|
|
} catch (Settings.SettingNotFoundException e) {
|
|
// note this is not persisting
|
|
WifiManager wM = (WifiManager)
|
|
mContext.getSystemService(Context.WIFI_SERVICE);
|
|
wM.setNumAllowedChannels(wifiChannels, false);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Utility code to set the system locale if it's not set already
|
|
* @param langauge Two character language code desired
|
|
* @param country Two character country code desired
|
|
*
|
|
* {@hide}
|
|
*/
|
|
public void setSystemLocale(String language, String country) {
|
|
String l = SystemProperties.get("persist.sys.language");
|
|
String c = SystemProperties.get("persist.sys.country");
|
|
|
|
if (null == language) {
|
|
return; // no match possible
|
|
}
|
|
language = language.toLowerCase();
|
|
if (null == country) {
|
|
country = "";
|
|
}
|
|
country = country.toUpperCase();
|
|
|
|
if((null == l || 0 == l.length()) && (null == c || 0 == c.length())) {
|
|
try {
|
|
// try to find a good match
|
|
String[] locales = mContext.getAssets().getLocales();
|
|
final int N = locales.length;
|
|
String bestMatch = null;
|
|
for(int i = 0; i < N; i++) {
|
|
// only match full (lang + country) locales
|
|
if (locales[i]!=null && locales[i].length() >= 5 &&
|
|
locales[i].substring(0,2).equals(language)) {
|
|
if (locales[i].substring(3,5).equals(country)) {
|
|
bestMatch = locales[i];
|
|
break;
|
|
} else if (null == bestMatch) {
|
|
bestMatch = locales[i];
|
|
}
|
|
}
|
|
}
|
|
if (null != bestMatch) {
|
|
IActivityManager am = ActivityManagerNative.getDefault();
|
|
Configuration config = am.getConfiguration();
|
|
config.locale = new Locale(bestMatch.substring(0,2),
|
|
bestMatch.substring(3,5));
|
|
config.userSetLocale = true;
|
|
am.updateConfiguration(config);
|
|
}
|
|
} catch (Exception e) {
|
|
// Intentionally left blank
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get state
|
|
*/
|
|
public abstract Phone.State getState();
|
|
|
|
/**
|
|
* Retrieves the IccFileHandler of the Phone instance
|
|
*/
|
|
public abstract IccFileHandler getIccFileHandler();
|
|
|
|
/*
|
|
* Retrieves the Handler of the Phone instance
|
|
*/
|
|
public Handler getHandler() {
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Query the status of the CDMA roaming preference
|
|
*/
|
|
public void queryCdmaRoamingPreference(Message response) {
|
|
mCM.queryCdmaRoamingPreference(response);
|
|
}
|
|
|
|
/**
|
|
* Set the status of the CDMA roaming preference
|
|
*/
|
|
public void setCdmaRoamingPreference(int cdmaRoamingType, Message response) {
|
|
mCM.setCdmaRoamingPreference(cdmaRoamingType, response);
|
|
}
|
|
|
|
/**
|
|
* Set the status of the CDMA subscription mode
|
|
*/
|
|
public void setCdmaSubscription(int cdmaSubscriptionType, Message response) {
|
|
mCM.setCdmaSubscription(cdmaSubscriptionType, response);
|
|
}
|
|
|
|
/**
|
|
* Set the preferred Network Type: Global, CDMA only or GSM/UMTS only
|
|
*/
|
|
public void setPreferredNetworkType(int networkType, Message response) {
|
|
mCM.setPreferredNetworkType(networkType, response);
|
|
}
|
|
|
|
public void getPreferredNetworkType(Message response) {
|
|
mCM.getPreferredNetworkType(response);
|
|
}
|
|
|
|
public void getSmscAddress(Message result) {
|
|
mCM.getSmscAddress(result);
|
|
}
|
|
|
|
public void setSmscAddress(String address, Message result) {
|
|
mCM.setSmscAddress(address, result);
|
|
}
|
|
|
|
public void setTTYMode(int ttyMode, Message onComplete) {
|
|
// This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
|
|
Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
|
|
}
|
|
|
|
public void queryTTYMode(Message onComplete) {
|
|
// This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
|
|
Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
|
|
}
|
|
|
|
/**
|
|
* This should only be called in GSM mode.
|
|
* Only here for some backward compatibility
|
|
* issues concerning the GSMPhone class.
|
|
* @deprecated Always returns null.
|
|
*/
|
|
public List<PdpConnection> getCurrentPdpList() {
|
|
return null;
|
|
}
|
|
|
|
public void enableEnhancedVoicePrivacy(boolean enable, Message onComplete) {
|
|
// This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
|
|
Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
|
|
}
|
|
|
|
public void getEnhancedVoicePrivacy(Message onComplete) {
|
|
// This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
|
|
Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
|
|
}
|
|
|
|
public void setBandMode(int bandMode, Message response) {
|
|
mCM.setBandMode(bandMode, response);
|
|
}
|
|
|
|
public void queryAvailableBandMode(Message response) {
|
|
mCM.queryAvailableBandMode(response);
|
|
}
|
|
|
|
public void invokeOemRilRequestRaw(byte[] data, Message response) {
|
|
mCM.invokeOemRilRequestRaw(data, response);
|
|
}
|
|
|
|
public void invokeOemRilRequestStrings(String[] strings, Message response) {
|
|
mCM.invokeOemRilRequestStrings(strings, response);
|
|
}
|
|
|
|
public void notifyDataActivity() {
|
|
mNotifier.notifyDataActivity(this);
|
|
}
|
|
|
|
public void notifyMessageWaitingIndicator() {
|
|
// This function is added to send the notification to DefaultPhoneNotifier.
|
|
mNotifier.notifyMessageWaitingChanged(this);
|
|
}
|
|
|
|
public void notifyDataConnection(String reason) {
|
|
mNotifier.notifyDataConnection(this, reason);
|
|
}
|
|
|
|
public abstract String getPhoneName();
|
|
|
|
public abstract int getPhoneType();
|
|
|
|
/** @hide */
|
|
public int getVoiceMessageCount(){
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Returns the CDMA ERI icon index to display
|
|
*/
|
|
public int getCdmaEriIconIndex() {
|
|
Log.e(LOG_TAG, "Error! getCdmaEriIconIndex should never be executed in GSM mode");
|
|
return -1;
|
|
}
|
|
|
|
/**
|
|
* Returns the CDMA ERI icon mode,
|
|
* 0 - ON
|
|
* 1 - FLASHING
|
|
*/
|
|
public int getCdmaEriIconMode() {
|
|
Log.e(LOG_TAG, "Error! getCdmaEriIconMode should never be executed in GSM mode");
|
|
return -1;
|
|
}
|
|
|
|
/**
|
|
* Returns the CDMA ERI text,
|
|
*/
|
|
public String getCdmaEriText() {
|
|
Log.e(LOG_TAG, "Error! getCdmaEriText should never be executed in GSM mode");
|
|
return "GSM nw, no ERI";
|
|
}
|
|
|
|
public String getCdmaMin() {
|
|
// This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
|
|
Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
|
|
return null;
|
|
}
|
|
|
|
public boolean isMinInfoReady() {
|
|
// This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
|
|
Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
|
|
return false;
|
|
}
|
|
|
|
public String getCdmaPrlVersion(){
|
|
// This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
|
|
Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
|
|
return null;
|
|
}
|
|
|
|
public void sendBurstDtmf(String dtmfString, int on, int off, Message onComplete) {
|
|
// This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
|
|
Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
|
|
}
|
|
|
|
public void exitEmergencyCallbackMode() {
|
|
// This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
|
|
Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
|
|
}
|
|
|
|
public void registerForCdmaOtaStatusChange(Handler h, int what, Object obj) {
|
|
// This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
|
|
Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
|
|
}
|
|
|
|
public void unregisterForCdmaOtaStatusChange(Handler h) {
|
|
// This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
|
|
Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
|
|
}
|
|
|
|
public void registerForSubscriptionInfoReady(Handler h, int what, Object obj) {
|
|
// This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
|
|
Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
|
|
}
|
|
|
|
public void unregisterForSubscriptionInfoReady(Handler h) {
|
|
// This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
|
|
Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
|
|
}
|
|
|
|
public boolean isOtaSpNumber(String dialStr) {
|
|
// This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
|
|
Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
|
|
return false;
|
|
}
|
|
|
|
public void registerForCallWaiting(Handler h, int what, Object obj){
|
|
// This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
|
|
Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
|
|
}
|
|
|
|
public void unregisterForCallWaiting(Handler h){
|
|
// This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
|
|
Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
|
|
}
|
|
|
|
public void registerForEcmTimerReset(Handler h, int what, Object obj) {
|
|
// This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
|
|
Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
|
|
}
|
|
|
|
public void unregisterForEcmTimerReset(Handler h) {
|
|
// This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
|
|
Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
|
|
}
|
|
|
|
public void registerForSignalInfo(Handler h, int what, Object obj) {
|
|
mCM.registerForSignalInfo(h, what, obj);
|
|
}
|
|
|
|
public void unregisterForSignalInfo(Handler h) {
|
|
mCM.unregisterForSignalInfo(h);
|
|
}
|
|
|
|
public void registerForDisplayInfo(Handler h, int what, Object obj) {
|
|
mCM.registerForDisplayInfo(h, what, obj);
|
|
}
|
|
|
|
public void unregisterForDisplayInfo(Handler h) {
|
|
mCM.unregisterForDisplayInfo(h);
|
|
}
|
|
|
|
public void registerForNumberInfo(Handler h, int what, Object obj) {
|
|
mCM.registerForNumberInfo(h, what, obj);
|
|
}
|
|
|
|
public void unregisterForNumberInfo(Handler h) {
|
|
mCM.unregisterForNumberInfo(h);
|
|
}
|
|
|
|
public void registerForRedirectedNumberInfo(Handler h, int what, Object obj) {
|
|
mCM.registerForRedirectedNumberInfo(h, what, obj);
|
|
}
|
|
|
|
public void unregisterForRedirectedNumberInfo(Handler h) {
|
|
mCM.unregisterForRedirectedNumberInfo(h);
|
|
}
|
|
|
|
public void registerForLineControlInfo(Handler h, int what, Object obj) {
|
|
mCM.registerForLineControlInfo( h, what, obj);
|
|
}
|
|
|
|
public void unregisterForLineControlInfo(Handler h) {
|
|
mCM.unregisterForLineControlInfo(h);
|
|
}
|
|
|
|
public void registerFoT53ClirlInfo(Handler h, int what, Object obj) {
|
|
mCM.registerFoT53ClirlInfo(h, what, obj);
|
|
}
|
|
|
|
public void unregisterForT53ClirInfo(Handler h) {
|
|
mCM.unregisterForT53ClirInfo(h);
|
|
}
|
|
|
|
public void registerForT53AudioControlInfo(Handler h, int what, Object obj) {
|
|
mCM.registerForT53AudioControlInfo( h, what, obj);
|
|
}
|
|
|
|
public void unregisterForT53AudioControlInfo(Handler h) {
|
|
mCM.unregisterForT53AudioControlInfo(h);
|
|
}
|
|
|
|
public void setOnEcbModeExitResponse(Handler h, int what, Object obj){
|
|
// This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
|
|
Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
|
|
}
|
|
|
|
public void unsetOnEcbModeExitResponse(Handler h){
|
|
// This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
|
|
Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
|
|
}
|
|
|
|
public String getInterfaceName(String apnType) {
|
|
return mDataConnection.getInterfaceName(apnType);
|
|
}
|
|
|
|
public String getIpAddress(String apnType) {
|
|
return mDataConnection.getIpAddress(apnType);
|
|
}
|
|
|
|
public boolean isDataConnectivityEnabled() {
|
|
return mDataConnection.getDataEnabled();
|
|
}
|
|
|
|
public String getGateway(String apnType) {
|
|
return mDataConnection.getGateway(apnType);
|
|
}
|
|
|
|
public String[] getDnsServers(String apnType) {
|
|
return mDataConnection.getDnsServers(apnType);
|
|
}
|
|
|
|
public String[] getActiveApnTypes() {
|
|
return mDataConnection.getActiveApnTypes();
|
|
}
|
|
|
|
public String getActiveApn() {
|
|
return mDataConnection.getActiveApnString();
|
|
}
|
|
|
|
public int enableApnType(String type) {
|
|
return mDataConnection.enableApnType(type);
|
|
}
|
|
|
|
public int disableApnType(String type) {
|
|
return mDataConnection.disableApnType(type);
|
|
}
|
|
|
|
/**
|
|
* simulateDataConnection
|
|
*
|
|
* simulates various data connection states. This messes with
|
|
* DataConnectionTracker's internal states, but doesn't actually change
|
|
* the underlying radio connection states.
|
|
*
|
|
* @param state Phone.DataState enum.
|
|
*/
|
|
public void simulateDataConnection(Phone.DataState state) {
|
|
DataConnectionTracker.State dcState;
|
|
|
|
switch (state) {
|
|
case CONNECTED:
|
|
dcState = DataConnectionTracker.State.CONNECTED;
|
|
break;
|
|
case SUSPENDED:
|
|
dcState = DataConnectionTracker.State.CONNECTED;
|
|
break;
|
|
case DISCONNECTED:
|
|
dcState = DataConnectionTracker.State.FAILED;
|
|
break;
|
|
default:
|
|
dcState = DataConnectionTracker.State.CONNECTING;
|
|
break;
|
|
}
|
|
|
|
mDataConnection.setState(dcState);
|
|
notifyDataConnection(null);
|
|
}
|
|
|
|
/**
|
|
* Notifiy 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) {
|
|
AsyncResult ar = new AsyncResult(null, cn, null);
|
|
mNewRingingConnectionRegistrants.notifyRegistrants(ar);
|
|
}
|
|
|
|
/**
|
|
* Notify registrants of a RING event.
|
|
*/
|
|
private void notifyIncomingRing() {
|
|
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 (!mDoesRilSendMultipleCallRing && (token == mCallRingContinueToken)) {
|
|
Log.d(LOG_TAG, "Sending notifyIncomingRing");
|
|
notifyIncomingRing();
|
|
sendMessageDelayed(
|
|
obtainMessage(EVENT_CALL_RING_CONTINUE, token, 0), mCallRingDelay);
|
|
} else {
|
|
Log.d(LOG_TAG, "Ignoring ring notification request,"
|
|
+ " mDoesRilSendMultipleCallRing=" + mDoesRilSendMultipleCallRing
|
|
+ " token=" + token
|
|
+ " mCallRingContinueToken=" + mCallRingContinueToken);
|
|
}
|
|
}
|
|
}
|