1 /**
2 **
3 ** Copyright 2006, The Android Open Source Project
4 **
5 ** Licensed under the Apache License, Version 2.0 (the "License");
6 ** you may not use this file except in compliance with the License.
7 ** You may obtain a copy of the License at
8 **
9 **     http://www.apache.org/licenses/LICENSE-2.0
10 **
11 ** Unless required by applicable law or agreed to in writing, software
12 ** distributed under the License is distributed on an "AS IS" BASIS,
13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 ** See the License for the specific language governing permissions and
15 ** limitations under the License.
16 */
17 
18 package com.android.development;
19 
20 import android.app.Activity;
21 import android.app.AlarmManager;
22 import android.app.PendingIntent;
23 import android.content.BroadcastReceiver;
24 import android.content.Context;
25 import android.content.Intent;
26 import android.content.IntentFilter;
27 import android.content.SharedPreferences;
28 import android.content.pm.PackageManager.NameNotFoundException;
29 import android.net.ConnectivityManager;
30 import android.net.ConnectivityManager.NetworkCallback;
31 import android.net.LinkAddress;
32 import android.net.LinkProperties;
33 import android.net.Network;
34 import android.net.NetworkCapabilities;
35 import android.net.NetworkRequest;
36 import android.net.RouteInfo;
37 import android.net.wifi.ScanResult;
38 import android.net.wifi.WifiManager;
39 import android.os.RemoteException;
40 import android.os.Handler;
41 import android.os.Message;
42 import android.os.IBinder;
43 import android.os.INetworkManagementService;
44 import android.os.Parcel;
45 import android.os.PowerManager;
46 import android.os.PowerManager.WakeLock;
47 import android.os.ServiceManager;
48 import android.os.SystemClock;
49 import android.provider.Settings;
50 import android.os.Bundle;
51 import android.os.connectivity.WifiActivityEnergyInfo;
52 import android.text.TextUtils;
53 import android.util.Log;
54 import android.view.IWindowManager;
55 import android.view.View;
56 import android.widget.ArrayAdapter;
57 import android.widget.Button;
58 import android.widget.CheckBox;
59 import android.widget.CompoundButton;
60 import android.widget.EditText;
61 import android.widget.Spinner;
62 import android.widget.TextView;
63 import android.widget.Toast;
64 import android.widget.AdapterView.OnItemSelectedListener;
65 
66 import com.android.internal.telephony.Phone;
67 import libcore.io.IoUtils;
68 
69 import java.io.BufferedReader;
70 import java.io.FileInputStream;
71 import java.io.FileOutputStream;
72 import java.io.InputStreamReader;
73 import java.io.IOException;
74 import java.io.OutputStreamWriter;
75 import java.io.PrintWriter;
76 import java.net.HttpURLConnection;
77 import java.net.InetAddress;
78 import java.net.Proxy;
79 import java.net.Socket;
80 import java.net.URL;
81 import java.util.ArrayList;
82 import java.util.Enumeration;
83 import java.util.List;
84 import java.util.Random;
85 
86 import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
87 import static android.net.NetworkCapabilities.*;
88 
89 public class Connectivity extends Activity {
90     private static final String TAG = "DevToolsConnectivity";
91     private static final String GET_SCAN_RES = "Get Results";
92     private static final String START_SCAN = "Start Scan";
93     private static final String PROGRESS_SCAN = "In Progress";
94 
95     private static final long SCAN_CYCLES = 15;
96 
97     private static final int EVENT_TOGGLE_WIFI = 1;
98     private static final int EVENT_TOGGLE_SCREEN = 2;
99 
100     private EditText mDCOnDurationEdit;
101     private EditText mDCOffDurationEdit;
102     private TextView mDCCycleCountView;
103     private long mDCOnDuration = 120000;
104     private long mDCOffDuration = 120000;
105     private int mDCCycleCount = 0;
106 
107     private EditText mSCOnDurationEdit;
108     private EditText mSCOffDurationEdit;
109     private TextView mSCCycleCountView;
110     private long mSCOnDuration = 120000;
111     private long mSCOffDuration = 12000;
112     private int mSCCycleCount = 0;
113 
114     private boolean mDelayedCycleStarted = false;
115 
116     private Button mScanButton;
117     private TextView mScanResults;
118     private EditText mScanCyclesEdit;
119     private CheckBox mScanDisconnect;
120     private long mScanCycles = SCAN_CYCLES;
121     private long mScanCur = -1;
122     private long mStartTime = -1;
123     private long mStopTime;
124     private long mTotalScanTime = 0;
125     private long mTotalScanCount = 0;
126 
127     private TextView mLinkStatsResults;
128     private TextView mHttpRequestResults;
129 
130     private String mTdlsAddr = null;
131 
132     private WifiManager mWm;
133     private WifiManager.MulticastLock mWml;
134     private PowerManager mPm;
135     private ConnectivityManager mCm;
136     private INetworkManagementService mNetd;
137 
138     private WifiScanReceiver mScanRecv;
139     IntentFilter mIntentFilter;
140 
141     private WakeLock mWakeLock = null;
142     private WakeLock mScreenonWakeLock = null;
143 
144     private boolean mScreenOffToggleRunning = false;
145     private boolean mScreenOff = false;
146 
147     private static final String CONNECTIVITY_TEST_ALARM =
148             "com.android.development.CONNECTIVITY_TEST_ALARM";
149     private static final String TEST_ALARM_EXTRA = "CONNECTIVITY_TEST_EXTRA";
150     private static final String TEST_ALARM_ON_EXTRA = "CONNECTIVITY_TEST_ON_EXTRA";
151     private static final String TEST_ALARM_OFF_EXTRA = "CONNECTIVITY_TEST_OFF_EXTRA";
152     private static final String TEST_ALARM_CYCLE_EXTRA = "CONNECTIVITY_TEST_CYCLE_EXTRA";
153     private static final String SCREEN_ON = "SCREEN_ON";
154     private static final String SCREEN_OFF = "SCREEN_OFF";
155 
156     private static final String NETWORK_CONDITIONS_MEASURED =
157             "android.net.conn.NETWORK_CONDITIONS_MEASURED";
158 
logBroadcast(Intent intent)159     private void logBroadcast(Intent intent) {
160         StringBuilder sb = new StringBuilder();
161         Bundle b = intent.getExtras();
162         for (String key : b.keySet()) {
163             sb.append(String.format(" %s=%s", key, b.get(key)));
164         }
165         Log.d(TAG, "Got broadcast " + intent.getAction() + " extras:" + sb.toString());
166     }
167 
168     public BroadcastReceiver mReceiver = new BroadcastReceiver() {
169         public void onReceive(Context context, Intent intent) {
170             logBroadcast(intent);
171 
172             if (intent.getAction().equals(CONNECTIVITY_TEST_ALARM)) {
173                 String extra = (String)intent.getExtra(TEST_ALARM_EXTRA);
174                 PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
175                 Long on = new Long(120000);
176                 Long off = new Long(120000);
177                 int cycle = 0;
178                 try {
179                     on = Long.parseLong((String)intent.getExtra(TEST_ALARM_ON_EXTRA));
180                     off = Long.parseLong((String)intent.getExtra(TEST_ALARM_OFF_EXTRA));
181                     cycle = Integer.parseInt((String)intent.getExtra(TEST_ALARM_CYCLE_EXTRA));
182                 } catch (Exception e) {}
183 
184                 if (extra.equals(SCREEN_ON)) {
185                     mScreenonWakeLock = mPm.newWakeLock(PowerManager.FULL_WAKE_LOCK |
186                             PowerManager.ACQUIRE_CAUSES_WAKEUP,
187                             "ConnectivityTest");
188                     mScreenonWakeLock.acquire();
189 
190                     mSCCycleCount = cycle+1;
191                     mSCOnDuration = on;
192                     mSCOffDuration = off;
193                     mSCCycleCountView.setText(Integer.toString(mSCCycleCount));
194 
195                     scheduleAlarm(mSCOnDuration, SCREEN_OFF);
196                 } else if (extra.equals(SCREEN_OFF)) {
197 
198                     mSCCycleCount = cycle;
199                     mSCOnDuration = on;
200                     mSCOffDuration = off;
201 
202                     mScreenonWakeLock.release();
203                     mScreenonWakeLock = null;
204                     scheduleAlarm(mSCOffDuration, SCREEN_ON);
205                     pm.goToSleep(SystemClock.uptimeMillis());
206                 }
207             }
208         }
209     };
210 
211     public Handler mHandler2 = new Handler() {
212         public void handleMessage(Message msg) {
213             switch(msg.what) {
214                 case EVENT_TOGGLE_WIFI:
215                     Log.e(TAG, "EVENT_TOGGLE_WIFI");
216                     if (mDelayedCycleStarted && mWm != null) {
217                         long delay;
218                         switch (mWm.getWifiState()) {
219                             case WifiManager.WIFI_STATE_ENABLED:
220                             case WifiManager.WIFI_STATE_ENABLING:
221                                 mWm.setWifiEnabled(false);
222                                 delay = mDCOffDuration;
223                                 break;
224                             default:
225                                 mWm.setWifiEnabled(true);
226                                 delay = mDCOnDuration;
227                                 mDCCycleCount++;
228                                 mDCCycleCountView.setText(Integer.toString(mDCCycleCount));
229                         }
230                         sendMessageDelayed(obtainMessage(EVENT_TOGGLE_WIFI),
231                                 delay);
232                     }
233                     break;
234             }
235         }
236     };
237 
238    /**
239      * Wifi Scan Listener
240      */
241     private class WifiScanReceiver extends BroadcastReceiver {
242         @Override
onReceive(Context context, Intent intent)243         public void onReceive(Context context, Intent intent) {
244             String action = intent.getAction();
245 
246             if (action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
247                 mStopTime = SystemClock.elapsedRealtime();
248                 if (mStartTime != -1) {
249                     mTotalScanTime += (mStopTime - mStartTime);
250                     mStartTime = -1;
251                 }
252                 Log.d(TAG, "Scan: READY " + mScanCur);
253                 mScanResults.setVisibility(View.INVISIBLE);
254 
255                 List<ScanResult> wifiScanResults = mWm.getScanResults();
256                 if (wifiScanResults != null) {
257                     mTotalScanCount += wifiScanResults.size();
258                     mScanResults.setText("Current scan = " + Long.toString(wifiScanResults.size()));
259                     mScanResults.setVisibility(View.VISIBLE);
260                     Log.d(TAG, "Scan: Results = " + wifiScanResults.size());
261                 }
262 
263                 mScanCur--;
264                 mScanCyclesEdit.setText(Long.toString(mScanCur));
265                 if (mScanCur == 0) {
266                     unregisterReceiver(mScanRecv);
267                     mScanButton.setText(GET_SCAN_RES);
268                     mScanResults.setVisibility(View.INVISIBLE);
269                 } else {
270                     Log.d(TAG, "Scan: START " + mScanCur);
271                     mStartTime = SystemClock.elapsedRealtime();
272                     mWm.startScan();
273                 }
274             }
275         }
276     }
277 
278     private static class DevToolsNetworkCallback extends NetworkCallback {
279         private static final String TAG = "DevToolsNetworkCallback";
280 
onAvailable(Network network)281         public void onAvailable(Network network) {
282             Log.d(TAG, "onAvailable: " + network);
283         }
284 
onCapabilitiesChanged(Network network, NetworkCapabilities nc)285         public void onCapabilitiesChanged(Network network, NetworkCapabilities nc) {
286             Log.d(TAG, "onCapabilitiesChanged: " + network + " " + nc.toString());
287         }
288 
onLinkPropertiesChanged(Network network, LinkProperties lp)289         public void onLinkPropertiesChanged(Network network, LinkProperties lp) {
290             Log.d(TAG, "onLinkPropertiesChanged: " + network + " " + lp.toString());
291         }
292 
onLosing(Network network, int maxMsToLive)293         public void onLosing(Network network, int maxMsToLive) {
294             Log.d(TAG, "onLosing: " + network + " " + maxMsToLive);
295         }
296 
onLost(Network network)297         public void onLost(Network network) {
298             Log.d(TAG, "onLost: " + network);
299         }
300     }
301     private DevToolsNetworkCallback mCallback;
302 
303     private class RequestableNetwork {
304         private final NetworkRequest mRequest;
305         private final int mRequestButton, mReleaseButton, mProgressBar;
306         private NetworkCallback mCallback;
307         private Network mNetwork;
308 
RequestableNetwork(NetworkRequest request, int requestButton, int releaseButton, int progressBar)309         public RequestableNetwork(NetworkRequest request, int requestButton, int releaseButton,
310                 int progressBar) {
311             mRequest = request;
312             mRequestButton = requestButton;
313             mReleaseButton = releaseButton;
314             mProgressBar = progressBar;
315         }
316 
RequestableNetwork(int capability, int requestButton, int releaseButton, int progressBar)317         public RequestableNetwork(int capability, int requestButton, int releaseButton,
318                 int progressBar) {
319             this(new NetworkRequest.Builder()
320                     .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
321                     .addCapability(capability)
322                     .build(),
323                     requestButton, releaseButton, progressBar);
324         }
325 
addOnClickListener()326         public void addOnClickListener() {
327             findViewById(mRequestButton).setOnClickListener(
328                     new View.OnClickListener() { public void onClick(View v) { request(); }});
329             findViewById(mReleaseButton).setOnClickListener(
330                     new View.OnClickListener() { public void onClick(View v) { release(); }});
331         }
332 
setRequested(boolean requested)333         public void setRequested(boolean requested) {
334             findViewById(mRequestButton).setEnabled(!requested);
335             findViewById(mReleaseButton).setEnabled(requested);
336             findViewById(mProgressBar).setVisibility(
337                     requested ? View.VISIBLE : View.GONE);
338         }
339 
request()340         public void request() {
341             if (mCallback == null) {
342                 mCallback = new NetworkCallback() {
343                     @Override
344                     public void onAvailable(Network network) {
345                         mNetwork = network;
346                         onHttpRequestResults(null);
347                         runOnUiThread(() -> findViewById(mProgressBar).setVisibility(View.GONE));
348                     }
349                     @Override
350                     public void onLost(Network network) {
351                         mNetwork = null;
352                         onHttpRequestResults(null);
353                     }
354                 };
355                 mCm.requestNetwork(mRequest, mCallback);
356                 setRequested(true);
357             }
358         }
359 
release()360         public void release() {
361             if (mCallback != null) {
362                 mNetwork = null;
363                 onHttpRequestResults(null);
364                 mCm.unregisterNetworkCallback(mCallback);
365                 mCallback = null;
366                 setRequested(false);
367             }
368         }
369 
getNetwork()370         public Network getNetwork() {
371             return mNetwork;
372         }
373     }
374 
375     private final ArrayList<RequestableNetwork> mRequestableNetworks = new ArrayList<>();
376     private final RequestableNetwork mBoundTestNetwork;
377     private boolean mRequestRunning;
378 
addRequestableNetwork(RequestableNetwork network)379     private void addRequestableNetwork(RequestableNetwork network) {
380         mRequestableNetworks.add(network);
381     }
382 
addRequestableNetwork(int capability, int requestButton, int releaseButton, int progressBar)383     private void addRequestableNetwork(int capability, int requestButton, int releaseButton,
384             int progressBar) {
385         mRequestableNetworks.add(new RequestableNetwork(capability, requestButton, releaseButton,
386                 progressBar));
387     }
388 
Connectivity()389     public Connectivity() {
390         super();
391         addRequestableNetwork(NET_CAPABILITY_MMS, R.id.request_mms, R.id.release_mms,
392                 R.id.mms_progress);
393         addRequestableNetwork(NET_CAPABILITY_SUPL, R.id.request_supl, R.id.release_supl,
394                 R.id.supl_progress);
395         addRequestableNetwork(NET_CAPABILITY_INTERNET, R.id.request_cell, R.id.release_cell,
396                 R.id.cell_progress);
397 
398         // Make bound requests use cell data.
399         mBoundTestNetwork = mRequestableNetworks.get(mRequestableNetworks.size() - 1);
400 
401         NetworkRequest wifiRequest = new NetworkRequest.Builder()
402             .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
403             .build();
404         addRequestableNetwork(new RequestableNetwork(wifiRequest,
405                 R.id.request_wifi, R.id.release_wifi, R.id.wifi_progress));
406     }
407 
408     final NetworkRequest mEmptyRequest = new NetworkRequest.Builder().clearCapabilities().build();
409 
410     @Override
onCreate(Bundle icicle)411     public void onCreate(Bundle icicle) {
412         super.onCreate(icicle);
413 
414         setContentView(R.layout.connectivity);
415 
416         mWm = (WifiManager)getSystemService(Context.WIFI_SERVICE);
417         mWml = mWm.createMulticastLock(TAG);
418         mWml.setReferenceCounted(false);
419         mPm = (PowerManager)getSystemService(Context.POWER_SERVICE);
420         mCm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
421         IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
422         mNetd = INetworkManagementService.Stub.asInterface(b);
423 
424         findViewById(R.id.enableWifi).setOnClickListener(mClickListener);
425         findViewById(R.id.disableWifi).setOnClickListener(mClickListener);
426         findViewById(R.id.acquireWifiMulticastLock).setOnClickListener(mClickListener);
427         findViewById(R.id.releaseWifiMulticastLock).setOnClickListener(mClickListener);
428         findViewById(R.id.releaseWifiMulticastLock).setEnabled(false);
429 
430         findViewById(R.id.startDelayedCycle).setOnClickListener(mClickListener);
431         findViewById(R.id.stopDelayedCycle).setOnClickListener(mClickListener);
432         mDCOnDurationEdit = (EditText)findViewById(R.id.dc_wifi_on_duration);
433         mDCOnDurationEdit.setText(Long.toString(mDCOnDuration));
434         mDCOffDurationEdit = (EditText)findViewById(R.id.dc_wifi_off_duration);
435         mDCOffDurationEdit.setText(Long.toString(mDCOffDuration));
436         mDCCycleCountView = (TextView)findViewById(R.id.dc_wifi_cycles_done);
437         mDCCycleCountView.setText(Integer.toString(mDCCycleCount));
438 
439         findViewById(R.id.startScreenCycle).setOnClickListener(mClickListener);
440         findViewById(R.id.stopScreenCycle).setOnClickListener(mClickListener);
441         mSCOnDurationEdit = (EditText)findViewById(R.id.sc_wifi_on_duration);
442         mSCOnDurationEdit.setText(Long.toString(mSCOnDuration));
443         mSCOffDurationEdit = (EditText)findViewById(R.id.sc_wifi_off_duration);
444         mSCOffDurationEdit.setText(Long.toString(mSCOffDuration));
445         mSCCycleCountView = (TextView)findViewById(R.id.sc_wifi_cycles_done);
446         mSCCycleCountView.setText(Integer.toString(mSCCycleCount));
447 
448         mScanButton = (Button)findViewById(R.id.startScan);
449         mScanButton.setOnClickListener(mClickListener);
450         mScanCyclesEdit = (EditText)findViewById(R.id.sc_scan_cycles);
451         mScanCyclesEdit.setText(Long.toString(mScanCycles));
452         mScanDisconnect = (CheckBox)findViewById(R.id.scanDisconnect);
453         mScanDisconnect.setChecked(true);
454         mScanResults = (TextView)findViewById(R.id.sc_scan_results);
455         mScanResults.setVisibility(View.INVISIBLE);
456 
457         mScanRecv = new WifiScanReceiver();
458         mIntentFilter = new IntentFilter();
459         mIntentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
460 
461         findViewById(R.id.startTdls).setOnClickListener(mClickListener);
462         findViewById(R.id.stopTdls).setOnClickListener(mClickListener);
463 
464         findViewById(R.id.report_all_bad).setOnClickListener(mClickListener);
465 
466         findViewById(R.id.default_request).setOnClickListener(mClickListener);
467         findViewById(R.id.bound_http_request).setOnClickListener(mClickListener);
468         findViewById(R.id.bound_socket_request).setOnClickListener(mClickListener);
469 
470         findViewById(R.id.link_stats).setOnClickListener(mClickListener);
471 
472         for (RequestableNetwork network : mRequestableNetworks) {
473             network.setRequested(false);
474             network.addOnClickListener();
475         }
476         onHttpRequestResults(null);
477 
478         IntentFilter broadcastFilter = new IntentFilter();
479         broadcastFilter.addAction(CONNECTIVITY_ACTION);
480         broadcastFilter.addAction(CONNECTIVITY_TEST_ALARM);
481         broadcastFilter.addAction(NETWORK_CONDITIONS_MEASURED);
482 
483         registerReceiver(mReceiver, broadcastFilter);
484 
485         mLinkStatsResults = (TextView)findViewById(R.id.stats);
486         mLinkStatsResults.setVisibility(View.VISIBLE);
487 
488         mHttpRequestResults = (TextView)findViewById(R.id.http_response);
489         mHttpRequestResults.setVisibility(View.VISIBLE);
490 
491         mCallback = new DevToolsNetworkCallback();
492         mCm.registerNetworkCallback(mEmptyRequest, mCallback);
493     }
494 
495     @Override
onDestroy()496     public void onDestroy() {
497         super.onDestroy();
498         for (RequestableNetwork network : mRequestableNetworks) {
499             network.release();
500         }
501         mCm.unregisterNetworkCallback(mCallback);
502         mCallback = null;
503         unregisterReceiver(mReceiver);
504         mWml.release();
505     }
506 
507     @Override
onResume()508     public void onResume() {
509         super.onResume();
510         findViewById(R.id.connectivity_layout).requestFocus();
511     }
512 
513     private View.OnClickListener mClickListener = new View.OnClickListener() {
514         public void onClick(View v) {
515             switch (v.getId()) {
516                 case R.id.enableWifi:
517                     mWm.setWifiEnabled(true);
518                     break;
519                 case R.id.disableWifi:
520                     mWm.setWifiEnabled(false);
521                     break;
522                 case R.id.acquireWifiMulticastLock:
523                 case R.id.releaseWifiMulticastLock:
524                     onWifiMulticastLock(v.getId() == R.id.acquireWifiMulticastLock);
525                     break;
526                 case R.id.startDelayedCycle:
527                     onStartDelayedCycle();
528                     break;
529                 case R.id.stopDelayedCycle:
530                     onStopDelayedCycle();
531                     break;
532                 case R.id.startScreenCycle:
533                     onStartScreenCycle();
534                     break;
535                 case R.id.stopScreenCycle:
536                     onStopScreenCycle();
537                     break;
538                 case R.id.startScan:
539                     onStartScanCycle();
540                     break;
541                 case R.id.startTdls:
542                     onStartTdls();
543                     break;
544                 case R.id.stopTdls:
545                     onStopTdls();
546                     break;
547                 case R.id.default_request:
548                     onHttpRequest(DEFAULT);
549                     break;
550                 case R.id.bound_http_request:
551                     onHttpRequest(HTTPS);
552                     break;
553                 case R.id.bound_socket_request:
554                     onHttpRequest(SOCKET);
555                     break;
556                 case R.id.report_all_bad:
557                     onReportAllBad();
558                     break;
559                 case R.id.link_stats:
560                     onLinkStats();
561                     break;
562             }
563         }
564     };
565 
566 
onStartDelayedCycle()567     private void onStartDelayedCycle() {
568         if (!mDelayedCycleStarted) {
569             mDelayedCycleStarted = true;
570             try {
571                 mDCOnDuration = Long.parseLong(mDCOnDurationEdit.getText().toString());
572                 mDCOffDuration = Long.parseLong(mDCOffDurationEdit.getText().toString());
573             } catch (Exception e) { };
574             mDCCycleCount = 0;
575 
576             mWakeLock = mPm.newWakeLock(PowerManager.FULL_WAKE_LOCK, "ConnectivityTest");
577             mWakeLock.acquire();
578             mHandler2.sendMessage(mHandler2.obtainMessage(EVENT_TOGGLE_WIFI));
579         }
580     }
581 
onStopDelayedCycle()582     private void onStopDelayedCycle() {
583         if (mDelayedCycleStarted) {
584             mDelayedCycleStarted = false;
585             mWakeLock.release();
586             mWakeLock = null;
587             if(mHandler2.hasMessages(EVENT_TOGGLE_WIFI)) {
588                 mHandler2.removeMessages(EVENT_TOGGLE_WIFI);
589             }
590         }
591     }
592 
onStartScreenCycle()593     private void onStartScreenCycle() {
594         try {
595             mSCOnDuration = Long.parseLong(mSCOnDurationEdit.getText().toString());
596             mSCOffDuration = Long.parseLong(mSCOffDurationEdit.getText().toString());
597         } catch (Exception e) { };
598         mSCCycleCount = 0;
599 
600         mScreenonWakeLock = mPm.newWakeLock(PowerManager.FULL_WAKE_LOCK,
601                 "ConnectivityTest");
602         mScreenonWakeLock.acquire();
603 
604         scheduleAlarm(10, SCREEN_OFF);
605     }
606 
scheduleAlarm(long delayMs, String eventType)607     private void scheduleAlarm(long delayMs, String eventType) {
608         AlarmManager am = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
609         Intent i = new Intent(CONNECTIVITY_TEST_ALARM);
610 
611         i.putExtra(TEST_ALARM_EXTRA, eventType);
612         i.putExtra(TEST_ALARM_ON_EXTRA, Long.toString(mSCOnDuration));
613         i.putExtra(TEST_ALARM_OFF_EXTRA, Long.toString(mSCOffDuration));
614         i.putExtra(TEST_ALARM_CYCLE_EXTRA, Integer.toString(mSCCycleCount));
615 
616         PendingIntent p = PendingIntent.getBroadcast(this, 0, i, PendingIntent.FLAG_UPDATE_CURRENT);
617 
618         am.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + delayMs, p);
619     }
620 
onStopScreenCycle()621     private void onStopScreenCycle() {
622     }
623 
onReportAllBad()624     private void onReportAllBad() {
625         Network[] networks = mCm.getAllNetworks();
626         for (Network network : networks) {
627             mCm.reportBadNetwork(network);
628         }
629     }
630 
onStartScanCycle()631     private void onStartScanCycle() {
632         if (mScanCur == -1) {
633             try {
634                 mScanCur = Long.parseLong(mScanCyclesEdit.getText().toString());
635                 mScanCycles = mScanCur;
636             } catch (Exception e) { };
637             if (mScanCur <= 0) {
638                 mScanCur = -1;
639                 mScanCycles = SCAN_CYCLES;
640                 return;
641             }
642         }
643         if (mScanCur > 0) {
644             registerReceiver(mScanRecv, mIntentFilter);
645             mScanButton.setText(PROGRESS_SCAN);
646             mScanResults.setVisibility(View.INVISIBLE);
647             if (mScanDisconnect.isChecked())
648                 mWm.disconnect();
649             mTotalScanTime = 0;
650             mTotalScanCount = 0;
651             Log.d(TAG, "Scan: START " + mScanCur);
652             mStartTime = SystemClock.elapsedRealtime();
653             mWm.startScan();
654         } else {
655             // Show results
656             mScanResults.setText("Average Scan Time = " +
657                 Long.toString(mTotalScanTime / mScanCycles) + " ms ; Average Scan Amount = " +
658                 Long.toString(mTotalScanCount / mScanCycles));
659             mScanResults.setVisibility(View.VISIBLE);
660             mScanButton.setText(START_SCAN);
661             mScanCur = -1;
662             mScanCyclesEdit.setText(Long.toString(mScanCycles));
663             if (mScanDisconnect.isChecked())
664                 mWm.reassociate();
665         }
666     }
667 
onStartTdls()668     private void onStartTdls() {
669         mTdlsAddr = ((EditText)findViewById(R.id.sc_ip_mac)).getText().toString();
670         Log.d(TAG, "TDLS: START " + mTdlsAddr);
671         InetAddress inetAddress = null;
672         try {
673             inetAddress = InetAddress.getByName(mTdlsAddr);
674             mWm.setTdlsEnabled(inetAddress, true);
675         } catch (Exception e) {
676             mWm.setTdlsEnabledWithMacAddress(mTdlsAddr, true);
677         }
678     }
679 
onStopTdls()680     private void onStopTdls() {
681         if (mTdlsAddr == null) return;
682         Log.d(TAG, "TDLS: STOP " + mTdlsAddr);
683         InetAddress inetAddress = null;
684         try {
685             inetAddress = InetAddress.getByName(mTdlsAddr);
686             mWm.setTdlsEnabled(inetAddress, false);
687         } catch (Exception e) {
688             mWm.setTdlsEnabledWithMacAddress(mTdlsAddr, false);
689         }
690     }
691 
onLinkStats()692     private void onLinkStats() {
693         Log.e(TAG, "LINK STATS:  ");
694         try {
695             mWm.getWifiActivityEnergyInfoAsync(getMainExecutor(), info -> {
696                 if (info != null) {
697                     mLinkStatsResults.setText(" power " + info.toString());
698                 } else {
699                     mLinkStatsResults.setText(" null! ");
700                 }
701             });
702         } catch (Exception e) {
703             mLinkStatsResults.setText(" failed! " + e.toString());
704         }
705     }
706 
707 
708     private final static int DEFAULT = 0;
709     private final static int SOCKET = 1;
710     private final static int HTTPS  = 2;
711 
onHttpRequestResults(final String results)712     private void onHttpRequestResults(final String results) {
713         runOnUiThread(new Runnable() {
714             @Override
715             public void run() {
716                 boolean enabled = !mRequestRunning;
717                 findViewById(R.id.default_request).setEnabled(enabled);
718 
719                 enabled = !mRequestRunning && mBoundTestNetwork.getNetwork() != null;
720                 findViewById(R.id.bound_http_request).setEnabled(enabled);
721                 findViewById(R.id.bound_socket_request).setEnabled(enabled);
722 
723                 if (!TextUtils.isEmpty(results) || !mRequestRunning) {
724                     ((TextView) findViewById(R.id.http_response)).setText(results);
725                 }
726             }
727         });
728     }
729 
doSocketRequest(Network network, String host, String path)730     private String doSocketRequest(Network network, String host, String path) throws IOException {
731         Socket sock = network.getSocketFactory().createSocket(host, 80);
732         try {
733           sock.setSoTimeout(5000);
734           OutputStreamWriter writer = new OutputStreamWriter(sock.getOutputStream());
735           String request = String.format(
736                   "GET %s HTTP/1.1\nHost: %s\nConnection: close\n\n", path, host);
737           writer.write(request);
738           writer.flush();
739           BufferedReader reader = new BufferedReader(new InputStreamReader(sock.getInputStream()));
740           String line = reader.readLine();
741 
742           if (line == null || !line.startsWith("HTTP/1.1 200")) {
743               // Error.
744               return "Error: " + line;
745           }
746 
747           do {
748               // Consume headers.
749               line = reader.readLine();
750           } while (!TextUtils.isEmpty(line));
751 
752           // Return first line of body.
753           return reader.readLine();
754         } finally {
755             if (sock != null) {
756                 IoUtils.closeQuietly(sock);
757             }
758         }
759     }
760 
onHttpRequest(final int type)761     private void onHttpRequest(final int type) {
762         mRequestRunning = true;
763         onHttpRequestResults(null);
764 
765         Thread requestThread = new Thread() {
766             public void run() {
767                 final String path = "/ip.js?fmt=text";
768                 final String randomHost =
769                         "h" + Integer.toString(new Random().nextInt()) + ".ds.ipv6test.google.com";
770                 final String fixedHost = "google-ipv6test.appspot.com";
771 
772                 Network network = mBoundTestNetwork.getNetwork();
773                 HttpURLConnection conn = null;
774                 InputStreamReader in = null;
775 
776                 try {
777                     final URL httpsUrl = new URL("https", fixedHost, path);
778                     BufferedReader reader;
779 
780                     switch (type) {
781                         case DEFAULT:
782                             conn = (HttpURLConnection) httpsUrl.openConnection(Proxy.NO_PROXY);
783                             in = new InputStreamReader(conn.getInputStream());
784                             reader = new BufferedReader(in);
785                             onHttpRequestResults(reader.readLine());
786                             break;
787                         case SOCKET:
788                             String response = doSocketRequest(network, randomHost, path);
789                             onHttpRequestResults(response);
790                             break;
791                         case HTTPS:
792                             conn = (HttpURLConnection) network.openConnection(httpsUrl,
793                                     Proxy.NO_PROXY);
794                             in = new InputStreamReader(conn.getInputStream());
795                             reader = new BufferedReader(in);
796                             onHttpRequestResults(reader.readLine());
797                             break;
798                         default:
799                             throw new IllegalArgumentException("Cannot happen");
800                     }
801                 } catch(IOException e) {
802                     onHttpRequestResults("Error! ");
803                 } finally {
804                     mRequestRunning = false;
805                     if (in != null) IoUtils.closeQuietly(in);
806                     if (conn != null) conn.disconnect();
807                 }
808             }
809         };
810         requestThread.start();
811     }
812 
onWifiMulticastLock(boolean enable)813     private void onWifiMulticastLock(boolean enable) {
814         Log.d(TAG, (enable ? "Acquiring" : "Releasing") + " wifi multicast lock");
815         if (enable) {
816             mWml.acquire();
817         } else {
818             mWml.release();
819         }
820         findViewById(R.id.acquireWifiMulticastLock).setEnabled(!enable);
821         findViewById(R.id.releaseWifiMulticastLock).setEnabled(enable);
822     }
823 }
824