summaryrefslogtreecommitdiffstats
path: root/wifi
diff options
context:
space:
mode:
authorIrfan Sheriff <isheriff@google.com>2012-10-15 12:00:29 -0700
committerIrfan Sheriff <isheriff@google.com>2012-10-17 10:35:39 -0700
commit9f452d0b5ccad77fb6acfd1b20d5f77c9f425d22 (patch)
tree7d1fb44307bfdf1201d2a474d9b9172e10a43e07 /wifi
parenta30d969401a8533a5a341664421ba9b1e150bac3 (diff)
downloadframeworks_base-9f452d0b5ccad77fb6acfd1b20d5f77c9f425d22.zip
frameworks_base-9f452d0b5ccad77fb6acfd1b20d5f77c9f425d22.tar.gz
frameworks_base-9f452d0b5ccad77fb6acfd1b20d5f77c9f425d22.tar.bz2
Frequency conflict handling
We now show a dialog to user and let him handle whether to choose wifi or p2p when there is a frequency conflict. If user chooses to disable wifi tempoarily, we disconnect wifi until p2p connection is established and removed. Bug: 6590401 Change-Id: I73871ddcb3732ae61997d8771b6aa90ad56270af
Diffstat (limited to 'wifi')
-rw-r--r--wifi/java/android/net/wifi/WifiMonitor.java37
-rw-r--r--wifi/java/android/net/wifi/WifiStateMachine.java34
-rw-r--r--wifi/java/android/net/wifi/p2p/WifiP2pService.java154
3 files changed, 194 insertions, 31 deletions
diff --git a/wifi/java/android/net/wifi/WifiMonitor.java b/wifi/java/android/net/wifi/WifiMonitor.java
index 93ab4a4..0b0d738 100644
--- a/wifi/java/android/net/wifi/WifiMonitor.java
+++ b/wifi/java/android/net/wifi/WifiMonitor.java
@@ -178,6 +178,7 @@ public class WifiMonitor {
private static final String P2P_GO_NEG_SUCCESS_STR = "P2P-GO-NEG-SUCCESS";
+ /* P2P-GO-NEG-FAILURE status=x */
private static final String P2P_GO_NEG_FAILURE_STR = "P2P-GO-NEG-FAILURE";
private static final String P2P_GROUP_FORMATION_SUCCESS_STR =
@@ -566,6 +567,26 @@ public class WifiMonitor {
WifiManager.ERROR, 0));
}
+ /* <event> status=<err> and the special case of <event> reason=FREQ_CONFLICT */
+ private P2pStatus p2pError(String dataString) {
+ P2pStatus err = P2pStatus.UNKNOWN;
+ String[] tokens = dataString.split(" ");
+ if (tokens.length < 2) return err;
+ String[] nameValue = tokens[1].split("=");
+ if (nameValue.length != 2) return err;
+
+ /* Handle the special case of reason=FREQ+CONFLICT */
+ if (nameValue[1].equals("FREQ_CONFLICT")) {
+ return P2pStatus.NO_COMMON_CHANNEL;
+ }
+ try {
+ err = P2pStatus.valueOf(Integer.parseInt(nameValue[1]));
+ } catch (NumberFormatException e) {
+ e.printStackTrace();
+ }
+ return err;
+ }
+
/**
* Handle p2p events
*/
@@ -582,11 +603,11 @@ public class WifiMonitor {
} else if (dataString.startsWith(P2P_GO_NEG_SUCCESS_STR)) {
mStateMachine.sendMessage(P2P_GO_NEGOTIATION_SUCCESS_EVENT);
} else if (dataString.startsWith(P2P_GO_NEG_FAILURE_STR)) {
- mStateMachine.sendMessage(P2P_GO_NEGOTIATION_FAILURE_EVENT);
+ mStateMachine.sendMessage(P2P_GO_NEGOTIATION_FAILURE_EVENT, p2pError(dataString));
} else if (dataString.startsWith(P2P_GROUP_FORMATION_SUCCESS_STR)) {
mStateMachine.sendMessage(P2P_GROUP_FORMATION_SUCCESS_EVENT);
} else if (dataString.startsWith(P2P_GROUP_FORMATION_FAILURE_STR)) {
- mStateMachine.sendMessage(P2P_GROUP_FORMATION_FAILURE_EVENT);
+ mStateMachine.sendMessage(P2P_GROUP_FORMATION_FAILURE_EVENT, p2pError(dataString));
} else if (dataString.startsWith(P2P_GROUP_STARTED_STR)) {
mStateMachine.sendMessage(P2P_GROUP_STARTED_EVENT, new WifiP2pGroup(dataString));
} else if (dataString.startsWith(P2P_GROUP_REMOVED_STR)) {
@@ -595,17 +616,7 @@ public class WifiMonitor {
mStateMachine.sendMessage(P2P_INVITATION_RECEIVED_EVENT,
new WifiP2pGroup(dataString));
} else if (dataString.startsWith(P2P_INVITATION_RESULT_STR)) {
- String[] tokens = dataString.split(" ");
- if (tokens.length != 2) return;
- String[] nameValue = tokens[1].split("=");
- if (nameValue.length != 2) return;
- P2pStatus err = P2pStatus.UNKNOWN;
- try {
- err = P2pStatus.valueOf(Integer.parseInt(nameValue[1]));
- } catch (NumberFormatException e) {
- e.printStackTrace();
- }
- mStateMachine.sendMessage(P2P_INVITATION_RESULT_EVENT, err);
+ mStateMachine.sendMessage(P2P_INVITATION_RESULT_EVENT, p2pError(dataString));
} else if (dataString.startsWith(P2P_PROV_DISC_PBC_REQ_STR)) {
mStateMachine.sendMessage(P2P_PROV_DISC_PBC_REQ_EVENT,
new WifiP2pProvDiscEvent(dataString));
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index db539e4..196bf2e 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -114,6 +114,7 @@ public class WifiStateMachine extends StateMachine {
private final boolean mP2pSupported;
private final AtomicBoolean mP2pConnected = new AtomicBoolean(false);
+ private boolean mTemporarilyDisconnectWifi = false;
private final String mPrimaryDeviceType;
/* Scan results handling */
@@ -2017,6 +2018,10 @@ public class WifiStateMachine extends StateMachine {
NetworkInfo info = (NetworkInfo) message.obj;
mP2pConnected.set(info.isConnected());
break;
+ case WifiP2pService.DISCONNECT_WIFI_REQUEST:
+ mTemporarilyDisconnectWifi = (message.arg1 == 1);
+ replyToMessage(message, WifiP2pService.DISCONNECT_WIFI_RESPONSE);
+ break;
default:
loge("Error! unhandled message" + message);
break;
@@ -3030,6 +3035,15 @@ public class WifiStateMachine extends StateMachine {
transitionTo(mDisconnectedState);
}
break;
+ case WifiP2pService.DISCONNECT_WIFI_REQUEST:
+ if (message.arg1 == 1) {
+ mWifiNative.disconnect();
+ mTemporarilyDisconnectWifi = true;
+ } else {
+ mWifiNative.reconnect();
+ mTemporarilyDisconnectWifi = false;
+ }
+ break;
/* Do a redundant disconnect without transition */
case CMD_DISCONNECT:
mWifiNative.disconnect();
@@ -3159,6 +3173,13 @@ public class WifiStateMachine extends StateMachine {
mWifiNative.disconnect();
transitionTo(mDisconnectingState);
break;
+ case WifiP2pService.DISCONNECT_WIFI_REQUEST:
+ if (message.arg1 == 1) {
+ mWifiNative.disconnect();
+ mTemporarilyDisconnectWifi = true;
+ transitionTo(mDisconnectingState);
+ }
+ break;
case CMD_SET_SCAN_MODE:
if (message.arg1 == SCAN_ONLY_MODE) {
sendMessage(CMD_DISCONNECT);
@@ -3465,6 +3486,13 @@ public class WifiStateMachine extends StateMachine {
if (DBG) log(getName() + "\n");
EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
+ // We dont scan frequently if this is a temporary disconnect
+ // due to p2p
+ if (mTemporarilyDisconnectWifi) {
+ mWifiP2pChannel.sendMessage(WifiP2pService.DISCONNECT_WIFI_RESPONSE);
+ return;
+ }
+
mFrameworkScanIntervalMs = Settings.Global.getLong(mContext.getContentResolver(),
Settings.Global.WIFI_FRAMEWORK_SCAN_INTERVAL_MS,
mDefaultFrameworkScanIntervalMs);
@@ -3579,6 +3607,12 @@ public class WifiStateMachine extends StateMachine {
sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN,
++mPeriodicScanToken, 0), mSupplicantScanIntervalMs);
}
+ case CMD_RECONNECT:
+ case CMD_REASSOCIATE:
+ // Drop a third party reconnect/reassociate if we are
+ // tempoarily disconnected for p2p
+ if (mTemporarilyDisconnectWifi) ret = NOT_HANDLED;
+ break;
default:
ret = NOT_HANDLED;
}
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pService.java b/wifi/java/android/net/wifi/p2p/WifiP2pService.java
index 70baf13..4b90901 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pService.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pService.java
@@ -149,9 +149,28 @@ public class WifiP2pService extends IWifiP2pManager.Stub {
private static final int PEER_CONNECTION_USER_ACCEPT = BASE + 2;
/* User rejected a peer request */
private static final int PEER_CONNECTION_USER_REJECT = BASE + 3;
+ /* User wants to disconnect wifi in favour of p2p */
+ private static final int DROP_WIFI_USER_ACCEPT = BASE + 4;
+ /* User wants to keep his wifi connection and drop p2p */
+ private static final int DROP_WIFI_USER_REJECT = BASE + 5;
+
/* Commands to the WifiStateMachine */
- public static final int P2P_CONNECTION_CHANGED = BASE + 11;
+ public static final int P2P_CONNECTION_CHANGED = BASE + 11;
+
+ /* These commands are used to tempoarily disconnect wifi when we detect
+ * a frequency conflict which would make it impossible to have with p2p
+ * and wifi active at the same time.
+ *
+ * If the user chooses to disable wifi tempoarily, we keep wifi disconnected
+ * until the p2p connection is done and terminated at which point we will
+ * bring back wifi up
+ *
+ * DISCONNECT_WIFI_REQUEST
+ * msg.arg1 = 1 enables temporary disconnect and 0 disables it.
+ */
+ public static final int DISCONNECT_WIFI_REQUEST = BASE + 12;
+ public static final int DISCONNECT_WIFI_RESPONSE = BASE + 13;
private final boolean mP2pSupported;
@@ -172,6 +191,8 @@ public class WifiP2pService extends IWifiP2pManager.Stub {
private NetworkInfo mNetworkInfo;
+ private boolean mTempoarilyDisconnectedWifi = false;
+
/* The transaction Id of service discovery request */
private byte mServiceTransactionId = 0;
@@ -222,7 +243,7 @@ public class WifiP2pService extends IWifiP2pManager.Stub {
PREVIOUS_PROTOCOL_ERROR,
/* There is no common channels the both devices can use. */
- NO_COMMON_CHANNE,
+ NO_COMMON_CHANNEL,
/* Unknown p2p group. For example, Device A tries to invoke the previous persistent group,
* but device B has removed the specified credential already. */
@@ -257,7 +278,7 @@ public class WifiP2pService extends IWifiP2pManager.Stub {
case 6:
return PREVIOUS_PROTOCOL_ERROR;
case 7:
- return NO_COMMON_CHANNE;
+ return NO_COMMON_CHANNEL;
case 8:
return UNKNOWN_P2P_GROUP;
case 9:
@@ -346,6 +367,7 @@ public class WifiP2pService extends IWifiP2pManager.Stub {
= new UserAuthorizingInvitationState();
private ProvisionDiscoveryState mProvisionDiscoveryState = new ProvisionDiscoveryState();
private GroupNegotiationState mGroupNegotiationState = new GroupNegotiationState();
+ private FrequencyConflictState mFrequencyConflictState =new FrequencyConflictState();
private GroupCreatedState mGroupCreatedState = new GroupCreatedState();
private UserAuthorizingJoinState mUserAuthorizingJoinState = new UserAuthorizingJoinState();
@@ -400,6 +422,7 @@ public class WifiP2pService extends IWifiP2pManager.Stub {
addState(mUserAuthorizingInvitationState, mGroupCreatingState);
addState(mProvisionDiscoveryState, mGroupCreatingState);
addState(mGroupNegotiationState, mGroupCreatingState);
+ addState(mFrequencyConflictState, mGroupCreatingState);
addState(mGroupCreatedState, mP2pEnabledState);
addState(mUserAuthorizingJoinState, mGroupCreatedState);
addState(mOngoingGroupRemovalState, mGroupCreatedState);
@@ -555,6 +578,9 @@ public class WifiP2pService extends IWifiP2pManager.Stub {
case WifiStateMachine.CMD_DISABLE_P2P:
case PEER_CONNECTION_USER_ACCEPT:
case PEER_CONNECTION_USER_REJECT:
+ case DISCONNECT_WIFI_RESPONSE:
+ case DROP_WIFI_USER_ACCEPT:
+ case DROP_WIFI_USER_REJECT:
case GROUP_CREATING_TIMED_OUT:
case DhcpStateMachine.CMD_PRE_DHCP_ACTION:
case DhcpStateMachine.CMD_POST_DHCP_ACTION:
@@ -1027,20 +1053,7 @@ public class WifiP2pService extends IWifiP2pManager.Stub {
// remain at this state.
}
break;
- case WifiMonitor.P2P_GROUP_STARTED_EVENT:
- mGroup = (WifiP2pGroup) message.obj;
- if (DBG) logd(getName() + " group started");
-
- if (mGroup.getNetworkId() == WifiP2pGroup.PERSISTENT_NET_ID) {
- // This is an invocation case.
- mAutonomousGroup = false;
- deferMessage(message);
- transitionTo(mGroupNegotiationState);
- } else {
- return NOT_HANDLED;
- }
- break;
- default:
+ default:
return NOT_HANDLED;
}
return HANDLED;
@@ -1074,6 +1087,10 @@ public class WifiP2pService extends IWifiP2pManager.Stub {
// mSavedPeerConfig can be empty
if (mSavedPeerConfig != null &&
!mSavedPeerConfig.deviceAddress.equals(device.deviceAddress)) {
+ if (DBG) {
+ logd("mSavedPeerConfig " + mSavedPeerConfig.deviceAddress +
+ "device " + device.deviceAddress);
+ }
// Do the regular device lost handling
ret = NOT_HANDLED;
break;
@@ -1269,6 +1286,12 @@ public class WifiP2pService extends IWifiP2pManager.Stub {
transitionTo(mGroupCreatedState);
break;
case WifiMonitor.P2P_GO_NEGOTIATION_FAILURE_EVENT:
+ P2pStatus status = (P2pStatus) message.obj;
+ if (status == P2pStatus.NO_COMMON_CHANNEL) {
+ transitionTo(mFrequencyConflictState);
+ break;
+ }
+ /* continue with group removal handling */
case WifiMonitor.P2P_GROUP_REMOVED_EVENT:
if (DBG) logd(getName() + " go failure");
handleGroupCreationFailure();
@@ -1278,9 +1301,14 @@ public class WifiP2pService extends IWifiP2pManager.Stub {
// a group removed event. Flushing things at group formation
// failure causes supplicant issues. Ignore right now.
case WifiMonitor.P2P_GROUP_FORMATION_FAILURE_EVENT:
+ status = (P2pStatus) message.obj;
+ if (status == P2pStatus.NO_COMMON_CHANNEL) {
+ transitionTo(mFrequencyConflictState);
+ break;
+ }
break;
case WifiMonitor.P2P_INVITATION_RESULT_EVENT:
- P2pStatus status = (P2pStatus)message.obj;
+ status = (P2pStatus)message.obj;
if (status == P2pStatus.SUCCESS) {
// invocation was succeeded.
// wait P2P_GROUP_STARTED_EVENT.
@@ -1300,6 +1328,8 @@ public class WifiP2pService extends IWifiP2pManager.Stub {
handleGroupCreationFailure();
transitionTo(mInactiveState);
}
+ } else if (status == P2pStatus.NO_COMMON_CHANNEL) {
+ transitionTo(mFrequencyConflictState);
} else {
handleGroupCreationFailure();
transitionTo(mInactiveState);
@@ -1312,7 +1342,90 @@ public class WifiP2pService extends IWifiP2pManager.Stub {
}
}
+ class FrequencyConflictState extends State {
+ private AlertDialog mFrequencyConflictDialog;
+ @Override
+ public void enter() {
+ if (DBG) logd(getName());
+ notifyFrequencyConflict();
+ }
+
+ private void notifyFrequencyConflict() {
+ logd("Notify frequency conflict");
+ Resources r = Resources.getSystem();
+
+ AlertDialog dialog = new AlertDialog.Builder(mContext)
+ .setMessage(r.getString(R.string.wifi_p2p_frequency_conflict_message,
+ getDeviceName(mSavedPeerConfig.deviceAddress)))
+ .setPositiveButton(r.getString(R.string.dlg_ok), new OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ sendMessage(DROP_WIFI_USER_ACCEPT);
+ }
+ })
+ .setNegativeButton(r.getString(R.string.decline), new OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ sendMessage(DROP_WIFI_USER_REJECT);
+ }
+ })
+ .setOnCancelListener(new DialogInterface.OnCancelListener() {
+ @Override
+ public void onCancel(DialogInterface arg0) {
+ sendMessage(DROP_WIFI_USER_REJECT);
+ }
+ })
+ .create();
+
+ dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
+ dialog.show();
+ mFrequencyConflictDialog = dialog;
+ }
+ @Override
+ public boolean processMessage(Message message) {
+ if (DBG) logd(getName() + message.toString());
+ switch (message.what) {
+ case WifiMonitor.P2P_GO_NEGOTIATION_SUCCESS_EVENT:
+ case WifiMonitor.P2P_GROUP_FORMATION_SUCCESS_EVENT:
+ loge(getName() + "group sucess during freq conflict!");
+ break;
+ case WifiMonitor.P2P_GROUP_STARTED_EVENT:
+ loge(getName() + "group started after freq conflict, handle anyway");
+ deferMessage(message);
+ transitionTo(mGroupNegotiationState);
+ break;
+ case WifiMonitor.P2P_GO_NEGOTIATION_FAILURE_EVENT:
+ case WifiMonitor.P2P_GROUP_REMOVED_EVENT:
+ case WifiMonitor.P2P_GROUP_FORMATION_FAILURE_EVENT:
+ // Ignore failures since we retry again
+ break;
+ case DROP_WIFI_USER_REJECT:
+ // User rejected dropping wifi in favour of p2p
+ handleGroupCreationFailure();
+ transitionTo(mInactiveState);
+ break;
+ case DROP_WIFI_USER_ACCEPT:
+ // User accepted dropping wifi in favour of p2p
+ mWifiChannel.sendMessage(WifiP2pService.DISCONNECT_WIFI_REQUEST, 1);
+ mTempoarilyDisconnectedWifi = true;
+ break;
+ case DISCONNECT_WIFI_RESPONSE:
+ // Got a response from wifistatemachine, retry p2p
+ if (DBG) logd(getName() + "Wifi disconnected, retry p2p");
+ transitionTo(mInactiveState);
+ sendMessage(WifiP2pManager.CONNECT, mSavedPeerConfig);
+ break;
+ default:
+ return NOT_HANDLED;
+ }
+ return HANDLED;
+ }
+
+ public void exit() {
+ if (mFrequencyConflictDialog != null) mFrequencyConflictDialog.dismiss();
+ }
+ }
class GroupCreatedState extends State {
@Override
@@ -2195,6 +2308,11 @@ public class WifiP2pService extends IWifiP2pManager.Stub {
mPeersLostDuringConnection.clear();
mServiceDiscReqId = null;
if (changed) sendP2pPeersChangedBroadcast();
+
+ if (mTempoarilyDisconnectedWifi) {
+ mWifiChannel.sendMessage(WifiP2pService.DISCONNECT_WIFI_REQUEST, 0);
+ mTempoarilyDisconnectedWifi = false;
+ }
}
//State machine initiated requests can have replyTo set to null indicating