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