RadioInfo.java revision 87fa11b90e9a4a5fdd73e71e6c0b057f9df1a860
1/*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.settings;
18
19import android.app.Activity;
20import android.app.AlertDialog;
21import android.content.DialogInterface;
22import android.content.Intent;
23import android.content.SharedPreferences;
24import android.content.res.Resources;
25import android.net.Uri;
26import android.os.AsyncResult;
27import android.os.Bundle;
28import android.os.Handler;
29import android.os.INetStatService;
30import android.os.Message;
31import android.os.RemoteException;
32import android.os.ServiceManager;
33import android.os.SystemProperties;
34import android.preference.PreferenceManager;
35import android.telephony.CellLocation;
36import android.telephony.PhoneStateListener;
37import android.telephony.ServiceState;
38import android.telephony.TelephonyManager;
39import android.telephony.NeighboringCellInfo;
40import android.telephony.gsm.GsmCellLocation;
41import android.text.format.DateUtils;
42import android.util.Log;
43import android.view.Menu;
44import android.view.MenuItem;
45import android.view.View;
46import android.view.View.OnClickListener;
47import android.widget.AdapterView;
48import android.widget.ArrayAdapter;
49import android.widget.Button;
50import android.widget.Spinner;
51import android.widget.TextView;
52import android.widget.EditText;
53
54import com.android.internal.telephony.DataConnection;
55import com.android.internal.telephony.Phone;
56import com.android.internal.telephony.PhoneFactory;
57import com.android.internal.telephony.PhoneStateIntentReceiver;
58import com.android.internal.telephony.TelephonyProperties;
59import com.android.internal.telephony.gsm.GSMPhone;
60import com.android.internal.telephony.gsm.PdpConnection;
61
62import org.apache.http.HttpResponse;
63import org.apache.http.client.HttpClient;
64import org.apache.http.client.methods.HttpGet;
65import org.apache.http.impl.client.DefaultHttpClient;
66
67import java.io.ByteArrayOutputStream;
68import java.io.DataOutputStream;
69import java.io.IOException;
70import java.net.UnknownHostException;
71import java.util.ArrayList;
72import java.util.List;
73
74public class RadioInfo extends Activity {
75    private final String TAG = "phone";
76
77    private static final int EVENT_PHONE_STATE_CHANGED = 100;
78    private static final int EVENT_SIGNAL_STRENGTH_CHANGED = 200;
79    private static final int EVENT_SERVICE_STATE_CHANGED = 300;
80    private static final int EVENT_CFI_CHANGED = 302;
81
82    private static final int EVENT_QUERY_PREFERRED_TYPE_DONE = 1000;
83    private static final int EVENT_SET_PREFERRED_TYPE_DONE = 1001;
84    private static final int EVENT_QUERY_NEIGHBORING_CIDS_DONE = 1002;
85    private static final int EVENT_SET_QXDMLOG_DONE = 1003;
86    private static final int EVENT_SET_CIPHER_DONE = 1004;
87    private static final int EVENT_QUERY_SMSC_DONE = 1005;
88    private static final int EVENT_UPDATE_SMSC_DONE = 1006;
89
90    private static final int MENU_ITEM_SELECT_BAND  = 0;
91    private static final int MENU_ITEM_VIEW_ADN     = 1;
92    private static final int MENU_ITEM_VIEW_FDN     = 2;
93    private static final int MENU_ITEM_VIEW_SDN     = 3;
94    private static final int MENU_ITEM_GET_PDP_LIST = 4;
95    private static final int MENU_ITEM_TOGGLE_DATA  = 5;
96    private static final int MENU_ITEM_TOGGLE_DATA_ON_BOOT = 6;
97
98    private TextView mDeviceId; //DeviceId is the IMEI in GSM and the MEID in CDMA
99    private TextView number;
100    private TextView callState;
101    private TextView operatorName;
102    private TextView roamingState;
103    private TextView gsmState;
104    private TextView gprsState;
105    private TextView network;
106    private TextView dBm;
107    private TextView mMwi;
108    private TextView mCfi;
109    private TextView mLocation;
110    private TextView mNeighboringCids;
111    private TextView resets;
112    private TextView attempts;
113    private TextView successes;
114    private TextView disconnects;
115    private TextView sentSinceReceived;
116    private TextView sent;
117    private TextView received;
118    private TextView mPingIpAddr;
119    private TextView mPingHostname;
120    private TextView mHttpClientTest;
121    private TextView cipherState;
122    private TextView dnsCheckState;
123    private EditText smsc;
124    private Button radioPowerButton;
125    private Button qxdmLogButton;
126    private Button cipherToggleButton;
127    private Button dnsCheckToggleButton;
128    private Button pingTestButton;
129    private Button updateSmscButton;
130    private Button refreshSmscButton;
131    private Spinner preferredNetworkType;
132
133    private TelephonyManager mTelephonyManager;
134    private Phone phone = null;
135    private PhoneStateIntentReceiver mPhoneStateReceiver;
136    private INetStatService netstat;
137
138    private OemCommands mOem = null;
139    private boolean mQxdmLogEnabled;
140    // The requested cipher state
141    private boolean mCipherOn;
142
143    private String mPingIpAddrResult;
144    private String mPingHostnameResult;
145    private String mHttpClientTestResult;
146    private boolean mMwiValue = false;
147    private boolean mCfiValue = false;
148
149    private PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
150        @Override
151        public void onDataConnectionStateChanged(int state) {
152            updateDataState();
153            updateDataStats();
154            updatePdpList();
155            updateNetworkType();
156        }
157
158        @Override
159        public void onDataActivity(int direction) {
160            updateDataStats2();
161        }
162
163        @Override
164        public void onCellLocationChanged(CellLocation location) {
165            updateLocation(location);
166        }
167
168        @Override
169        public void onMessageWaitingIndicatorChanged(boolean mwi) {
170            mMwiValue = mwi;
171            updateMessageWaiting();
172        }
173
174        @Override
175        public void onCallForwardingIndicatorChanged(boolean cfi) {
176            mCfiValue = cfi;
177            updateCallRedirect();
178        }
179    };
180
181    private Handler mHandler = new Handler() {
182        public void handleMessage(Message msg) {
183            AsyncResult ar;
184            switch (msg.what) {
185                case EVENT_PHONE_STATE_CHANGED:
186                    updatePhoneState();
187                    break;
188
189                case EVENT_SIGNAL_STRENGTH_CHANGED:
190                    updateSignalStrength();
191                    break;
192
193                case EVENT_SERVICE_STATE_CHANGED:
194                    updateServiceState();
195                    updatePowerState();
196                    break;
197
198                case EVENT_QUERY_PREFERRED_TYPE_DONE:
199                    ar= (AsyncResult) msg.obj;
200                    if (ar.exception == null) {
201                        int type = ((int[])ar.result)[0];
202                        preferredNetworkType.setSelection(type, true);
203                    } else {
204                        preferredNetworkType.setSelection(8, true);
205                    }
206                    break;
207                case EVENT_SET_PREFERRED_TYPE_DONE:
208                    ar= (AsyncResult) msg.obj;
209                    if (ar.exception != null) {
210                        phone.getPreferredNetworkType(
211                                obtainMessage(EVENT_QUERY_PREFERRED_TYPE_DONE));
212                    }
213                    break;
214                case EVENT_QUERY_NEIGHBORING_CIDS_DONE:
215                    ar= (AsyncResult) msg.obj;
216                    if (ar.exception == null) {
217                        updateNeighboringCids((ArrayList<NeighboringCellInfo>)ar.result);
218                    } else {
219                        mNeighboringCids.setText("unknown");
220                    }
221                    break;
222                case EVENT_SET_QXDMLOG_DONE:
223                    ar= (AsyncResult) msg.obj;
224                    if (ar.exception == null) {
225                        mQxdmLogEnabled = !mQxdmLogEnabled;
226
227                        updateQxdmState(mQxdmLogEnabled);
228                        displayQxdmEnableResult();
229                    }
230                    break;
231                case EVENT_SET_CIPHER_DONE:
232                    ar= (AsyncResult) msg.obj;
233                    if (ar.exception == null) {
234                        setCiphPref(mCipherOn);
235                    }
236                    updateCiphState();
237                    break;
238                case EVENT_QUERY_SMSC_DONE:
239                    ar= (AsyncResult) msg.obj;
240                    if (ar.exception != null) {
241                        smsc.setText("refresh error");
242                    } else {
243                        smsc.setText((String)ar.result);
244                    }
245                    break;
246                case EVENT_UPDATE_SMSC_DONE:
247                    updateSmscButton.setEnabled(true);
248                    ar= (AsyncResult) msg.obj;
249                    if (ar.exception != null) {
250                        smsc.setText("update error");
251                    }
252                    break;
253                default:
254                    break;
255
256            }
257        }
258    };
259
260    static private class OemCommands {
261
262        public static final int OEM_QXDM_SDLOG_DEFAULT_FILE_SIZE = 32;
263        public static final int OEM_QXDM_SDLOG_DEFAULT_MASK = 0;
264        public static final int OEM_QXDM_SDLOG_DEFAULT_MAX_INDEX = 8;
265
266        static final int SIZE_OF_INT = 4;
267        static final int OEM_FEATURE_ENABLE = 1;
268        static final int OEM_FEATURE_DISABLE = 0;
269        static final int OEM_SIMPE_FEAUTURE_LEN = 1;
270
271        static final int OEM_QXDM_SDLOG_FUNCTAG = 0x00010000;
272        static final int OEM_QXDM_SDLOG_LEN = 4;
273        static final int OEM_PS_AUTO_ATTACH_FUNCTAG = 0x00020000;
274        static final int OEM_CIPHERING_FUNCTAG = 0x00020001;
275
276        /**
277         * The OEM interface to store QXDM to SD.
278         *
279         * To start/stop logging QXDM logs to SD card, use tag
280         * OEM_RIL_HOOK_QXDM_SD_LOG_SETUP 0x00010000
281         *
282         * "data" is a const oem_ril_hook_qxdm_sdlog_setup_data_st *
283         * ((const oem_ril_hook_qxdm_sdlog_setup_data_st *)data)->head.func_tag
284         * should be OEM_RIL_HOOK_QXDM_SD_LOG_SETUP
285         * ((const oem_ril_hook_qxdm_sdlog_setup_data_st *)data)->head.len
286         * should be "sizeof(unsigned int) * 4"
287         * ((const oem_ril_hook_qxdm_sdlog_setup_data_st *)data)->mode
288         * could be 0 for 'stop logging', or 1 for 'start logging'
289         * ((const oem_ril_hook_qxdm_sdlog_setup_data_st *)data)->log_file_size
290         * will assign the size of each log file, and it could be a value between
291         * 1 and 512 (in megabytes, default value is recommended to set as 32).
292         * This value will be ignored when mode == 0.
293         * ((const oem_ril_hook_qxdm_sdlog_setup_data_st *)data)->log_mask will
294         * assign the rule to filter logs, and it is a bitmask (bit0 is for MsgAll,
295         * bit1 is for LogAll, and bit2 is for EventAll) recommended to be set as 0
296         * by default. This value will be ignored when mode == 0.
297         * ((const oem_ril_hook_qxdm_sdlog_setup_data_st *)data)->log_max_fileindex
298         * set the how many logfiles will storted before roll over. This value will
299         * be ignored when mode == 0.
300         *
301         * "response" is NULL
302         *
303         * typedef struct _oem_ril_hook_raw_head_st {
304         *      unsigned int func_tag;
305         *      unsigned int len;
306         * } oem_ril_hook_raw_head_st;
307         *
308         * typedef struct _oem_ril_hook_qxdm_sdlog_setup_data_st {
309         *      oem_ril_hook_raw_head_st head;
310         *      unsigned int mode;
311         *      unsigned int log_file_size;
312         *      unsigned int log_mask;
313         *      unsigned int log_max_fileindex;
314         * } oem_ril_hook_qxdm_sdlog_setup_data_st;
315         *
316         * @param enable set true to start logging QXDM in SD card
317         * @param fileSize is the log file size in MB
318         * @param mask is the log mask to filter
319         * @param maxIndex is the maximum roll-over file number
320         * @return byteArray to use in RIL RAW command
321         */
322        byte[] getQxdmSdlogData(boolean enable, int fileSize, int mask, int maxIndex) {
323            ByteArrayOutputStream bos = new ByteArrayOutputStream();
324            DataOutputStream dos = new DataOutputStream(bos);
325            try {
326                writeIntLittleEndian(dos, OEM_QXDM_SDLOG_FUNCTAG);
327                writeIntLittleEndian(dos, OEM_QXDM_SDLOG_LEN * SIZE_OF_INT);
328                writeIntLittleEndian(dos, enable ?
329                        OEM_FEATURE_ENABLE : OEM_FEATURE_DISABLE);
330                writeIntLittleEndian(dos, fileSize);
331                writeIntLittleEndian(dos, mask);
332                writeIntLittleEndian(dos, maxIndex);
333            } catch (IOException e) {
334                return null;
335            }
336            return bos.toByteArray();
337        }
338
339        byte[] getPsAutoAttachData(boolean enable) {
340            return getSimpleFeatureData(OEM_PS_AUTO_ATTACH_FUNCTAG, enable);
341        }
342
343        byte[] getCipheringData(boolean enable) {
344            return getSimpleFeatureData(OEM_CIPHERING_FUNCTAG, enable);
345        }
346
347        private byte[] getSimpleFeatureData(int tag, boolean enable) {
348            ByteArrayOutputStream bos = new ByteArrayOutputStream();
349            DataOutputStream dos = new DataOutputStream(bos);
350            try {
351                writeIntLittleEndian(dos, tag);
352                writeIntLittleEndian(dos, OEM_SIMPE_FEAUTURE_LEN * SIZE_OF_INT);
353                writeIntLittleEndian(dos, enable ?
354                        OEM_FEATURE_ENABLE : OEM_FEATURE_DISABLE);
355            } catch (IOException e) {
356                return null;
357            }
358            return bos.toByteArray();
359        }
360
361        private void writeIntLittleEndian(DataOutputStream dos, int val)
362                throws IOException {
363            dos.writeByte(val);
364            dos.writeByte(val >> 8);
365            dos.writeByte(val >> 16);
366            dos.writeByte(val >> 24);
367        }
368    }
369
370    @Override
371    public void onCreate(Bundle icicle) {
372        super.onCreate(icicle);
373
374        setContentView(R.layout.radio_info);
375
376        mTelephonyManager = (TelephonyManager)getSystemService(TELEPHONY_SERVICE);
377        phone = PhoneFactory.getDefaultPhone();
378
379        mDeviceId= (TextView) findViewById(R.id.imei);
380        number = (TextView) findViewById(R.id.number);
381        callState = (TextView) findViewById(R.id.call);
382        operatorName = (TextView) findViewById(R.id.operator);
383        roamingState = (TextView) findViewById(R.id.roaming);
384        gsmState = (TextView) findViewById(R.id.gsm);
385        gprsState = (TextView) findViewById(R.id.gprs);
386        network = (TextView) findViewById(R.id.network);
387        dBm = (TextView) findViewById(R.id.dbm);
388        mMwi = (TextView) findViewById(R.id.mwi);
389        mCfi = (TextView) findViewById(R.id.cfi);
390        mLocation = (TextView) findViewById(R.id.location);
391        mNeighboringCids = (TextView) findViewById(R.id.neighboring);
392
393        resets = (TextView) findViewById(R.id.resets);
394        attempts = (TextView) findViewById(R.id.attempts);
395        successes = (TextView) findViewById(R.id.successes);
396        disconnects = (TextView) findViewById(R.id.disconnects);
397        sentSinceReceived = (TextView) findViewById(R.id.sentSinceReceived);
398        sent = (TextView) findViewById(R.id.sent);
399        received = (TextView) findViewById(R.id.received);
400        cipherState = (TextView) findViewById(R.id.ciphState);
401        smsc = (EditText) findViewById(R.id.smsc);
402        dnsCheckState = (TextView) findViewById(R.id.dnsCheckState);
403
404        mPingIpAddr = (TextView) findViewById(R.id.pingIpAddr);
405        mPingHostname = (TextView) findViewById(R.id.pingHostname);
406        mHttpClientTest = (TextView) findViewById(R.id.httpClientTest);
407
408        preferredNetworkType = (Spinner) findViewById(R.id.preferredNetworkType);
409        ArrayAdapter<String> adapter = new ArrayAdapter<String> (this,
410                android.R.layout.simple_spinner_item, mPreferredNetworkLabels);
411        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
412        preferredNetworkType.setAdapter(adapter);
413        preferredNetworkType.setOnItemSelectedListener(mPreferredNetworkHandler);
414
415        radioPowerButton = (Button) findViewById(R.id.radio_power);
416        radioPowerButton.setOnClickListener(mPowerButtonHandler);
417
418        qxdmLogButton = (Button) findViewById(R.id.qxdm_log);
419        qxdmLogButton.setOnClickListener(mQxdmButtonHandler);
420
421        cipherToggleButton = (Button) findViewById(R.id.ciph_toggle);
422        cipherToggleButton.setOnClickListener(mCipherButtonHandler);
423        pingTestButton = (Button) findViewById(R.id.ping_test);
424        pingTestButton.setOnClickListener(mPingButtonHandler);
425        updateSmscButton = (Button) findViewById(R.id.update_smsc);
426        updateSmscButton.setOnClickListener(mUpdateSmscButtonHandler);
427        refreshSmscButton = (Button) findViewById(R.id.refresh_smsc);
428        refreshSmscButton.setOnClickListener(mRefreshSmscButtonHandler);
429        dnsCheckToggleButton = (Button) findViewById(R.id.dns_check_toggle);
430        dnsCheckToggleButton.setOnClickListener(mDnsCheckButtonHandler);
431
432        mPhoneStateReceiver = new PhoneStateIntentReceiver(this, mHandler);
433        mPhoneStateReceiver.notifySignalStrength(EVENT_SIGNAL_STRENGTH_CHANGED);
434        mPhoneStateReceiver.notifyServiceState(EVENT_SERVICE_STATE_CHANGED);
435        mPhoneStateReceiver.notifyPhoneCallState(EVENT_PHONE_STATE_CHANGED);
436
437        updateQxdmState(null);
438        mOem = new OemCommands();
439
440        phone.getPreferredNetworkType(
441                mHandler.obtainMessage(EVENT_QUERY_PREFERRED_TYPE_DONE));
442        phone.getNeighboringCids(
443                mHandler.obtainMessage(EVENT_QUERY_NEIGHBORING_CIDS_DONE));
444
445        netstat = INetStatService.Stub.asInterface(ServiceManager.getService("netstat"));
446
447        CellLocation.requestLocationUpdate();
448    }
449
450    @Override
451    protected void onResume() {
452        super.onResume();
453
454        updatePhoneState();
455        updateSignalStrength();
456        updateMessageWaiting();
457        updateCallRedirect();
458        updateServiceState();
459        updateLocation(mTelephonyManager.getCellLocation());
460        updateDataState();
461        updateDataStats();
462        updateDataStats2();
463        updatePowerState();
464        updateQxdmState(null);
465        updateProperties();
466        updateCiphState();
467        updateDnsCheckState();
468
469        Log.i(TAG, "[RadioInfo] onResume: register phone & data intents");
470
471        mPhoneStateReceiver.registerIntent();
472        mTelephonyManager.listen(mPhoneStateListener,
473                  PhoneStateListener.LISTEN_DATA_CONNECTION_STATE
474                | PhoneStateListener.LISTEN_DATA_ACTIVITY
475                | PhoneStateListener.LISTEN_CELL_LOCATION
476                | PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR
477                | PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR);
478    }
479
480    @Override
481    public void onPause() {
482        super.onPause();
483
484        Log.i(TAG, "[RadioInfo] onPause: unregister phone & data intents");
485
486        mPhoneStateReceiver.unregisterIntent();
487        mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
488    }
489
490    @Override
491    public boolean onCreateOptionsMenu(Menu menu) {
492        menu.add(0, MENU_ITEM_SELECT_BAND, 0, R.string.radio_info_band_mode_label)
493                .setOnMenuItemClickListener(mSelectBandCallback)
494                .setAlphabeticShortcut('b');
495        menu.add(1, MENU_ITEM_VIEW_ADN, 0,
496                R.string.radioInfo_menu_viewADN).setOnMenuItemClickListener(mViewADNCallback);
497        menu.add(1, MENU_ITEM_VIEW_FDN, 0,
498                R.string.radioInfo_menu_viewFDN).setOnMenuItemClickListener(mViewFDNCallback);
499        menu.add(1, MENU_ITEM_VIEW_SDN, 0,
500                R.string.radioInfo_menu_viewSDN).setOnMenuItemClickListener(mViewSDNCallback);
501        menu.add(1, MENU_ITEM_GET_PDP_LIST,
502                0, R.string.radioInfo_menu_getPDP).setOnMenuItemClickListener(mGetPdpList);
503        menu.add(1, MENU_ITEM_TOGGLE_DATA,
504                0, R.string.radioInfo_menu_disableData).setOnMenuItemClickListener(mToggleData);
505        menu.add(1, MENU_ITEM_TOGGLE_DATA_ON_BOOT,
506                0, R.string.radioInfo_menu_disableDataOnBoot).setOnMenuItemClickListener(
507                mToggleDataOnBoot);
508        return true;
509    }
510
511
512    @Override
513    public boolean onPrepareOptionsMenu(Menu menu) {
514        // Get the TOGGLE DATA menu item in the right state.
515        MenuItem item = menu.findItem(MENU_ITEM_TOGGLE_DATA);
516        int state = mTelephonyManager.getDataState();
517        boolean visible = true;
518
519        switch (state) {
520            case TelephonyManager.DATA_CONNECTED:
521            case TelephonyManager.DATA_SUSPENDED:
522                item.setTitle(R.string.radioInfo_menu_disableData);
523                break;
524            case TelephonyManager.DATA_DISCONNECTED:
525                item.setTitle(R.string.radioInfo_menu_enableData);
526                break;
527            default:
528                visible = false;
529                break;
530        }
531        item.setVisible(visible);
532
533        // Get the toggle-data-on-boot menu item in the right state.
534        item = menu.findItem(MENU_ITEM_TOGGLE_DATA_ON_BOOT);
535        SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(phone.getContext());
536        boolean value = sp.getBoolean(GSMPhone.DATA_DISABLED_ON_BOOT_KEY, false);
537        if (value) {
538            item.setTitle(R.string.radioInfo_menu_enableDataOnBoot);
539        } else {
540            item.setTitle(R.string.radioInfo_menu_disableDataOnBoot);
541        }
542        return true;
543    }
544
545    private boolean isRadioOn() {
546        return phone.getServiceState().getState() != ServiceState.STATE_POWER_OFF;
547    }
548
549    private void updatePowerState() {
550        String buttonText = isRadioOn() ?
551                            getString(R.string.turn_off_radio) :
552                            getString(R.string.turn_on_radio);
553        radioPowerButton.setText(buttonText);
554    }
555
556    private void updateQxdmState(Boolean newQxdmStatus) {
557        SharedPreferences sp =
558          PreferenceManager.getDefaultSharedPreferences(phone.getContext());
559        mQxdmLogEnabled = sp.getBoolean("qxdmstatus", false);
560        // This is called from onCreate, onResume, and the handler when the status
561        // is updated.
562        if (newQxdmStatus != null) {
563            SharedPreferences.Editor editor = sp.edit();
564            editor.putBoolean("qxdmstatus", newQxdmStatus);
565            editor.commit();
566            mQxdmLogEnabled = newQxdmStatus;
567        }
568
569        String buttonText = mQxdmLogEnabled ?
570                            getString(R.string.turn_off_qxdm) :
571                            getString(R.string.turn_on_qxdm);
572        qxdmLogButton.setText(buttonText);
573    }
574
575    private void setCiphPref(boolean value) {
576        SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(phone.getContext());
577        SharedPreferences.Editor editor = sp.edit();
578        editor.putBoolean(GSMPhone.CIPHERING_KEY, value);
579        editor.commit();
580    }
581
582    private boolean getCiphPref() {
583        SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(phone.getContext());
584        boolean ret = sp.getBoolean(GSMPhone.CIPHERING_KEY, true);
585        return ret;
586    }
587
588    private void updateCiphState() {
589        cipherState.setText(getCiphPref() ? "Ciphering ON" : "Ciphering OFF");
590    }
591
592    private void updateDnsCheckState() {
593        dnsCheckState.setText(phone.isDnsCheckDisabled() ?
594                "0.0.0.0 allowed" :"0.0.0.0 not allowed");
595    }
596
597    private final void
598    updateSignalStrength() {
599        // TODO PhoneStateIntentReceiver is deprecated and PhoneStateListener
600        // should probably used instead.
601        int state = mPhoneStateReceiver.getServiceState().getState();
602        Resources r = getResources();
603
604        if ((ServiceState.STATE_OUT_OF_SERVICE == state) ||
605                (ServiceState.STATE_POWER_OFF == state)) {
606            dBm.setText("0");
607        }
608
609        int signalDbm = mPhoneStateReceiver.getSignalStrengthDbm();
610
611        if (-1 == signalDbm) signalDbm = 0;
612
613        int signalAsu = mPhoneStateReceiver.getSignalStrength();
614
615        if (-1 == signalAsu) signalAsu = 0;
616
617        dBm.setText(String.valueOf(signalDbm) + " "
618            + r.getString(R.string.radioInfo_display_dbm) + "   "
619            + String.valueOf(signalAsu) + " "
620            + r.getString(R.string.radioInfo_display_asu));
621    }
622
623    private final void updateLocation(CellLocation location) {
624        int lac = -1;
625        int cid = -1;
626        if (location instanceof GsmCellLocation) {
627            GsmCellLocation loc = (GsmCellLocation)location;
628            lac = loc.getLac();
629            cid = loc.getCid();
630        }
631
632        Resources r = getResources();
633
634        mLocation.setText(r.getString(R.string.radioInfo_lac) + " = "
635                          + ((lac == -1) ? "unknown" : Integer.toHexString(lac))
636                          + "   "
637                          + r.getString(R.string.radioInfo_cid) + " = "
638                + ((cid == -1) ? "unknown" : Integer.toHexString(cid)));
639    }
640
641    private final void updateNeighboringCids(ArrayList<NeighboringCellInfo> cids) {
642        String neighborings = "";
643        if (cids != null) {
644            if ( cids.isEmpty() ) {
645                neighborings = "no neighboring cells";
646            } else {
647                for (NeighboringCellInfo cell : cids) {
648                    neighborings += "{" + Integer.toHexString(cell.getCid())
649                    + "@" + cell.getRssi() + "} ";
650                }
651            }
652        } else {
653            neighborings = "unknown";
654        }
655        mNeighboringCids.setText(neighborings);
656    }
657
658    private final void
659    updateMessageWaiting() {
660        mMwi.setText(String.valueOf(mMwiValue));
661    }
662
663    private final void
664    updateCallRedirect() {
665        mCfi.setText(String.valueOf(mCfiValue));
666    }
667
668
669    private final void
670    updateServiceState() {
671        ServiceState serviceState = mPhoneStateReceiver.getServiceState();
672        int state = serviceState.getState();
673        Resources r = getResources();
674        String display = r.getString(R.string.radioInfo_unknown);
675
676        switch (state) {
677            case ServiceState.STATE_IN_SERVICE:
678                display = r.getString(R.string.radioInfo_service_in);
679                break;
680            case ServiceState.STATE_OUT_OF_SERVICE:
681            case ServiceState.STATE_EMERGENCY_ONLY:
682                display = r.getString(R.string.radioInfo_service_emergency);
683                break;
684            case ServiceState.STATE_POWER_OFF:
685                display = r.getString(R.string.radioInfo_service_off);
686                break;
687        }
688
689        gsmState.setText(display);
690
691        if (serviceState.getRoaming()) {
692            roamingState.setText(R.string.radioInfo_roaming_in);
693        } else {
694            roamingState.setText(R.string.radioInfo_roaming_not);
695        }
696
697        operatorName.setText(serviceState.getOperatorAlphaLong());
698    }
699
700    private final void
701    updatePhoneState() {
702        Phone.State state = mPhoneStateReceiver.getPhoneState();
703        Resources r = getResources();
704        String display = r.getString(R.string.radioInfo_unknown);
705
706        switch (state) {
707            case IDLE:
708                display = r.getString(R.string.radioInfo_phone_idle);
709                break;
710            case RINGING:
711                display = r.getString(R.string.radioInfo_phone_ringing);
712                break;
713            case OFFHOOK:
714                display = r.getString(R.string.radioInfo_phone_offhook);
715                break;
716        }
717
718        callState.setText(display);
719    }
720
721    private final void
722    updateDataState() {
723        int state = mTelephonyManager.getDataState();
724        Resources r = getResources();
725        String display = r.getString(R.string.radioInfo_unknown);
726
727        switch (state) {
728            case TelephonyManager.DATA_CONNECTED:
729                display = r.getString(R.string.radioInfo_data_connected);
730                break;
731            case TelephonyManager.DATA_CONNECTING:
732                display = r.getString(R.string.radioInfo_data_connecting);
733                break;
734            case TelephonyManager.DATA_DISCONNECTED:
735                display = r.getString(R.string.radioInfo_data_disconnected);
736                break;
737            case TelephonyManager.DATA_SUSPENDED:
738                display = r.getString(R.string.radioInfo_data_suspended);
739                break;
740        }
741
742        gprsState.setText(display);
743    }
744
745    private final void updateNetworkType() {
746        Resources r = getResources();
747        String display = SystemProperties.get(TelephonyProperties.PROPERTY_DATA_NETWORK_TYPE,
748                r.getString(R.string.radioInfo_unknown));
749
750        network.setText(display);
751    }
752
753    private final void
754    updateProperties() {
755        String s;
756        Resources r = getResources();
757
758        s = phone.getDeviceId();
759        if (s == null) s = r.getString(R.string.radioInfo_unknown);
760        mDeviceId.setText(s);
761
762
763        s = phone.getLine1Number();
764        if (s == null) s = r.getString(R.string.radioInfo_unknown);
765        number.setText(s);
766    }
767
768    private final void updateDataStats() {
769        String s;
770
771        s = SystemProperties.get("net.gsm.radio-reset", "0");
772        resets.setText(s);
773
774        s = SystemProperties.get("net.gsm.attempt-gprs", "0");
775        attempts.setText(s);
776
777        s = SystemProperties.get("net.gsm.succeed-gprs", "0");
778        successes.setText(s);
779
780        //s = SystemProperties.get("net.gsm.disconnect", "0");
781        //disconnects.setText(s);
782
783        s = SystemProperties.get("net.ppp.reset-by-timeout", "0");
784        sentSinceReceived.setText(s);
785    }
786
787    private final void updateDataStats2() {
788        Resources r = getResources();
789
790        try {
791            long txPackets = netstat.getMobileTxPackets();
792            long rxPackets = netstat.getMobileRxPackets();
793            long txBytes   = netstat.getMobileTxBytes();
794            long rxBytes   = netstat.getMobileRxBytes();
795
796            String packets = r.getString(R.string.radioInfo_display_packets);
797            String bytes   = r.getString(R.string.radioInfo_display_bytes);
798
799            sent.setText(txPackets + " " + packets + ", " + txBytes + " " + bytes);
800            received.setText(rxPackets + " " + packets + ", " + rxBytes + " " + bytes);
801        } catch (RemoteException e) {
802        }
803    }
804
805    /**
806     * Ping a IP address.
807     */
808    private final void pingIpAddr() {
809        try {
810            // This is hardcoded IP addr. This is for testing purposes.
811            // We would need to get rid of this before release.
812            String ipAddress = "74.125.47.104";
813            Process p = Runtime.getRuntime().exec("ping -c 1 " + ipAddress);
814            int status = p.waitFor();
815            if (status == 0) {
816                mPingIpAddrResult = "Pass";
817            } else {
818                mPingIpAddrResult = "Fail: IP addr not reachable";
819            }
820        } catch (IOException e) {
821            mPingIpAddrResult = "Fail: IOException";
822        } catch (InterruptedException e) {
823            mPingIpAddrResult = "Fail: InterruptedException";
824        }
825    }
826
827    /**
828     *  Ping a host name
829     */
830    private final void pingHostname() {
831        try {
832            Process p = Runtime.getRuntime().exec("ping -c 1 www.google.com");
833            int status = p.waitFor();
834            if (status == 0) {
835                mPingHostnameResult = "Pass";
836            } else {
837                mPingHostnameResult = "Fail: Host unreachable";
838            }
839        } catch (UnknownHostException e) {
840            mPingHostnameResult = "Fail: Unknown Host";
841        } catch (IOException e) {
842            mPingHostnameResult= "Fail: IOException";
843        } catch (InterruptedException e) {
844            mPingHostnameResult = "Fail: InterruptedException";
845        }
846    }
847
848    /**
849     * This function checks for basic functionality of HTTP Client.
850     */
851    private void httpClientTest() {
852        HttpClient client = new DefaultHttpClient();
853        try {
854            HttpGet request = new HttpGet("http://www.google.com");
855            HttpResponse response = client.execute(request);
856            if (response.getStatusLine().getStatusCode() == 200) {
857                mHttpClientTestResult = "Pass";
858            } else {
859                mHttpClientTestResult = "Fail: Code: " + String.valueOf(response);
860            }
861            request.abort();
862        } catch (IOException e) {
863            mHttpClientTestResult = "Fail: IOException";
864        }
865    }
866
867    private void refreshSmsc() {
868        phone.getSmscAddress(mHandler.obtainMessage(EVENT_QUERY_SMSC_DONE));
869    }
870
871    private final void updatePingState() {
872        final Handler handler = new Handler();
873        // Set all to unknown since the threads will take a few secs to update.
874        mPingIpAddrResult = getResources().getString(R.string.radioInfo_unknown);
875        mPingHostnameResult = getResources().getString(R.string.radioInfo_unknown);
876        mHttpClientTestResult = getResources().getString(R.string.radioInfo_unknown);
877
878        mPingIpAddr.setText(mPingIpAddrResult);
879        mPingHostname.setText(mPingHostnameResult);
880        mHttpClientTest.setText(mHttpClientTestResult);
881
882        final Runnable updatePingResults = new Runnable() {
883            public void run() {
884                mPingIpAddr.setText(mPingIpAddrResult);
885                mPingHostname.setText(mPingHostnameResult);
886                mHttpClientTest.setText(mHttpClientTestResult);
887            }
888        };
889        Thread ipAddr = new Thread() {
890            @Override
891            public void run() {
892                pingIpAddr();
893                handler.post(updatePingResults);
894            }
895        };
896        ipAddr.start();
897
898        Thread hostname = new Thread() {
899            @Override
900            public void run() {
901                pingHostname();
902                handler.post(updatePingResults);
903            }
904        };
905        hostname.start();
906
907        Thread httpClient = new Thread() {
908            @Override
909            public void run() {
910                httpClientTest();
911                handler.post(updatePingResults);
912            }
913        };
914        httpClient.start();
915    }
916
917    private final void updatePdpList() {
918        StringBuilder sb = new StringBuilder("========DATA=======\n");
919
920        List<DataConnection> dcs = phone.getCurrentDataConnectionList();
921
922        for (DataConnection dc : dcs) {
923            sb.append("    State: ").append(dc.getState().toString()).append("\n");
924            if (dc.getState().isActive()) {
925                long timeElapsed =
926                    (System.currentTimeMillis() - dc.getConnectionTime())/1000;
927                sb.append("    connected at ")
928                  .append(DateUtils.timeString(dc.getConnectionTime()))
929                  .append(" and elapsed ")
930                  .append(DateUtils.formatElapsedTime(timeElapsed));
931
932                if (dc instanceof PdpConnection) {
933                    PdpConnection pdp = (PdpConnection)dc;
934                    sb.append("\n    to ")
935                      .append(pdp.getApn().toString());
936                }
937                sb.append("\ninterface: ")
938                  .append(phone.getInterfaceName(phone.getActiveApnTypes()[0]))
939                  .append("\naddress: ")
940                  .append(phone.getIpAddress(phone.getActiveApnTypes()[0]))
941                  .append("\ngateway: ")
942                  .append(phone.getGateway(phone.getActiveApnTypes()[0]));
943                String[] dns = phone.getDnsServers(phone.getActiveApnTypes()[0]);
944                if (dns != null) {
945                    sb.append("\ndns: ").append(dns[0]).append(", ").append(dns[1]);
946                }
947            } else if (dc.getState().isInactive()) {
948                sb.append("    disconnected with last try at ")
949                  .append(DateUtils.timeString(dc.getLastFailTime()))
950                  .append("\n    fail because ")
951                  .append(dc.getLastFailCause().toString());
952            } else {
953                if (dc instanceof PdpConnection) {
954                    PdpConnection pdp = (PdpConnection)dc;
955                    sb.append("    is connecting to ")
956                      .append(pdp.getApn().toString());
957                } else {
958                    sb.append("    is connecting");
959                }
960            }
961            sb.append("\n===================");
962        }
963
964
965        disconnects.setText(sb.toString());
966    }
967
968    private void displayQxdmEnableResult() {
969        String status = mQxdmLogEnabled ? "Start QXDM Log" : "Stop QXDM Log";
970
971        new AlertDialog.Builder(this).setMessage(status).show();
972
973        mHandler.postDelayed(
974                new Runnable() {
975                    public void run() {
976                        finish();
977                    }
978                }, 2000);
979    }
980
981    private MenuItem.OnMenuItemClickListener mViewADNCallback = new MenuItem.OnMenuItemClickListener() {
982        public boolean onMenuItemClick(MenuItem item) {
983            Intent intent = new Intent(Intent.ACTION_VIEW);
984            // XXX We need to specify the component here because if we don't
985            // the activity manager will try to resolve the type by calling
986            // the content provider, which causes it to be loaded in a process
987            // other than the Dialer process, which causes a lot of stuff to
988            // break.
989            intent.setClassName("com.android.phone",
990                    "com.android.phone.SimContacts");
991            startActivity(intent);
992            return true;
993        }
994    };
995
996    private MenuItem.OnMenuItemClickListener mViewFDNCallback = new MenuItem.OnMenuItemClickListener() {
997        public boolean onMenuItemClick(MenuItem item) {
998            Intent intent = new Intent(Intent.ACTION_VIEW);
999            // XXX We need to specify the component here because if we don't
1000            // the activity manager will try to resolve the type by calling
1001            // the content provider, which causes it to be loaded in a process
1002            // other than the Dialer process, which causes a lot of stuff to
1003            // break.
1004            intent.setClassName("com.android.phone",
1005                    "com.android.phone.FdnList");
1006            startActivity(intent);
1007            return true;
1008        }
1009    };
1010
1011    private MenuItem.OnMenuItemClickListener mViewSDNCallback = new MenuItem.OnMenuItemClickListener() {
1012        public boolean onMenuItemClick(MenuItem item) {
1013            Intent intent = new Intent(
1014                    Intent.ACTION_VIEW, Uri.parse("content://icc/sdn"));
1015            // XXX We need to specify the component here because if we don't
1016            // the activity manager will try to resolve the type by calling
1017            // the content provider, which causes it to be loaded in a process
1018            // other than the Dialer process, which causes a lot of stuff to
1019            // break.
1020            intent.setClassName("com.android.phone",
1021                    "com.android.phone.ADNList");
1022            startActivity(intent);
1023            return true;
1024        }
1025    };
1026
1027    private void toggleDataDisabledOnBoot() {
1028        SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(phone.getContext());
1029        SharedPreferences.Editor editor = sp.edit();
1030        boolean value = sp.getBoolean(GSMPhone.DATA_DISABLED_ON_BOOT_KEY, false);
1031        editor.putBoolean(GSMPhone.DATA_DISABLED_ON_BOOT_KEY, !value);
1032        byte[] data = mOem.getPsAutoAttachData(value);
1033        if (data == null) {
1034            // don't commit
1035            return;
1036        }
1037
1038        editor.commit();
1039        phone.invokeOemRilRequestRaw(data, null);
1040    }
1041
1042    private MenuItem.OnMenuItemClickListener mToggleDataOnBoot = new MenuItem.OnMenuItemClickListener() {
1043        public boolean onMenuItemClick(MenuItem item) {
1044            toggleDataDisabledOnBoot();
1045            return true;
1046        }
1047    };
1048
1049    private MenuItem.OnMenuItemClickListener mToggleData = new MenuItem.OnMenuItemClickListener() {
1050        public boolean onMenuItemClick(MenuItem item) {
1051            int state = mTelephonyManager.getDataState();
1052            switch (state) {
1053                case TelephonyManager.DATA_CONNECTED:
1054                    phone.disableDataConnectivity();
1055                    break;
1056                case TelephonyManager.DATA_DISCONNECTED:
1057                    phone.enableDataConnectivity();
1058                    break;
1059                default:
1060                    // do nothing
1061                    break;
1062            }
1063            return true;
1064        }
1065    };
1066
1067    private MenuItem.OnMenuItemClickListener mGetPdpList = new MenuItem.OnMenuItemClickListener() {
1068        public boolean onMenuItemClick(MenuItem item) {
1069            phone.getDataCallList(null);
1070            return true;
1071        }
1072    };
1073
1074    private MenuItem.OnMenuItemClickListener mSelectBandCallback = new MenuItem.OnMenuItemClickListener() {
1075        public boolean onMenuItemClick(MenuItem item) {
1076            Intent intent = new Intent();
1077            intent.setClass(RadioInfo.this, BandMode.class);
1078            startActivity(intent);
1079            return true;
1080        }
1081    };
1082
1083    OnClickListener mPowerButtonHandler = new OnClickListener() {
1084        public void onClick(View v) {
1085            //log("toggle radio power: currently " + (isRadioOn()?"on":"off"));
1086            phone.setRadioPower(!isRadioOn());
1087        }
1088    };
1089
1090    OnClickListener mCipherButtonHandler = new OnClickListener() {
1091        public void onClick(View v) {
1092            mCipherOn = !getCiphPref();
1093            byte[] data = mOem.getCipheringData(mCipherOn);
1094
1095            if (data == null)
1096                return;
1097
1098            cipherState.setText("Setting...");
1099            phone.invokeOemRilRequestRaw(data,
1100                    mHandler.obtainMessage(EVENT_SET_CIPHER_DONE));
1101        }
1102    };
1103
1104    OnClickListener mDnsCheckButtonHandler = new OnClickListener() {
1105        public void onClick(View v) {
1106            phone.disableDnsCheck(!phone.isDnsCheckDisabled());
1107            updateDnsCheckState();
1108        }
1109    };
1110
1111    OnClickListener mPingButtonHandler = new OnClickListener() {
1112        public void onClick(View v) {
1113            updatePingState();
1114        }
1115    };
1116
1117    OnClickListener mUpdateSmscButtonHandler = new OnClickListener() {
1118        public void onClick(View v) {
1119            updateSmscButton.setEnabled(false);
1120            phone.setSmscAddress(smsc.getText().toString(),
1121                    mHandler.obtainMessage(EVENT_UPDATE_SMSC_DONE));
1122        }
1123    };
1124
1125    OnClickListener mRefreshSmscButtonHandler = new OnClickListener() {
1126        public void onClick(View v) {
1127            refreshSmsc();
1128        }
1129    };
1130
1131    OnClickListener mQxdmButtonHandler = new OnClickListener() {
1132        public void onClick(View v) {
1133            byte[] data = mOem.getQxdmSdlogData(
1134                    !mQxdmLogEnabled,
1135                    mOem.OEM_QXDM_SDLOG_DEFAULT_FILE_SIZE,
1136                    mOem.OEM_QXDM_SDLOG_DEFAULT_MASK,
1137                    mOem.OEM_QXDM_SDLOG_DEFAULT_MAX_INDEX);
1138
1139            if (data == null)
1140                return;
1141
1142            phone.invokeOemRilRequestRaw(data,
1143                    mHandler.obtainMessage(EVENT_SET_QXDMLOG_DONE));
1144        }
1145    };
1146
1147    AdapterView.OnItemSelectedListener
1148            mPreferredNetworkHandler = new AdapterView.OnItemSelectedListener() {
1149        public void onItemSelected(AdapterView parent, View v, int pos, long id) {
1150            Message msg = mHandler.obtainMessage(EVENT_SET_PREFERRED_TYPE_DONE);
1151            if (pos>=0 && pos<=7) { //IS THIS NEEDED to extend to the entire range of values
1152                phone.setPreferredNetworkType(pos, msg);
1153            }
1154        }
1155
1156        public void onNothingSelected(AdapterView parent) {
1157        }
1158    };
1159
1160    private String[] mPreferredNetworkLabels = {
1161            "WCDMA preferred",
1162            "GSM only",
1163            "WCDMA only",
1164            "GSM auto (PRL)",
1165            "CDMA auto (PRL)",
1166            "CDMA only",
1167            "EvDo only",
1168            "GSM/CDMA auto (PRL)",
1169            "Unknown"};
1170}
1171