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