1/*
2 * Copyright (C) 2010, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.connectivitymanagertest;
18
19import android.app.Activity;
20import android.content.Context;
21import android.content.BroadcastReceiver;
22import android.content.Intent;
23import android.content.IntentFilter;
24import android.net.ConnectivityManager;
25import android.net.NetworkInfo;
26import android.net.NetworkInfo.State;
27import android.net.wifi.WifiConfiguration;
28import android.net.wifi.WifiManager;
29import android.net.wifi.WifiInfo;
30import android.net.wifi.ScanResult;
31import android.net.wifi.WifiConfiguration.KeyMgmt;
32import android.os.Bundle;
33import android.os.Handler;
34import android.os.IPowerManager;
35import android.os.Message;
36import android.os.PowerManager;
37import android.os.ServiceManager;
38import android.os.SystemClock;
39import android.os.UserHandle;
40import android.provider.Settings;
41import android.util.Log;
42import android.view.KeyEvent;
43import android.widget.LinearLayout;
44
45import com.android.internal.util.AsyncChannel;
46
47import java.io.IOException;
48import java.io.InputStream;
49import java.net.UnknownHostException;
50import java.util.ArrayList;
51import java.util.List;
52
53
54/**
55 * An activity registered with connectivity manager broadcast
56 * provides network connectivity information and
57 * can be used to set device states: Cellular, Wifi, Airplane mode.
58 */
59public class ConnectivityManagerTestActivity extends Activity {
60
61    public static final String LOG_TAG = "ConnectivityManagerTestActivity";
62    public static final int WAIT_FOR_SCAN_RESULT = 10 * 1000; //10 seconds
63    public static final int WIFI_SCAN_TIMEOUT = 50 * 1000;
64    public static final int SHORT_TIMEOUT = 5 * 1000;
65    public static final long LONG_TIMEOUT = 50 * 1000;
66    // 2 minutes timer between wifi stop and start
67    public static final long  WIFI_STOP_START_INTERVAL = 2 * 60 * 1000;
68    // Set ping test timer to be 3 minutes
69    public static final long PING_TIMER = 3 * 60 *1000;
70    public static final int SUCCESS = 0;  // for Wifi tethering state change
71    public static final int FAILURE = 1;
72    public static final int INIT = -1;
73    private static final String ACCESS_POINT_FILE = "accesspoints.xml";
74    public ConnectivityReceiver mConnectivityReceiver = null;
75    public WifiReceiver mWifiReceiver = null;
76    private AccessPointParserHelper mParseHelper = null;
77    /*
78     * Track network connectivity information
79     */
80    public State mState;
81    public NetworkInfo mNetworkInfo;
82    public NetworkInfo mOtherNetworkInfo;
83    public boolean mIsFailOver;
84    public String mReason;
85    public boolean mScanResultIsAvailable = false;
86    public ConnectivityManager mCM;
87    public Object wifiObject = new Object();
88    public Object connectivityObject = new Object();
89    public int mWifiState;
90    public NetworkInfo mWifiNetworkInfo;
91    public String mBssid;
92    public String mPowerSsid = "opennet"; //Default power SSID
93    private Context mContext;
94    public boolean scanResultAvailable = false;
95
96    /*
97     * Control Wifi States
98     */
99    public WifiManager mWifiManager;
100
101    /*
102     * Verify connectivity state
103     */
104    public static final int NUM_NETWORK_TYPES = ConnectivityManager.MAX_NETWORK_TYPE + 1;
105    NetworkState[] connectivityState = new NetworkState[NUM_NETWORK_TYPES];
106
107    // For wifi tethering tests
108    private String[] mWifiRegexs;
109    public int mWifiTetherResult = INIT;    // -1 is initialization state
110
111    /**
112     * A wrapper of a broadcast receiver which provides network connectivity information
113     * for all kinds of network: wifi, mobile, etc.
114     */
115    private class ConnectivityReceiver extends BroadcastReceiver {
116        @Override
117        public void onReceive(Context context, Intent intent) {
118            log("ConnectivityReceiver: onReceive() is called with " + intent);
119            String action = intent.getAction();
120            if (!action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
121                Log.v("ConnectivityReceiver", "onReceive() called with " + intent);
122                return;
123            }
124
125            boolean noConnectivity =
126                intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
127
128            if (noConnectivity) {
129                mState = State.DISCONNECTED;
130            } else {
131                mState = State.CONNECTED;
132            }
133
134            mNetworkInfo = (NetworkInfo)
135                intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
136
137            mOtherNetworkInfo = (NetworkInfo)
138                intent.getParcelableExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO);
139
140            mReason = intent.getStringExtra(ConnectivityManager.EXTRA_REASON);
141            mIsFailOver = intent.getBooleanExtra(ConnectivityManager.EXTRA_IS_FAILOVER, false);
142
143            log("mNetworkInfo: " + mNetworkInfo.toString());
144            if (mOtherNetworkInfo != null) {
145                log("mOtherNetworkInfo: " + mOtherNetworkInfo.toString());
146            }
147            recordNetworkState(mNetworkInfo.getType(), mNetworkInfo.getState());
148            if (mOtherNetworkInfo != null) {
149                recordNetworkState(mOtherNetworkInfo.getType(), mOtherNetworkInfo.getState());
150            }
151            notifyNetworkConnectivityChange();
152        }
153    }
154
155    private class WifiReceiver extends BroadcastReceiver {
156        @Override
157        public void onReceive(Context context, Intent intent) {
158            String action = intent.getAction();
159            Log.v("WifiReceiver", "onReceive() is calleld with " + intent);
160            if (action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
161                log("scan results are available");
162                notifyScanResult();
163            } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
164                mWifiNetworkInfo =
165                    (NetworkInfo) intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
166                log("mWifiNetworkInfo: " + mWifiNetworkInfo.toString());
167                if (mWifiNetworkInfo.getState() == State.CONNECTED) {
168                    mBssid = intent.getStringExtra(WifiManager.EXTRA_BSSID);
169                }
170                notifyWifiState();
171            } else if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
172                mWifiState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
173                                                WifiManager.WIFI_STATE_UNKNOWN);
174                notifyWifiState();
175            } else if (action.equals(WifiManager.WIFI_AP_STATE_CHANGED_ACTION)) {
176                notifyWifiAPState();
177            } else if (action.equals(ConnectivityManager.ACTION_TETHER_STATE_CHANGED)) {
178                ArrayList<String> available = intent.getStringArrayListExtra(
179                        ConnectivityManager.EXTRA_AVAILABLE_TETHER);
180                ArrayList<String> active = intent.getStringArrayListExtra(
181                        ConnectivityManager.EXTRA_ACTIVE_TETHER);
182                ArrayList<String> errored = intent.getStringArrayListExtra(
183                        ConnectivityManager.EXTRA_ERRORED_TETHER);
184                updateTetherState(available.toArray(), active.toArray(), errored.toArray());
185            }
186            else {
187                return;
188            }
189        }
190    }
191
192    private class WifiServiceHandler extends Handler {
193        @Override
194        public void handleMessage(Message msg) {
195            switch (msg.what) {
196                case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
197                    if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
198                        //AsyncChannel in msg.obj
199                    } else {
200                        log("Failed to establish AsyncChannel connection");
201                    }
202                    break;
203                default:
204                    //Ignore
205                    break;
206            }
207        }
208    }
209
210    public ConnectivityManagerTestActivity() {
211        mState = State.UNKNOWN;
212        scanResultAvailable = false;
213    }
214
215    @Override
216    protected void onCreate(Bundle savedInstanceState) {
217        super.onCreate(savedInstanceState);
218        log("onCreate, inst=" + Integer.toHexString(hashCode()));
219
220        // Create a simple layout
221        LinearLayout contentView = new LinearLayout(this);
222        contentView.setOrientation(LinearLayout.VERTICAL);
223        setContentView(contentView);
224        setTitle("ConnectivityManagerTestActivity");
225
226
227        // register a connectivity receiver for CONNECTIVITY_ACTION;
228        mConnectivityReceiver = new ConnectivityReceiver();
229        registerReceiver(mConnectivityReceiver,
230                new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
231
232        mWifiReceiver = new WifiReceiver();
233        IntentFilter mIntentFilter = new IntentFilter();
234        mIntentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
235        mIntentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
236        mIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
237        mIntentFilter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
238        mIntentFilter.addAction(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
239        mIntentFilter.addAction(ConnectivityManager.ACTION_TETHER_STATE_CHANGED);
240        registerReceiver(mWifiReceiver, mIntentFilter);
241
242        // Get an instance of ConnectivityManager
243        mCM = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
244        // Get an instance of WifiManager
245        mWifiManager =(WifiManager)getSystemService(Context.WIFI_SERVICE);
246        mContext = this;
247
248        if (mWifiManager.isWifiApEnabled()) {
249            // if soft AP is enabled, disable it
250            mWifiManager.setWifiApEnabled(null, false);
251            log("Disable soft ap");
252        }
253
254        initializeNetworkStates();
255        log("Clear Wifi before we start the test.");
256        removeConfiguredNetworksAndDisableWifi();
257        mWifiRegexs = mCM.getTetherableWifiRegexs();
258     }
259
260    public List<WifiConfiguration> loadNetworkConfigurations() throws Exception {
261        InputStream in = getAssets().open(ACCESS_POINT_FILE);
262        mParseHelper = new AccessPointParserHelper(in);
263        return mParseHelper.getNetworkConfigurations();
264    }
265
266    // for each network type, initialize network states to UNKNOWN, and no verification flag is set
267    public void initializeNetworkStates() {
268        for (int networkType = NUM_NETWORK_TYPES - 1; networkType >=0; networkType--) {
269            connectivityState[networkType] =  new NetworkState();
270            log("Initialize network state for " + networkType + ": " +
271                    connectivityState[networkType].toString());
272        }
273    }
274
275    // deposit a network state
276    public void recordNetworkState(int networkType, State networkState) {
277        log("record network state for network " +  networkType +
278                ", state is " + networkState);
279        connectivityState[networkType].recordState(networkState);
280    }
281
282    // set the state transition criteria
283    public void setStateTransitionCriteria(int networkType, State initState,
284            int transitionDir, State targetState) {
285        connectivityState[networkType].setStateTransitionCriteria(
286                initState, transitionDir, targetState);
287    }
288
289    // Validate the states recorded
290    public boolean validateNetworkStates(int networkType) {
291        log("validate network state for " + networkType + ": ");
292        return connectivityState[networkType].validateStateTransition();
293    }
294
295    // return result from network state validation
296    public String getTransitionFailureReason(int networkType) {
297        log("get network state transition failure reason for " + networkType + ": " +
298                connectivityState[networkType].toString());
299        return connectivityState[networkType].getReason();
300    }
301
302    private void notifyNetworkConnectivityChange() {
303        synchronized(connectivityObject) {
304            log("notify network connectivity changed");
305            connectivityObject.notifyAll();
306        }
307    }
308    private void notifyScanResult() {
309        synchronized (this) {
310            log("notify that scan results are available");
311            scanResultAvailable = true;
312            this.notify();
313        }
314    }
315
316    private void notifyWifiState() {
317        synchronized (wifiObject) {
318            log("notify wifi state changed");
319            wifiObject.notify();
320        }
321    }
322
323    private void notifyWifiAPState() {
324        synchronized (this) {
325            log("notify wifi AP state changed");
326            this.notify();
327        }
328    }
329
330    // Update wifi tethering state
331    private void updateTetherState(Object[] available, Object[] tethered, Object[] errored) {
332        boolean wifiTethered = false;
333        boolean wifiErrored = false;
334
335        synchronized (this) {
336            for (Object obj: tethered) {
337                String str = (String)obj;
338                for (String tethRex: mWifiRegexs) {
339                    log("str: " + str +"tethRex: " + tethRex);
340                    if (str.matches(tethRex)) {
341                        wifiTethered = true;
342                    }
343                }
344            }
345
346            for (Object obj: errored) {
347                String str = (String)obj;
348                for (String tethRex: mWifiRegexs) {
349                    log("error: str: " + str +"tethRex: " + tethRex);
350                    if (str.matches(tethRex)) {
351                        wifiErrored = true;
352                    }
353                }
354            }
355
356            if (wifiTethered) {
357                mWifiTetherResult = SUCCESS;   // wifi tethering is successful
358            } else if (wifiErrored) {
359                mWifiTetherResult = FAILURE;   // wifi tethering failed
360            }
361            log("mWifiTetherResult: " + mWifiTetherResult);
362            this.notify();
363        }
364    }
365
366
367    // Wait for network connectivity state: CONNECTING, CONNECTED, SUSPENDED,
368    //                                      DISCONNECTING, DISCONNECTED, UNKNOWN
369    public boolean waitForNetworkState(int networkType, State expectedState, long timeout) {
370        long startTime = System.currentTimeMillis();
371        while (true) {
372            if ((System.currentTimeMillis() - startTime) > timeout) {
373                log("waitForNetworkState time out, the state of network type " + networkType +
374                        " is: " + mCM.getNetworkInfo(networkType).getState());
375                if (mCM.getNetworkInfo(networkType).getState() != expectedState) {
376                    return false;
377                } else {
378                    // the broadcast has been sent out. the state has been changed.
379                    log("networktype: " + networkType + " state: " +
380                            mCM.getNetworkInfo(networkType));
381                    return true;
382                }
383            }
384            log("Wait for the connectivity state for network: " + networkType +
385                    " to be " + expectedState.toString());
386            synchronized (connectivityObject) {
387                try {
388                    connectivityObject.wait(SHORT_TIMEOUT);
389                } catch (InterruptedException e) {
390                    e.printStackTrace();
391                }
392                if ((mNetworkInfo.getType() != networkType) ||
393                    (mNetworkInfo.getState() != expectedState)) {
394                    log("network state for " + mNetworkInfo.getType() +
395                            "is: " + mNetworkInfo.getState());
396                    continue;
397                }
398                return true;
399            }
400        }
401    }
402
403    // Wait for Wifi state: WIFI_STATE_DISABLED, WIFI_STATE_DISABLING, WIFI_STATE_ENABLED,
404    //                      WIFI_STATE_ENALBING, WIFI_STATE_UNKNOWN
405    public boolean waitForWifiState(int expectedState, long timeout) {
406        long startTime = System.currentTimeMillis();
407        while (true) {
408            if ((System.currentTimeMillis() - startTime) > timeout) {
409                if (mWifiState != expectedState) {
410                    return false;
411                } else {
412                    return true;
413                }
414            }
415            log("Wait for wifi state to be: " + expectedState);
416            synchronized (wifiObject) {
417                try {
418                    wifiObject.wait(SHORT_TIMEOUT);
419                } catch (InterruptedException e) {
420                    e.printStackTrace();
421                }
422                if (mWifiState != expectedState) {
423                    log("Wifi state is: " + mWifiState);
424                    continue;
425                }
426                return true;
427            }
428        }
429    }
430
431    // Wait for Wifi AP state: WIFI_AP_STATE_DISABLED, WIFI_AP_STATE_DISABLING,
432    //                         WIFI_AP_STATE_ENABLED, WIFI_STATE_ENALBING, WIFI_STATE_UNKNOWN
433    public boolean waitForWifiAPState(int expectedState, long timeout) {
434        long startTime = System.currentTimeMillis();
435        while (true) {
436            if ((System.currentTimeMillis() - startTime) > timeout) {
437                if (mWifiManager.getWifiApState() != expectedState) {
438                    return false;
439                } else {
440                    return true;
441                }
442            }
443            log("Wait for wifi AP state to be: " + expectedState);
444            synchronized (wifiObject) {
445                try {
446                    wifiObject.wait(SHORT_TIMEOUT);
447                } catch (InterruptedException e) {
448                    e.printStackTrace();
449                }
450                if (mWifiManager.getWifiApState() != expectedState) {
451                    log("Wifi state is: " + mWifiManager.getWifiApState());
452                    continue;
453                }
454                return true;
455            }
456        }
457    }
458
459    /**
460     * Wait for the wifi tethering result:
461     * @param timeout is the maximum waiting time
462     * @return SUCCESS if tethering result is successful
463     *         FAILURE if tethering result returns error.
464     */
465    public int waitForTetherStateChange(long timeout) {
466        long startTime = System.currentTimeMillis();
467        while (true) {
468            if ((System.currentTimeMillis() - startTime) > timeout) {
469                return mWifiTetherResult;
470            }
471            log("Wait for wifi tethering result.");
472            synchronized (this) {
473                try {
474                    this.wait(SHORT_TIMEOUT);
475                } catch (InterruptedException e) {
476                    e.printStackTrace();
477                }
478                if (mWifiTetherResult == INIT ) {
479                    continue;
480                } else {
481                    return mWifiTetherResult;
482                }
483            }
484        }
485    }
486
487    // Return true if device is currently connected to mobile network
488    public boolean isConnectedToMobile() {
489        return (mNetworkInfo.getType() == ConnectivityManager.TYPE_MOBILE);
490    }
491
492    // Return true if device is currently connected to Wifi
493    public boolean isConnectedToWifi() {
494        return (mNetworkInfo.getType() == ConnectivityManager.TYPE_WIFI);
495    }
496
497    public boolean enableWifi() {
498        return mWifiManager.setWifiEnabled(true);
499    }
500
501    // Turn screen off
502    public void turnScreenOff() {
503        log("Turn screen off");
504        PowerManager pm =
505            (PowerManager) getSystemService(Context.POWER_SERVICE);
506        pm.goToSleep(SystemClock.uptimeMillis());
507    }
508
509    // Turn screen on
510    public void turnScreenOn() {
511        log("Turn screen on");
512        PowerManager pm =
513                (PowerManager) getSystemService(Context.POWER_SERVICE);
514        pm.wakeUp(SystemClock.uptimeMillis());
515    }
516
517    /**
518     * @param pingServerList a list of servers that can be used for ping test, can be null
519     * @return true if the ping test is successful, false otherwise.
520     */
521    public boolean pingTest(String[] pingServerList) {
522        String[] hostList = {"www.google.com", "www.yahoo.com",
523                "www.bing.com", "www.facebook.com", "www.ask.com"};
524        if (pingServerList != null) {
525            hostList = pingServerList;
526        }
527
528        long startTime = System.currentTimeMillis();
529        while ((System.currentTimeMillis() - startTime) < PING_TIMER) {
530            try {
531                // assume the chance that all servers are down is very small
532                for (int i = 0; i < hostList.length; i++ ) {
533                    String host = hostList[i];
534                    log("Start ping test, ping " + host);
535                    Process p = Runtime.getRuntime().exec("ping -c 10 -w 100 " + host);
536                    int status = p.waitFor();
537                    if (status == 0) {
538                        // if any of the ping test is successful, return true
539                        return true;
540                    }
541                }
542            } catch (UnknownHostException e) {
543                log("Ping test Fail: Unknown Host");
544            } catch (IOException e) {
545                log("Ping test Fail:  IOException");
546            } catch (InterruptedException e) {
547                log("Ping test Fail: InterruptedException");
548            }
549        }
550        // ping test timeout
551        return false;
552    }
553
554    /**
555     * Associate the device to given SSID
556     * If the device is already associated with a WiFi, disconnect and forget it,
557     * We don't verify whether the connection is successful or not, leave this to the test
558     */
559    public boolean connectToWifi(String knownSSID) {
560        WifiConfiguration config = new WifiConfiguration();
561        config.SSID = knownSSID;
562        config.allowedKeyManagement.set(KeyMgmt.NONE);
563        return connectToWifiWithConfiguration(config);
564    }
565
566    /**
567     * Connect to Wi-Fi with the given configuration. Note the SSID in the configuration
568     * is pure string, we need to convert it to quoted string.
569     * @param config
570     * @return
571     */
572    public boolean connectToWifiWithConfiguration(WifiConfiguration config) {
573        String ssid = config.SSID;
574        config.SSID = convertToQuotedString(ssid);
575
576        //If Wifi is not enabled, enable it
577        if (!mWifiManager.isWifiEnabled()) {
578            log("Wifi is not enabled, enable it");
579            mWifiManager.setWifiEnabled(true);
580            // wait for the wifi state change before start scanning.
581            if (!waitForWifiState(WifiManager.WIFI_STATE_ENABLED, 2*SHORT_TIMEOUT)) {
582                log("wait for WIFI_STATE_ENABLED failed");
583                return false;
584            }
585        }
586
587        boolean foundApInScanResults = false;
588        for (int retry = 0; retry < 5; retry++) {
589            List<ScanResult> netList = mWifiManager.getScanResults();
590            if (netList != null) {
591                log("size of scan result list: " + netList.size());
592                for (int i = 0; i < netList.size(); i++) {
593                    ScanResult sr= netList.get(i);
594                    if (sr.SSID.equals(ssid)) {
595                        log("found " + ssid + " in the scan result list");
596                        log("retry: " + retry);
597                        foundApInScanResults = true;
598                        mWifiManager.connect(config,
599                                new WifiManager.ActionListener() {
600                                    public void onSuccess() {
601                                    }
602                                    public void onFailure(int reason) {
603                                        log("connect failure " + reason);
604                                    }
605                                });
606                        break;
607                   }
608                }
609            }
610            if (foundApInScanResults) {
611                return true;
612            } else {
613                // Start an active scan
614                mWifiManager.startScanActive();
615                mScanResultIsAvailable = false;
616                long startTime = System.currentTimeMillis();
617                while (!mScanResultIsAvailable) {
618                    if ((System.currentTimeMillis() - startTime) > WIFI_SCAN_TIMEOUT) {
619                        log("wait for scan results timeout");
620                        return false;
621                    }
622                    // wait for the scan results to be available
623                    synchronized (this) {
624                        // wait for the scan result to be available
625                        try {
626                            this.wait(WAIT_FOR_SCAN_RESULT);
627                        } catch (InterruptedException e) {
628                            e.printStackTrace();
629                        }
630                        if ((mWifiManager.getScanResults() == null) ||
631                                (mWifiManager.getScanResults().size() <= 0)) {
632                            continue;
633                        }
634                        mScanResultIsAvailable = true;
635                    }
636                }
637            }
638        }
639        return false;
640    }
641
642    /*
643     * Disconnect from the current AP and remove configured networks.
644     */
645    public boolean disconnectAP() {
646        // remove saved networks
647        if (!mWifiManager.isWifiEnabled()) {
648            log("Enabled wifi before remove configured networks");
649            mWifiManager.setWifiEnabled(true);
650            sleep(SHORT_TIMEOUT);
651        }
652        List<WifiConfiguration> wifiConfigList = mWifiManager.getConfiguredNetworks();
653        log("size of wifiConfigList: " + wifiConfigList.size());
654        for (WifiConfiguration wifiConfig: wifiConfigList) {
655            log("remove wifi configuration: " + wifiConfig.networkId);
656            int netId = wifiConfig.networkId;
657            mWifiManager.forget(netId, new WifiManager.ActionListener() {
658                    public void onSuccess() {
659                    }
660                    public void onFailure(int reason) {
661                        log("Failed to forget " + reason);
662                    }
663                });
664        }
665        return true;
666    }
667    /**
668     * Disable Wifi
669     * @return true if Wifi is disabled successfully
670     */
671    public boolean disableWifi() {
672        return mWifiManager.setWifiEnabled(false);
673    }
674
675    /**
676     * Remove configured networks and disable wifi
677     */
678    public boolean removeConfiguredNetworksAndDisableWifi() {
679        if (!disconnectAP()) {
680           return false;
681        }
682        sleep(SHORT_TIMEOUT);
683        if (!mWifiManager.setWifiEnabled(false)) {
684            return false;
685        }
686        sleep(SHORT_TIMEOUT);
687        return true;
688    }
689
690    private void sleep(long sleeptime) {
691        try {
692            Thread.sleep(sleeptime);
693        } catch (InterruptedException e) {}
694    }
695
696    /**
697     * Set airplane mode
698     */
699    public void setAirplaneMode(Context context, boolean enableAM) {
700        //set the airplane mode
701        Settings.Global.putInt(context.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON,
702                enableAM ? 1 : 0);
703        // Post the intent
704        Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
705        intent.putExtra("state", enableAM);
706        context.sendBroadcastAsUser(intent, UserHandle.ALL);
707    }
708
709    protected static String convertToQuotedString(String string) {
710        return "\"" + string + "\"";
711    }
712
713    @Override
714    protected void onDestroy() {
715        super.onDestroy();
716
717        //Unregister receiver
718        if (mConnectivityReceiver != null) {
719            unregisterReceiver(mConnectivityReceiver);
720        }
721        if (mWifiReceiver != null) {
722            unregisterReceiver(mWifiReceiver);
723        }
724        log("onDestroy, inst=" + Integer.toHexString(hashCode()));
725    }
726
727    @Override
728    public void onStart() {
729        super.onStart();
730        mContext = this;
731        Bundle bundle = this.getIntent().getExtras();
732        if (bundle != null){
733            mPowerSsid = bundle.getString("power_ssid");
734        }
735    }
736    //A thread to set the device into airplane mode then turn on wifi.
737    Thread setDeviceWifiAndAirplaneThread = new Thread(new Runnable() {
738        public void run() {
739            setAirplaneMode(mContext, true);
740            connectToWifi(mPowerSsid);
741        }
742    });
743
744    //A thread to set the device into wifi
745    Thread setDeviceInWifiOnlyThread = new Thread(new Runnable() {
746        public void run() {
747            connectToWifi(mPowerSsid);
748        }
749    });
750
751    @Override
752    public boolean onKeyDown(int keyCode, KeyEvent event) {
753        switch (keyCode) {
754            //This is a tricky way for the scripted monkey to
755            //set the device in wifi and wifi in airplane mode.
756            case KeyEvent.KEYCODE_1:
757                setDeviceWifiAndAirplaneThread.start();
758                break;
759
760            case KeyEvent.KEYCODE_2:
761                setDeviceInWifiOnlyThread.start();
762                break;
763        }
764        return super.onKeyDown(keyCode, event);
765    }
766
767    private void log(String message) {
768        Log.v(LOG_TAG, message);
769    }
770}
771