This class enables a device to learn the credential needed to join a network using a technique + * called "in-band commissioning". + * + * @hide + */ +//@SystemApi +public abstract class LowpanCommissioningSession { + public LowpanCommissioningSession() {} + + /** + * Callback base class for {@link LowpanCommissioningSession} + * + * @hide + */ + //@SystemApi + public class Callback { + public void onReceiveFromCommissioner(@NonNull byte[] packet) {}; + + public void onClosed() {}; + } + + /** TODO: doc */ + @NonNull + public abstract LowpanBeaconInfo getBeaconInfo(); + + /** TODO: doc */ + public abstract void sendToCommissioner(@NonNull byte[] packet); + + /** TODO: doc */ + public abstract void setCallback(@Nullable Callback cb, @Nullable Handler handler); + + /** TODO: doc */ + public abstract void close(); + + /** + * This method is largely for Nest Weave, as an alternative to {@link #sendToCommissioner()} + * and @{link Callback#onReceiveFromCommissioner()}. + * + *
When used with the Network instance obtained from getNetwork(), the caller can use the
+ * given InetSocketAddress to communicate with the commissioner using a UDP (or, under certain
+ * circumstances, TCP) socket.
+ */
+ public abstract @Nullable InetSocketAddress getInetSocketAddress();
+
+ public abstract @Nullable Network getNetwork();
+}
diff --git a/lowpan/java/android/net/lowpan/LowpanCredential.java b/lowpan/java/android/net/lowpan/LowpanCredential.java
new file mode 100644
index 0000000000000..dea4d78888845
--- /dev/null
+++ b/lowpan/java/android/net/lowpan/LowpanCredential.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2017 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.lowpan;
+
+
+import java.util.Map;
+
+/**
+ * Describes a credential for a LoWPAN network.
+ *
+ * @hide
+ */
+//@SystemApi
+public class LowpanCredential {
+
+ public static final int UNSPECIFIED_KEY_INDEX = 0;
+
+ private byte[] mMasterKey = null;
+ private int mMasterKeyIndex = UNSPECIFIED_KEY_INDEX;
+
+ LowpanCredential() {}
+
+ private LowpanCredential(byte[] masterKey, int keyIndex) {
+ setMasterKey(masterKey, keyIndex);
+ }
+
+ private LowpanCredential(byte[] masterKey) {
+ setMasterKey(masterKey);
+ }
+
+ public static LowpanCredential createMasterKey(byte[] masterKey) {
+ return new LowpanCredential(masterKey);
+ }
+
+ public static LowpanCredential createMasterKey(byte[] masterKey, int keyIndex) {
+ return new LowpanCredential(masterKey, keyIndex);
+ }
+
+ public void setMasterKey(byte[] masterKey) {
+ if (masterKey != null) {
+ masterKey = masterKey.clone();
+ }
+ mMasterKey = masterKey;
+ }
+
+ public void setMasterKeyIndex(int keyIndex) {
+ mMasterKeyIndex = keyIndex;
+ }
+
+ public void setMasterKey(byte[] masterKey, int keyIndex) {
+ setMasterKey(masterKey);
+ setMasterKeyIndex(keyIndex);
+ }
+
+ public byte[] getMasterKey() {
+ if (mMasterKey != null) {
+ return mMasterKey.clone();
+ }
+ return null;
+ }
+
+ public int getMasterKeyIndex() {
+ return mMasterKeyIndex;
+ }
+
+ public boolean isMasterKey() {
+ return mMasterKey != null;
+ }
+
+ void addToMap(Map End devices with this role are nominally asleep, waking up periodically to check in with
+ * their parent to see if there are packets destined for them. Such devices are capable of
+ * extraordinarilly low power consumption, but packet latency can be on the order of dozens of
+ * seconds(depending on how the node is configured).
+ */
+ public static final String ROLE_SLEEPY_END_DEVICE = "sleepy-end-device";
+
+ /**
+ * Sleepy-router role.
+ *
+ * Routers with this role are nominally asleep, waking up periodically to check in with other
+ * routers and their children.
+ */
+ public static final String ROLE_SLEEPY_ROUTER = "sleepy-router";
+
+ /** TODO: doc */
+ public static final String ROLE_LEADER = "leader";
+
+ /** TODO: doc */
+ public static final String ROLE_COORDINATOR = "coordinator";
+
+ /**
+ * Offline state.
+ *
+ * This is the initial state of the LoWPAN interface when the underlying driver starts. In
+ * this state the NCP is idle and not connected to any network.
+ *
+ * This state can be explicitly entered by calling {@link #reset()}, {@link #leave()}, or
+ * The interface enters this state after a call to {@link #startCommissioningSession()}. This
+ * state may only be entered directly from the {@link #STATE_OFFLINE} state.
+ *
+ * @see #startCommissioningSession()
+ * @see #getState()
+ * @hide
+ */
+ public static final String STATE_COMMISSIONING = "commissioning";
+
+ /**
+ * Attaching state.
+ *
+ * The interface enters this state when it starts the process of trying to find other nodes
+ * so that it can attach to any pre-existing network fragment, or when it is in the process of
+ * calculating the optimal values for unspecified parameters when forming a new network.
+ *
+ * The interface may stay in this state for a prolonged period of time (or may spontaneously
+ * enter this state from {@link #STATE_ATTACHED}) if the underlying network technology is
+ * heirarchical (like ZigBeeIP) or if the device role is that of an "end-device" ({@link
+ * #ROLE_END_DEVICE} or {@link #ROLE_SLEEPY_END_DEVICE}). This is because such roles cannot
+ * create their own network fragments.
+ *
+ * @see #STATE_ATTACHED
+ * @see #getState()
+ */
+ public static final String STATE_ATTACHING = "attaching";
+
+ /**
+ * Attached state.
+ *
+ * The interface enters this state from {@link #STATE_ATTACHING} once it is actively
+ * participating on a network fragment.
+ *
+ * @see #STATE_ATTACHING
+ * @see #getState()
+ */
+ public static final String STATE_ATTACHED = "attached";
+
+ /**
+ * Fault state.
+ *
+ * The interface will enter this state when the driver has detected some sort of problem from
+ * which it was not immediately able to recover.
+ *
+ * This state can be entered spontaneously from any other state. Calling {@link #reset} will
+ * cause the device to return to the {@link #STATE_OFFLINE} state.
+ *
+ * @see #getState
+ * @see #STATE_OFFLINE
+ */
+ public static final String STATE_FAULT = "fault";
+
+ /**
+ * Network type for Thread 1.x networks.
+ *
+ * @see android.net.lowpan.LowpanIdentity#getType
+ * @see #getLowpanIdentity
+ * @hide
+ */
+ public static final String NETWORK_TYPE_THREAD = "org.threadgroup.thread.v1";
+
+ /**
+ * Network type for ZigBeeIP 1.x networks.
+ *
+ * @see android.net.lowpan.LowpanIdentity#getType
+ * @see #getLowpanIdentity
+ * @hide
+ */
+ public static final String NETWORK_TYPE_ZIGBEE_IP = "org.zigbee.zigbeeip.v1";
+
+ private static final String NETWORK_PROPERTY_KEYS[] = {
+ LowpanProperties.KEY_NETWORK_NAME.getName(),
+ LowpanProperties.KEY_NETWORK_PANID.getName(),
+ LowpanProperties.KEY_NETWORK_XPANID.getName(),
+ LowpanProperties.KEY_CHANNEL.getName()
+ };
+
+ /**
+ * Callback base class for LowpanInterface
+ *
+ * @hide
+ */
+ //@SystemApi
+ public abstract static class Callback {
+ public void onConnectedChanged(boolean value) {}
+
+ public void onEnabledChanged(boolean value) {}
+
+ public void onUpChanged(boolean value) {}
+
+ public void onRoleChanged(@NonNull String value) {}
+
+ public void onStateChanged(@NonNull String state) {}
+
+ public void onLowpanIdentityChanged(@NonNull LowpanIdentity value) {}
+
+ /** @hide */
+ public void onPropertiesChanged(@NonNull Map properties) {}
+ }
+
+ private ILowpanInterface mBinder;
+ private final HashMap This method will block until either the network was successfully formed or an error
+ * prevents the network form being formed.
+ *
+ * Upon success, the interface will be up and attached to the newly formed network.
+ *
+ * @see #join(LowpanProvision)
+ */
+ public void form(@NonNull LowpanProvision provision) throws LowpanException {
+ try {
+ Map Note that “joining” is distinct from “attaching”: Joining requires at least one other peer
+ * device to be present in order for the operation to complete successfully.
+ */
+ public void join(@NonNull LowpanProvision provision) throws LowpanException {
+ try {
+ Map This method will block execution until the operation has completed.
+ */
+ public void attach(@NonNull LowpanProvision provision) throws LowpanException {
+ if (ROLE_DETACHED.equals(getRole())) {
+ Map This method will block execution until the operation has completed.
+ */
+ public void leave() throws LowpanException {
+ try {
+ mBinder.leave();
+ } catch (RemoteException x) {
+ throwAsPublicException(x);
+ } catch (ServiceSpecificException x) {
+ throwAsPublicException(x);
+ }
+ }
+
+ /**
+ * Start a new commissioning session. Will fail if the interface is attached to a network or if
+ * the interface is disabled.
+ */
+ public @NonNull LowpanCommissioningSession startCommissioningSession(
+ @NonNull LowpanBeaconInfo beaconInfo) throws LowpanException {
+
+ /* TODO: Implement startCommissioningSession */
+ throw new LowpanException(LowpanException.LOWPAN_FEATURE_NOT_SUPPORTED);
+ }
+
+ /**
+ * Reset this network interface as if it has been power cycled. Will bring the network interface
+ * down if it was previously up. Will not erase any non-volatile settings.
+ *
+ * This method will block execution until the operation has completed.
+ *
+ * @hide
+ */
+ public void reset() throws LowpanException {
+ try {
+ mBinder.reset();
+ } catch (RemoteException x) {
+ throwAsPublicException(x);
+ } catch (ServiceSpecificException x) {
+ throwAsPublicException(x);
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Public Getters and Setters
+
+ /**
+ * Returns the name of this network interface.
+ *
+ * Will return empty string if this interface is no longer viable.
+ */
+ @NonNull
+ public String getName() {
+ try {
+ return mBinder.getName();
+ } catch (RemoteException x) {
+ // Catch and ignore all binder exceptions
+ // when fetching the name.
+ Log.e(TAG, x.toString());
+ } catch (ServiceSpecificException x) {
+ // Catch and ignore all service-specific exceptions
+ // when fetching the name.
+ Log.e(TAG, x.toString());
+ }
+ return "";
+ }
+
+ /**
+ * Indicates if the interface is enabled or disabled.
+ *
+ * @see #setEnabled
+ * @see android.net.lowpan.LowpanException#LOWPAN_DISABLED
+ */
+ public boolean isEnabled() {
+ try {
+ return getPropertyAsBoolean(LowpanProperties.KEY_INTERFACE_ENABLED);
+ } catch (LowpanException x) {
+ return false;
+ }
+ }
+
+ /**
+ * Enables or disables the LoWPAN interface. When disabled, the interface is put into a low-power
+ * state and all commands that require the NCP to be queried will fail with {@link
+ * android.net.lowpan.LowpanException#LOWPAN_DISABLED}.
+ *
+ * @see #isEnabled
+ * @see android.net.lowpan.LowpanException#LOWPAN_DISABLED
+ * @hide
+ */
+ public void setEnabled(boolean enabled) throws LowpanException {
+ setProperty(LowpanProperties.KEY_INTERFACE_ENABLED, enabled);
+ }
+
+ /**
+ * Indicates if the network interface is up or down.
+ *
+ * @hide
+ */
+ public boolean isUp() {
+ try {
+ return getPropertyAsBoolean(LowpanProperties.KEY_INTERFACE_UP);
+ } catch (LowpanException x) {
+ return false;
+ }
+ }
+
+ /**
+ * Bring up or shut down the network interface.
+ *
+ * This method brings up or shuts down the network interface, attaching or (gracefully)
+ * detaching from the currently configured LoWPAN network as appropriate.
+ *
+ * @hide
+ */
+ public void setUp(boolean interfaceUp) throws LowpanException {
+ setProperty(LowpanProperties.KEY_INTERFACE_UP, interfaceUp);
+ }
+
+ /**
+ * Indicates if there is at least one peer in range.
+ *
+ * @return The thread upon which events will be dispatched is unspecified.
+ *
+ * @param cb Subclass of {@link LowpanInterface.Callback} which will receive events.
+ * @see #registerCallback(Callback, Handler)
+ * @see #unregisterCallback(Callback)
+ */
+ public void registerCallback(Callback cb) {
+ registerCallback(cb, null);
+ }
+
+ /**
+ * Unregisters a previously registered callback class.
+ *
+ * @param cb Subclass of {@link LowpanInterface.Callback} which was previously registered to
+ * receive events.
+ * @see #registerCallback(Callback, Handler)
+ * @see #registerCallback(Callback)
+ */
+ public void unregisterCallback(Callback cb) {
+ int hashCode = System.identityHashCode(cb);
+ ILowpanInterfaceListener listenerBinder = mListenerMap.get(hashCode);
+
+ if (listenerBinder != null) {
+ synchronized (mListenerMap) {
+ mListenerMap.remove(hashCode);
+ }
+ try {
+ mBinder.removeListener(listenerBinder);
+ } catch (RemoteException x) {
+ // Catch and ignore all binder exceptions
+ Log.e(TAG, x.toString());
+ }
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Active and Passive Scanning
+
+ /**
+ * Creates a new {@link android.net.lowpan.LowpanScanner} object for this interface.
+ *
+ * This method allocates a new unique object for each call.
+ *
+ * @see android.net.lowpan.LowpanScanner
+ */
+ public @NonNull LowpanScanner createScanner() {
+ return new LowpanScanner(mBinder);
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Route Management
+
+ /**
+ * Advertise the given IP prefix as an on-mesh prefix.
+ *
+ * @hide
+ */
+ public void addOnMeshPrefix(IpPrefix prefix, int flags) throws LowpanException {
+ try {
+ mBinder.addOnMeshPrefix(prefix, flags);
+ } catch (RemoteException x) {
+ throwAsPublicException(x);
+ } catch (ServiceSpecificException x) {
+ throwAsPublicException(x);
+ }
+ }
+
+ /**
+ * Remove an IP prefix previously advertised by this device from the list of advertised on-mesh
+ * prefixes.
+ *
+ * @hide
+ */
+ public void removeOnMeshPrefix(IpPrefix prefix) {
+ try {
+ mBinder.removeOnMeshPrefix(prefix);
+ } catch (RemoteException x) {
+ // Catch and ignore all binder exceptions
+ Log.e(TAG, x.toString());
+ } catch (ServiceSpecificException x) {
+ // Catch and ignore all service exceptions
+ Log.e(TAG, x.toString());
+ }
+ }
+
+ /**
+ * Advertise this device to other devices on the mesh network as having a specific route to the
+ * given network. This device will then receive forwarded traffic for that network.
+ *
+ * @hide
+ */
+ public void addExternalRoute(IpPrefix prefix, int flags) throws LowpanException {
+ try {
+ mBinder.addExternalRoute(prefix, flags);
+ } catch (RemoteException x) {
+ throwAsPublicException(x);
+ } catch (ServiceSpecificException x) {
+ throwAsPublicException(x);
+ }
+ }
+
+ /**
+ * Revoke a previously advertised specific route to the given network.
+ *
+ * @hide
+ */
+ public void removeExternalRoute(IpPrefix prefix) {
+ try {
+ mBinder.removeExternalRoute(prefix);
+ } catch (RemoteException x) {
+ // Catch and ignore all binder exceptions
+ Log.e(TAG, x.toString());
+ } catch (ServiceSpecificException x) {
+ // Catch and ignore all service exceptions
+ Log.e(TAG, x.toString());
+ }
+ }
+}
diff --git a/lowpan/java/android/net/lowpan/LowpanManager.java b/lowpan/java/android/net/lowpan/LowpanManager.java
new file mode 100644
index 0000000000000..b58608da7c215
--- /dev/null
+++ b/lowpan/java/android/net/lowpan/LowpanManager.java
@@ -0,0 +1,283 @@
+/*
+ * Copyright (C) 2017 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.lowpan;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.os.DeadObjectException;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.AndroidException;
+import android.util.Log;
+import java.util.HashMap;
+
+/**
+ * Manager object for looking up LoWPAN interfaces.
+ *
+ * @hide
+ */
+//@SystemApi
+public class LowpanManager {
+ private static final String TAG = LowpanManager.class.getSimpleName();
+
+ //////////////////////////////////////////////////////////////////////////
+ // Public Classes
+
+ /** @hide */
+ //@SystemApi
+ public abstract static class Callback {
+ public void onInterfaceAdded(LowpanInterface lowpan_interface) {}
+
+ public void onInterfaceRemoved(LowpanInterface lowpan_interface) {}
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Instance Variables
+
+ private ILowpanManager mManager;
+ private HashMap This class allows performing network (active) scans and energy (passive) scans.
+ *
+ * @see LowpanInterface
+ * @hide
+ */
+//@SystemApi
+public class LowpanScanner {
+ private static final String TAG = LowpanInterface.class.getSimpleName();
+
+ //////////////////////////////////////////////////////////////////////////
+ // Public Classes
+
+ /**
+ * Callback base class for LowpanScanner
+ *
+ * @hide
+ */
+ //@SystemApi
+ public abstract static class Callback {
+ public void onNetScanBeacon(LowpanBeaconInfo beacon) {}
+
+ public void onEnergyScanResult(LowpanEnergyScanResult result) {}
+
+ public void onScanFinished() {}
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Instance Variables
+
+ private ILowpanInterface mBinder;
+ private Callback mCallback = null;
+ private Handler mHandler = null;
+ private List If a channel mask was previously The actual transmit power used is the lesser of this value and the currently configured
+ * maximum transmit power for the interface.
+ *
+ * @see #getTxPower
+ */
+ public void setTxPower(int txPower) {
+ mTxPower = txPower;
+ }
+
+ /**
+ * Gets the maximum transmit power used for active scanning.
+ *
+ * @see #setTxPower
+ */
+ public int getTxPower() {
+ return mTxPower;
+ }
+
+ private Map This method will return once the scan has started.
+ *
+ * @see #stopNetScan
+ */
+ public void startNetScan() throws LowpanException {
+ Map This method will return once the scan has started.
+ *
+ * @see #stopEnergyScan
+ */
+ public void startEnergyScan() throws LowpanException {
+ Map @SystemApi Provides classes to manage Low-power Wireless Personal Area Network (LoWPAN) functionality on the device.
+Examples of such network technologies include Thread and
+ZigBee IP. The LoWPAN APIs provide a means by which applications can communicate
+with the lower-level wireless stack that provides LoWPAN network access. Some APIs may require the following user permissions: Note: Not all Android-powered devices provide LoWPAN functionality.
+If your application uses these APIs, declare so with a {@code LowpanException is thrown if an action to a LoWPAN interface could not be performed
+ * or a LoWPAN interface property could not be fetched or changed.
+ *
+ * @see LowpanInterface
+ * @hide
+ */
+//@SystemApi
+public class LowpanException extends AndroidException {
+ // Make the eclipse warning about serializable exceptions go away
+ private static final long serialVersionUID = 0x31863cbe562b0e11l; // randomly generated
+
+ public static final int LOWPAN_ERROR = 1;
+ public static final int LOWPAN_CREDENTIAL_NEEDED = 2;
+ public static final int LOWPAN_DEAD = 3;
+ public static final int LOWPAN_DISABLED = 4;
+ public static final int LOWPAN_WRONG_STATE = 5;
+ public static final int LOWPAN_BUSY = 7;
+ public static final int LOWPAN_NCP_PROBLEM = 8;
+ public static final int LOWPAN_ALREADY = 9;
+ public static final int LOWPAN_CANCELED = 10;
+ public static final int LOWPAN_FEATURE_NOT_SUPPORTED = 12;
+ public static final int LOWPAN_PROPERTY_NOT_FOUND = 13;
+ public static final int LOWPAN_JOIN_FAILED_UNKNOWN = 14;
+ public static final int LOWPAN_JOIN_FAILED_AT_SCAN = 15;
+ public static final int LOWPAN_JOIN_FAILED_AT_AUTH = 16;
+ public static final int LOWPAN_FORM_FAILED_AT_SCAN = 17;
+
+ /**
+ * Convert ServiceSpecificExceptions and Binder RemoteExceptions from LoWPAN binder interfaces
+ * into the correct public exceptions.
+ *
+ * @hide
+ */
+ public static void throwAsPublicException(Throwable t) throws LowpanException {
+ if (t instanceof ServiceSpecificException) {
+ ServiceSpecificException e = (ServiceSpecificException) t;
+ int reason;
+ switch (e.errorCode) {
+ case ILowpanInterface.ERROR_INVALID_ARGUMENT:
+ case ILowpanInterface.ERROR_INVALID_TYPE:
+ case ILowpanInterface.ERROR_INVALID_VALUE:
+ throw new IllegalArgumentException(e.getMessage(), e);
+
+ case ILowpanInterface.ERROR_PERMISSION_DENIED:
+ throw new SecurityException(e.getMessage(), e);
+
+ case ILowpanInterface.ERROR_DISABLED:
+ reason = LowpanException.LOWPAN_DISABLED;
+ break;
+
+ case ILowpanInterface.ERROR_WRONG_STATE:
+ reason = LowpanException.LOWPAN_WRONG_STATE;
+ break;
+
+ case ILowpanInterface.ERROR_BUSY:
+ reason = LowpanException.LOWPAN_BUSY;
+ break;
+
+ case ILowpanInterface.ERROR_ALREADY:
+ reason = LowpanException.LOWPAN_ALREADY;
+ break;
+
+ case ILowpanInterface.ERROR_CANCELED:
+ reason = LowpanException.LOWPAN_CANCELED;
+ break;
+
+ case ILowpanInterface.ERROR_CREDENTIAL_NEEDED:
+ reason = LowpanException.LOWPAN_CREDENTIAL_NEEDED;
+ break;
+
+ case ILowpanInterface.ERROR_FEATURE_NOT_SUPPORTED:
+ reason = LowpanException.LOWPAN_FEATURE_NOT_SUPPORTED;
+ break;
+
+ case ILowpanInterface.ERROR_PROPERTY_NOT_FOUND:
+ reason = LowpanException.LOWPAN_PROPERTY_NOT_FOUND;
+ break;
+
+ case ILowpanInterface.ERROR_JOIN_FAILED_UNKNOWN:
+ reason = LowpanException.LOWPAN_JOIN_FAILED_UNKNOWN;
+ break;
+
+ case ILowpanInterface.ERROR_JOIN_FAILED_AT_SCAN:
+ reason = LowpanException.LOWPAN_JOIN_FAILED_AT_SCAN;
+ break;
+
+ case ILowpanInterface.ERROR_JOIN_FAILED_AT_AUTH:
+ reason = LowpanException.LOWPAN_JOIN_FAILED_AT_AUTH;
+ break;
+
+ case ILowpanInterface.ERROR_FORM_FAILED_AT_SCAN:
+ reason = LowpanException.LOWPAN_FORM_FAILED_AT_SCAN;
+ break;
+
+ case ILowpanInterface.ERROR_TIMEOUT:
+ case ILowpanInterface.ERROR_NCP_PROBLEM:
+ reason = LowpanException.LOWPAN_NCP_PROBLEM;
+ break;
+ case ILowpanInterface.ERROR_UNSPECIFIED:
+ default:
+ reason = LOWPAN_ERROR;
+ break;
+ }
+ throw new LowpanException(reason, e.getMessage(), e);
+ } else if (t instanceof DeadObjectException) {
+ throw new LowpanException(LOWPAN_DEAD, t);
+ } else if (t instanceof RemoteException) {
+ throw new UnsupportedOperationException(
+ "An unknown RemoteException was thrown" + " which should never happen.", t);
+ } else if (t instanceof RuntimeException) {
+ RuntimeException e = (RuntimeException) t;
+ throw e;
+ }
+ }
+
+ private final int mReason;
+
+ public final int getReason() {
+ return mReason;
+ }
+
+ public LowpanException(int problem) {
+ super(getDefaultMessage(problem));
+ mReason = problem;
+ }
+
+ public LowpanException(String message) {
+ super(getCombinedMessage(LOWPAN_ERROR, message));
+ mReason = LOWPAN_ERROR;
+ }
+
+ public LowpanException(int problem, String message, Throwable cause) {
+ super(getCombinedMessage(problem, message), cause);
+ mReason = problem;
+ }
+
+ public LowpanException(int problem, Throwable cause) {
+ super(getDefaultMessage(problem), cause);
+ mReason = problem;
+ }
+
+ /** @hide */
+ public static String getDefaultMessage(int problem) {
+ String problemString;
+
+ // TODO: Does this need localization?
+
+ switch (problem) {
+ case LOWPAN_DEAD:
+ problemString = "LoWPAN interface is no longer alive";
+ break;
+ case LOWPAN_DISABLED:
+ problemString = "LoWPAN interface is disabled";
+ break;
+ case LOWPAN_WRONG_STATE:
+ problemString = "LoWPAN interface in wrong state to perfom requested action";
+ break;
+ case LOWPAN_BUSY:
+ problemString =
+ "LoWPAN interface was unable to perform the requestion action because it was busy";
+ break;
+ case LOWPAN_NCP_PROBLEM:
+ problemString =
+ "The Network Co-Processor associated with this interface has experienced a problem";
+ break;
+ case LOWPAN_ALREADY:
+ problemString = "The LoWPAN interface is already in the given state";
+ break;
+ case LOWPAN_CANCELED:
+ problemString = "This operation was canceled";
+ break;
+ case LOWPAN_CREDENTIAL_NEEDED:
+ problemString = "Additional credentials are required to complete this operation";
+ break;
+ case LOWPAN_FEATURE_NOT_SUPPORTED:
+ problemString =
+ "A dependent feature required to perform the given action is not currently supported";
+ break;
+ case LOWPAN_PROPERTY_NOT_FOUND:
+ problemString = "The given property was not found";
+ break;
+ case LOWPAN_JOIN_FAILED_UNKNOWN:
+ problemString = "The join operation failed for an unspecified reason";
+ break;
+ case LOWPAN_JOIN_FAILED_AT_SCAN:
+ problemString =
+ "The join operation failed because it could not communicate with any peers";
+ break;
+ case LOWPAN_JOIN_FAILED_AT_AUTH:
+ problemString =
+ "The join operation failed because the credentials were not accepted by any peers";
+ break;
+ case LOWPAN_FORM_FAILED_AT_SCAN:
+ problemString = "Network form failed";
+ break;
+ case LOWPAN_ERROR:
+ default:
+ problemString = "The requested LoWPAN operation failed";
+ break;
+ }
+
+ return problemString;
+ }
+
+ private static String getCombinedMessage(int problem, String message) {
+ String problemString = getProblemString(problem);
+ return String.format("%s (%d): %s", problemString, problem, message);
+ }
+
+ private static String getProblemString(int problem) {
+ String problemString;
+
+ switch (problem) {
+ case LOWPAN_ERROR:
+ problemString = "LOWPAN_ERROR";
+ break;
+ case LOWPAN_DEAD:
+ problemString = "LOWPAN_DEAD";
+ break;
+ case LOWPAN_DISABLED:
+ problemString = "LOWPAN_DISABLED";
+ break;
+ case LOWPAN_WRONG_STATE:
+ problemString = "LOWPAN_WRONG_STATE";
+ break;
+ case LOWPAN_BUSY:
+ problemString = "LOWPAN_BUSY";
+ break;
+ case LOWPAN_NCP_PROBLEM:
+ problemString = "LOWPAN_NCP_PROBLEM";
+ break;
+ case LOWPAN_ALREADY:
+ problemString = "LOWPAN_ALREADY";
+ break;
+ case LOWPAN_CANCELED:
+ problemString = "LOWPAN_CANCELED";
+ break;
+ case LOWPAN_CREDENTIAL_NEEDED:
+ problemString = "LOWPAN_CREDENTIAL_NEEDED";
+ break;
+ case LOWPAN_FEATURE_NOT_SUPPORTED:
+ problemString = "LOWPAN_FEATURE_NOT_SUPPORTED";
+ break;
+ case LOWPAN_PROPERTY_NOT_FOUND:
+ problemString = "LOWPAN_PROPERTY_NOT_FOUND";
+ break;
+ case LOWPAN_JOIN_FAILED_UNKNOWN:
+ problemString = "LOWPAN_JOIN_FAILED_UNKNOWN";
+ break;
+ case LOWPAN_JOIN_FAILED_AT_SCAN:
+ problemString = "LOWPAN_JOIN_FAILED_AT_SCAN";
+ break;
+ case LOWPAN_JOIN_FAILED_AT_AUTH:
+ problemString = "LOWPAN_JOIN_FAILED_AT_AUTH";
+ break;
+ case LOWPAN_FORM_FAILED_AT_SCAN:
+ problemString = "LOWPAN_FORM_FAILED_AT_SCAN";
+ break;
+ default:
+ problemString = "LOWPAN_ERROR_CODE_" + problem;
+ break;
+ }
+
+ return problemString;
+ }
+}
diff --git a/lowpan/java/android/net/lowpan/LowpanIdentity.java b/lowpan/java/android/net/lowpan/LowpanIdentity.java
new file mode 100644
index 0000000000000..2e7b560fda5e1
--- /dev/null
+++ b/lowpan/java/android/net/lowpan/LowpanIdentity.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2017 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.lowpan;
+
+import com.android.internal.util.HexDump;
+import java.util.Map;
+
+/**
+ * Describes an instance of a LoWPAN network.
+ *
+ * @hide
+ */
+//@SystemApi
+public class LowpanIdentity {
+
+ //////////////////////////////////////////////////////////////////////////
+ // Constants
+
+ /** @hide */
+ public static final int TYPE_ZIGBEE = 1;
+
+ /** @hide */
+ public static final int TYPE_ZIGBEE_IP = 2;
+
+ /** @hide */
+ public static final int TYPE_THREAD = 3;
+
+ public static final int UNKNOWN = Integer.MAX_VALUE;
+
+ //////////////////////////////////////////////////////////////////////////
+ // Builder
+
+ /** @hide */
+ //@SystemApi
+ public static class Builder {
+ private final LowpanIdentity identity = new LowpanIdentity();
+
+ public Builder setName(String x) {
+ identity.mName = x;
+ return this;
+ }
+
+ public Builder setXpanid(byte x[]) {
+ identity.mXpanid = x.clone();
+ return this;
+ }
+
+ public Builder setPanid(int x) {
+ identity.mPanid = x;
+ return this;
+ }
+
+ /** @hide */
+ public Builder setType(int x) {
+ identity.mType = x;
+ return this;
+ }
+
+ public Builder setChannel(int x) {
+ identity.mChannel = x;
+ return this;
+ }
+
+ /** @hide */
+ Builder updateFromMap(Map map) {
+ if (map.containsKey(ILowpanInterface.KEY_NETWORK_NAME)) {
+ setName(LowpanProperties.KEY_NETWORK_NAME.getFromMap(map));
+ }
+ if (map.containsKey(ILowpanInterface.KEY_NETWORK_PANID)) {
+ setPanid(LowpanProperties.KEY_NETWORK_PANID.getFromMap(map));
+ }
+ if (map.containsKey(ILowpanInterface.KEY_NETWORK_XPANID)) {
+ setXpanid(LowpanProperties.KEY_NETWORK_XPANID.getFromMap(map));
+ }
+ if (map.containsKey(ILowpanInterface.KEY_CHANNEL)) {
+ setChannel(LowpanProperties.KEY_CHANNEL.getFromMap(map));
+ }
+ if (map.containsKey(ILowpanInterface.KEY_NETWORK_TYPE)) {
+ setType(LowpanProperties.KEY_NETWORK_TYPE.getFromMap(map));
+ }
+ return this;
+ }
+
+ public LowpanIdentity build() {
+ return identity;
+ }
+ }
+
+ LowpanIdentity() {}
+
+ //////////////////////////////////////////////////////////////////////////
+ // Instance Variables
+
+ private String mName = null;
+ private byte[] mXpanid = null;
+ private int mType = UNKNOWN;
+ private int mPanid = UNKNOWN;
+ private int mChannel = UNKNOWN;
+
+ //////////////////////////////////////////////////////////////////////////
+ // Public Getters and Setters
+
+ public String getName() {
+ return mName;
+ }
+
+ public byte[] getXpanid() {
+ return mXpanid.clone();
+ }
+
+ public int getPanid() {
+ return mPanid;
+ }
+
+ /** @hide */
+ public int getType() {
+ return mType;
+ }
+
+ public int getChannel() {
+ return mChannel;
+ }
+
+ static void addToMap(MapsetUp(false), with the later two only working if we were not previously in the
+ * {@link #STATE_FAULT} state.
+ *
+ * @see #getState()
+ * @see #STATE_FAULT
+ */
+ public static final String STATE_OFFLINE = "offline";
+
+ /**
+ * Commissioning state.
+ *
+ * true if we have at least one other peer in range, false
+ * otherwise.
+ */
+ public boolean isConnected() {
+ try {
+ return getPropertyAsBoolean(LowpanProperties.KEY_INTERFACE_CONNECTED);
+ } catch (LowpanException x) {
+ return false;
+ }
+ }
+
+ /**
+ * Indicates if this interface is currently commissioned onto an existing network. If the
+ * interface is commissioned, the interface may be brought up using setUp().
+ */
+ public boolean isCommissioned() {
+ try {
+ return getPropertyAsBoolean(LowpanProperties.KEY_INTERFACE_COMMISSIONED);
+ } catch (LowpanException x) {
+ return false;
+ }
+ }
+
+ /**
+ * Get interface state
+ *
+ * State Diagram
+ *
+ *
+ *
+ * @return The current state of the interface.
+ * @see #STATE_OFFLINE
+ * @see #STATE_COMMISSIONING
+ * @see #STATE_ATTACHING
+ * @see #STATE_ATTACHED
+ * @see #STATE_FAULT
+ */
+ public String getState() {
+ try {
+ return getProperty(LowpanProperties.KEY_INTERFACE_STATE);
+ } catch (LowpanException x) {
+ Log.e(TAG, x.toString());
+ return STATE_FAULT;
+ }
+ }
+
+ /** TODO: doc */
+ public LowpanIdentity getLowpanIdentity() {
+ LowpanIdentity.Builder builder = new LowpanIdentity.Builder();
+ try {
+ builder.updateFromMap(getProperties(NETWORK_PROPERTY_KEYS));
+ } catch (LowpanException x) {
+ // We ignore all LoWPAN-specitic exceptions here.
+ }
+
+ return builder.build();
+ }
+
+ /**
+ * TODO: doc
+ *
+ * @hide
+ */
+ public void setLowpanIdentity(LowpanIdentity network) throws LowpanException {
+ Mapnull, events will be dispatched via the given handler
+ * object. If null, the thread upon which events will be dispatched is
+ * unspecified.
+ * @see #registerCallback(Callback)
+ * @see #unregisterCallback(Callback)
+ */
+ public void registerCallback(@NonNull Callback cb, @Nullable Handler handler) {
+ ILowpanInterfaceListener.Stub listenerBinder =
+ new ILowpanInterfaceListener.Stub() {
+ public void onPropertiesChanged(Map> KEY_LINK_ADDRESS_ARRAY =
+ new LowpanStandardProperty(
+ "android.net.lowpan.property.LINK_ADDRESS_ARRAY", LinkAddress[].class);
+
+ public static final LowpanProperty
> KEY_ROUTE_INFO_ARRAY =
+ new LowpanStandardProperty(
+ "android.net.lowpan.property.ROUTE_INFO_ARRAY", RouteInfo[].class);
+
+ /** @hide */
+ public static final LowpanProperty
null, any previously set
+ * channel mask will be cleared and all channels not masked by the current regulatory zone
+ * will be scanned.
+ */
+ public void setChannelMask(@Nullable Collectionnull if no channel mask is currently set.
+ */
+ public @Nullable Collectionnull, a new one is created containing only
+ * this channel. May be called multiple times to add additional channels ot the channel mask.
+ *
+ * @see #setChannelMask
+ * @see #getChannelMask
+ * @see #getTxPower
+ */
+ public void addChannel(int channel) {
+ if (mChannelMask == null) {
+ mChannelMask = new ArrayList<>();
+ }
+ mChannelMask.add(Integer.valueOf(channel));
+ }
+
+ /**
+ * Sets the maximum transmit power to be used for active scanning.
+ *
+ *
+
+
+
+<manifest ...>
+ <uses-feature android:name="android.hardware.lowpan" />
+ ...
+</manifest>
+
+
+