/* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.net.wifi.nan; import android.os.Binder; import android.os.IBinder; import android.os.RemoteException; import android.util.Log; /** * This class provides the primary API for managing Wi-Fi NAN operation: * including discovery and data-links. Get an instance of this class by calling * {@link android.content.Context#getSystemService(String) * Context.getSystemService(Context.WIFI_NAN_SERVICE)}. * <p> * The class provides access to: * <ul> * <li>Configure a NAN connection and register for events. * <li>Create publish and subscribe sessions. * <li>Create NAN network specifier to be used to create a NAN network. * </ul> * * @hide PROPOSED_NAN_API */ public class WifiNanManager { private static final String TAG = "WifiNanManager"; private static final boolean DBG = false; private static final boolean VDBG = false; // STOPSHIP if true private IBinder mBinder; private IWifiNanManager mService; /** * {@hide} */ public WifiNanManager(IWifiNanManager service) { mService = service; } /** * Re-connect to the Wi-Fi NAN service - enabling the application to execute * {@link WifiNanManager} APIs. Application don't normally need to call this * API since it is executed in the constructor. However, applications which * have explicitly {@link WifiNanManager#disconnect()} need to call this * function to re-connect. * * @param listener A listener extended from {@link WifiNanEventListener}. * @param events The set of events to be delivered to the {@code listener}. * OR'd event flags from {@link WifiNanEventListener * NanEventListener.LISTEN*}. */ public void connect(WifiNanEventListener listener, int events) { try { if (VDBG) Log.v(TAG, "connect()"); if (listener == null) { throw new IllegalArgumentException("Invalid listener - must not be null"); } if (mBinder == null) { mBinder = new Binder(); } mService.connect(mBinder, listener.callback, events); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Disconnect from the Wi-Fi NAN service and destroy all outstanding * operations - i.e. all publish and subscribes are terminated, any * outstanding data-link is shut-down, and all requested NAN configurations * are cancelled. * <p> * An application may then re-connect using * {@link WifiNanManager#connect(WifiNanEventListener, int)} . */ public void disconnect() { try { if (VDBG) Log.v(TAG, "disconnect()"); mService.disconnect(mBinder); mBinder = null; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Requests a NAN configuration, specified by {@link ConfigRequest}. Note * that NAN is a shared resource and the device can only be a member of a * single cluster. Thus the service may merge configuration requests from * multiple applications and configure NAN differently from individual * requests. * <p> * The {@link WifiNanEventListener#onConfigCompleted(ConfigRequest)} will be * called when configuration is completed (if a listener is registered for * this specific event). * * @param configRequest The requested NAN configuration. */ public void requestConfig(ConfigRequest configRequest) { if (VDBG) Log.v(TAG, "requestConfig(): configRequest=" + configRequest); try { mService.requestConfig(configRequest); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Request a NAN publish session. The results of the publish session * operation will result in callbacks to the indicated listener: * {@link WifiNanSessionListener NanSessionListener.on*}. * * @param publishData The {@link PublishData} specifying the contents of the * publish session. * @param publishSettings The {@link PublishSettings} specifying the * settings for the publish session. * @param listener The {@link WifiNanSessionListener} derived objects to be used * for the event callbacks specified by {@code events}. * @param events The list of events to be delivered to the {@code listener} * object. An OR'd value of {@link WifiNanSessionListener * NanSessionListener.LISTEN_*}. * @return The {@link WifiNanPublishSession} which can be used to further * control the publish session. */ public WifiNanPublishSession publish(PublishData publishData, PublishSettings publishSettings, WifiNanSessionListener listener, int events) { return publishRaw(publishData, publishSettings, listener, events | WifiNanSessionListener.LISTEN_HIDDEN_FLAGS); } /** * Same as publish(*) but does not modify the event flag * * @hide */ public WifiNanPublishSession publishRaw(PublishData publishData, PublishSettings publishSettings, WifiNanSessionListener listener, int events) { if (VDBG) Log.v(TAG, "publish(): data='" + publishData + "', settings=" + publishSettings); if (publishSettings.mPublishType == PublishSettings.PUBLISH_TYPE_UNSOLICITED && publishData.mRxFilterLength != 0) { throw new IllegalArgumentException("Invalid publish data & settings: UNSOLICITED " + "publishes (active) can't have an Rx filter"); } if (publishSettings.mPublishType == PublishSettings.PUBLISH_TYPE_SOLICITED && publishData.mTxFilterLength != 0) { throw new IllegalArgumentException("Invalid publish data & settings: SOLICITED " + "publishes (passive) can't have a Tx filter"); } if (listener == null) { throw new IllegalArgumentException("Invalid listener - must not be null"); } int sessionId; try { sessionId = mService.createSession(listener.callback, events); if (DBG) Log.d(TAG, "publish: session created - sessionId=" + sessionId); mService.publish(sessionId, publishData, publishSettings); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } return new WifiNanPublishSession(this, sessionId); } /** * {@hide} */ public void publish(int sessionId, PublishData publishData, PublishSettings publishSettings) { if (VDBG) Log.v(TAG, "publish(): data='" + publishData + "', settings=" + publishSettings); if (publishSettings.mPublishType == PublishSettings.PUBLISH_TYPE_UNSOLICITED && publishData.mRxFilterLength != 0) { throw new IllegalArgumentException("Invalid publish data & settings: UNSOLICITED " + "publishes (active) can't have an Rx filter"); } if (publishSettings.mPublishType == PublishSettings.PUBLISH_TYPE_SOLICITED && publishData.mTxFilterLength != 0) { throw new IllegalArgumentException("Invalid publish data & settings: SOLICITED " + "publishes (passive) can't have a Tx filter"); } try { mService.publish(sessionId, publishData, publishSettings); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Request a NAN subscribe session. The results of the subscribe session * operation will result in callbacks to the indicated listener: * {@link WifiNanSessionListener NanSessionListener.on*}. * * @param subscribeData The {@link SubscribeData} specifying the contents of * the subscribe session. * @param subscribeSettings The {@link SubscribeSettings} specifying the * settings for the subscribe session. * @param listener The {@link WifiNanSessionListener} derived objects to be used * for the event callbacks specified by {@code events}. * @param events The list of events to be delivered to the {@code listener} * object. An OR'd value of {@link WifiNanSessionListener * NanSessionListener.LISTEN_*}. * @return The {@link WifiNanSubscribeSession} which can be used to further * control the subscribe session. */ public WifiNanSubscribeSession subscribe(SubscribeData subscribeData, SubscribeSettings subscribeSettings, WifiNanSessionListener listener, int events) { return subscribeRaw(subscribeData, subscribeSettings, listener, events | WifiNanSessionListener.LISTEN_HIDDEN_FLAGS); } /** * Same as subscribe(*) but does not modify the event flag * * @hide */ public WifiNanSubscribeSession subscribeRaw(SubscribeData subscribeData, SubscribeSettings subscribeSettings, WifiNanSessionListener listener, int events) { if (VDBG) { Log.v(TAG, "subscribe(): data='" + subscribeData + "', settings=" + subscribeSettings); } if (subscribeSettings.mSubscribeType == SubscribeSettings.SUBSCRIBE_TYPE_ACTIVE && subscribeData.mRxFilterLength != 0) { throw new IllegalArgumentException( "Invalid subscribe data & settings: ACTIVE subscribes can't have an Rx filter"); } if (subscribeSettings.mSubscribeType == SubscribeSettings.SUBSCRIBE_TYPE_PASSIVE && subscribeData.mTxFilterLength != 0) { throw new IllegalArgumentException( "Invalid subscribe data & settings: PASSIVE subscribes can't have a Tx filter"); } int sessionId; try { sessionId = mService.createSession(listener.callback, events); if (DBG) Log.d(TAG, "subscribe: session created - sessionId=" + sessionId); mService.subscribe(sessionId, subscribeData, subscribeSettings); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } return new WifiNanSubscribeSession(this, sessionId); } /** * {@hide} */ public void subscribe(int sessionId, SubscribeData subscribeData, SubscribeSettings subscribeSettings) { if (VDBG) { Log.v(TAG, "subscribe(): data='" + subscribeData + "', settings=" + subscribeSettings); } if (subscribeSettings.mSubscribeType == SubscribeSettings.SUBSCRIBE_TYPE_ACTIVE && subscribeData.mRxFilterLength != 0) { throw new IllegalArgumentException( "Invalid subscribe data & settings: ACTIVE subscribes can't have an Rx filter"); } if (subscribeSettings.mSubscribeType == SubscribeSettings.SUBSCRIBE_TYPE_PASSIVE && subscribeData.mTxFilterLength != 0) { throw new IllegalArgumentException( "Invalid subscribe data & settings: PASSIVE subscribes can't have a Tx filter"); } try { mService.subscribe(sessionId, subscribeData, subscribeSettings); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * {@hide} */ public void stopSession(int sessionId) { if (DBG) Log.d(TAG, "Stop NAN session #" + sessionId); try { mService.stopSession(sessionId); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * {@hide} */ public void destroySession(int sessionId) { if (DBG) Log.d(TAG, "Destroy NAN session #" + sessionId); try { mService.destroySession(sessionId); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * {@hide} */ public void sendMessage(int sessionId, int peerId, byte[] message, int messageLength, int messageId) { try { if (VDBG) { Log.v(TAG, "sendMessage(): sessionId=" + sessionId + ", peerId=" + peerId + ", messageLength=" + messageLength + ", messageId=" + messageId); } mService.sendMessage(sessionId, peerId, message, messageLength, messageId); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } }