1e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu/* 2e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu * Copyright (C) 2016 The Android Open Source Project 3e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu * 4e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu * Licensed under the Apache License, Version 2.0 (the "License"); 5e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu * you may not use this file except in compliance with the License. 6e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu * You may obtain a copy of the License at 7e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu * 8e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu * http://www.apache.org/licenses/LICENSE-2.0 9e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu * 10e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu * Unless required by applicable law or agreed to in writing, software 11e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu * distributed under the License is distributed on an "AS IS" BASIS, 12e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu * See the License for the specific language governing permissions and 14e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu * limitations under the License. 15e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu */ 16e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu 17e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiupackage com.android.server.wifi; 18e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu 19e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiuimport static com.android.server.wifi.util.ApConfigUtil.ERROR_GENERIC; 20e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiuimport static com.android.server.wifi.util.ApConfigUtil.ERROR_NO_CHANNEL; 21e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiuimport static com.android.server.wifi.util.ApConfigUtil.SUCCESS; 22e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu 23e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiuimport android.content.BroadcastReceiver; 24e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiuimport android.content.Context; 25e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiuimport android.content.Intent; 26e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiuimport android.content.IntentFilter; 27e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiuimport android.net.ConnectivityManager; 28e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiuimport android.net.InterfaceConfiguration; 29e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiuimport android.net.LinkAddress; 30e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiuimport android.net.NetworkUtils; 31e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiuimport android.net.wifi.WifiConfiguration; 32e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiuimport android.net.wifi.WifiManager; 33e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiuimport android.os.INetworkManagementService; 34e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiuimport android.os.Looper; 35e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiuimport android.os.Message; 36e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiuimport android.util.Log; 37e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu 38e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiuimport com.android.internal.util.State; 39e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiuimport com.android.internal.util.StateMachine; 40e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiuimport com.android.server.wifi.util.ApConfigUtil; 41e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu 42e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiuimport java.util.ArrayList; 43e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiuimport java.util.Locale; 44e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu 45e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu/** 46e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu * Manage WiFi in AP mode. 47e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu * The internal state machine runs under "WifiStateMachine" thread context. 48e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu */ 49e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiupublic class SoftApManager { 50e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu private static final String TAG = "SoftApManager"; 51e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu 52e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu private final Context mContext; 53e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu private final INetworkManagementService mNmService; 54e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu private final WifiNative mWifiNative; 55e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu private final ConnectivityManager mConnectivityManager; 56e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu private final ArrayList<Integer> mAllowed2GChannels; 57e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu 58e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu private final String mCountryCode; 59e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu 60e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu private final String mInterfaceName; 61e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu private String mTetherInterfaceName; 62e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu 63e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu private final SoftApStateMachine mStateMachine; 64e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu 65e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu private final Listener mListener; 66e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu 67e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu private static class TetherStateChange { 68e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu public ArrayList<String> available; 69e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu public ArrayList<String> active; 70e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu 71e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu TetherStateChange(ArrayList<String> av, ArrayList<String> ac) { 72e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu available = av; 73e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu active = ac; 74e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu } 75e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu } 76e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu 77e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu /** 78e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu * Listener for soft AP state changes. 79e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu */ 80e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu public interface Listener { 81e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu /** 82e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu * Invoke when AP state changed. 83e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu * @param state new AP state 84e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu * @param failureReason reason when in failed state 85e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu */ 86e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu void onStateChanged(int state, int failureReason); 87e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu } 88e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu 89e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu public SoftApManager(Context context, 90e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu Looper looper, 91e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu WifiNative wifiNative, 92e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu INetworkManagementService nmService, 93e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu ConnectivityManager connectivityManager, 94e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu String countryCode, 95e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu ArrayList<Integer> allowed2GChannels, 96e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu Listener listener) { 97e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu mStateMachine = new SoftApStateMachine(looper); 98e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu 99e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu mContext = context; 100e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu mNmService = nmService; 101e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu mWifiNative = wifiNative; 102e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu mConnectivityManager = connectivityManager; 103e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu mCountryCode = countryCode; 104e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu mAllowed2GChannels = allowed2GChannels; 105e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu mListener = listener; 106e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu 107e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu mInterfaceName = mWifiNative.getInterfaceName(); 108e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu 109e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu /* Register receiver for tether state changes. */ 110e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu mContext.registerReceiver( 111e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu new BroadcastReceiver() { 112e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu @Override 113e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu public void onReceive(Context context, Intent intent) { 114e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu ArrayList<String> available = intent.getStringArrayListExtra( 115e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu ConnectivityManager.EXTRA_AVAILABLE_TETHER); 116e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu ArrayList<String> active = intent.getStringArrayListExtra( 117e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu ConnectivityManager.EXTRA_ACTIVE_TETHER); 118e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu mStateMachine.sendMessage( 119e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu SoftApStateMachine.CMD_TETHER_STATE_CHANGE, 120e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu new TetherStateChange(available, active)); 121e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu } 122e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu }, new IntentFilter(ConnectivityManager.ACTION_TETHER_STATE_CHANGED)); 123e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu } 124e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu 125e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu /** 126e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu * Start soft AP with given configuration. 127e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu * @param config AP configuration 128e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu */ 129e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu public void start(WifiConfiguration config) { 130e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu mStateMachine.sendMessage(SoftApStateMachine.CMD_START, config); 131e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu } 132e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu 133e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu /** 134e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu * Stop soft AP. 135e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu */ 136e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu public void stop() { 137e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu mStateMachine.sendMessage(SoftApStateMachine.CMD_STOP); 138e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu } 139e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu 140e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu /** 141e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu * Update AP state. 142e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu * @param state new AP state 143e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu * @param reason Failure reason if the new AP state is in failure state 144e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu */ 145e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu private void updateApState(int state, int reason) { 146e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu if (mListener != null) { 147e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu mListener.onStateChanged(state, reason); 148e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu } 149e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu } 150e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu 151e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu /** 152e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu * Start a soft AP instance with the given configuration. 153e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu * @param config AP configuration 154e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu * @return integer result code 155e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu */ 156e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu private int startSoftAp(WifiConfiguration config) { 157e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu if (config == null) { 158e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu Log.e(TAG, "Unable to start soft AP without configuration"); 159e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu return ERROR_GENERIC; 160e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu } 161e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu 162e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu /* Make a copy of configuration for updating AP band and channel. */ 163e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu WifiConfiguration localConfig = new WifiConfiguration(config); 164e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu 165e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu int result = ApConfigUtil.updateApChannelConfig( 166e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu mWifiNative, mCountryCode, mAllowed2GChannels, localConfig); 167e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu if (result != SUCCESS) { 168e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu Log.e(TAG, "Failed to update AP band and channel"); 169e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu return result; 170e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu } 171e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu 172e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu /* Setup country code if it is provide. */ 173e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu if (mCountryCode != null) { 174e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu /** 175e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu * Country code is mandatory for 5GHz band, return an error if failed to set 176e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu * country code when AP is configured for 5GHz band. 177e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu */ 178e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu if (!mWifiNative.setCountryCodeHal(mCountryCode.toUpperCase(Locale.ROOT)) 179e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu && config.apBand == WifiConfiguration.AP_BAND_5GHZ) { 180e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu Log.e(TAG, "Failed to set country code, required for setting up " 181e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu + "soft ap in 5GHz"); 182e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu return ERROR_GENERIC; 183e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu } 184e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu } 185e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu 186e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu try { 187e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu mNmService.startAccessPoint(localConfig, mInterfaceName); 188e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu } catch (Exception e) { 189e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu Log.e(TAG, "Exception in starting soft AP: " + e); 190e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu return ERROR_GENERIC; 191e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu } 192e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu 193e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu Log.d(TAG, "Soft AP is started"); 194e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu 195e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu return SUCCESS; 196e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu } 197e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu 198e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu /** 199e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu * Teardown soft AP. 200e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu */ 201e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu private void stopSoftAp() { 202e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu try { 203e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu mNmService.stopAccessPoint(mInterfaceName); 204e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu } catch (Exception e) { 205e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu Log.e(TAG, "Exception in stopping soft AP: " + e); 206e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu return; 207e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu } 208e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu Log.d(TAG, "Soft AP is stopped"); 209e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu } 210e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu 211e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu private boolean startTethering(ArrayList<String> available) { 212e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu String[] wifiRegexs = mConnectivityManager.getTetherableWifiRegexs(); 213e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu 214e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu for (String intf : available) { 215e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu for (String regex : wifiRegexs) { 216e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu if (intf.matches(regex)) { 217e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu try { 218e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu InterfaceConfiguration ifcg = 219e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu mNmService.getInterfaceConfig(intf); 220e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu if (ifcg != null) { 221e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu /* IP/netmask: 192.168.43.1/255.255.255.0 */ 222e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu ifcg.setLinkAddress(new LinkAddress( 223e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu NetworkUtils.numericToInetAddress("192.168.43.1"), 24)); 224e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu ifcg.setInterfaceUp(); 225e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu 226e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu mNmService.setInterfaceConfig(intf, ifcg); 227e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu } 228e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu } catch (Exception e) { 229e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu Log.e(TAG, "Error configuring interface " + intf + ", :" + e); 230e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu return false; 231e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu } 232e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu 233e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu if (mConnectivityManager.tether(intf) 234e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu != ConnectivityManager.TETHER_ERROR_NO_ERROR) { 235e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu Log.e(TAG, "Error tethering on " + intf); 236e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu return false; 237e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu } 238e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu mTetherInterfaceName = intf; 239e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu return true; 240e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu } 241e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu } 242e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu } 243e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu /* We found no interfaces to tether. */ 244e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu return false; 245e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu } 246e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu 247e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu private void stopTethering() { 248e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu try { 249e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu /* Clear the interface address. */ 250e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu InterfaceConfiguration ifcg = 251e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu mNmService.getInterfaceConfig(mTetherInterfaceName); 252e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu if (ifcg != null) { 253e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu ifcg.setLinkAddress( 254e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu new LinkAddress( 255e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu NetworkUtils.numericToInetAddress("0.0.0.0"), 0)); 256e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu mNmService.setInterfaceConfig(mTetherInterfaceName, ifcg); 257e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu } 258e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu } catch (Exception e) { 259e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu Log.e(TAG, "Error resetting interface " + mTetherInterfaceName + ", :" + e); 260e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu } 261e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu 262e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu if (mConnectivityManager.untether(mTetherInterfaceName) 263e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu != ConnectivityManager.TETHER_ERROR_NO_ERROR) { 264e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu Log.e(TAG, "Untether initiate failed!"); 265e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu } 266e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu } 267e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu 268e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu private boolean isWifiTethered(ArrayList<String> active) { 269e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu String[] wifiRegexs = mConnectivityManager.getTetherableWifiRegexs(); 270e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu for (String intf : active) { 271e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu for (String regex : wifiRegexs) { 272e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu if (intf.matches(regex)) { 273e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu return true; 274e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu } 275e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu } 276e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu } 277e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu /* No tethered interface. */ 278e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu return false; 279e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu } 280e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu 281e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu private class SoftApStateMachine extends StateMachine { 282e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu /* Commands for the state machine. */ 283e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu public static final int CMD_START = 0; 284e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu public static final int CMD_STOP = 1; 285e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu public static final int CMD_TETHER_STATE_CHANGE = 2; 286e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu public static final int CMD_TETHER_NOTIFICATION_TIMEOUT = 3; 287e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu 288e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu private static final int TETHER_NOTIFICATION_TIME_OUT_MSECS = 5000; 289e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu 290e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu /* Sequence number used to track tether notification timeout. */ 291e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu private int mTetherToken = 0; 292e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu 293e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu private final State mIdleState = new IdleState(); 294e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu private final State mStartedState = new StartedState(); 295e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu private final State mTetheringState = new TetheringState(); 296e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu private final State mTetheredState = new TetheredState(); 297e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu private final State mUntetheringState = new UntetheringState(); 298e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu 299e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu SoftApStateMachine(Looper looper) { 300e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu super(TAG, looper); 301e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu 302e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu // CHECKSTYLE:OFF IndentationCheck 303e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu addState(mIdleState); 304e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu addState(mStartedState, mIdleState); 305e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu addState(mTetheringState, mStartedState); 306e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu addState(mTetheredState, mStartedState); 307e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu addState(mUntetheringState, mStartedState); 308e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu // CHECKSTYLE:ON IndentationCheck 309e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu 310e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu setInitialState(mIdleState); 311e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu start(); 312e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu } 313e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu 314e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu private class IdleState extends State { 315e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu @Override 316e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu public boolean processMessage(Message message) { 317e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu switch (message.what) { 318e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu case CMD_START: 319e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu updateApState(WifiManager.WIFI_AP_STATE_ENABLING, 0); 320e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu int result = startSoftAp((WifiConfiguration) message.obj); 321e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu if (result == SUCCESS) { 322e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu updateApState(WifiManager.WIFI_AP_STATE_ENABLED, 0); 323e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu transitionTo(mStartedState); 324e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu } else { 325e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu int reason = WifiManager.SAP_START_FAILURE_GENERAL; 326e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu if (result == ERROR_NO_CHANNEL) { 327e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu reason = WifiManager.SAP_START_FAILURE_NO_CHANNEL; 328e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu } 329e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu updateApState(WifiManager.WIFI_AP_STATE_FAILED, reason); 330e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu } 331e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu break; 332e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu default: 333e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu /* Ignore all other commands. */ 334e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu break; 335e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu } 336e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu return HANDLED; 337e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu } 338e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu } 339e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu 340e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu private class StartedState extends State { 341e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu @Override 342e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu public boolean processMessage(Message message) { 343e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu switch (message.what) { 344e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu case CMD_START: 345e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu /* Already started, ignore this command. */ 346e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu break; 347e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu case CMD_STOP: 348e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu updateApState(WifiManager.WIFI_AP_STATE_DISABLING, 0); 349e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu stopSoftAp(); 350e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu updateApState(WifiManager.WIFI_AP_STATE_DISABLED, 0); 351e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu transitionTo(mIdleState); 352e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu break; 353e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu case CMD_TETHER_STATE_CHANGE: 354e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu TetherStateChange stateChange = (TetherStateChange) message.obj; 355e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu if (startTethering(stateChange.available)) { 356e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu transitionTo(mTetheringState); 357e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu } 358e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu break; 359e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu default: 360e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu return NOT_HANDLED; 361e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu } 362e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu return HANDLED; 363e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu } 364e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu } 365e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu 366e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu /** 367e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu * This is a transient state. We will transition out of this state when 368e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu * we receive a notification that WiFi is tethered (TetheredState) or 369e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu * we timed out waiting for that notification (StartedState). 370e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu */ 371e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu private class TetheringState extends State { 372e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu @Override 373e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu public void enter() { 374e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu /* Send a delayed message to terminate if tethering fails to notify. */ 375e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu sendMessageDelayed( 376e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu obtainMessage(CMD_TETHER_NOTIFICATION_TIMEOUT, ++mTetherToken), 377e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu TETHER_NOTIFICATION_TIME_OUT_MSECS); 378e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu } 379e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu 380e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu @Override 381e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu public boolean processMessage(Message message) { 382e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu switch (message.what) { 383e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu case CMD_TETHER_STATE_CHANGE: 384e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu TetherStateChange stateChange = (TetherStateChange) message.obj; 385e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu if (isWifiTethered(stateChange.active)) { 386e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu transitionTo(mTetheredState); 387e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu } 388e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu break; 389e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu case CMD_TETHER_NOTIFICATION_TIMEOUT: 390e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu if (message.arg1 == mTetherToken) { 391e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu Log.e(TAG, "Failed to get tether update, " 392e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu + "shutdown soft access point"); 393e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu transitionTo(mStartedState); 394e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu /* Needs to be first thing handled. */ 395e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu sendMessageAtFrontOfQueue(CMD_STOP); 396e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu } 397e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu break; 398e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu default: 399e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu return NOT_HANDLED; 400e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu } 401e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu return HANDLED; 402e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu } 403e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu } 404e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu 405e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu private class TetheredState extends State { 406e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu @Override 407e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu public boolean processMessage(Message message) { 408e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu switch (message.what) { 409e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu case CMD_TETHER_STATE_CHANGE: 410e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu TetherStateChange stateChange = (TetherStateChange) message.obj; 411e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu if (!isWifiTethered(stateChange.active)) { 412e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu Log.e(TAG, "Tethering reports wifi as untethered!, " 413e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu + "shut down soft Ap"); 414e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu sendMessage(CMD_STOP); 415e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu } 416e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu break; 417e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu case CMD_STOP: 418e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu Log.d(TAG, "Untethering before stopping AP"); 419e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu stopTethering(); 420e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu transitionTo(mUntetheringState); 421e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu break; 422e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu 423e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu default: 424e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu return NOT_HANDLED; 425e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu } 426e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu return HANDLED; 427e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu } 428e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu } 429e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu 430e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu /** 431e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu * This is a transient state, will transition out of this state to StartedState 432e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu * when we receive a notification that WiFi is untethered or we timed out waiting 433e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu * for that notification. 434e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu */ 435e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu private class UntetheringState extends State { 436e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu @Override 437e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu public void enter() { 438e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu /* Send a delayed message to terminate if tethering fails to notify. */ 439e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu sendMessageDelayed( 440e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu obtainMessage(CMD_TETHER_NOTIFICATION_TIMEOUT, ++mTetherToken), 441e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu TETHER_NOTIFICATION_TIME_OUT_MSECS); 442e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu } 443e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu 444e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu @Override 445e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu public boolean processMessage(Message message) { 446e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu switch (message.what) { 447e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu case CMD_TETHER_STATE_CHANGE: 448e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu TetherStateChange stateChange = (TetherStateChange) message.obj; 449e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu /* Transition back to StartedState when WiFi is untethered. */ 450e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu if (!isWifiTethered(stateChange.active)) { 451e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu transitionTo(mStartedState); 452e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu /* Needs to be first thing handled */ 453e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu sendMessageAtFrontOfQueue(CMD_STOP); 454e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu } 455e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu break; 456e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu case CMD_TETHER_NOTIFICATION_TIMEOUT: 457e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu if (message.arg1 == mTetherToken) { 458e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu Log.e(TAG, "Failed to get tether update, " 459e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu + "force stop access point"); 460e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu transitionTo(mStartedState); 461e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu /* Needs to be first thing handled. */ 462e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu sendMessageAtFrontOfQueue(CMD_STOP); 463e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu } 464e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu break; 465e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu default: 466e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu /* Defer handling of this message until untethering is completed. */ 467e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu deferMessage(message); 468e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu break; 469e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu } 470e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu return HANDLED; 471e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu } 472e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu } 473e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu } 474e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu} 475