|
19 | 19 | import android.content.Context; |
20 | 20 | import android.net.wifi.WifiConfiguration.KeyMgmt; |
21 | 21 | import android.os.Environment; |
22 | | -import android.os.Message; |
23 | 22 | import android.os.Handler; |
24 | | -import android.os.HandlerThread; |
| 23 | +import android.os.Message; |
| 24 | +import android.os.Messenger; |
25 | 25 | import android.util.Log; |
26 | 26 |
|
| 27 | +import com.android.internal.util.AsyncChannel; |
| 28 | +import com.android.internal.R; |
| 29 | +import com.android.internal.util.State; |
| 30 | +import com.android.internal.util.StateMachine; |
| 31 | + |
27 | 32 | import java.io.BufferedInputStream; |
28 | 33 | import java.io.BufferedOutputStream; |
29 | 34 | import java.io.DataInputStream; |
|
34 | 39 | import java.net.InetAddress; |
35 | 40 | import java.util.UUID; |
36 | 41 |
|
37 | | -import com.android.internal.R; |
38 | | - |
39 | | - |
40 | 42 | /** |
41 | 43 | * Provides API to the WifiStateMachine for doing read/write access |
42 | 44 | * to soft access point configuration |
43 | 45 | */ |
44 | | -class WifiApConfigStore { |
| 46 | +class WifiApConfigStore extends StateMachine { |
45 | 47 |
|
46 | | - private static Context sContext; |
| 48 | + private Context mContext; |
47 | 49 | private static final String TAG = "WifiApConfigStore"; |
48 | 50 |
|
49 | 51 | private static final String AP_CONFIG_FILE = Environment.getDataDirectory() + |
50 | 52 | "/misc/wifi/softap.conf"; |
51 | 53 |
|
52 | 54 | private static final int AP_CONFIG_FILE_VERSION = 1; |
53 | 55 |
|
54 | | - private static WifiConfiguration sApConfig = new WifiConfiguration(); |
55 | | - private static final Object sApConfigLock = new Object(); |
| 56 | + private State mDefaultState = new DefaultState(); |
| 57 | + private State mInactiveState = new InactiveState(); |
| 58 | + private State mActiveState = new ActiveState(); |
| 59 | + |
| 60 | + private WifiConfiguration mWifiApConfig = null; |
| 61 | + private AsyncChannel mReplyChannel = new AsyncChannel(); |
56 | 62 |
|
57 | | - private static FileReadWriteHandler sFileReadWriteHandler; |
58 | | - private static final int READ_AP_CONFIG = 1; |
59 | | - private static final int WRITE_AP_CONFIG = 2; |
| 63 | + WifiApConfigStore(Context context, Handler target) { |
| 64 | + super(TAG, target.getLooper()); |
60 | 65 |
|
61 | | - static void initialize(Context context) { |
62 | | - sContext = context; |
| 66 | + mContext = context; |
| 67 | + addState(mDefaultState); |
| 68 | + addState(mInactiveState, mDefaultState); |
| 69 | + addState(mActiveState, mDefaultState); |
63 | 70 |
|
64 | | - /* File operations happen on a seperate thread */ |
65 | | - HandlerThread configThread = new HandlerThread("WifiApConfigStore"); |
66 | | - configThread.start(); |
67 | | - sFileReadWriteHandler = new FileReadWriteHandler(configThread.getLooper()); |
68 | | - Message.obtain(sFileReadWriteHandler, READ_AP_CONFIG).sendToTarget(); |
| 71 | + setInitialState(mInactiveState); |
69 | 72 | } |
70 | 73 |
|
| 74 | + public static WifiApConfigStore makeWifiApConfigStore(Context context, Handler target) { |
| 75 | + WifiApConfigStore s = new WifiApConfigStore(context, target); |
| 76 | + s.start(); |
| 77 | + return s; |
| 78 | + } |
71 | 79 |
|
72 | | - static void setApConfiguration(WifiConfiguration config) { |
73 | | - synchronized (sApConfigLock) { |
74 | | - sApConfig = config; |
| 80 | + class DefaultState extends State { |
| 81 | + public boolean processMessage(Message message) { |
| 82 | + switch (message.what) { |
| 83 | + case WifiStateMachine.CMD_SET_AP_CONFIG: |
| 84 | + case WifiStateMachine.CMD_SET_AP_CONFIG_COMPLETED: |
| 85 | + Log.e(TAG, "Unexpected message: " + message); |
| 86 | + break; |
| 87 | + case WifiStateMachine.CMD_REQUEST_AP_CONFIG: |
| 88 | + mReplyChannel.replyToMessage(message, |
| 89 | + WifiStateMachine.CMD_RESPONSE_AP_CONFIG, mWifiApConfig); |
| 90 | + break; |
| 91 | + default: |
| 92 | + Log.e(TAG, "Failed to handle " + message); |
| 93 | + break; |
| 94 | + } |
| 95 | + return HANDLED; |
75 | 96 | } |
76 | | - Message.obtain(sFileReadWriteHandler, WRITE_AP_CONFIG, new WifiConfiguration(config)) |
77 | | - .sendToTarget(); |
78 | 97 | } |
79 | 98 |
|
80 | | - static WifiConfiguration getApConfiguration() { |
81 | | - synchronized (sApConfigLock) { |
82 | | - return new WifiConfiguration(sApConfig); |
| 99 | + class InactiveState extends State { |
| 100 | + public boolean processMessage(Message message) { |
| 101 | + switch (message.what) { |
| 102 | + case WifiStateMachine.CMD_SET_AP_CONFIG: |
| 103 | + mWifiApConfig = (WifiConfiguration) message.obj; |
| 104 | + transitionTo(mActiveState); |
| 105 | + break; |
| 106 | + default: |
| 107 | + return NOT_HANDLED; |
| 108 | + } |
| 109 | + return HANDLED; |
83 | 110 | } |
84 | 111 | } |
85 | 112 |
|
86 | | - /** |
87 | | - * File read/write handler |
88 | | - */ |
89 | | - private static class FileReadWriteHandler extends Handler { |
90 | | - |
91 | | - public FileReadWriteHandler(android.os.Looper looper) { |
92 | | - super(looper); |
| 113 | + class ActiveState extends State { |
| 114 | + public void enter() { |
| 115 | + new Thread(new Runnable() { |
| 116 | + public void run() { |
| 117 | + writeApConfiguration(mWifiApConfig); |
| 118 | + sendMessage(WifiStateMachine.CMD_SET_AP_CONFIG_COMPLETED); |
| 119 | + } |
| 120 | + }).start(); |
93 | 121 | } |
94 | 122 |
|
95 | | - @Override |
96 | | - public void handleMessage(Message msg) { |
97 | | - switch (msg.what) { |
98 | | - case WRITE_AP_CONFIG: |
99 | | - writeApConfiguration((WifiConfiguration) msg.obj); |
| 123 | + public boolean processMessage(Message message) { |
| 124 | + switch (message.what) { |
| 125 | + //TODO: have feedback to the user when we do this |
| 126 | + //to indicate the write is currently in progress |
| 127 | + case WifiStateMachine.CMD_SET_AP_CONFIG: |
| 128 | + deferMessage(message); |
100 | 129 | break; |
101 | | - case READ_AP_CONFIG: |
102 | | - readApConfiguration(); |
| 130 | + case WifiStateMachine.CMD_SET_AP_CONFIG_COMPLETED: |
| 131 | + transitionTo(mInactiveState); |
103 | 132 | break; |
104 | 133 | default: |
105 | | - Log.e(TAG, "Unknown command in FileReadWriteHandler: " + msg); |
106 | | - break; |
| 134 | + return NOT_HANDLED; |
107 | 135 | } |
| 136 | + return HANDLED; |
108 | 137 | } |
| 138 | + } |
109 | 139 |
|
110 | | - private static void writeApConfiguration(final WifiConfiguration config) { |
111 | | - DataOutputStream out = null; |
112 | | - try { |
113 | | - out = new DataOutputStream(new BufferedOutputStream( |
114 | | - new FileOutputStream(AP_CONFIG_FILE))); |
115 | | - |
116 | | - out.writeInt(AP_CONFIG_FILE_VERSION); |
117 | | - out.writeUTF(config.SSID); |
118 | | - int authType = config.getAuthType(); |
119 | | - out.writeInt(authType); |
120 | | - if(authType != KeyMgmt.NONE) { |
121 | | - out.writeUTF(config.preSharedKey); |
122 | | - } |
123 | | - } catch (IOException e) { |
124 | | - Log.e(TAG, "Error writing hotspot configuration" + e); |
125 | | - } finally { |
126 | | - if (out != null) { |
127 | | - try { |
128 | | - out.close(); |
129 | | - } catch (IOException e) {} |
130 | | - } |
131 | | - } |
132 | | - } |
| 140 | + void loadApConfiguration() { |
| 141 | + DataInputStream in = null; |
| 142 | + try { |
| 143 | + WifiConfiguration config = new WifiConfiguration(); |
| 144 | + in = new DataInputStream(new BufferedInputStream(new FileInputStream( |
| 145 | + AP_CONFIG_FILE))); |
133 | 146 |
|
134 | | - private static void readApConfiguration() { |
135 | | - DataInputStream in = null; |
136 | | - try { |
137 | | - WifiConfiguration config = new WifiConfiguration(); |
138 | | - in = new DataInputStream(new BufferedInputStream(new FileInputStream( |
139 | | - AP_CONFIG_FILE))); |
140 | | - |
141 | | - int version = in.readInt(); |
142 | | - if (version != 1) { |
143 | | - Log.e(TAG, "Bad version on hotspot configuration file, set defaults"); |
144 | | - setDefaultApConfiguration(); |
145 | | - return; |
146 | | - } |
147 | | - config.SSID = in.readUTF(); |
148 | | - int authType = in.readInt(); |
149 | | - config.allowedKeyManagement.set(authType); |
150 | | - if (authType != KeyMgmt.NONE) { |
151 | | - config.preSharedKey = in.readUTF(); |
152 | | - } |
153 | | - synchronized (sApConfigLock) { |
154 | | - sApConfig = config; |
155 | | - } |
156 | | - } catch (IOException ignore) { |
| 147 | + int version = in.readInt(); |
| 148 | + if (version != 1) { |
| 149 | + Log.e(TAG, "Bad version on hotspot configuration file, set defaults"); |
157 | 150 | setDefaultApConfiguration(); |
158 | | - } finally { |
159 | | - if (in != null) { |
160 | | - try { |
161 | | - in.close(); |
162 | | - } catch (IOException e) {} |
163 | | - } |
| 151 | + return; |
| 152 | + } |
| 153 | + config.SSID = in.readUTF(); |
| 154 | + int authType = in.readInt(); |
| 155 | + config.allowedKeyManagement.set(authType); |
| 156 | + if (authType != KeyMgmt.NONE) { |
| 157 | + config.preSharedKey = in.readUTF(); |
| 158 | + } |
| 159 | + mWifiApConfig = config; |
| 160 | + } catch (IOException ignore) { |
| 161 | + setDefaultApConfiguration(); |
| 162 | + } finally { |
| 163 | + if (in != null) { |
| 164 | + try { |
| 165 | + in.close(); |
| 166 | + } catch (IOException e) {} |
164 | 167 | } |
165 | 168 | } |
| 169 | + } |
166 | 170 |
|
167 | | - /* Generate a default WPA2 based configuration with a random password. |
168 | | - We are changing the Wifi Ap configuration storage from secure settings to a |
169 | | - flat file accessible only by the system. A WPA2 based default configuration |
170 | | - will keep the device secure after the update */ |
171 | | - private static void setDefaultApConfiguration() { |
172 | | - WifiConfiguration config = new WifiConfiguration(); |
173 | | - config.SSID = sContext.getString(R.string.wifi_tether_configure_ssid_default); |
174 | | - config.allowedKeyManagement.set(KeyMgmt.WPA2_PSK); |
175 | | - String randomUUID = UUID.randomUUID().toString(); |
176 | | - //first 12 chars from xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx |
177 | | - config.preSharedKey = randomUUID.substring(0, 8) + randomUUID.substring(9,13); |
178 | | - setApConfiguration(config); |
| 171 | + Messenger getMessenger() { |
| 172 | + return new Messenger(getHandler()); |
| 173 | + } |
| 174 | + |
| 175 | + private void writeApConfiguration(final WifiConfiguration config) { |
| 176 | + DataOutputStream out = null; |
| 177 | + try { |
| 178 | + out = new DataOutputStream(new BufferedOutputStream( |
| 179 | + new FileOutputStream(AP_CONFIG_FILE))); |
| 180 | + |
| 181 | + out.writeInt(AP_CONFIG_FILE_VERSION); |
| 182 | + out.writeUTF(config.SSID); |
| 183 | + int authType = config.getAuthType(); |
| 184 | + out.writeInt(authType); |
| 185 | + if(authType != KeyMgmt.NONE) { |
| 186 | + out.writeUTF(config.preSharedKey); |
| 187 | + } |
| 188 | + } catch (IOException e) { |
| 189 | + Log.e(TAG, "Error writing hotspot configuration" + e); |
| 190 | + } finally { |
| 191 | + if (out != null) { |
| 192 | + try { |
| 193 | + out.close(); |
| 194 | + } catch (IOException e) {} |
| 195 | + } |
179 | 196 | } |
180 | 197 | } |
| 198 | + |
| 199 | + /* Generate a default WPA2 based configuration with a random password. |
| 200 | + We are changing the Wifi Ap configuration storage from secure settings to a |
| 201 | + flat file accessible only by the system. A WPA2 based default configuration |
| 202 | + will keep the device secure after the update */ |
| 203 | + private void setDefaultApConfiguration() { |
| 204 | + WifiConfiguration config = new WifiConfiguration(); |
| 205 | + config.SSID = mContext.getString(R.string.wifi_tether_configure_ssid_default); |
| 206 | + config.allowedKeyManagement.set(KeyMgmt.WPA2_PSK); |
| 207 | + String randomUUID = UUID.randomUUID().toString(); |
| 208 | + //first 12 chars from xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx |
| 209 | + config.preSharedKey = randomUUID.substring(0, 8) + randomUUID.substring(9,13); |
| 210 | + sendMessage(WifiStateMachine.CMD_SET_AP_CONFIG, config); |
| 211 | + } |
181 | 212 | } |
0 commit comments