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