- Create thread when needed - asynchronous interaction with wifi state machine Bug: 5587391 Change-Id: Ie6d01b5a6b398a3fa12c384920a473e242443131
213 lines
7.3 KiB
Java
213 lines
7.3 KiB
Java
/*
|
|
* Copyright (C) 2010 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
package android.net.wifi;
|
|
|
|
import android.content.Context;
|
|
import android.net.wifi.WifiConfiguration.KeyMgmt;
|
|
import android.os.Environment;
|
|
import android.os.Handler;
|
|
import android.os.Message;
|
|
import android.os.Messenger;
|
|
import android.util.Log;
|
|
|
|
import com.android.internal.util.AsyncChannel;
|
|
import com.android.internal.R;
|
|
import com.android.internal.util.State;
|
|
import com.android.internal.util.StateMachine;
|
|
|
|
import java.io.BufferedInputStream;
|
|
import java.io.BufferedOutputStream;
|
|
import java.io.DataInputStream;
|
|
import java.io.DataOutputStream;
|
|
import java.io.FileInputStream;
|
|
import java.io.FileOutputStream;
|
|
import java.io.IOException;
|
|
import java.net.InetAddress;
|
|
import java.util.UUID;
|
|
|
|
/**
|
|
* Provides API to the WifiStateMachine for doing read/write access
|
|
* to soft access point configuration
|
|
*/
|
|
class WifiApConfigStore extends StateMachine {
|
|
|
|
private Context mContext;
|
|
private static final String TAG = "WifiApConfigStore";
|
|
|
|
private static final String AP_CONFIG_FILE = Environment.getDataDirectory() +
|
|
"/misc/wifi/softap.conf";
|
|
|
|
private static final int AP_CONFIG_FILE_VERSION = 1;
|
|
|
|
private State mDefaultState = new DefaultState();
|
|
private State mInactiveState = new InactiveState();
|
|
private State mActiveState = new ActiveState();
|
|
|
|
private WifiConfiguration mWifiApConfig = null;
|
|
private AsyncChannel mReplyChannel = new AsyncChannel();
|
|
|
|
WifiApConfigStore(Context context, Handler target) {
|
|
super(TAG, target.getLooper());
|
|
|
|
mContext = context;
|
|
addState(mDefaultState);
|
|
addState(mInactiveState, mDefaultState);
|
|
addState(mActiveState, mDefaultState);
|
|
|
|
setInitialState(mInactiveState);
|
|
}
|
|
|
|
public static WifiApConfigStore makeWifiApConfigStore(Context context, Handler target) {
|
|
WifiApConfigStore s = new WifiApConfigStore(context, target);
|
|
s.start();
|
|
return s;
|
|
}
|
|
|
|
class DefaultState extends State {
|
|
public boolean processMessage(Message message) {
|
|
switch (message.what) {
|
|
case WifiStateMachine.CMD_SET_AP_CONFIG:
|
|
case WifiStateMachine.CMD_SET_AP_CONFIG_COMPLETED:
|
|
Log.e(TAG, "Unexpected message: " + message);
|
|
break;
|
|
case WifiStateMachine.CMD_REQUEST_AP_CONFIG:
|
|
mReplyChannel.replyToMessage(message,
|
|
WifiStateMachine.CMD_RESPONSE_AP_CONFIG, mWifiApConfig);
|
|
break;
|
|
default:
|
|
Log.e(TAG, "Failed to handle " + message);
|
|
break;
|
|
}
|
|
return HANDLED;
|
|
}
|
|
}
|
|
|
|
class InactiveState extends State {
|
|
public boolean processMessage(Message message) {
|
|
switch (message.what) {
|
|
case WifiStateMachine.CMD_SET_AP_CONFIG:
|
|
mWifiApConfig = (WifiConfiguration) message.obj;
|
|
transitionTo(mActiveState);
|
|
break;
|
|
default:
|
|
return NOT_HANDLED;
|
|
}
|
|
return HANDLED;
|
|
}
|
|
}
|
|
|
|
class ActiveState extends State {
|
|
public void enter() {
|
|
new Thread(new Runnable() {
|
|
public void run() {
|
|
writeApConfiguration(mWifiApConfig);
|
|
sendMessage(WifiStateMachine.CMD_SET_AP_CONFIG_COMPLETED);
|
|
}
|
|
}).start();
|
|
}
|
|
|
|
public boolean processMessage(Message message) {
|
|
switch (message.what) {
|
|
//TODO: have feedback to the user when we do this
|
|
//to indicate the write is currently in progress
|
|
case WifiStateMachine.CMD_SET_AP_CONFIG:
|
|
deferMessage(message);
|
|
break;
|
|
case WifiStateMachine.CMD_SET_AP_CONFIG_COMPLETED:
|
|
transitionTo(mInactiveState);
|
|
break;
|
|
default:
|
|
return NOT_HANDLED;
|
|
}
|
|
return HANDLED;
|
|
}
|
|
}
|
|
|
|
void loadApConfiguration() {
|
|
DataInputStream in = null;
|
|
try {
|
|
WifiConfiguration config = new WifiConfiguration();
|
|
in = new DataInputStream(new BufferedInputStream(new FileInputStream(
|
|
AP_CONFIG_FILE)));
|
|
|
|
int version = in.readInt();
|
|
if (version != 1) {
|
|
Log.e(TAG, "Bad version on hotspot configuration file, set defaults");
|
|
setDefaultApConfiguration();
|
|
return;
|
|
}
|
|
config.SSID = in.readUTF();
|
|
int authType = in.readInt();
|
|
config.allowedKeyManagement.set(authType);
|
|
if (authType != KeyMgmt.NONE) {
|
|
config.preSharedKey = in.readUTF();
|
|
}
|
|
mWifiApConfig = config;
|
|
} catch (IOException ignore) {
|
|
setDefaultApConfiguration();
|
|
} finally {
|
|
if (in != null) {
|
|
try {
|
|
in.close();
|
|
} catch (IOException e) {}
|
|
}
|
|
}
|
|
}
|
|
|
|
Messenger getMessenger() {
|
|
return new Messenger(getHandler());
|
|
}
|
|
|
|
private void writeApConfiguration(final WifiConfiguration config) {
|
|
DataOutputStream out = null;
|
|
try {
|
|
out = new DataOutputStream(new BufferedOutputStream(
|
|
new FileOutputStream(AP_CONFIG_FILE)));
|
|
|
|
out.writeInt(AP_CONFIG_FILE_VERSION);
|
|
out.writeUTF(config.SSID);
|
|
int authType = config.getAuthType();
|
|
out.writeInt(authType);
|
|
if(authType != KeyMgmt.NONE) {
|
|
out.writeUTF(config.preSharedKey);
|
|
}
|
|
} catch (IOException e) {
|
|
Log.e(TAG, "Error writing hotspot configuration" + e);
|
|
} finally {
|
|
if (out != null) {
|
|
try {
|
|
out.close();
|
|
} catch (IOException e) {}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Generate a default WPA2 based configuration with a random password.
|
|
We are changing the Wifi Ap configuration storage from secure settings to a
|
|
flat file accessible only by the system. A WPA2 based default configuration
|
|
will keep the device secure after the update */
|
|
private void setDefaultApConfiguration() {
|
|
WifiConfiguration config = new WifiConfiguration();
|
|
config.SSID = mContext.getString(R.string.wifi_tether_configure_ssid_default);
|
|
config.allowedKeyManagement.set(KeyMgmt.WPA2_PSK);
|
|
String randomUUID = UUID.randomUUID().toString();
|
|
//first 12 chars from xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
|
|
config.preSharedKey = randomUUID.substring(0, 8) + randomUUID.substring(9,13);
|
|
sendMessage(WifiStateMachine.CMD_SET_AP_CONFIG, config);
|
|
}
|
|
}
|