summaryrefslogtreecommitdiffstats
path: root/wifi/java/android/net
diff options
context:
space:
mode:
Diffstat (limited to 'wifi/java/android/net')
-rw-r--r--wifi/java/android/net/wifi/WifiInfo.java1
-rw-r--r--wifi/java/android/net/wifi/WifiNative.java33
-rw-r--r--wifi/java/android/net/wifi/WifiStateMachine.java42
-rw-r--r--wifi/java/android/net/wifi/p2p/WifiP2pDeviceList.java10
-rw-r--r--wifi/java/android/net/wifi/p2p/WifiP2pManager.java179
-rw-r--r--wifi/java/android/net/wifi/p2p/WifiP2pService.java366
6 files changed, 503 insertions, 128 deletions
diff --git a/wifi/java/android/net/wifi/WifiInfo.java b/wifi/java/android/net/wifi/WifiInfo.java
index 30e4a20..1f1cfdd 100644
--- a/wifi/java/android/net/wifi/WifiInfo.java
+++ b/wifi/java/android/net/wifi/WifiInfo.java
@@ -266,6 +266,7 @@ public class WifiInfo implements Parcelable {
/** {@hide} */
public static String removeDoubleQuotes(String string) {
+ if (string == null) return null;
final int length = string.length();
if ((length > 1) && (string.charAt(0) == '"') && (string.charAt(length - 1) == '"')) {
return string.substring(1, length - 1);
diff --git a/wifi/java/android/net/wifi/WifiNative.java b/wifi/java/android/net/wifi/WifiNative.java
index 4ec2e02..26229be 100644
--- a/wifi/java/android/net/wifi/WifiNative.java
+++ b/wifi/java/android/net/wifi/WifiNative.java
@@ -270,25 +270,6 @@ public class WifiNative {
&& doBooleanCommand("DRIVER RXFILTER-START");
}
- public int getPowerMode() {
- String ret = doStringCommand("DRIVER GETPOWER");
- if (!TextUtils.isEmpty(ret)) {
- // reply comes back in the form "powermode = XX" where XX is the
- // number we're interested in.
- String[] tokens = ret.split(" = ");
- try {
- if (tokens.length == 2) return Integer.parseInt(tokens[1]);
- } catch (NumberFormatException e) {
- return -1;
- }
- }
- return -1;
- }
-
- public boolean setPowerMode(int mode) {
- return doBooleanCommand("DRIVER POWERMODE " + mode);
- }
-
public int getBand() {
String ret = doStringCommand("DRIVER GETBAND");
if (!TextUtils.isEmpty(ret)) {
@@ -366,12 +347,10 @@ public class WifiNative {
}
public void enableBackgroundScan(boolean enable) {
- //Note: BGSCAN-START and BGSCAN-STOP are documented in core/res/res/values/config.xml
- //and will need an update if the names are changed
if (enable) {
- doBooleanCommand("DRIVER BGSCAN-START");
+ doBooleanCommand("SET pno 1");
} else {
- doBooleanCommand("DRIVER BGSCAN-STOP");
+ doBooleanCommand("SET pno 0");
}
}
@@ -467,6 +446,14 @@ public class WifiNative {
return doBooleanCommand("SET interface=" + iface + " p2p_group_idle " + time);
}
+ public void setPowerSave(boolean enabled) {
+ if (enabled) {
+ doBooleanCommand("SET ps 1");
+ } else {
+ doBooleanCommand("SET ps 0");
+ }
+ }
+
public boolean setP2pPowerSave(String iface, boolean enabled) {
if (enabled) {
return doBooleanCommand("P2P_SET interface=" + iface + " ps 1");
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index 0962035..a85083d 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -305,13 +305,11 @@ public class WifiStateMachine extends StateMachine {
static final int CMD_RECONNECT = BASE + 75;
/* Reassociate to a network */
static final int CMD_REASSOCIATE = BASE + 76;
- /* Controls power mode and suspend mode optimizations
+ /* Controls suspend mode optimizations
*
- * When high perf mode is enabled, power mode is set to
- * POWER_MODE_ACTIVE and suspend mode optimizations are disabled
+ * When high perf mode is enabled, suspend mode optimizations are disabled
*
- * When high perf mode is disabled, power mode is set to
- * POWER_MODE_AUTO and suspend mode optimizations are enabled
+ * When high perf mode is disabled, suspend mode optimizations are enabled
*
* Suspend mode optimizations include:
* - packet filtering
@@ -374,11 +372,8 @@ public class WifiStateMachine extends StateMachine {
*/
private static final int DEFAULT_MAX_DHCP_RETRIES = 9;
- static final int POWER_MODE_ACTIVE = 1;
- static final int POWER_MODE_AUTO = 0;
-
- /* Tracks the power mode for restoration after a DHCP request/renewal goes through */
- private int mPowerMode = POWER_MODE_AUTO;
+ /* Tracks if power save is enabled in driver */
+ private boolean mPowerSaveEnabled = true;;
/**
* Default framework scan interval in milliseconds. This is used in the scenario in which
@@ -1683,21 +1678,18 @@ public class WifiStateMachine extends StateMachine {
mWifiNative.BLUETOOTH_COEXISTENCE_MODE_DISABLED);
}
- mPowerMode = mWifiNative.getPowerMode();
- if (mPowerMode < 0) {
- // Handle the case where supplicant driver does not support
- // getPowerModeCommand.
- mPowerMode = WifiStateMachine.POWER_MODE_AUTO;
- }
- if (mPowerMode != WifiStateMachine.POWER_MODE_ACTIVE) {
- mWifiNative.setPowerMode(WifiStateMachine.POWER_MODE_ACTIVE);
+ /* Disable power save during DHCP */
+ if (mPowerSaveEnabled) {
+ mPowerSaveEnabled = false;
+ mWifiNative.setPowerSave(mPowerSaveEnabled);
}
}
void handlePostDhcpSetup() {
- /* restore power mode */
- mWifiNative.setPowerMode(mPowerMode);
+ /* Restore power save */
+ mPowerSaveEnabled = true;
+ mWifiNative.setPowerSave(mPowerSaveEnabled);
// Set the coexistence mode back to its default value
mWifiNative.setBluetoothCoexistenceMode(
@@ -2549,6 +2541,8 @@ public class WifiStateMachine extends StateMachine {
mWifiNative.stopFilteringMulticastV4Packets();
}
+ mWifiNative.setPowerSave(mPowerSaveEnabled);
+
if (mIsScanMode) {
mWifiNative.setScanResultHandling(SCAN_ONLY_MODE);
mWifiNative.disconnect();
@@ -2820,15 +2814,15 @@ public class WifiStateMachine extends StateMachine {
break;
case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
SupplicantState state = handleSupplicantStateChange(message);
- // Due to a WEXT bug, during the time of driver start/stop
- // we can go into a driver stopped state in an unexpected way.
- // The sequence eventually puts interface
- // up and we should be back to a connected state
+ // A driver/firmware hang can now put the interface in a down state.
+ // We detect the interface going down and recover from it
if (!SupplicantState.isDriverActive(state)) {
if (mNetworkInfo.getState() != NetworkInfo.State.DISCONNECTED) {
handleNetworkDisconnect();
}
+ log("Detected an interface down, restart driver");
transitionTo(mDriverStoppedState);
+ sendMessage(CMD_START_DRIVER);
break;
}
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pDeviceList.java b/wifi/java/android/net/wifi/p2p/WifiP2pDeviceList.java
index 3751727..8942ff1 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pDeviceList.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pDeviceList.java
@@ -27,8 +27,9 @@ import java.util.Collections;
import java.util.HashMap;
/**
- * A class representing a Wi-Fi P2p device list
+ * A class representing a Wi-Fi P2p device list.
*
+ * Note that the operations are not thread safe.
* {@see WifiP2pManager}
*/
public class WifiP2pDeviceList implements Parcelable {
@@ -83,6 +84,13 @@ public class WifiP2pDeviceList implements Parcelable {
}
/** @hide */
+ public void updateStatus(String deviceAddress, int status) {
+ if (deviceAddress == null) return;
+ WifiP2pDevice d = mDevices.get(deviceAddress);
+ d.status = status;
+ }
+
+ /** @hide */
public WifiP2pDevice get(String deviceAddress) {
if (deviceAddress == null) return null;
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
index b25bf91..ef77d45 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
@@ -30,6 +30,7 @@ import android.net.wifi.p2p.nsd.WifiP2pServiceResponse;
import android.net.wifi.p2p.nsd.WifiP2pUpnpServiceInfo;
import android.net.wifi.p2p.nsd.WifiP2pUpnpServiceResponse;
import android.os.Binder;
+import android.os.Bundle;
import android.os.IBinder;
import android.os.Handler;
import android.os.Looper;
@@ -265,6 +266,41 @@ public class WifiP2pManager {
*/
public static final String EXTRA_WIFI_P2P_DEVICE = "wifiP2pDevice";
+ /**
+ * The lookup key for a {@link #String} object.
+ * Retrieve with {@link android.os.Bundle#getString(String)}.
+ * @hide
+ */
+ public static final String APP_PKG_BUNDLE_KEY = "appPkgName";
+
+ /**
+ * The lookup key for a {@link #Boolean} object.
+ * Retrieve with {@link android.os.Bundle#getBoolean(String)}.
+ * @hide
+ */
+ public static final String RESET_DIALOG_LISTENER_BUNDLE_KEY = "dialogResetFlag";
+
+ /**
+ * The lookup key for a {@link #String} object.
+ * Retrieve with {@link android.os.Bundle#getString(String)}.
+ * @hide
+ */
+ public static final String WPS_PIN_BUNDLE_KEY = "wpsPin";
+
+ /**
+ * The lookup key for a {@link android.net.wifi.p2p.WifiP2pDevice} object
+ * Retrieve with {@link android.os.Bundle#getParcelable(String)}.
+ * @hide
+ */
+ public static final String P2P_DEV_BUNDLE_KEY = "wifiP2pDevice";
+
+ /**
+ * The lookup key for a {@link android.net.wifi.p2p.WifiP2pConfig} object
+ * Retrieve with {@link android.os.Bundle#getParcelable(String)}.
+ * @hide
+ */
+ public static final String P2P_CONFIG_BUNDLE_KEY = "wifiP2pConfig";
+
IWifiP2pManager mService;
private static final int BASE = Protocol.BASE_WIFI_P2P_MANAGER;
@@ -388,6 +424,18 @@ public class WifiP2pManager {
/** @hide */
public static final int SET_DEVICE_NAME_SUCCEEDED = BASE + 53;
+ /** @hide */
+ public static final int SET_DIALOG_LISTENER = BASE + 54;
+ /** @hide */
+ public static final int DIALOG_LISTENER_DETACHED = BASE + 55;
+ /** @hide */
+ public static final int DIALOG_LISTENER_ATTACHED = BASE + 56;
+
+ /** @hide */
+ public static final int CONNECTION_REQUESTED = BASE + 57;
+ /** @hide */
+ public static final int SHOW_PIN_REQUESTED = BASE + 58;
+
/**
* Create a new WifiP2pManager instance. Applications use
* {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve
@@ -427,6 +475,14 @@ public class WifiP2pManager {
*/
public static final int NO_SERVICE_REQUESTS = 3;
+ /**
+ * Passed with {@link DialogListener#onDetached}.
+ * Indicates that the registered listener was detached from the system because
+ * the application went into background.
+ * @hide
+ */
+ public static final int NOT_IN_FOREGROUND = 4;
+
/** Interface for callback invocation when framework channel is lost */
public interface ChannelListener {
/**
@@ -475,7 +531,7 @@ public class WifiP2pManager {
public void onGroupInfoAvailable(WifiP2pGroup group);
}
- /**
+ /**
* Interface for callback invocation when service discovery response other than
* Upnp or Bonjour is received
*/
@@ -559,15 +615,59 @@ public class WifiP2pManager {
/**
+ * Interface for callback invocation when dialog events are received.
+ * see {@link #setDialogListener}.
+ * @hide
+ */
+ public interface DialogListener {
+
+ /**
+ * Called by the system when a request to show WPS pin is received.
+ *
+ * @param pin WPS pin.
+ */
+ public void onShowPinRequested(String pin);
+
+ /**
+ * Called by the system when a request to establish the connection is received.
+ *
+ * Application can then call {@link #connect} with the given config if the request
+ * is acceptable.
+ *
+ * @param device the source device.
+ * @param config p2p configuration.
+ */
+ public void onConnectionRequested(WifiP2pDevice device, WifiP2pConfig config);
+
+ /**
+ * Called by the system when this listener was attached to the system.
+ */
+ public void onAttached();
+
+ /**
+ * Called by the system when this listener was detached from the system or
+ * failed to attach.
+ *
+ * Application can request again using {@link #setDialogListener} when it is
+ * in the foreground.
+ *
+ * @param reason The reason for failure could be one of {@link #ERROR},
+ * {@link #BUSY}, {@link #P2P_UNSUPPORTED} or {@link #NOT_IN_FOREGROUND}
+ */
+ public void onDetached(int reason);
+ }
+
+ /**
* A channel that connects the application to the Wifi p2p framework.
* Most p2p operations require a Channel as an argument. An instance of Channel is obtained
* by doing a call on {@link #initialize}
*/
public static class Channel {
- Channel(Looper looper, ChannelListener l) {
+ Channel(Context context, Looper looper, ChannelListener l) {
mAsyncChannel = new AsyncChannel();
mHandler = new P2pHandler(looper);
mChannelListener = l;
+ mContext = context;
}
private final static int INVALID_LISTENER_KEY = 0;
private ChannelListener mChannelListener;
@@ -578,9 +678,11 @@ public class WifiP2pManager {
private HashMap<Integer, Object> mListenerMap = new HashMap<Integer, Object>();
private Object mListenerMapLock = new Object();
private int mListenerKey = 0;
+ private DialogListener mDialogListener;
- AsyncChannel mAsyncChannel;
- P2pHandler mHandler;
+ private AsyncChannel mAsyncChannel;
+ private P2pHandler mHandler;
+ Context mContext;
class P2pHandler extends Handler {
P2pHandler(Looper looper) {
super(looper);
@@ -656,6 +758,34 @@ public class WifiP2pManager {
WifiP2pServiceResponse resp = (WifiP2pServiceResponse) message.obj;
handleServiceResponse(resp);
break;
+ case WifiP2pManager.CONNECTION_REQUESTED:
+ if (mDialogListener != null) {
+ Bundle bundle = message.getData();
+ mDialogListener.onConnectionRequested(
+ (WifiP2pDevice)bundle.getParcelable(
+ P2P_DEV_BUNDLE_KEY),
+ (WifiP2pConfig)bundle.getParcelable(
+ P2P_CONFIG_BUNDLE_KEY));
+ }
+ break;
+ case WifiP2pManager.SHOW_PIN_REQUESTED:
+ if (mDialogListener != null) {
+ Bundle bundle = message.getData();
+ mDialogListener.onShowPinRequested(
+ bundle.getString(WPS_PIN_BUNDLE_KEY));
+ }
+ break;
+ case WifiP2pManager.DIALOG_LISTENER_ATTACHED:
+ if (mDialogListener != null) {
+ mDialogListener.onAttached();
+ }
+ break;
+ case WifiP2pManager.DIALOG_LISTENER_DETACHED:
+ if (mDialogListener != null) {
+ mDialogListener.onDetached(message.arg1);
+ mDialogListener = null;
+ }
+ break;
default:
Log.d(TAG, "Ignored " + message);
break;
@@ -721,6 +851,10 @@ public class WifiP2pManager {
return mListenerMap.remove(key);
}
}
+
+ private void setDialogListener(DialogListener listener) {
+ mDialogListener = listener;
+ }
}
private static void checkChannel(Channel c) {
@@ -748,7 +882,7 @@ public class WifiP2pManager {
Messenger messenger = getMessenger();
if (messenger == null) return null;
- Channel c = new Channel(srcLooper, listener);
+ Channel c = new Channel(srcContext, srcLooper, listener);
if (c.mAsyncChannel.connectSync(srcContext, c.mHandler, messenger)
== AsyncChannel.STATUS_SUCCESSFUL) {
return c;
@@ -1126,6 +1260,41 @@ public class WifiP2pManager {
}
+ /**
+ * Set dialog listener to over-ride system dialogs on p2p events. This function
+ * allows an application to receive notifications on connection requests from
+ * peers so that it can customize the user experience for connection with
+ * peers.
+ *
+ * <p> The function call immediately returns after sending a request
+ * to the framework. The application is notified of a success or failure to attach
+ * to the system through listener callbacks {@link DialogListener#onAttached} or
+ * {@link DialogListener#onDetached}.
+ *
+ * <p> Note that only foreground application will be successful in overriding the
+ * system dialogs.
+ * @hide
+ *
+ * @param c is the channel created at {@link #initialize}
+ * @param listener for callback on a dialog event.
+ */
+ public void setDialogListener(Channel c, DialogListener listener) {
+ checkChannel(c);
+ c.setDialogListener(listener);
+
+ /**
+ * mAsyncChannel should always stay private and inaccessible from the app
+ * to prevent an app from sending a message with a fake app name to gain
+ * control over the dialogs
+ */
+ Message msg = Message.obtain();
+ Bundle bundle = new Bundle();
+ bundle.putString(APP_PKG_BUNDLE_KEY, c.mContext.getPackageName());
+ bundle.putBoolean(RESET_DIALOG_LISTENER_BUNDLE_KEY, listener == null);
+ msg.what = SET_DIALOG_LISTENER;
+ msg.setData(bundle);
+ c.mAsyncChannel.sendMessage(msg);
+ }
/**
* Get a reference to WifiP2pService handler. This is used to establish
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pService.java b/wifi/java/android/net/wifi/p2p/WifiP2pService.java
index 77e6187..f0adb25 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pService.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pService.java
@@ -16,10 +16,13 @@
package android.net.wifi.p2p;
+import android.app.Activity;
+import android.app.ActivityManager;
import android.app.AlertDialog;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
+import android.app.ActivityManager.RunningTaskInfo;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
@@ -46,15 +49,19 @@ import android.net.wifi.p2p.nsd.WifiP2pServiceInfo;
import android.net.wifi.p2p.nsd.WifiP2pServiceRequest;
import android.net.wifi.p2p.nsd.WifiP2pServiceResponse;
import android.os.Binder;
+import android.os.Bundle;
import android.os.IBinder;
import android.os.INetworkManagementService;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
import android.os.Messenger;
+import android.os.Parcel;
+import android.os.Parcelable;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemProperties;
+import android.os.Parcelable.Creator;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.Slog;
@@ -102,6 +109,8 @@ public class WifiP2pService extends IWifiP2pManager.Stub {
INetworkManagementService mNwService;
private DhcpStateMachine mDhcpStateMachine;
+ private ActivityManager mActivityMgr;
+
private P2pStateMachine mP2pStateMachine;
private AsyncChannel mReplyChannel = new AsyncChannel();
private AsyncChannel mWifiChannel;
@@ -148,7 +157,7 @@ public class WifiP2pService extends IWifiP2pManager.Stub {
/* When a group has been explicitly created by an app, we persist the group
* even after all clients have been disconnected until an explicit remove
* is invoked */
- private boolean mPersistGroup;
+ private boolean mAutonomousGroup;
/* Track whether we are in p2p discovery. This is used to avoid sending duplicate
* broadcasts
@@ -167,6 +176,13 @@ public class WifiP2pService extends IWifiP2pManager.Stub {
/* clients(application) information list. */
private HashMap<Messenger, ClientInfo> mClientInfoList = new HashMap<Messenger, ClientInfo>();
+ /* The foreground application's messenger.
+ * The connection request is notified only to foreground application */
+ private Messenger mForegroundAppMessenger;
+
+ /* the package name of foreground application. */
+ private String mForegroundAppPkgName;
+
/* Is chosen as a unique range to avoid conflict with
the range defined in Tethering.java */
private static final String[] DHCP_RANGE = {"192.168.49.2", "192.168.49.254"};
@@ -177,6 +193,8 @@ public class WifiP2pService extends IWifiP2pManager.Stub {
//STOPSHIP: get this from native side
mInterface = "p2p0";
+ mActivityMgr = (ActivityManager)context.getSystemService(Activity.ACTIVITY_SERVICE);
+
mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI_P2P, 0, NETWORKTYPE, "");
mP2pSupported = mContext.getPackageManager().hasSystemFeature(
@@ -261,6 +279,9 @@ public class WifiP2pService extends IWifiP2pManager.Stub {
// Saved WifiP2pGroup from invitation request
private WifiP2pGroup mSavedP2pGroup;
+ // Saved WifiP2pDevice from provisioning request
+ private WifiP2pDevice mSavedProvDiscDevice;
+
P2pStateMachine(String name, boolean p2pSupported) {
super(name);
@@ -380,6 +401,18 @@ public class WifiP2pService extends IWifiP2pManager.Stub {
case WifiP2pManager.REQUEST_GROUP_INFO:
replyToMessage(message, WifiP2pManager.RESPONSE_GROUP_INFO, mGroup);
break;
+ case WifiP2pManager.SET_DIALOG_LISTENER:
+ String appPkgName = (String)message.getData().getString(
+ WifiP2pManager.APP_PKG_BUNDLE_KEY);
+ boolean isReset = message.getData().getBoolean(
+ WifiP2pManager.RESET_DIALOG_LISTENER_BUNDLE_KEY);
+ if (setDialogListenerApp(message.replyTo, appPkgName, isReset)) {
+ replyToMessage(message, WifiP2pManager.DIALOG_LISTENER_ATTACHED);
+ } else {
+ replyToMessage(message, WifiP2pManager.DIALOG_LISTENER_DETACHED,
+ WifiP2pManager.NOT_IN_FOREGROUND);
+ }
+ break;
// Ignore
case WifiMonitor.P2P_INVITATION_RESULT_EVENT:
case WifiMonitor.SCAN_RESULTS_EVENT:
@@ -393,7 +426,7 @@ public class WifiP2pService extends IWifiP2pManager.Stub {
case PEER_CONNECTION_USER_REJECT:
case GROUP_CREATING_TIMED_OUT:
break;
- /* unexpected group created, remove */
+ /* unexpected group created, remove */
case WifiMonitor.P2P_GROUP_STARTED_EVENT:
mGroup = (WifiP2pGroup) message.obj;
loge("Unexpected group creation, remove " + mGroup);
@@ -447,6 +480,10 @@ public class WifiP2pService extends IWifiP2pManager.Stub {
replyToMessage(message, WifiP2pManager.ADD_LOCAL_SERVICE_FAILED,
WifiP2pManager.P2P_UNSUPPORTED);
break;
+ case WifiP2pManager.SET_DIALOG_LISTENER:
+ replyToMessage(message, WifiP2pManager.DIALOG_LISTENER_DETACHED,
+ WifiP2pManager.P2P_UNSUPPORTED);
+ break;
case WifiP2pManager.REMOVE_LOCAL_SERVICE:
replyToMessage(message, WifiP2pManager.REMOVE_LOCAL_SERVICE_FAILED,
WifiP2pManager.P2P_UNSUPPORTED);
@@ -714,33 +751,53 @@ public class WifiP2pService extends IWifiP2pManager.Stub {
switch (message.what) {
case WifiP2pManager.CONNECT:
if (DBG) logd(getName() + " sending connect");
- mSavedPeerConfig = (WifiP2pConfig) message.obj;
- mPersistGroup = false;
- int netId = configuredNetworkId(mSavedPeerConfig.deviceAddress);
- if (netId >= 0) {
- //TODO: if failure, remove config and do a regular p2pConnect()
- mWifiNative.p2pReinvoke(netId, mSavedPeerConfig.deviceAddress);
- } else {
+ WifiP2pConfig config = (WifiP2pConfig) message.obj;
+ mAutonomousGroup = false;
+
+ if (mSavedPeerConfig != null && config.deviceAddress.equals(
+ mSavedPeerConfig.deviceAddress)) {
+ mSavedPeerConfig = config;
+
//Stop discovery before issuing connect
mWifiNative.p2pStopFind();
- //If peer is a GO, we do not need to send provisional discovery,
- //the supplicant takes care of it.
if (mWifiNative.isGroupOwner(mSavedPeerConfig.deviceAddress)) {
- if (DBG) logd("Sending join to GO");
p2pConnectWithPinDisplay(mSavedPeerConfig, JOIN_GROUP);
- transitionTo(mGroupNegotiationState);
} else {
- if (DBG) logd("Sending prov disc");
- transitionTo(mProvisionDiscoveryState);
+ p2pConnectWithPinDisplay(mSavedPeerConfig, FORM_GROUP);
+ }
+ transitionTo(mGroupNegotiationState);
+ } else {
+ mSavedPeerConfig = config;
+ int netId = configuredNetworkId(mSavedPeerConfig.deviceAddress);
+ if (netId >= 0) {
+ //TODO: if failure, remove config and do a regular p2pConnect()
+ mWifiNative.p2pReinvoke(netId, mSavedPeerConfig.deviceAddress);
+ } else {
+ //Stop discovery before issuing connect
+ mWifiNative.p2pStopFind();
+ //If peer is a GO, we do not need to send provisional discovery,
+ //the supplicant takes care of it.
+ if (mWifiNative.isGroupOwner(mSavedPeerConfig.deviceAddress)) {
+ if (DBG) logd("Sending join to GO");
+ p2pConnectWithPinDisplay(mSavedPeerConfig, JOIN_GROUP);
+ transitionTo(mGroupNegotiationState);
+ } else {
+ if (DBG) logd("Sending prov disc");
+ transitionTo(mProvisionDiscoveryState);
+ }
}
}
- updateDeviceStatus(mSavedPeerConfig.deviceAddress, WifiP2pDevice.INVITED);
+ mPeers.updateStatus(mSavedPeerConfig.deviceAddress, WifiP2pDevice.INVITED);
sendP2pPeersChangedBroadcast();
replyToMessage(message, WifiP2pManager.CONNECT_SUCCEEDED);
break;
case WifiMonitor.P2P_GO_NEGOTIATION_REQUEST_EVENT:
mSavedPeerConfig = (WifiP2pConfig) message.obj;
- transitionTo(mUserAuthorizingInvitationState);
+
+ if (!sendConnectNoticeToApp(mPeers.get(mSavedPeerConfig.deviceAddress),
+ mSavedPeerConfig)) {
+ transitionTo(mUserAuthorizingInvitationState);
+ }
break;
case WifiMonitor.P2P_INVITATION_RECEIVED_EVENT:
WifiP2pGroup group = (WifiP2pGroup) message.obj;
@@ -756,7 +813,7 @@ public class WifiP2pService extends IWifiP2pManager.Stub {
//Check if we have the owner in peer list and use appropriate
//wps method. Default is to use PBC.
- if ((owner = getDeviceFromPeerList(owner.deviceAddress)) != null) {
+ if ((owner = mPeers.get(owner.deviceAddress)) != null) {
if (owner.wpsPbcSupported()) {
mSavedPeerConfig.wps.setup = WpsInfo.PBC;
} else if (owner.wpsKeypadSupported()) {
@@ -765,29 +822,23 @@ public class WifiP2pService extends IWifiP2pManager.Stub {
mSavedPeerConfig.wps.setup = WpsInfo.DISPLAY;
}
}
- transitionTo(mUserAuthorizingInvitationState);
+
+ //TODO In the p2p client case, we should set source address correctly.
+ if (!sendConnectNoticeToApp(mPeers.get(mSavedPeerConfig.deviceAddress),
+ mSavedPeerConfig)) {
+ transitionTo(mUserAuthorizingInvitationState);
+ }
break;
case WifiMonitor.P2P_PROV_DISC_PBC_REQ_EVENT:
case WifiMonitor.P2P_PROV_DISC_ENTER_PIN_EVENT:
case WifiMonitor.P2P_PROV_DISC_SHOW_PIN_EVENT:
- WifiP2pProvDiscEvent provDisc = (WifiP2pProvDiscEvent) message.obj;
- mSavedPeerConfig = new WifiP2pConfig();
- mSavedPeerConfig.deviceAddress = provDisc.device.deviceAddress;
- if (message.what == WifiMonitor.P2P_PROV_DISC_ENTER_PIN_EVENT) {
- mSavedPeerConfig.wps.setup = WpsInfo.KEYPAD;
- if (DBG) logd("Keypad prov disc request");
- } else if (message.what == WifiMonitor.P2P_PROV_DISC_SHOW_PIN_EVENT) {
- mSavedPeerConfig.wps.setup = WpsInfo.DISPLAY;
- mSavedPeerConfig.wps.pin = provDisc.pin;
- if (DBG) logd("Display prov disc request");
- } else {
- mSavedPeerConfig.wps.setup = WpsInfo.PBC;
- if (DBG) logd("PBC prov disc request");
- }
- transitionTo(mUserAuthorizingInvitationState);
- break;
+ //We let the supplicant handle the provision discovery response
+ //and wait instead for the GO_NEGOTIATION_REQUEST_EVENT.
+ //Handling provision discovery and issuing a p2p_connect before
+ //group negotiation comes through causes issues
+ break;
case WifiP2pManager.CREATE_GROUP:
- mPersistGroup = true;
+ mAutonomousGroup = true;
if (mWifiNative.p2pGroupAdd()) {
replyToMessage(message, WifiP2pManager.CREATE_GROUP_SUCCEEDED);
} else {
@@ -849,12 +900,16 @@ public class WifiP2pService extends IWifiP2pManager.Stub {
@Override
public void enter() {
if (DBG) logd(getName());
- notifyInvitationReceived();
+ if (!sendConnectNoticeToApp(mPeers.get(mSavedPeerConfig.deviceAddress),
+ mSavedPeerConfig)) {
+ notifyInvitationReceived();
+ }
}
@Override
public boolean processMessage(Message message) {
if (DBG) logd(getName() + message.toString());
+ boolean ret = HANDLED;
switch (message.what) {
case PEER_CONNECTION_USER_ACCEPT:
//TODO: handle persistence
@@ -863,7 +918,7 @@ public class WifiP2pService extends IWifiP2pManager.Stub {
} else {
p2pConnectWithPinDisplay(mSavedPeerConfig, FORM_GROUP);
}
- updateDeviceStatus(mSavedPeerConfig.deviceAddress, WifiP2pDevice.INVITED);
+ mPeers.updateStatus(mSavedPeerConfig.deviceAddress, WifiP2pDevice.INVITED);
sendP2pPeersChangedBroadcast();
transitionTo(mGroupNegotiationState);
break;
@@ -875,7 +930,7 @@ public class WifiP2pService extends IWifiP2pManager.Stub {
default:
return NOT_HANDLED;
}
- return HANDLED;
+ return ret;
}
@Override
@@ -933,7 +988,9 @@ public class WifiP2pService extends IWifiP2pManager.Stub {
if (DBG) logd("Found a match " + mSavedPeerConfig);
mSavedPeerConfig.wps.pin = provDisc.pin;
mWifiNative.p2pConnect(mSavedPeerConfig, FORM_GROUP);
- notifyInvitationSent(provDisc.pin, device.deviceAddress);
+ if (!sendShowPinReqToFrontApp(provDisc.pin)) {
+ notifyInvitationSent(provDisc.pin, device.deviceAddress);
+ }
transitionTo(mGroupNegotiationState);
}
break;
@@ -970,7 +1027,7 @@ public class WifiP2pService extends IWifiP2pManager.Stub {
P2pStateMachine.this, mGroup.getInterface());
mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_START_DHCP);
WifiP2pDevice groupOwner = mGroup.getOwner();
- updateDeviceStatus(groupOwner.deviceAddress, WifiP2pDevice.CONNECTED);
+ mPeers.updateStatus(groupOwner.deviceAddress, WifiP2pDevice.CONNECTED);
sendP2pPeersChangedBroadcast();
}
mSavedPeerConfig = null;
@@ -1005,7 +1062,7 @@ public class WifiP2pService extends IWifiP2pManager.Stub {
sendP2pConnectionChangedBroadcast();
}
- if (!mPersistGroup) {
+ if (!mAutonomousGroup) {
mWifiNative.setP2pGroupIdle(mGroup.getInterface(), GROUP_IDLE_TIME_S);
}
}
@@ -1018,8 +1075,12 @@ public class WifiP2pService extends IWifiP2pManager.Stub {
WifiP2pDevice device = (WifiP2pDevice) message.obj;
String deviceAddress = device.deviceAddress;
if (deviceAddress != null) {
+ if (mSavedProvDiscDevice != null &&
+ deviceAddress.equals(mSavedProvDiscDevice.deviceAddress)) {
+ mSavedProvDiscDevice = null;
+ }
mGroup.addClient(deviceAddress);
- updateDeviceStatus(deviceAddress, WifiP2pDevice.CONNECTED);
+ mPeers.updateStatus(deviceAddress, WifiP2pDevice.CONNECTED);
if (DBG) logd(getName() + " ap sta connected");
sendP2pPeersChangedBroadcast();
} else {
@@ -1030,10 +1091,10 @@ public class WifiP2pService extends IWifiP2pManager.Stub {
device = (WifiP2pDevice) message.obj;
deviceAddress = device.deviceAddress;
if (deviceAddress != null) {
- updateDeviceStatus(deviceAddress, WifiP2pDevice.AVAILABLE);
+ mPeers.updateStatus(deviceAddress, WifiP2pDevice.AVAILABLE);
if (mGroup.removeClient(deviceAddress)) {
if (DBG) logd("Removed client " + deviceAddress);
- if (!mPersistGroup && mGroup.isClientListEmpty()) {
+ if (!mAutonomousGroup && mGroup.isClientListEmpty()) {
Slog.d(TAG, "Client list empty, remove non-persistent p2p group");
mWifiNative.p2pGroupRemove(mGroup.getInterface());
}
@@ -1112,14 +1173,45 @@ public class WifiP2pService extends IWifiP2pManager.Stub {
break;
case WifiP2pManager.CONNECT:
WifiP2pConfig config = (WifiP2pConfig) message.obj;
- logd("Inviting device : " + config.deviceAddress);
- if (mWifiNative.p2pInvite(mGroup, config.deviceAddress)) {
- updateDeviceStatus(config.deviceAddress, WifiP2pDevice.INVITED);
- sendP2pPeersChangedBroadcast();
+ if (config.deviceAddress == null ||
+ (mSavedProvDiscDevice != null &&
+ mSavedProvDiscDevice.deviceAddress.equals(
+ config.deviceAddress))) {
+ if (config.wps.setup == WpsInfo.PBC) {
+ mWifiNative.startWpsPbc(mGroup.getInterface(), null);
+ } else {
+ if (config.wps.pin == null) {
+ String pin = mWifiNative.startWpsPinDisplay(mGroup.getInterface());
+ try {
+ Integer.parseInt(pin);
+ if (!sendShowPinReqToFrontApp(pin)) {
+ notifyInvitationSent(pin,
+ config.deviceAddress != null ?
+ config.deviceAddress : "any");
+ }
+ } catch (NumberFormatException ignore) {
+ // do nothing if pin is invalid
+ }
+ } else {
+ mWifiNative.startWpsPinKeypad(mGroup.getInterface(),
+ config.wps.pin);
+ }
+ }
+ if (config.deviceAddress != null) {
+ mPeers.updateStatus(config.deviceAddress, WifiP2pDevice.INVITED);
+ sendP2pPeersChangedBroadcast();
+ }
replyToMessage(message, WifiP2pManager.CONNECT_SUCCEEDED);
} else {
- replyToMessage(message, WifiP2pManager.CONNECT_FAILED,
- WifiP2pManager.ERROR);
+ logd("Inviting device : " + config.deviceAddress);
+ if (mWifiNative.p2pInvite(mGroup, config.deviceAddress)) {
+ mPeers.updateStatus(config.deviceAddress, WifiP2pDevice.INVITED);
+ sendP2pPeersChangedBroadcast();
+ replyToMessage(message, WifiP2pManager.CONNECT_SUCCEEDED);
+ } else {
+ replyToMessage(message, WifiP2pManager.CONNECT_FAILED,
+ WifiP2pManager.ERROR);
+ }
}
// TODO: figure out updating the status to declined when invitation is rejected
break;
@@ -1127,6 +1219,7 @@ public class WifiP2pService extends IWifiP2pManager.Stub {
case WifiMonitor.P2P_PROV_DISC_ENTER_PIN_EVENT:
case WifiMonitor.P2P_PROV_DISC_SHOW_PIN_EVENT:
WifiP2pProvDiscEvent provDisc = (WifiP2pProvDiscEvent) message.obj;
+ mSavedProvDiscDevice = provDisc.device;
mSavedPeerConfig = new WifiP2pConfig();
mSavedPeerConfig.deviceAddress = provDisc.device.deviceAddress;
if (message.what == WifiMonitor.P2P_PROV_DISC_ENTER_PIN_EVENT) {
@@ -1137,7 +1230,9 @@ public class WifiP2pService extends IWifiP2pManager.Stub {
} else {
mSavedPeerConfig.wps.setup = WpsInfo.PBC;
}
- transitionTo(mUserAuthorizingJoinState);
+ if (!sendConnectNoticeToApp(mSavedProvDiscDevice, mSavedPeerConfig)) {
+ transitionTo(mUserAuthorizingJoinState);
+ }
break;
case WifiMonitor.P2P_GROUP_STARTED_EVENT:
Slog.e(TAG, "Duplicate group creation event notice, ignore");
@@ -1149,6 +1244,7 @@ public class WifiP2pService extends IWifiP2pManager.Stub {
}
public void exit() {
+ mSavedProvDiscDevice = null;
updateThisDevice(WifiP2pDevice.AVAILABLE);
setWifiP2pInfoOnGroupTermination();
mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED, null, null);
@@ -1160,6 +1256,7 @@ public class WifiP2pService extends IWifiP2pManager.Stub {
@Override
public void enter() {
if (DBG) logd(getName());
+
notifyInvitationReceived();
}
@@ -1174,9 +1271,10 @@ public class WifiP2pService extends IWifiP2pManager.Stub {
break;
case PEER_CONNECTION_USER_ACCEPT:
if (mSavedPeerConfig.wps.setup == WpsInfo.PBC) {
- mWifiNative.startWpsPbc(null);
+ mWifiNative.startWpsPbc(mGroup.getInterface(), null);
} else {
- mWifiNative.startWpsPinKeypad(mSavedPeerConfig.wps.pin);
+ mWifiNative.startWpsPinKeypad(mGroup.getInterface(),
+ mSavedPeerConfig.wps.pin);
}
mSavedPeerConfig = null;
transitionTo(mGroupCreatedState);
@@ -1367,14 +1465,6 @@ public class WifiP2pService extends IWifiP2pManager.Stub {
dialog.show();
}
- private void updateDeviceStatus(String deviceAddress, int status) {
- for (WifiP2pDevice d : mPeers.getDeviceList()) {
- if (d.deviceAddress.equals(deviceAddress)) {
- d.status = status;
- }
- }
- }
-
//TODO: implement when wpa_supplicant is fixed
private int configuredNetworkId(String deviceAddress) {
return -1;
@@ -1393,29 +1483,21 @@ public class WifiP2pService extends IWifiP2pManager.Stub {
}
private String getDeviceName(String deviceAddress) {
- for (WifiP2pDevice d : mPeers.getDeviceList()) {
- if (d.deviceAddress.equals(deviceAddress)) {
+ WifiP2pDevice d = mPeers.get(deviceAddress);
+ if (d != null) {
return d.deviceName;
- }
}
//Treat the address as name if there is no match
return deviceAddress;
}
- private WifiP2pDevice getDeviceFromPeerList(String deviceAddress) {
- for (WifiP2pDevice d : mPeers.getDeviceList()) {
- if (d.deviceAddress.equals(deviceAddress)) {
- return d;
- }
- }
- return null;
- }
-
private void p2pConnectWithPinDisplay(WifiP2pConfig config, boolean join) {
String pin = mWifiNative.p2pConnect(config, join);
try {
Integer.parseInt(pin);
- notifyInvitationSent(pin, config.deviceAddress);
+ if (!sendShowPinReqToFrontApp(pin)) {
+ notifyInvitationSent(pin, config.deviceAddress);
+ }
} catch (NumberFormatException ignore) {
// do nothing if p2pConnect did not return a pin
}
@@ -1776,6 +1858,139 @@ public class WifiP2pService extends IWifiP2pManager.Stub {
return clientInfo;
}
+ /**
+ * Send detached message to dialog listener in the foreground application.
+ * @param reason
+ */
+ private void sendDetachedMsg(int reason) {
+ if (mForegroundAppMessenger == null) return;
+
+ Message msg = Message.obtain();
+ msg.what = WifiP2pManager.DIALOG_LISTENER_DETACHED;
+ msg.arg1 = reason;
+ try {
+ mForegroundAppMessenger.send(msg);
+ } catch (RemoteException e) {
+ }
+ mForegroundAppMessenger = null;
+ mForegroundAppPkgName = null;
+ }
+
+ /**
+ * Send a request to show wps pin to dialog listener in the foreground application.
+ * @param pin WPS pin
+ * @return
+ */
+ private boolean sendShowPinReqToFrontApp(String pin) {
+ if (!isForegroundApp(mForegroundAppPkgName)) {
+ sendDetachedMsg(WifiP2pManager.NOT_IN_FOREGROUND);
+ return false;
+ }
+ Message msg = Message.obtain();
+ msg.what = WifiP2pManager.SHOW_PIN_REQUESTED;
+ Bundle bundle = new Bundle();
+ bundle.putString(WifiP2pManager.WPS_PIN_BUNDLE_KEY, pin);
+ msg.setData(bundle);
+ return sendDialogMsgToFrontApp(msg);
+ }
+
+ /**
+ * Send a request to establish the connection to dialog listener in the foreground
+ * application.
+ * @param dev source device
+ * @param config
+ * @return
+ */
+ private boolean sendConnectNoticeToApp(WifiP2pDevice dev, WifiP2pConfig config) {
+ if (dev == null) {
+ dev = new WifiP2pDevice(config.deviceAddress);
+ }
+
+ if (!isForegroundApp(mForegroundAppPkgName)) {
+ if (DBG) logd("application is NOT foreground");
+ sendDetachedMsg(WifiP2pManager.NOT_IN_FOREGROUND);
+ return false;
+ }
+
+ Message msg = Message.obtain();
+ msg.what = WifiP2pManager.CONNECTION_REQUESTED;
+ Bundle bundle = new Bundle();
+ bundle.putParcelable(WifiP2pManager.P2P_DEV_BUNDLE_KEY, dev);
+ bundle.putParcelable(WifiP2pManager.P2P_CONFIG_BUNDLE_KEY, config);
+ msg.setData(bundle);
+ return sendDialogMsgToFrontApp(msg);
+ }
+
+ /**
+ * Send dialog event message to front application's dialog listener.
+ * @param msg
+ * @return true if success.
+ */
+ private boolean sendDialogMsgToFrontApp(Message msg) {
+ try {
+ mForegroundAppMessenger.send(msg);
+ } catch (RemoteException e) {
+ mForegroundAppMessenger = null;
+ mForegroundAppPkgName = null;
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Set dialog listener application.
+ * @param m
+ * @param appPkgName if null, reset the listener.
+ * @param isReset if true, try to reset.
+ * @return
+ */
+ private boolean setDialogListenerApp(Messenger m,
+ String appPkgName, boolean isReset) {
+
+ if (mForegroundAppPkgName != null && !mForegroundAppPkgName.equals(appPkgName)) {
+ if (isForegroundApp(mForegroundAppPkgName)) {
+ // The current dialog listener is foreground app's.
+ if (DBG) logd("application is NOT foreground");
+ return false;
+ }
+ // detach an old listener.
+ sendDetachedMsg(WifiP2pManager.NOT_IN_FOREGROUND);
+ }
+
+ if (isReset) {
+ if (DBG) logd("reset dialog listener");
+ mForegroundAppMessenger = null;
+ mForegroundAppPkgName = null;
+ return true;
+ }
+
+ if (!isForegroundApp(appPkgName)) {
+ return false;
+ }
+
+ mForegroundAppMessenger = m;
+ mForegroundAppPkgName = appPkgName;
+ if (DBG) logd("set dialog listener. app=" + appPkgName);
+ return true;
+ }
+
+ /**
+ * Return true if the specified package name is foreground app's.
+ *
+ * @param pkgName application package name.
+ * @return
+ */
+ private boolean isForegroundApp(String pkgName) {
+ if (pkgName == null) return false;
+
+ List<RunningTaskInfo> tasks = mActivityMgr.getRunningTasks(1);
+ if (tasks.size() == 0) {
+ return false;
+ }
+
+ return pkgName.equals(tasks.get(0).baseActivity.getPackageName());
+ }
+
}
/**
@@ -1806,4 +2021,5 @@ public class WifiP2pService extends IWifiP2pManager.Stub {
mServList = new ArrayList<WifiP2pServiceInfo>();
}
}
+
}