1 /*
2  * Copyright (C) 2019 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 
17 package com.android.car.developeroptions;
18 
19 import static android.net.ConnectivityManager.NetworkCallback;
20 import static android.provider.Settings.Global.PREFERRED_NETWORK_MODE;
21 
22 import android.app.Activity;
23 import android.app.QueuedWork;
24 import android.content.ComponentName;
25 import android.content.Context;
26 import android.content.DialogInterface;
27 import android.content.Intent;
28 import android.content.pm.PackageManager;
29 import android.content.pm.ResolveInfo;
30 import android.content.res.Resources;
31 import android.graphics.Typeface;
32 import android.net.ConnectivityManager;
33 import android.net.Network;
34 import android.net.NetworkCapabilities;
35 import android.net.NetworkRequest;
36 import android.net.TrafficStats;
37 import android.net.Uri;
38 import android.os.AsyncResult;
39 import android.os.Build;
40 import android.os.Bundle;
41 import android.os.Handler;
42 import android.os.Message;
43 import android.provider.Settings;
44 import android.telephony.CarrierConfigManager;
45 import android.telephony.CellIdentityCdma;
46 import android.telephony.CellIdentityGsm;
47 import android.telephony.CellIdentityLte;
48 import android.telephony.CellIdentityWcdma;
49 import android.telephony.CellInfo;
50 import android.telephony.CellInfoCdma;
51 import android.telephony.CellInfoGsm;
52 import android.telephony.CellInfoLte;
53 import android.telephony.CellInfoWcdma;
54 import android.telephony.CellLocation;
55 import android.telephony.CellSignalStrengthCdma;
56 import android.telephony.CellSignalStrengthGsm;
57 import android.telephony.CellSignalStrengthLte;
58 import android.telephony.CellSignalStrengthWcdma;
59 import android.telephony.PhoneStateListener;
60 import android.telephony.PhysicalChannelConfig;
61 import android.telephony.PreciseCallState;
62 import android.telephony.ServiceState;
63 import android.telephony.SignalStrength;
64 import android.telephony.SubscriptionManager;
65 import android.telephony.TelephonyManager;
66 import android.telephony.cdma.CdmaCellLocation;
67 import android.telephony.gsm.GsmCellLocation;
68 import android.text.TextUtils;
69 import android.util.Log;
70 import android.view.Menu;
71 import android.view.MenuItem;
72 import android.view.View;
73 import android.view.View.OnClickListener;
74 import android.widget.AdapterView;
75 import android.widget.ArrayAdapter;
76 import android.widget.Button;
77 import android.widget.CompoundButton;
78 import android.widget.CompoundButton.OnCheckedChangeListener;
79 import android.widget.EditText;
80 import android.widget.Spinner;
81 import android.widget.Switch;
82 import android.widget.TextView;
83 
84 import androidx.appcompat.app.AlertDialog;
85 import androidx.appcompat.app.AlertDialog.Builder;
86 
87 import com.android.ims.ImsConfig;
88 import com.android.ims.ImsException;
89 import com.android.ims.ImsManager;
90 import com.android.internal.telephony.Phone;
91 import com.android.internal.telephony.PhoneFactory;
92 
93 import java.io.IOException;
94 import java.net.HttpURLConnection;
95 import java.net.URL;
96 import java.util.List;
97 
98 // TODO(b/123598192) consider to move this activity to telephony package.
99 public class RadioInfo extends Activity {
100     private static final String TAG = "RadioInfo";
101 
102     private static final String[] mPreferredNetworkLabels = {
103             "WCDMA preferred",
104             "GSM only",
105             "WCDMA only",
106             "GSM auto (PRL)",
107             "CDMA auto (PRL)",
108             "CDMA only",
109             "EvDo only",
110             "Global auto (PRL)",
111             "LTE/CDMA auto (PRL)",
112             "LTE/UMTS auto (PRL)",
113             "LTE/CDMA/UMTS auto (PRL)",
114             "LTE only",
115             "LTE/WCDMA",
116             "TD-SCDMA only",
117             "TD-SCDMA/WCDMA",
118             "LTE/TD-SCDMA",
119             "TD-SCDMA/GSM",
120             "TD-SCDMA/UMTS",
121             "LTE/TD-SCDMA/WCDMA",
122             "LTE/TD-SCDMA/UMTS",
123             "TD-SCDMA/CDMA/UMTS",
124             "Global/TD-SCDMA",
125             "Unknown"
126     };
127 
128 
129     private static final int CELL_INFO_LIST_RATE_DISABLED = Integer.MAX_VALUE;
130     private static final int CELL_INFO_LIST_RATE_MAX = 0;
131 
132 
133     private static final int IMS_VOLTE_PROVISIONED_CONFIG_ID =
134         ImsConfig.ConfigConstants.VLT_SETTING_ENABLED;
135 
136     private static final int IMS_VT_PROVISIONED_CONFIG_ID =
137         ImsConfig.ConfigConstants.LVC_SETTING_ENABLED;
138 
139     private static final int IMS_WFC_PROVISIONED_CONFIG_ID =
140         ImsConfig.ConfigConstants.VOICE_OVER_WIFI_SETTING_ENABLED;
141 
142     private static final int EAB_PROVISIONED_CONFIG_ID =
143         ImsConfig.ConfigConstants.EAB_SETTING_ENABLED;
144 
145     //Values in must match mCellInfoRefreshRates
146     private static final String[] mCellInfoRefreshRateLabels = {
147             "Disabled",
148             "Immediate",
149             "Min 5s",
150             "Min 10s",
151             "Min 60s"
152     };
153 
154     //Values in seconds, must match mCellInfoRefreshRateLabels
155     private static final int mCellInfoRefreshRates[] = {
156         CELL_INFO_LIST_RATE_DISABLED,
157         CELL_INFO_LIST_RATE_MAX,
158         5000,
159         10000,
160         60000
161     };
162 
log(String s)163     private void log(String s) {
164         Log.d(TAG, s);
165     }
166 
167     private static final int EVENT_CFI_CHANGED = 302;
168 
169     private static final int EVENT_QUERY_PREFERRED_TYPE_DONE = 1000;
170     private static final int EVENT_SET_PREFERRED_TYPE_DONE = 1001;
171     private static final int EVENT_QUERY_SMSC_DONE = 1005;
172     private static final int EVENT_UPDATE_SMSC_DONE = 1006;
173     private static final int EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED = 1007;
174 
175     private static final int MENU_ITEM_SELECT_BAND  = 0;
176     private static final int MENU_ITEM_VIEW_ADN     = 1;
177     private static final int MENU_ITEM_VIEW_FDN     = 2;
178     private static final int MENU_ITEM_VIEW_SDN     = 3;
179     private static final int MENU_ITEM_GET_IMS_STATUS = 4;
180     private static final int MENU_ITEM_TOGGLE_DATA  = 5;
181 
182     private TextView mDeviceId; //DeviceId is the IMEI in GSM and the MEID in CDMA
183     private TextView number;
184     private TextView mSubscriberId;
185     private TextView callState;
186     private TextView operatorName;
187     private TextView roamingState;
188     private TextView gsmState;
189     private TextView gprsState;
190     private TextView voiceNetwork;
191     private TextView dataNetwork;
192     private TextView dBm;
193     private TextView mMwi;
194     private TextView mCfi;
195     private TextView mLocation;
196     private TextView mCellInfo;
197     private TextView sent;
198     private TextView received;
199     private TextView mPingHostnameV4;
200     private TextView mPingHostnameV6;
201     private TextView mHttpClientTest;
202     private TextView mPhyChanConfig;
203     private TextView dnsCheckState;
204     private TextView mDownlinkKbps;
205     private TextView mUplinkKbps;
206     private EditText smsc;
207     private Switch radioPowerOnSwitch;
208     private Button cellInfoRefreshRateButton;
209     private Button dnsCheckToggleButton;
210     private Button pingTestButton;
211     private Button updateSmscButton;
212     private Button refreshSmscButton;
213     private Button oemInfoButton;
214     private Button carrierProvisioningButton;
215     private Button triggercarrierProvisioningButton;
216     private Switch imsVolteProvisionedSwitch;
217     private Switch imsVtProvisionedSwitch;
218     private Switch imsWfcProvisionedSwitch;
219     private Switch eabProvisionedSwitch;
220     private Switch cbrsDataSwitch;
221     private Switch dsdsSwitch;
222     private Spinner preferredNetworkType;
223     private Spinner cellInfoRefreshRateSpinner;
224 
225     private ConnectivityManager mConnectivityManager;
226     private TelephonyManager mTelephonyManager;
227     private ImsManager mImsManager = null;
228     private Phone phone = null;
229 
230     private String mPingHostnameResultV4;
231     private String mPingHostnameResultV6;
232     private String mHttpClientTestResult;
233     private boolean mMwiValue = false;
234     private boolean mCfiValue = false;
235 
236     private List<CellInfo> mCellInfoResult = null;
237     private CellLocation mCellLocationResult = null;
238 
239     private int mPreferredNetworkTypeResult;
240     private int mCellInfoRefreshRateIndex;
241 
242     private final NetworkRequest mDefaultNetworkRequest = new NetworkRequest.Builder()
243             .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
244             .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
245             .build();
246 
247     private final NetworkCallback mNetworkCallback = new NetworkCallback() {
248         public void onCapabilitiesChanged(Network n, NetworkCapabilities nc) {
249             int dlbw = nc.getLinkDownstreamBandwidthKbps();
250             int ulbw = nc.getLinkUpstreamBandwidthKbps();
251             updateBandwidths(dlbw, ulbw);
252         }
253     };
254 
255     private final PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
256         @Override
257         public void onDataConnectionStateChanged(int state) {
258             updateDataState();
259             updateNetworkType();
260         }
261 
262         @Override
263         public void onDataActivity(int direction) {
264             updateDataStats2();
265         }
266 
267         @Override
268         public void onCallStateChanged(int state, String incomingNumber) {
269             updateNetworkType();
270             updatePhoneState(state);
271         }
272 
273         @Override
274         public void onPreciseCallStateChanged(PreciseCallState preciseState) {
275             updateNetworkType();
276         }
277 
278         @Override
279         public void onCellLocationChanged(CellLocation location) {
280             updateLocation(location);
281         }
282 
283         @Override
284         public void onMessageWaitingIndicatorChanged(boolean mwi) {
285             mMwiValue = mwi;
286             updateMessageWaiting();
287         }
288 
289         @Override
290         public void onCallForwardingIndicatorChanged(boolean cfi) {
291             mCfiValue = cfi;
292             updateCallRedirect();
293         }
294 
295         @Override
296         public void onCellInfoChanged(List<CellInfo> arrayCi) {
297             log("onCellInfoChanged: arrayCi=" + arrayCi);
298             mCellInfoResult = arrayCi;
299             updateCellInfo(mCellInfoResult);
300         }
301 
302         @Override
303         public void onSignalStrengthsChanged(SignalStrength signalStrength) {
304             log("onSignalStrengthChanged: SignalStrength=" +signalStrength);
305             updateSignalStrength(signalStrength);
306         }
307 
308         @Override
309         public void onServiceStateChanged(ServiceState serviceState) {
310             log("onServiceStateChanged: ServiceState=" + serviceState);
311             updateServiceState(serviceState);
312             updateRadioPowerState();
313             updateNetworkType();
314             updateImsProvisionedState();
315         }
316 
317     };
318 
updatePhysicalChannelConfiguration(List<PhysicalChannelConfig> configs)319     private void updatePhysicalChannelConfiguration(List<PhysicalChannelConfig> configs) {
320             StringBuilder sb = new StringBuilder();
321             String div = "";
322             sb.append("{");
323             if (configs != null) {
324                 for(PhysicalChannelConfig c : configs) {
325                     sb.append(div).append(c);
326                     div = ",";
327                 }
328             }
329             sb.append("}");
330             mPhyChanConfig.setText(sb.toString());
331     }
332 
updatePreferredNetworkType(int type)333     private void updatePreferredNetworkType(int type) {
334         if (type >= mPreferredNetworkLabels.length || type < 0) {
335             log("EVENT_QUERY_PREFERRED_TYPE_DONE: unknown " +
336                     "type=" + type);
337             type = mPreferredNetworkLabels.length - 1; //set to Unknown
338         }
339         mPreferredNetworkTypeResult = type;
340 
341         preferredNetworkType.setSelection(mPreferredNetworkTypeResult, true);
342     }
343 
344     private Handler mHandler = new Handler() {
345         @Override
346         public void handleMessage(Message msg) {
347             AsyncResult ar;
348             switch (msg.what) {
349                 case EVENT_QUERY_PREFERRED_TYPE_DONE:
350                     ar= (AsyncResult) msg.obj;
351                     if (ar.exception == null && ar.result != null) {
352                         updatePreferredNetworkType(((int[])ar.result)[0]);
353                     } else {
354                         //In case of an exception, we will set this to unknown
355                         updatePreferredNetworkType(mPreferredNetworkLabels.length-1);
356                     }
357                     break;
358                 case EVENT_SET_PREFERRED_TYPE_DONE:
359                     ar= (AsyncResult) msg.obj;
360                     if (ar.exception != null) {
361                         log("Set preferred network type failed.");
362                     }
363                     break;
364                 case EVENT_QUERY_SMSC_DONE:
365                     ar= (AsyncResult) msg.obj;
366                     if (ar.exception != null) {
367                         smsc.setText("refresh error");
368                     } else {
369                         smsc.setText((String)ar.result);
370                     }
371                     break;
372                 case EVENT_UPDATE_SMSC_DONE:
373                     updateSmscButton.setEnabled(true);
374                     ar= (AsyncResult) msg.obj;
375                     if (ar.exception != null) {
376                         smsc.setText("update error");
377                     }
378                     break;
379                 case EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED:
380                     ar = (AsyncResult) msg.obj;
381                     if (ar.exception != null) {
382                         mPhyChanConfig.setText(("update error"));
383                     }
384                     updatePhysicalChannelConfiguration((List<PhysicalChannelConfig>) ar.result);
385                     break;
386                 default:
387                     super.handleMessage(msg);
388                     break;
389 
390             }
391         }
392     };
393 
394     @Override
onCreate(Bundle icicle)395     public void onCreate(Bundle icicle) {
396         super.onCreate(icicle);
397         if (!android.os.Process.myUserHandle().isSystem()) {
398             Log.e(TAG, "Not run from system user, don't do anything.");
399             finish();
400             return;
401         }
402 
403         setContentView(R.layout.radio_info);
404 
405         log("Started onCreate");
406 
407         mTelephonyManager = (TelephonyManager)getSystemService(TELEPHONY_SERVICE);
408         mConnectivityManager = (ConnectivityManager)getSystemService(CONNECTIVITY_SERVICE);
409         phone = PhoneFactory.getDefaultPhone();
410 
411         //TODO: Need to update this if the default phoneId changes?
412         //      Better to have an instance per phone?
413         mImsManager = ImsManager.getInstance(getApplicationContext(),
414                 SubscriptionManager.getDefaultVoicePhoneId());
415 
416         mDeviceId = (TextView) findViewById(R.id.imei);
417         number = (TextView) findViewById(R.id.number);
418         mSubscriberId = (TextView) findViewById(R.id.imsi);
419         callState = (TextView) findViewById(R.id.call);
420         operatorName = (TextView) findViewById(R.id.operator);
421         roamingState = (TextView) findViewById(R.id.roaming);
422         gsmState = (TextView) findViewById(R.id.gsm);
423         gprsState = (TextView) findViewById(R.id.gprs);
424         voiceNetwork = (TextView) findViewById(R.id.voice_network);
425         dataNetwork = (TextView) findViewById(R.id.data_network);
426         dBm = (TextView) findViewById(R.id.dbm);
427         mMwi = (TextView) findViewById(R.id.mwi);
428         mCfi = (TextView) findViewById(R.id.cfi);
429         mLocation = (TextView) findViewById(R.id.location);
430         mCellInfo = (TextView) findViewById(R.id.cellinfo);
431         mCellInfo.setTypeface(Typeface.MONOSPACE);
432 
433         sent = (TextView) findViewById(R.id.sent);
434         received = (TextView) findViewById(R.id.received);
435         smsc = (EditText) findViewById(R.id.smsc);
436         dnsCheckState = (TextView) findViewById(R.id.dnsCheckState);
437         mPingHostnameV4 = (TextView) findViewById(R.id.pingHostnameV4);
438         mPingHostnameV6 = (TextView) findViewById(R.id.pingHostnameV6);
439         mHttpClientTest = (TextView) findViewById(R.id.httpClientTest);
440 
441         mPhyChanConfig = (TextView) findViewById(R.id.phy_chan_config);
442 
443         preferredNetworkType = (Spinner) findViewById(R.id.preferredNetworkType);
444         ArrayAdapter<String> adapter = new ArrayAdapter<String> (this,
445                 android.R.layout.simple_spinner_item, mPreferredNetworkLabels);
446         adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
447         preferredNetworkType.setAdapter(adapter);
448 
449         cellInfoRefreshRateSpinner = (Spinner) findViewById(R.id.cell_info_rate_select);
450         ArrayAdapter<String> cellInfoAdapter = new ArrayAdapter<String>(this,
451                 android.R.layout.simple_spinner_item, mCellInfoRefreshRateLabels);
452         cellInfoAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
453         cellInfoRefreshRateSpinner.setAdapter(cellInfoAdapter);
454 
455         imsVolteProvisionedSwitch = (Switch) findViewById(R.id.volte_provisioned_switch);
456         imsVtProvisionedSwitch = (Switch) findViewById(R.id.vt_provisioned_switch);
457         imsWfcProvisionedSwitch = (Switch) findViewById(R.id.wfc_provisioned_switch);
458         eabProvisionedSwitch = (Switch) findViewById(R.id.eab_provisioned_switch);
459 
460         if (!ImsManager.isImsSupportedOnDevice(phone.getContext())) {
461             imsVolteProvisionedSwitch.setVisibility(View.GONE);
462             imsVtProvisionedSwitch.setVisibility(View.GONE);
463             imsWfcProvisionedSwitch.setVisibility(View.GONE);
464             eabProvisionedSwitch.setVisibility(View.GONE);
465         }
466 
467         cbrsDataSwitch = (Switch) findViewById(R.id.cbrs_data_switch);
468         cbrsDataSwitch.setVisibility(isCbrsSupported() ? View.VISIBLE : View.GONE);
469 
470         dsdsSwitch = findViewById(R.id.dsds_switch);
471         if (isDsdsSupported()) {
472             dsdsSwitch.setVisibility(View.VISIBLE);
473             dsdsSwitch.setOnClickListener(v -> {
474                 if (mTelephonyManager.doesSwitchMultiSimConfigTriggerReboot()) {
475                     // Undo the click action until user clicks the confirm dialog.
476                     dsdsSwitch.toggle();
477                     showDsdsChangeDialog();
478                 } else {
479                     performDsdsSwitch();
480                 }
481             });
482             dsdsSwitch.setChecked(isDsdsEnabled());
483         } else {
484             dsdsSwitch.setVisibility(View.GONE);
485         }
486 
487         radioPowerOnSwitch = (Switch) findViewById(R.id.radio_power);
488 
489         mDownlinkKbps = (TextView) findViewById(R.id.dl_kbps);
490         mUplinkKbps = (TextView) findViewById(R.id.ul_kbps);
491         updateBandwidths(0, 0);
492 
493         pingTestButton = (Button) findViewById(R.id.ping_test);
494         pingTestButton.setOnClickListener(mPingButtonHandler);
495         updateSmscButton = (Button) findViewById(R.id.update_smsc);
496         updateSmscButton.setOnClickListener(mUpdateSmscButtonHandler);
497         refreshSmscButton = (Button) findViewById(R.id.refresh_smsc);
498         refreshSmscButton.setOnClickListener(mRefreshSmscButtonHandler);
499         dnsCheckToggleButton = (Button) findViewById(R.id.dns_check_toggle);
500         dnsCheckToggleButton.setOnClickListener(mDnsCheckButtonHandler);
501         carrierProvisioningButton = (Button) findViewById(R.id.carrier_provisioning);
502         carrierProvisioningButton.setOnClickListener(mCarrierProvisioningButtonHandler);
503         triggercarrierProvisioningButton = (Button) findViewById(R.id.trigger_carrier_provisioning);
504         triggercarrierProvisioningButton.setOnClickListener(
505                 mTriggerCarrierProvisioningButtonHandler);
506 
507         oemInfoButton = (Button) findViewById(R.id.oem_info);
508         oemInfoButton.setOnClickListener(mOemInfoButtonHandler);
509         PackageManager pm = getPackageManager();
510         Intent oemInfoIntent = new Intent("com.android.car.developeroptions.OEM_RADIO_INFO");
511         List<ResolveInfo> oemInfoIntentList = pm.queryIntentActivities(oemInfoIntent, 0);
512         if (oemInfoIntentList.size() == 0) {
513             oemInfoButton.setEnabled(false);
514         }
515 
516         mCellInfoRefreshRateIndex = 0; //disabled
517         mPreferredNetworkTypeResult = mPreferredNetworkLabels.length - 1; //Unknown
518 
519         //FIXME: Replace with TelephonyManager call
520         phone.getPreferredNetworkType(
521                 mHandler.obtainMessage(EVENT_QUERY_PREFERRED_TYPE_DONE));
522 
523         restoreFromBundle(icicle);
524     }
525 
526     @Override
onResume()527     protected void onResume() {
528         super.onResume();
529 
530         log("Started onResume");
531 
532         updateMessageWaiting();
533         updateCallRedirect();
534         updateDataState();
535         updateDataStats2();
536         updateRadioPowerState();
537         updateImsProvisionedState();
538         updateProperties();
539         updateDnsCheckState();
540         updateNetworkType();
541 
542         updateLocation(mCellLocationResult);
543         updateCellInfo(mCellInfoResult);
544 
545         mPingHostnameV4.setText(mPingHostnameResultV4);
546         mPingHostnameV6.setText(mPingHostnameResultV6);
547         mHttpClientTest.setText(mHttpClientTestResult);
548 
549         cellInfoRefreshRateSpinner.setOnItemSelectedListener(mCellInfoRefreshRateHandler);
550         //set selection after registering listener to force update
551         cellInfoRefreshRateSpinner.setSelection(mCellInfoRefreshRateIndex);
552 
553         //set selection before registering to prevent update
554         preferredNetworkType.setSelection(mPreferredNetworkTypeResult, true);
555         preferredNetworkType.setOnItemSelectedListener(mPreferredNetworkHandler);
556 
557         radioPowerOnSwitch.setOnCheckedChangeListener(mRadioPowerOnChangeListener);
558         imsVolteProvisionedSwitch.setOnCheckedChangeListener(mImsVolteCheckedChangeListener);
559         imsVtProvisionedSwitch.setOnCheckedChangeListener(mImsVtCheckedChangeListener);
560         imsWfcProvisionedSwitch.setOnCheckedChangeListener(mImsWfcCheckedChangeListener);
561         eabProvisionedSwitch.setOnCheckedChangeListener(mEabCheckedChangeListener);
562 
563         if (isCbrsSupported()) {
564             cbrsDataSwitch.setChecked(getCbrsDataState());
565             cbrsDataSwitch.setOnCheckedChangeListener(mCbrsDataSwitchChangeListener);
566         }
567 
568         mTelephonyManager.listen(mPhoneStateListener,
569                   PhoneStateListener.LISTEN_CALL_STATE
570         //b/27803938 - RadioInfo currently cannot read PRECISE_CALL_STATE
571         //      | PhoneStateListener.LISTEN_PRECISE_CALL_STATE
572                 | PhoneStateListener.LISTEN_DATA_CONNECTION_STATE
573                 | PhoneStateListener.LISTEN_DATA_ACTIVITY
574                 | PhoneStateListener.LISTEN_CELL_LOCATION
575                 | PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR
576                 | PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR
577                 | PhoneStateListener.LISTEN_CELL_INFO
578                 | PhoneStateListener.LISTEN_SERVICE_STATE
579                 | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS);
580         phone.registerForPhysicalChannelConfig(mHandler,
581             EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED, null);
582 
583         mConnectivityManager.registerNetworkCallback(
584                 mDefaultNetworkRequest, mNetworkCallback, mHandler);
585 
586         smsc.clearFocus();
587     }
588 
589     @Override
onPause()590     protected void onPause() {
591         super.onPause();
592 
593         log("onPause: unregister phone & data intents");
594 
595         mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
596         mTelephonyManager.setCellInfoListRate(CELL_INFO_LIST_RATE_DISABLED);
597         mConnectivityManager.unregisterNetworkCallback(mNetworkCallback);
598         phone.unregisterForPhysicalChannelConfig(mHandler);
599     }
600 
restoreFromBundle(Bundle b)601     private void restoreFromBundle(Bundle b) {
602         if(b == null) {
603             return;
604         }
605 
606         mPingHostnameResultV4 = b.getString("mPingHostnameResultV4","");
607         mPingHostnameResultV6 = b.getString("mPingHostnameResultV6","");
608         mHttpClientTestResult = b.getString("mHttpClientTestResult","");
609 
610         mPingHostnameV4.setText(mPingHostnameResultV4);
611         mPingHostnameV6.setText(mPingHostnameResultV6);
612         mHttpClientTest.setText(mHttpClientTestResult);
613 
614         mPreferredNetworkTypeResult = b.getInt("mPreferredNetworkTypeResult",
615                                                mPreferredNetworkLabels.length - 1);
616 
617         mCellInfoRefreshRateIndex = b.getInt("mCellInfoRefreshRateIndex", 0);
618     }
619 
620     @Override
onSaveInstanceState(Bundle outState)621     protected void onSaveInstanceState(Bundle outState) {
622         outState.putString("mPingHostnameResultV4", mPingHostnameResultV4);
623         outState.putString("mPingHostnameResultV6", mPingHostnameResultV6);
624         outState.putString("mHttpClientTestResult", mHttpClientTestResult);
625 
626         outState.putInt("mPreferredNetworkTypeResult", mPreferredNetworkTypeResult);
627         outState.putInt("mCellInfoRefreshRateIndex", mCellInfoRefreshRateIndex);
628 
629     }
630 
631     @Override
onCreateOptionsMenu(Menu menu)632     public boolean onCreateOptionsMenu(Menu menu) {
633         menu.add(0, MENU_ITEM_SELECT_BAND, 0, R.string.radio_info_band_mode_label)
634                 .setOnMenuItemClickListener(mSelectBandCallback)
635                 .setAlphabeticShortcut('b');
636         menu.add(1, MENU_ITEM_VIEW_ADN, 0,
637                 R.string.radioInfo_menu_viewADN).setOnMenuItemClickListener(mViewADNCallback);
638         menu.add(1, MENU_ITEM_VIEW_FDN, 0,
639                 R.string.radioInfo_menu_viewFDN).setOnMenuItemClickListener(mViewFDNCallback);
640         menu.add(1, MENU_ITEM_VIEW_SDN, 0,
641                 R.string.radioInfo_menu_viewSDN).setOnMenuItemClickListener(mViewSDNCallback);
642         if (ImsManager.isImsSupportedOnDevice(phone.getContext())) {
643             menu.add(1, MENU_ITEM_GET_IMS_STATUS,
644                     0, R.string.radioInfo_menu_getIMS).setOnMenuItemClickListener(mGetImsStatus);
645         }
646         menu.add(1, MENU_ITEM_TOGGLE_DATA,
647                 0, R.string.radio_info_data_connection_disable).setOnMenuItemClickListener(mToggleData);
648         return true;
649     }
650 
651     @Override
onPrepareOptionsMenu(Menu menu)652     public boolean onPrepareOptionsMenu(Menu menu) {
653         // Get the TOGGLE DATA menu item in the right state.
654         MenuItem item = menu.findItem(MENU_ITEM_TOGGLE_DATA);
655         int state = mTelephonyManager.getDataState();
656         boolean visible = true;
657 
658         switch (state) {
659             case TelephonyManager.DATA_CONNECTED:
660             case TelephonyManager.DATA_SUSPENDED:
661                 item.setTitle(R.string.radio_info_data_connection_disable);
662                 break;
663             case TelephonyManager.DATA_DISCONNECTED:
664                 item.setTitle(R.string.radio_info_data_connection_enable);
665                 break;
666             default:
667                 visible = false;
668                 break;
669         }
670         item.setVisible(visible);
671         return true;
672     }
673 
updateDnsCheckState()674     private void updateDnsCheckState() {
675         //FIXME: Replace with a TelephonyManager call
676         dnsCheckState.setText(phone.isDnsCheckDisabled() ?
677                 "0.0.0.0 allowed" :"0.0.0.0 not allowed");
678     }
679 
updateBandwidths(int dlbw, int ulbw)680     private void updateBandwidths(int dlbw, int ulbw) {
681         dlbw = (dlbw < 0 || dlbw == Integer.MAX_VALUE) ? -1 : dlbw;
682         ulbw = (ulbw < 0 || ulbw == Integer.MAX_VALUE) ? -1 : ulbw;
683         mDownlinkKbps.setText(String.format("%-5d", dlbw));
684         mUplinkKbps.setText(String.format("%-5d", ulbw));
685     }
686 
687 
688     private final void
updateSignalStrength(SignalStrength signalStrength)689     updateSignalStrength(SignalStrength signalStrength) {
690         Resources r = getResources();
691 
692         int signalDbm = signalStrength.getDbm();
693 
694         int signalAsu = signalStrength.getAsuLevel();
695 
696         if (-1 == signalAsu) signalAsu = 0;
697 
698         dBm.setText(String.valueOf(signalDbm) + " "
699             + r.getString(R.string.radioInfo_display_dbm) + "   "
700             + String.valueOf(signalAsu) + " "
701             + r.getString(R.string.radioInfo_display_asu));
702     }
703 
updateLocation(CellLocation location)704     private final void updateLocation(CellLocation location) {
705         Resources r = getResources();
706         if (location instanceof GsmCellLocation) {
707             GsmCellLocation loc = (GsmCellLocation)location;
708             int lac = loc.getLac();
709             int cid = loc.getCid();
710             mLocation.setText(r.getString(R.string.radioInfo_lac) + " = "
711                     + ((lac == -1) ? "unknown" : Integer.toHexString(lac))
712                     + "   "
713                     + r.getString(R.string.radioInfo_cid) + " = "
714                     + ((cid == -1) ? "unknown" : Integer.toHexString(cid)));
715         } else if (location instanceof CdmaCellLocation) {
716             CdmaCellLocation loc = (CdmaCellLocation)location;
717             int bid = loc.getBaseStationId();
718             int sid = loc.getSystemId();
719             int nid = loc.getNetworkId();
720             int lat = loc.getBaseStationLatitude();
721             int lon = loc.getBaseStationLongitude();
722             mLocation.setText("BID = "
723                     + ((bid == -1) ? "unknown" : Integer.toHexString(bid))
724                     + "   "
725                     + "SID = "
726                     + ((sid == -1) ? "unknown" : Integer.toHexString(sid))
727                     + "   "
728                     + "NID = "
729                     + ((nid == -1) ? "unknown" : Integer.toHexString(nid))
730                     + "\n"
731                     + "LAT = "
732                     + ((lat == -1) ? "unknown" : Integer.toHexString(lat))
733                     + "   "
734                     + "LONG = "
735                     + ((lon == -1) ? "unknown" : Integer.toHexString(lon)));
736         } else {
737             mLocation.setText("unknown");
738         }
739 
740 
741     }
742 
getCellInfoDisplayString(int i)743     private final String getCellInfoDisplayString(int i) {
744         return (i != Integer.MAX_VALUE) ? Integer.toString(i) : "";
745     }
746 
getCellInfoDisplayString(long i)747     private final String getCellInfoDisplayString(long i) {
748         return (i != Long.MAX_VALUE) ? Long.toString(i) : "";
749     }
750 
getConnectionStatusString(CellInfo ci)751     private final String getConnectionStatusString(CellInfo ci) {
752         String regStr = "";
753         String connStatStr = "";
754         String connector = "";
755 
756         if (ci.isRegistered()) {
757             regStr = "R";
758         }
759         switch (ci.getCellConnectionStatus()) {
760             case CellInfo.CONNECTION_PRIMARY_SERVING: connStatStr = "P"; break;
761             case CellInfo.CONNECTION_SECONDARY_SERVING: connStatStr = "S"; break;
762             case CellInfo.CONNECTION_NONE: connStatStr = "N"; break;
763             case CellInfo.CONNECTION_UNKNOWN: /* Field is unsupported */ break;
764             default: break;
765         }
766         if (!TextUtils.isEmpty(regStr) && !TextUtils.isEmpty(connStatStr)) {
767             connector = "+";
768         }
769 
770         return regStr + connector + connStatStr;
771     }
772 
buildCdmaInfoString(CellInfoCdma ci)773     private final String buildCdmaInfoString(CellInfoCdma ci) {
774         CellIdentityCdma cidCdma = ci.getCellIdentity();
775         CellSignalStrengthCdma ssCdma = ci.getCellSignalStrength();
776 
777         return String.format("%-3.3s %-5.5s %-5.5s %-5.5s %-6.6s %-6.6s %-6.6s %-6.6s %-5.5s",
778                 getConnectionStatusString(ci),
779                 getCellInfoDisplayString(cidCdma.getSystemId()),
780                 getCellInfoDisplayString(cidCdma.getNetworkId()),
781                 getCellInfoDisplayString(cidCdma.getBasestationId()),
782                 getCellInfoDisplayString(ssCdma.getCdmaDbm()),
783                 getCellInfoDisplayString(ssCdma.getCdmaEcio()),
784                 getCellInfoDisplayString(ssCdma.getEvdoDbm()),
785                 getCellInfoDisplayString(ssCdma.getEvdoEcio()),
786                 getCellInfoDisplayString(ssCdma.getEvdoSnr()));
787     }
788 
buildGsmInfoString(CellInfoGsm ci)789     private final String buildGsmInfoString(CellInfoGsm ci) {
790         CellIdentityGsm cidGsm = ci.getCellIdentity();
791         CellSignalStrengthGsm ssGsm = ci.getCellSignalStrength();
792 
793         return String.format("%-3.3s %-3.3s %-3.3s %-5.5s %-5.5s %-6.6s %-4.4s %-4.4s\n",
794                 getConnectionStatusString(ci),
795                 getCellInfoDisplayString(cidGsm.getMcc()),
796                 getCellInfoDisplayString(cidGsm.getMnc()),
797                 getCellInfoDisplayString(cidGsm.getLac()),
798                 getCellInfoDisplayString(cidGsm.getCid()),
799                 getCellInfoDisplayString(cidGsm.getArfcn()),
800                 getCellInfoDisplayString(cidGsm.getBsic()),
801                 getCellInfoDisplayString(ssGsm.getDbm()));
802     }
803 
buildLteInfoString(CellInfoLte ci)804     private final String buildLteInfoString(CellInfoLte ci) {
805         CellIdentityLte cidLte = ci.getCellIdentity();
806         CellSignalStrengthLte ssLte = ci.getCellSignalStrength();
807 
808         return String.format(
809                 "%-3.3s %-3.3s %-3.3s %-5.5s %-5.5s %-3.3s %-6.6s %-2.2s %-4.4s %-4.4s %-2.2s\n",
810                 getConnectionStatusString(ci),
811                 getCellInfoDisplayString(cidLte.getMcc()),
812                 getCellInfoDisplayString(cidLte.getMnc()),
813                 getCellInfoDisplayString(cidLte.getTac()),
814                 getCellInfoDisplayString(cidLte.getCi()),
815                 getCellInfoDisplayString(cidLte.getPci()),
816                 getCellInfoDisplayString(cidLte.getEarfcn()),
817                 getCellInfoDisplayString(cidLte.getBandwidth()),
818                 getCellInfoDisplayString(ssLte.getDbm()),
819                 getCellInfoDisplayString(ssLte.getRsrq()),
820                 getCellInfoDisplayString(ssLte.getTimingAdvance()));
821     }
822 
buildWcdmaInfoString(CellInfoWcdma ci)823     private final String buildWcdmaInfoString(CellInfoWcdma ci) {
824         CellIdentityWcdma cidWcdma = ci.getCellIdentity();
825         CellSignalStrengthWcdma ssWcdma = ci.getCellSignalStrength();
826 
827         return String.format("%-3.3s %-3.3s %-3.3s %-5.5s %-5.5s %-6.6s %-3.3s %-4.4s\n",
828                 getConnectionStatusString(ci),
829                 getCellInfoDisplayString(cidWcdma.getMcc()),
830                 getCellInfoDisplayString(cidWcdma.getMnc()),
831                 getCellInfoDisplayString(cidWcdma.getLac()),
832                 getCellInfoDisplayString(cidWcdma.getCid()),
833                 getCellInfoDisplayString(cidWcdma.getUarfcn()),
834                 getCellInfoDisplayString(cidWcdma.getPsc()),
835                 getCellInfoDisplayString(ssWcdma.getDbm()));
836     }
837 
buildCellInfoString(List<CellInfo> arrayCi)838     private final String buildCellInfoString(List<CellInfo> arrayCi) {
839         String value = new String();
840         StringBuilder cdmaCells = new StringBuilder(),
841                 gsmCells = new StringBuilder(),
842                 lteCells = new StringBuilder(),
843                 wcdmaCells = new StringBuilder();
844 
845         if (arrayCi != null) {
846             for (CellInfo ci : arrayCi) {
847 
848                 if (ci instanceof CellInfoLte) {
849                     lteCells.append(buildLteInfoString((CellInfoLte) ci));
850                 } else if (ci instanceof CellInfoWcdma) {
851                     wcdmaCells.append(buildWcdmaInfoString((CellInfoWcdma) ci));
852                 } else if (ci instanceof CellInfoGsm) {
853                     gsmCells.append(buildGsmInfoString((CellInfoGsm) ci));
854                 } else if (ci instanceof CellInfoCdma) {
855                     cdmaCells.append(buildCdmaInfoString((CellInfoCdma) ci));
856                 }
857             }
858             if (lteCells.length() != 0) {
859                 value += String.format(
860                         "LTE\n%-3.3s %-3.3s %-3.3s %-5.5s %-5.5s %-3.3s"
861                                 + " %-6.6s %-2.2s %-4.4s %-4.4s %-2.2s\n",
862                         "SRV", "MCC", "MNC", "TAC", "CID", "PCI",
863                         "EARFCN", "BW", "RSRP", "RSRQ", "TA");
864                 value += lteCells.toString();
865             }
866             if (wcdmaCells.length() != 0) {
867                 value += String.format(
868                         "WCDMA\n%-3.3s %-3.3s %-3.3s %-5.5s %-5.5s %-6.6s %-3.3s %-4.4s\n",
869                         "SRV", "MCC", "MNC", "LAC", "CID", "UARFCN", "PSC", "RSCP");
870                 value += wcdmaCells.toString();
871             }
872             if (gsmCells.length() != 0) {
873                 value += String.format(
874                         "GSM\n%-3.3s %-3.3s %-3.3s %-5.5s %-5.5s %-6.6s %-4.4s %-4.4s\n",
875                         "SRV", "MCC", "MNC", "LAC", "CID", "ARFCN", "BSIC", "RSSI");
876                 value += gsmCells.toString();
877             }
878             if (cdmaCells.length() != 0) {
879                 value += String.format(
880                         "CDMA/EVDO\n%-3.3s %-5.5s %-5.5s %-5.5s %-6.6s %-6.6s %-6.6s %-6.6s %-5.5s\n",
881                         "SRV", "SID", "NID", "BSID", "C-RSSI", "C-ECIO", "E-RSSI", "E-ECIO", "E-SNR");
882                 value += cdmaCells.toString();
883             }
884         } else {
885             value ="unknown";
886         }
887 
888         return value.toString();
889     }
890 
updateCellInfo(List<CellInfo> arrayCi)891     private final void updateCellInfo(List<CellInfo> arrayCi) {
892         mCellInfo.setText(buildCellInfoString(arrayCi));
893     }
894 
895     private final void
updateMessageWaiting()896     updateMessageWaiting() {
897         mMwi.setText(String.valueOf(mMwiValue));
898     }
899 
900     private final void
updateCallRedirect()901     updateCallRedirect() {
902         mCfi.setText(String.valueOf(mCfiValue));
903     }
904 
905 
906     private final void
updateServiceState(ServiceState serviceState)907     updateServiceState(ServiceState serviceState) {
908         int state = serviceState.getState();
909         Resources r = getResources();
910         String display = r.getString(R.string.radioInfo_unknown);
911 
912         switch (state) {
913             case ServiceState.STATE_IN_SERVICE:
914                 display = r.getString(R.string.radioInfo_service_in);
915                 break;
916             case ServiceState.STATE_OUT_OF_SERVICE:
917             case ServiceState.STATE_EMERGENCY_ONLY:
918                 display = r.getString(R.string.radioInfo_service_emergency);
919                 break;
920             case ServiceState.STATE_POWER_OFF:
921                 display = r.getString(R.string.radioInfo_service_off);
922                 break;
923         }
924 
925         gsmState.setText(display);
926 
927         if (serviceState.getRoaming()) {
928             roamingState.setText(R.string.radioInfo_roaming_in);
929         } else {
930             roamingState.setText(R.string.radioInfo_roaming_not);
931         }
932 
933         operatorName.setText(serviceState.getOperatorAlphaLong());
934     }
935 
936     private final void
updatePhoneState(int state)937     updatePhoneState(int state) {
938         Resources r = getResources();
939         String display = r.getString(R.string.radioInfo_unknown);
940 
941         switch (state) {
942             case TelephonyManager.CALL_STATE_IDLE:
943                 display = r.getString(R.string.radioInfo_phone_idle);
944                 break;
945             case TelephonyManager.CALL_STATE_RINGING:
946                 display = r.getString(R.string.radioInfo_phone_ringing);
947                 break;
948             case TelephonyManager.CALL_STATE_OFFHOOK:
949                 display = r.getString(R.string.radioInfo_phone_offhook);
950                 break;
951         }
952 
953         callState.setText(display);
954     }
955 
956     private final void
updateDataState()957     updateDataState() {
958         int state = mTelephonyManager.getDataState();
959         Resources r = getResources();
960         String display = r.getString(R.string.radioInfo_unknown);
961 
962         switch (state) {
963             case TelephonyManager.DATA_CONNECTED:
964                 display = r.getString(R.string.radioInfo_data_connected);
965                 break;
966             case TelephonyManager.DATA_CONNECTING:
967                 display = r.getString(R.string.radioInfo_data_connecting);
968                 break;
969             case TelephonyManager.DATA_DISCONNECTED:
970                 display = r.getString(R.string.radioInfo_data_disconnected);
971                 break;
972             case TelephonyManager.DATA_SUSPENDED:
973                 display = r.getString(R.string.radioInfo_data_suspended);
974                 break;
975         }
976 
977         gprsState.setText(display);
978     }
979 
updateNetworkType()980     private final void updateNetworkType() {
981         if(phone != null) {
982             ServiceState ss = phone.getServiceState();
983             dataNetwork.setText(ServiceState.rilRadioTechnologyToString(
984                     phone.getServiceState().getRilDataRadioTechnology()));
985             voiceNetwork.setText(ServiceState.rilRadioTechnologyToString(
986                     phone.getServiceState().getRilVoiceRadioTechnology()));
987         }
988     }
989 
990     private final void
updateProperties()991     updateProperties() {
992         String s;
993         Resources r = getResources();
994 
995         s = phone.getDeviceId();
996         if (s == null) s = r.getString(R.string.radioInfo_unknown);
997         mDeviceId.setText(s);
998 
999         s = phone.getSubscriberId();
1000         if (s == null) s = r.getString(R.string.radioInfo_unknown);
1001         mSubscriberId.setText(s);
1002 
1003         //FIXME: Replace with a TelephonyManager call
1004         s = phone.getLine1Number();
1005         if (s == null) s = r.getString(R.string.radioInfo_unknown);
1006         number.setText(s);
1007     }
1008 
updateDataStats2()1009     private final void updateDataStats2() {
1010         Resources r = getResources();
1011 
1012         long txPackets = TrafficStats.getMobileTxPackets();
1013         long rxPackets = TrafficStats.getMobileRxPackets();
1014         long txBytes   = TrafficStats.getMobileTxBytes();
1015         long rxBytes   = TrafficStats.getMobileRxBytes();
1016 
1017         String packets = r.getString(R.string.radioInfo_display_packets);
1018         String bytes   = r.getString(R.string.radioInfo_display_bytes);
1019 
1020         sent.setText(txPackets + " " + packets + ", " + txBytes + " " + bytes);
1021         received.setText(rxPackets + " " + packets + ", " + rxBytes + " " + bytes);
1022     }
1023 
1024     /**
1025      *  Ping a host name
1026      */
pingHostname()1027     private final void pingHostname() {
1028         try {
1029             try {
1030                 Process p4 = Runtime.getRuntime().exec("ping -c 1 www.google.com");
1031                 int status4 = p4.waitFor();
1032                 if (status4 == 0) {
1033                     mPingHostnameResultV4 = "Pass";
1034                 } else {
1035                     mPingHostnameResultV4 = String.format("Fail(%d)", status4);
1036                 }
1037             } catch (IOException e) {
1038                 mPingHostnameResultV4 = "Fail: IOException";
1039             }
1040             try {
1041                 Process p6 = Runtime.getRuntime().exec("ping6 -c 1 www.google.com");
1042                 int status6 = p6.waitFor();
1043                 if (status6 == 0) {
1044                     mPingHostnameResultV6 = "Pass";
1045                 } else {
1046                     mPingHostnameResultV6 = String.format("Fail(%d)", status6);
1047                 }
1048             } catch (IOException e) {
1049                 mPingHostnameResultV6 = "Fail: IOException";
1050             }
1051         } catch (InterruptedException e) {
1052             mPingHostnameResultV4 = mPingHostnameResultV6 = "Fail: InterruptedException";
1053         }
1054     }
1055 
1056     /**
1057      * This function checks for basic functionality of HTTP Client.
1058      */
httpClientTest()1059     private void httpClientTest() {
1060         HttpURLConnection urlConnection = null;
1061         try {
1062             // TODO: Hardcoded for now, make it UI configurable
1063             URL url = new URL("https://www.google.com");
1064             urlConnection = (HttpURLConnection) url.openConnection();
1065             if (urlConnection.getResponseCode() == 200) {
1066                 mHttpClientTestResult = "Pass";
1067             } else {
1068                 mHttpClientTestResult = "Fail: Code: " + urlConnection.getResponseMessage();
1069             }
1070         } catch (IOException e) {
1071             mHttpClientTestResult = "Fail: IOException";
1072         } finally {
1073             if (urlConnection != null) {
1074                 urlConnection.disconnect();
1075             }
1076         }
1077     }
1078 
refreshSmsc()1079     private void refreshSmsc() {
1080         //FIXME: Replace with a TelephonyManager call
1081         phone.getSmscAddress(mHandler.obtainMessage(EVENT_QUERY_SMSC_DONE));
1082     }
1083 
updateAllCellInfo()1084     private final void updateAllCellInfo() {
1085 
1086         mCellInfo.setText("");
1087         mLocation.setText("");
1088 
1089         final Runnable updateAllCellInfoResults = new Runnable() {
1090             public void run() {
1091                 updateLocation(mCellLocationResult);
1092                 updateCellInfo(mCellInfoResult);
1093             }
1094         };
1095 
1096         Thread locThread = new Thread() {
1097             @Override
1098             public void run() {
1099                 mCellInfoResult = mTelephonyManager.getAllCellInfo();
1100                 mCellLocationResult = mTelephonyManager.getCellLocation();
1101 
1102                 mHandler.post(updateAllCellInfoResults);
1103             }
1104         };
1105         locThread.start();
1106     }
1107 
updatePingState()1108     private final void updatePingState() {
1109         // Set all to unknown since the threads will take a few secs to update.
1110         mPingHostnameResultV4 = getResources().getString(R.string.radioInfo_unknown);
1111         mPingHostnameResultV6 = getResources().getString(R.string.radioInfo_unknown);
1112         mHttpClientTestResult = getResources().getString(R.string.radioInfo_unknown);
1113 
1114         mPingHostnameV4.setText(mPingHostnameResultV4);
1115         mPingHostnameV6.setText(mPingHostnameResultV6);
1116         mHttpClientTest.setText(mHttpClientTestResult);
1117 
1118         final Runnable updatePingResults = new Runnable() {
1119             public void run() {
1120                 mPingHostnameV4.setText(mPingHostnameResultV4);
1121                 mPingHostnameV6.setText(mPingHostnameResultV6);
1122                 mHttpClientTest.setText(mHttpClientTestResult);
1123             }
1124         };
1125 
1126         Thread hostname = new Thread() {
1127             @Override
1128             public void run() {
1129                 pingHostname();
1130                 mHandler.post(updatePingResults);
1131             }
1132         };
1133         hostname.start();
1134 
1135         Thread httpClient = new Thread() {
1136             @Override
1137             public void run() {
1138                 httpClientTest();
1139                 mHandler.post(updatePingResults);
1140             }
1141         };
1142         httpClient.start();
1143     }
1144 
1145     private MenuItem.OnMenuItemClickListener mViewADNCallback = new MenuItem.OnMenuItemClickListener() {
1146         public boolean onMenuItemClick(MenuItem item) {
1147             Intent intent = new Intent(Intent.ACTION_VIEW);
1148             // XXX We need to specify the component here because if we don't
1149             // the activity manager will try to resolve the type by calling
1150             // the content provider, which causes it to be loaded in a process
1151             // other than the Dialer process, which causes a lot of stuff to
1152             // break.
1153             intent.setClassName("com.android.phone",
1154                     "com.android.phone.SimContacts");
1155             startActivity(intent);
1156             return true;
1157         }
1158     };
1159 
1160     private MenuItem.OnMenuItemClickListener mViewFDNCallback = new MenuItem.OnMenuItemClickListener() {
1161         public boolean onMenuItemClick(MenuItem item) {
1162             Intent intent = new Intent(Intent.ACTION_VIEW);
1163             // XXX We need to specify the component here because if we don't
1164             // the activity manager will try to resolve the type by calling
1165             // the content provider, which causes it to be loaded in a process
1166             // other than the Dialer process, which causes a lot of stuff to
1167             // break.
1168             intent.setClassName("com.android.phone",
1169                     "com.android.phone.settings.fdn.FdnList");
1170             startActivity(intent);
1171             return true;
1172         }
1173     };
1174 
1175     private MenuItem.OnMenuItemClickListener mViewSDNCallback = new MenuItem.OnMenuItemClickListener() {
1176         public boolean onMenuItemClick(MenuItem item) {
1177             Intent intent = new Intent(
1178                     Intent.ACTION_VIEW, Uri.parse("content://icc/sdn"));
1179             // XXX We need to specify the component here because if we don't
1180             // the activity manager will try to resolve the type by calling
1181             // the content provider, which causes it to be loaded in a process
1182             // other than the Dialer process, which causes a lot of stuff to
1183             // break.
1184             intent.setClassName("com.android.phone",
1185                     "com.android.phone.ADNList");
1186             startActivity(intent);
1187             return true;
1188         }
1189     };
1190 
1191     private MenuItem.OnMenuItemClickListener mGetImsStatus = new MenuItem.OnMenuItemClickListener() {
1192         public boolean onMenuItemClick(MenuItem item) {
1193             boolean isImsRegistered = phone.isImsRegistered();
1194             boolean availableVolte = phone.isVolteEnabled();
1195             boolean availableWfc = phone.isWifiCallingEnabled();
1196             boolean availableVt = phone.isVideoEnabled();
1197             boolean availableUt = phone.isUtEnabled();
1198 
1199             final String imsRegString = isImsRegistered ?
1200                 getString(R.string.radio_info_ims_reg_status_registered) :
1201                 getString(R.string.radio_info_ims_reg_status_not_registered);
1202 
1203             final String available = getString(R.string.radio_info_ims_feature_status_available);
1204             final String unavailable = getString(
1205                     R.string.radio_info_ims_feature_status_unavailable);
1206 
1207             String imsStatus = getString(R.string.radio_info_ims_reg_status,
1208                     imsRegString,
1209                     availableVolte ? available : unavailable,
1210                     availableWfc ? available : unavailable,
1211                     availableVt ? available : unavailable,
1212                     availableUt ? available : unavailable);
1213 
1214             AlertDialog imsDialog = new AlertDialog.Builder(RadioInfo.this)
1215                 .setMessage(imsStatus)
1216                 .setTitle(getString(R.string.radio_info_ims_reg_status_title))
1217                 .create();
1218 
1219             imsDialog.show();
1220 
1221             return true;
1222         }
1223     };
1224 
1225     private MenuItem.OnMenuItemClickListener mSelectBandCallback = new MenuItem.OnMenuItemClickListener() {
1226         public boolean onMenuItemClick(MenuItem item) {
1227             Intent intent = new Intent();
1228             intent.setClass(RadioInfo.this, BandMode.class);
1229             startActivity(intent);
1230             return true;
1231         }
1232     };
1233 
1234     private MenuItem.OnMenuItemClickListener mToggleData = new MenuItem.OnMenuItemClickListener() {
1235         public boolean onMenuItemClick(MenuItem item) {
1236             int state = mTelephonyManager.getDataState();
1237             switch (state) {
1238                 case TelephonyManager.DATA_CONNECTED:
1239                     mTelephonyManager.setDataEnabled(false);
1240                     break;
1241                 case TelephonyManager.DATA_DISCONNECTED:
1242                     mTelephonyManager.setDataEnabled(true);
1243                     break;
1244                 default:
1245                     // do nothing
1246                     break;
1247             }
1248             return true;
1249         }
1250     };
1251 
isRadioOn()1252     private boolean isRadioOn() {
1253         //FIXME: Replace with a TelephonyManager call
1254         return phone.getServiceState().getState() != ServiceState.STATE_POWER_OFF;
1255     }
1256 
updateRadioPowerState()1257     private void updateRadioPowerState() {
1258         //delightful hack to prevent on-checked-changed calls from
1259         //actually forcing the radio preference to its transient/current value.
1260         radioPowerOnSwitch.setOnCheckedChangeListener(null);
1261         radioPowerOnSwitch.setChecked(isRadioOn());
1262         radioPowerOnSwitch.setOnCheckedChangeListener(mRadioPowerOnChangeListener);
1263     }
1264 
setImsVolteProvisionedState(boolean state)1265     void setImsVolteProvisionedState(boolean state) {
1266         Log.d(TAG, "setImsVolteProvisioned state: " + ((state)? "on":"off"));
1267         setImsConfigProvisionedState(IMS_VOLTE_PROVISIONED_CONFIG_ID, state);
1268     }
1269 
setImsVtProvisionedState(boolean state)1270     void setImsVtProvisionedState(boolean state) {
1271         Log.d(TAG, "setImsVtProvisioned() state: " + ((state)? "on":"off"));
1272         setImsConfigProvisionedState(IMS_VT_PROVISIONED_CONFIG_ID, state);
1273     }
1274 
setImsWfcProvisionedState(boolean state)1275     void setImsWfcProvisionedState(boolean state) {
1276         Log.d(TAG, "setImsWfcProvisioned() state: " + ((state)? "on":"off"));
1277         setImsConfigProvisionedState(IMS_WFC_PROVISIONED_CONFIG_ID, state);
1278     }
1279 
setEabProvisionedState(boolean state)1280     void setEabProvisionedState(boolean state) {
1281         Log.d(TAG, "setEabProvisioned() state: " + ((state)? "on":"off"));
1282         setImsConfigProvisionedState(EAB_PROVISIONED_CONFIG_ID, state);
1283     }
1284 
setImsConfigProvisionedState(int configItem, boolean state)1285     void setImsConfigProvisionedState(int configItem, boolean state) {
1286         if (phone != null && mImsManager != null) {
1287             QueuedWork.queue(new Runnable() {
1288                 public void run() {
1289                     try {
1290                         mImsManager.getConfigInterface().setProvisionedValue(
1291                                 configItem,
1292                                 state? 1 : 0);
1293                     } catch (ImsException e) {
1294                         Log.e(TAG, "setImsConfigProvisioned() exception:", e);
1295                     }
1296                 }
1297             }, false);
1298         }
1299     }
1300 
1301     OnCheckedChangeListener mRadioPowerOnChangeListener = new OnCheckedChangeListener() {
1302         @Override
1303         public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
1304             log("toggle radio power: currently " + (isRadioOn()?"on":"off"));
1305             phone.setRadioPower(isChecked);
1306        }
1307     };
1308 
isImsVolteProvisioned()1309     private boolean isImsVolteProvisioned() {
1310         if (phone != null && mImsManager != null) {
1311             return mImsManager.isVolteEnabledByPlatform(phone.getContext())
1312                 && mImsManager.isVolteProvisionedOnDevice(phone.getContext());
1313         }
1314         return false;
1315     }
1316 
1317     OnCheckedChangeListener mImsVolteCheckedChangeListener = new OnCheckedChangeListener() {
1318         @Override
1319         public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
1320             setImsVolteProvisionedState(isChecked);
1321         }
1322     };
1323 
isImsVtProvisioned()1324     private boolean isImsVtProvisioned() {
1325         if (phone != null && mImsManager != null) {
1326             return mImsManager.isVtEnabledByPlatform(phone.getContext())
1327                 && mImsManager.isVtProvisionedOnDevice(phone.getContext());
1328         }
1329         return false;
1330     }
1331 
1332     OnCheckedChangeListener mImsVtCheckedChangeListener = new OnCheckedChangeListener() {
1333         @Override
1334         public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
1335             setImsVtProvisionedState(isChecked);
1336         }
1337     };
1338 
isImsWfcProvisioned()1339     private boolean isImsWfcProvisioned() {
1340         if (phone != null && mImsManager != null) {
1341             return mImsManager.isWfcEnabledByPlatform(phone.getContext())
1342                 && mImsManager.isWfcProvisionedOnDevice(phone.getContext());
1343         }
1344         return false;
1345     }
1346 
1347     OnCheckedChangeListener mImsWfcCheckedChangeListener = new OnCheckedChangeListener() {
1348         @Override
1349         public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
1350             setImsWfcProvisionedState(isChecked);
1351         }
1352     };
1353 
isEabProvisioned()1354     private boolean isEabProvisioned() {
1355         return isFeatureProvisioned(EAB_PROVISIONED_CONFIG_ID, false);
1356     }
1357 
1358     OnCheckedChangeListener mEabCheckedChangeListener = new OnCheckedChangeListener() {
1359         @Override
1360         public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
1361             setEabProvisionedState(isChecked);
1362         }
1363     };
1364 
isFeatureProvisioned(int featureId, boolean defaultValue)1365     private boolean isFeatureProvisioned(int featureId, boolean defaultValue) {
1366         boolean provisioned = defaultValue;
1367         if (mImsManager != null) {
1368             try {
1369                 ImsConfig imsConfig = mImsManager.getConfigInterface();
1370                 if (imsConfig != null) {
1371                     provisioned =
1372                             (imsConfig.getProvisionedValue(featureId)
1373                                     == ImsConfig.FeatureValueConstants.ON);
1374                 }
1375             } catch (ImsException ex) {
1376                 Log.e(TAG, "isFeatureProvisioned() exception:", ex);
1377             }
1378         }
1379 
1380         log("isFeatureProvisioned() featureId=" + featureId + " provisioned=" + provisioned);
1381         return provisioned;
1382     }
1383 
isEabEnabledByPlatform(Context context)1384     private static boolean isEabEnabledByPlatform(Context context) {
1385         if (context != null) {
1386             CarrierConfigManager configManager = (CarrierConfigManager)
1387                     context.getSystemService(Context.CARRIER_CONFIG_SERVICE);
1388             if (configManager != null && configManager.getConfig().getBoolean(
1389                         CarrierConfigManager.KEY_USE_RCS_PRESENCE_BOOL)) {
1390                 return true;
1391             }
1392         }
1393         return false;
1394     }
1395 
updateImsProvisionedState()1396     private void updateImsProvisionedState() {
1397         if (!ImsManager.isImsSupportedOnDevice(phone.getContext())) {
1398             return;
1399         }
1400         log("updateImsProvisionedState isImsVolteProvisioned()=" + isImsVolteProvisioned());
1401         //delightful hack to prevent on-checked-changed calls from
1402         //actually forcing the ims provisioning to its transient/current value.
1403         imsVolteProvisionedSwitch.setOnCheckedChangeListener(null);
1404         imsVolteProvisionedSwitch.setChecked(isImsVolteProvisioned());
1405         imsVolteProvisionedSwitch.setOnCheckedChangeListener(mImsVolteCheckedChangeListener);
1406         imsVolteProvisionedSwitch.setEnabled(!Build.IS_USER
1407                 && mImsManager.isVolteEnabledByPlatform(phone.getContext()));
1408 
1409         imsVtProvisionedSwitch.setOnCheckedChangeListener(null);
1410         imsVtProvisionedSwitch.setChecked(isImsVtProvisioned());
1411         imsVtProvisionedSwitch.setOnCheckedChangeListener(mImsVtCheckedChangeListener);
1412         imsVtProvisionedSwitch.setEnabled(!Build.IS_USER
1413                 && mImsManager.isVtEnabledByPlatform(phone.getContext()));
1414 
1415         imsWfcProvisionedSwitch.setOnCheckedChangeListener(null);
1416         imsWfcProvisionedSwitch.setChecked(isImsWfcProvisioned());
1417         imsWfcProvisionedSwitch.setOnCheckedChangeListener(mImsWfcCheckedChangeListener);
1418         imsWfcProvisionedSwitch.setEnabled(!Build.IS_USER
1419                 && mImsManager.isWfcEnabledByPlatform(phone.getContext()));
1420 
1421         eabProvisionedSwitch.setOnCheckedChangeListener(null);
1422         eabProvisionedSwitch.setChecked(isEabProvisioned());
1423         eabProvisionedSwitch.setOnCheckedChangeListener(mEabCheckedChangeListener);
1424         eabProvisionedSwitch.setEnabled(!Build.IS_USER
1425                 && isEabEnabledByPlatform(phone.getContext()));
1426     }
1427 
1428     OnClickListener mDnsCheckButtonHandler = new OnClickListener() {
1429         public void onClick(View v) {
1430             //FIXME: Replace with a TelephonyManager call
1431             phone.disableDnsCheck(!phone.isDnsCheckDisabled());
1432             updateDnsCheckState();
1433         }
1434     };
1435 
1436     OnClickListener mOemInfoButtonHandler = new OnClickListener() {
1437         public void onClick(View v) {
1438             Intent intent = new Intent("com.android.car.developeroptions.OEM_RADIO_INFO");
1439             try {
1440                 startActivity(intent);
1441             } catch (android.content.ActivityNotFoundException ex) {
1442                 log("OEM-specific Info/Settings Activity Not Found : " + ex);
1443                 // If the activity does not exist, there are no OEM
1444                 // settings, and so we can just do nothing...
1445             }
1446         }
1447     };
1448 
1449     OnClickListener mPingButtonHandler = new OnClickListener() {
1450         public void onClick(View v) {
1451             updatePingState();
1452         }
1453     };
1454 
1455     OnClickListener mUpdateSmscButtonHandler = new OnClickListener() {
1456         public void onClick(View v) {
1457             updateSmscButton.setEnabled(false);
1458             phone.setSmscAddress(smsc.getText().toString(),
1459                     mHandler.obtainMessage(EVENT_UPDATE_SMSC_DONE));
1460         }
1461     };
1462 
1463     OnClickListener mRefreshSmscButtonHandler = new OnClickListener() {
1464         public void onClick(View v) {
1465             refreshSmsc();
1466         }
1467     };
1468 
1469     OnClickListener mCarrierProvisioningButtonHandler = new OnClickListener() {
1470         public void onClick(View v) {
1471             final Intent intent = new Intent("com.android.car.developeroptions.CARRIER_PROVISIONING");
1472             final ComponentName serviceComponent = ComponentName.unflattenFromString(
1473                     "com.android.omadm.service/.DMIntentReceiver");
1474             intent.setComponent(serviceComponent);
1475             sendBroadcast(intent);
1476         }
1477     };
1478 
1479     OnClickListener mTriggerCarrierProvisioningButtonHandler = new OnClickListener() {
1480         public void onClick(View v) {
1481             final Intent intent = new Intent("com.android.car.developeroptions.TRIGGER_CARRIER_PROVISIONING");
1482             final ComponentName serviceComponent = ComponentName.unflattenFromString(
1483                     "com.android.omadm.service/.DMIntentReceiver");
1484             intent.setComponent(serviceComponent);
1485             sendBroadcast(intent);
1486         }
1487     };
1488 
1489     AdapterView.OnItemSelectedListener mPreferredNetworkHandler =
1490             new AdapterView.OnItemSelectedListener() {
1491 
1492         public void onItemSelected(AdapterView parent, View v, int pos, long id) {
1493             if (mPreferredNetworkTypeResult != pos && pos >= 0
1494                     && pos <= mPreferredNetworkLabels.length - 2) {
1495                 mPreferredNetworkTypeResult = pos;
1496 
1497                 // TODO: Possibly migrate this to TelephonyManager.setPreferredNetworkType()
1498                 // which today still has some issues (mostly that the "set" is conditional
1499                 // on a successful modem call, which is not what we want). Instead we always
1500                 // want this setting to be set, so that if the radio hiccups and this setting
1501                 // is for some reason unsuccessful, future calls to the radio will reflect
1502                 // the users's preference which is set here.
1503                 final int subId = phone.getSubId();
1504                 if (SubscriptionManager.isUsableSubIdValue(subId)) {
1505                     Settings.Global.putInt(phone.getContext().getContentResolver(),
1506                             PREFERRED_NETWORK_MODE + subId, mPreferredNetworkTypeResult);
1507                 }
1508                 log("Calling setPreferredNetworkType(" + mPreferredNetworkTypeResult + ")");
1509                 Message msg = mHandler.obtainMessage(EVENT_SET_PREFERRED_TYPE_DONE);
1510                 phone.setPreferredNetworkType(mPreferredNetworkTypeResult, msg);
1511             }
1512         }
1513 
1514         public void onNothingSelected(AdapterView parent) {
1515         }
1516     };
1517 
1518     AdapterView.OnItemSelectedListener mCellInfoRefreshRateHandler  =
1519             new AdapterView.OnItemSelectedListener() {
1520 
1521         public void onItemSelected(AdapterView parent, View v, int pos, long id) {
1522             mCellInfoRefreshRateIndex = pos;
1523             mTelephonyManager.setCellInfoListRate(mCellInfoRefreshRates[pos]);
1524             updateAllCellInfo();
1525         }
1526 
1527         public void onNothingSelected(AdapterView parent) {
1528         }
1529     };
1530 
isCbrsSupported()1531     boolean isCbrsSupported() {
1532         // No longer possible to access com.android.internal.R.bool.config_cbrs_supported, so
1533         // returning false for now.
1534         // TODO: This needs to be cleaned up in future CL.
1535         return false;
1536     }
1537 
updateCbrsDataState(boolean state)1538     void updateCbrsDataState(boolean state) {
1539         Log.d(TAG, "setCbrsDataSwitchState() state:" + ((state)? "on":"off"));
1540         if (mTelephonyManager != null) {
1541             QueuedWork.queue(new Runnable() {
1542                 public void run() {
1543                   mTelephonyManager.setOpportunisticNetworkState(state);
1544                   cbrsDataSwitch.setChecked(getCbrsDataState());
1545                 }
1546             }, false);
1547         }
1548     }
1549 
getCbrsDataState()1550     boolean getCbrsDataState() {
1551         boolean state = false;
1552         if (mTelephonyManager != null) {
1553             state = mTelephonyManager.isOpportunisticNetworkEnabled();
1554         }
1555         Log.d(TAG, "getCbrsDataState() state:" +((state)? "on":"off"));
1556         return state;
1557     }
1558 
1559     OnCheckedChangeListener mCbrsDataSwitchChangeListener = new OnCheckedChangeListener() {
1560         @Override
1561         public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
1562             updateCbrsDataState(isChecked);
1563         }
1564     };
1565 
showDsdsChangeDialog()1566     private void showDsdsChangeDialog() {
1567         final AlertDialog confirmDialog = new Builder(RadioInfo.this)
1568                 .setTitle(R.string.dsds_dialog_title)
1569                 .setMessage(R.string.dsds_dialog_message)
1570                 .setPositiveButton(R.string.dsds_dialog_confirm, mOnDsdsDialogConfirmedListener)
1571                 .setNegativeButton(R.string.dsds_dialog_cancel, mOnDsdsDialogConfirmedListener)
1572                 .create();
1573         confirmDialog.show();
1574     }
1575 
isDsdsSupported()1576     private static boolean isDsdsSupported() {
1577         return (TelephonyManager.getDefault().isMultiSimSupported()
1578             == TelephonyManager.MULTISIM_ALLOWED);
1579     }
1580 
isDsdsEnabled()1581     private static boolean isDsdsEnabled() {
1582         return TelephonyManager.getDefault().getPhoneCount() > 1;
1583     }
1584 
performDsdsSwitch()1585     private void performDsdsSwitch() {
1586         mTelephonyManager.switchMultiSimConfig(dsdsSwitch.isChecked() ? 2 : 1);
1587     }
1588 
1589     DialogInterface.OnClickListener mOnDsdsDialogConfirmedListener =
1590             new DialogInterface.OnClickListener() {
1591         @Override
1592         public void onClick(DialogInterface dialog, int which) {
1593             if (which == DialogInterface.BUTTON_POSITIVE) {
1594                 dsdsSwitch.toggle();
1595                 performDsdsSwitch();
1596             }
1597         }
1598     };
1599 }
1600