diff options
Diffstat (limited to 'wifi/java/android')
| -rw-r--r-- | wifi/java/android/net/wifi/p2p/WifiP2pDeviceList.java | 10 | ||||
| -rw-r--r-- | wifi/java/android/net/wifi/p2p/WifiP2pManager.java | 179 | ||||
| -rw-r--r-- | wifi/java/android/net/wifi/p2p/WifiP2pService.java | 366 |
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>(); } } + } |
