summaryrefslogtreecommitdiffstats
path: root/wifi/java/android
diff options
context:
space:
mode:
authorYoshihiko Ikenaga <yoshihiko.ikenaga@jp.sony.com>2012-02-14 11:28:35 +0900
committerIrfan Sheriff <isheriff@google.com>2012-04-27 11:18:14 -0700
commitbfb27bbefb013220af699881d486cc04be5ec1f5 (patch)
tree0172a0042988e6c28bb026476b76624eca877d92 /wifi/java/android
parentca7086f5bdbc404b01863770b6023d069f4ab720 (diff)
downloadframeworks_base-bfb27bbefb013220af699881d486cc04be5ec1f5.zip
frameworks_base-bfb27bbefb013220af699881d486cc04be5ec1f5.tar.gz
frameworks_base-bfb27bbefb013220af699881d486cc04be5ec1f5.tar.bz2
Allow override of p2p dialogs
By default, we show dialogs for connection requests and for user interaction for pin input from the framework. For applications, that want to make the experience more seamless we should allow automatic discovery and connection as long as one app can control it. We allow this for a foreground app alone right now. This will be a hidden API for now. Bug: 6411069 Change-Id: Id342e933073d30eb58bf5a03a47ca26a64df8ddb Signed-off-by: isheriff@google.com Signed-off-by: Yoshihiko Ikenaga <yoshihiko.ikenaga@jp.sony.com>
Diffstat (limited to 'wifi/java/android')
-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
3 files changed, 474 insertions, 81 deletions
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>();
}
}
+
}