Initial support for proposed android.net.lowpan

Change-Id: I0bf8edb5199d50d2a549a353b2785aef8134ff92
This commit is contained in:
Robert Quattlebaum
2017-02-08 12:13:19 -08:00
parent 4bfb604d04
commit 4e0c2195dd
23 changed files with 2985 additions and 0 deletions

View File

@@ -558,6 +558,15 @@ LOCAL_SRC_FILES += \
LOCAL_AIDL_INCLUDES += system/update_engine/binder_bindings
LOCAL_AIDL_INCLUDES += frameworks/base/lowpan/java
LOCAL_SRC_FILES += \
lowpan/java/android/net/lowpan/ILowpanEnergyScanCallback.aidl \
lowpan/java/android/net/lowpan/ILowpanNetScanCallback.aidl \
lowpan/java/android/net/lowpan/ILowpanInterfaceListener.aidl \
lowpan/java/android/net/lowpan/ILowpanInterface.aidl \
lowpan/java/android/net/lowpan/ILowpanManagerListener.aidl \
lowpan/java/android/net/lowpan/ILowpanManager.aidl
# FRAMEWORKS_BASE_JAVA_SRC_DIRS comes from build/core/pathmap.mk
LOCAL_AIDL_INCLUDES += \
$(FRAMEWORKS_BASE_JAVA_SRC_DIRS) \

View File

@@ -1322,6 +1322,27 @@
<permission android:name="android.permission.NETWORK_SETTINGS"
android:protectionLevel="signature" />
<!-- #SystemApi @hide Allows applications to access information about LoWPAN interfaces.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.ACCESS_LOWPAN_STATE"
android:protectionLevel="signature|privileged" />
<!-- #SystemApi @hide Allows applications to change LoWPAN connectivity state.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.CHANGE_LOWPAN_STATE"
android:protectionLevel="signature|privileged" />
<!-- #SystemApi @hide Allows applications to read LoWPAN credential.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.READ_LOWPAN_CREDENTIAL"
android:protectionLevel="signature|privileged" />
<!-- #SystemApi @hide Allows a service to register or unregister
new LoWPAN interfaces.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.MANAGE_LOWPAN_INTERFACES"
android:protectionLevel="signature|privileged" />
<!-- ======================================= -->
<!-- Permissions for short range, peripheral networks -->
<!-- ======================================= -->

31
lowpan/Android.mk Normal file
View File

@@ -0,0 +1,31 @@
#
# 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.
#
LOCAL_PATH := $(call my-dir)
ifneq (,$(findstring lowpan/java,$(FRAMEWORKS_BASE_SUBDIRS)))
include $(CLEAR_VARS)
LOCAL_MODULE := libandroid_net_lowpan
LOCAL_MODULE_TAGS := optional
LOCAL_SHARED_LIBRARIES += libbase
LOCAL_SHARED_LIBRARIES += libbinder
LOCAL_SHARED_LIBRARIES += libutils
LOCAL_AIDL_INCLUDES += frameworks/native/aidl/binder
LOCAL_AIDL_INCLUDES += frameworks/base/lowpan/java
LOCAL_AIDL_INCLUDES += frameworks/base/core/java
LOCAL_SRC_FILES += $(call all-Iaidl-files-under, java/android/net/lowpan)
include $(BUILD_SHARED_LIBRARY)
endif

View File

@@ -0,0 +1,23 @@
/*
* 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;
/** {@hide} */
interface ILowpanEnergyScanCallback {
oneway void onEnergyScanResult(int channel, int rssi);
oneway void onEnergyScanFinished();
}

View File

@@ -0,0 +1,154 @@
/*
* 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.net.lowpan.ILowpanInterfaceListener;
import android.net.lowpan.ILowpanNetScanCallback;
import android.net.lowpan.ILowpanEnergyScanCallback;
import android.os.PersistableBundle;
import android.net.IpPrefix;
/** {@hide} */
interface ILowpanInterface {
//////////////////////////////////////////////////////////////////////////
// Permission String Constants
/* These are here for the sake of C++ interface implementations. */
const String PERM_ACCESS_LOWPAN_STATE = "android.permission.ACCESS_LOWPAN_STATE";
const String PERM_CHANGE_LOWPAN_STATE = "android.permission.CHANGE_LOWPAN_STATE";
const String PERM_READ_LOWPAN_CREDENTIAL = "android.permission.READ_LOWPAN_CREDENTIAL";
//////////////////////////////////////////////////////////////////////////
// Property Key Constants
const String KEY_INTERFACE_ENABLED = "android.net.lowpan.property.INTERFACE_ENABLED";
const String KEY_INTERFACE_UP = "android.net.lowpan.property.INTERFACE_UP";
const String KEY_INTERFACE_COMMISSIONED = "android.net.lowpan.property.INTERFACE_COMMISSIONED";
const String KEY_INTERFACE_CONNECTED = "android.net.lowpan.property.INTERFACE_CONNECTED";
const String KEY_INTERFACE_STATE = "android.net.lowpan.property.INTERFACE_STATE";
const String KEY_NETWORK_NAME = "android.net.lowpan.property.NETWORK_NAME";
const String KEY_NETWORK_TYPE = "android.net.lowpan.property.NETWORK_TYPE";
const String KEY_NETWORK_PANID = "android.net.lowpan.property.NETWORK_PANID";
const String KEY_NETWORK_XPANID = "android.net.lowpan.property.NETWORK_XPANID";
const String KEY_NETWORK_ROLE = "android.net.lowpan.property.NETWORK_ROLE";
const String KEY_NETWORK_MASTER_KEY = "android.net.lowpan.property.NETWORK_MASTER_KEY";
const String KEY_NETWORK_MASTER_KEY_INDEX
= "android.net.lowpan.property.NETWORK_MASTER_KEY_INDEX";
const String KEY_SUPPORTED_CHANNELS = "android.net.lowpan.property.SUPPORTED_CHANNELS";
const String KEY_CHANNEL = "android.net.lowpan.property.CHANNEL";
const String KEY_CHANNEL_MASK = "android.net.lowpan.property.CHANNEL_MASK";
const String KEY_MAX_TX_POWER = "android.net.lowpan.property.MAX_TX_POWER";
const String KEY_RSSI = "android.net.lowpan.property.RSSI";
const String KEY_LQI = "android.net.lowpan.property.LQI";
const String KEY_LINK_ADDRESS_ARRAY = "android.net.lowpan.property.LINK_ADDRESS_ARRAY";
const String KEY_ROUTE_INFO_ARRAY = "android.net.lowpan.property.ROUTE_INFO_ARRAY";
const String KEY_BEACON_ADDRESS = "android.net.lowpan.property.BEACON_ORIGIN_ADDRESS";
const String KEY_BEACON_CAN_ASSIST = "android.net.lowpan.property.BEACON_CAN_ASSIST";
const String DRIVER_VERSION = "android.net.lowpan.property.DRIVER_VERSION";
const String NCP_VERSION = "android.net.lowpan.property.NCP_VERSION";
/** @hide */
const String KEY_EXTENDED_ADDRESS = "android.net.lowpan.property.EXTENDED_ADDRESS";
/** @hide */
const String KEY_MAC_ADDRESS = "android.net.lowpan.property.MAC_ADDRESS";
//////////////////////////////////////////////////////////////////////////
// Interface States
const String STATE_OFFLINE = "offline";
const String STATE_COMMISSIONING = "commissioning";
const String STATE_ATTACHING = "attaching";
const String STATE_ATTACHED = "attached";
const String STATE_FAULT = "fault";
//////////////////////////////////////////////////////////////////////////
// Device Roles
const String ROLE_END_DEVICE = "end-device";
const String ROLE_ROUTER = "router";
const String ROLE_SLEEPY_END_DEVICE = "sleepy-end-device";
const String ROLE_SLEEPY_ROUTER = "sleepy-router";
const String ROLE_UNKNOWN = "unknown";
//////////////////////////////////////////////////////////////////////////
// Service-Specific Error Code Constants
const int ERROR_UNSPECIFIED = 1;
const int ERROR_INVALID_ARGUMENT = 2;
const int ERROR_DISABLED = 3;
const int ERROR_WRONG_STATE = 4;
const int ERROR_INVALID_TYPE = 5;
const int ERROR_INVALID_VALUE = 6;
const int ERROR_TIMEOUT = 7;
const int ERROR_IO_FAILURE = 8;
const int ERROR_BUSY = 9;
const int ERROR_ALREADY = 10;
const int ERROR_CANCELED = 11;
const int ERROR_CREDENTIAL_NEEDED = 12;
const int ERROR_FEATURE_NOT_SUPPORTED = 14;
const int ERROR_PROPERTY_NOT_FOUND = 16;
const int ERROR_JOIN_FAILED_UNKNOWN = 18;
const int ERROR_JOIN_FAILED_AT_SCAN = 19;
const int ERROR_JOIN_FAILED_AT_AUTH = 20;
const int ERROR_FORM_FAILED_AT_SCAN = 21;
const int ERROR_NCP_PROBLEM = 27;
const int ERROR_PERMISSION_DENIED = 28;
//////////////////////////////////////////////////////////////////////////
// Methods
@utf8InCpp String getName();
void join(in Map parameters);
void form(in Map parameters);
void leave();
void reset();
void beginLowPower();
void pollForData();
oneway void onHostWake();
@utf8InCpp String[] getPropertyKeys();
Map getProperties(in @utf8InCpp String[] keys);
void setProperties(in Map properties);
void addListener(ILowpanInterfaceListener listener);
oneway void removeListener(ILowpanInterfaceListener listener);
void startNetScan(in Map properties, ILowpanNetScanCallback listener);
oneway void stopNetScan();
void startEnergyScan(in Map properties, ILowpanEnergyScanCallback listener);
oneway void stopEnergyScan();
void addOnMeshPrefix(in IpPrefix prefix, int flags);
oneway void removeOnMeshPrefix(in IpPrefix prefix);
void addExternalRoute(in IpPrefix prefix, int flags);
oneway void removeExternalRoute(in IpPrefix prefix);
@utf8InCpp String getPropertyAsString(@utf8InCpp String key);
}

View File

@@ -0,0 +1,22 @@
/*
* 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;
/** {@hide} */
interface ILowpanInterfaceListener {
oneway void onPropertiesChanged(in Map properties);
}

View File

@@ -0,0 +1,35 @@
/*
* 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.lowpan;
import android.net.lowpan.ILowpanInterface;
import android.net.lowpan.ILowpanManagerListener;
/** {@hide} */
interface ILowpanManager {
const String LOWPAN_SERVICE_NAME = "lowpan";
ILowpanInterface getInterface(@utf8InCpp String name);
@utf8InCpp String[] getInterfaceList();
void addListener(ILowpanManagerListener listener);
void removeListener(ILowpanManagerListener listener);
void addInterface(ILowpanInterface lowpan_interface);
void removeInterface(ILowpanInterface lowpan_interface);
}

View File

@@ -0,0 +1,25 @@
/*
* 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.lowpan;
import android.net.lowpan.ILowpanInterface;
/** {@hide} */
interface ILowpanManagerListener {
oneway void onInterfaceAdded(ILowpanInterface lowpanInterface);
oneway void onInterfaceRemoved(ILowpanInterface lowpanInterface);
}

View File

@@ -0,0 +1,23 @@
/*
* 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.lowpan;
/** {@hide} */
interface ILowpanNetScanCallback {
oneway void onNetScanBeacon(in Map parameters);
oneway void onNetScanFinished();
}

View File

@@ -0,0 +1,150 @@
/*
* 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.Collection;
import java.util.Map;
import java.util.TreeSet;
/**
* Describes a LoWPAN Beacon
*
* @hide
*/
//@SystemApi
public class LowpanBeaconInfo extends LowpanIdentity {
private int mRssi = UNKNOWN;
private int mLqi = UNKNOWN;
private byte[] mBeaconAddress = null;
private final TreeSet<Integer> mFlags = new TreeSet<>();
public static final int FLAG_CAN_ASSIST = 1;
static class Builder extends LowpanIdentity.Builder {
private final LowpanBeaconInfo identity = new LowpanBeaconInfo();
public Builder setRssi(int x) {
identity.mRssi = x;
return this;
}
public Builder setLqi(int x) {
identity.mLqi = x;
return this;
}
public Builder setBeaconAddress(byte x[]) {
identity.mBeaconAddress = x.clone();
return this;
}
public Builder setFlag(int x) {
identity.mFlags.add(x);
return this;
}
public Builder setFlags(Collection<Integer> x) {
identity.mFlags.addAll(x);
return this;
}
/** @hide */
Builder updateFromMap(Map map) {
if (map.containsKey(LowpanProperties.KEY_RSSI.getName())) {
setRssi(LowpanProperties.KEY_RSSI.getFromMap(map));
}
if (map.containsKey(LowpanProperties.KEY_LQI.getName())) {
setLqi(LowpanProperties.KEY_LQI.getFromMap(map));
}
if (map.containsKey(LowpanProperties.KEY_BEACON_ADDRESS.getName())) {
setBeaconAddress(LowpanProperties.KEY_BEACON_ADDRESS.getFromMap(map));
}
identity.mFlags.clear();
if (map.containsKey(LowpanProperties.KEY_BEACON_CAN_ASSIST.getName())
&& LowpanProperties.KEY_BEACON_CAN_ASSIST.getFromMap(map).booleanValue()) {
setFlag(FLAG_CAN_ASSIST);
}
super.updateFromMap(map);
return this;
}
public LowpanBeaconInfo build() {
return identity;
}
}
private LowpanBeaconInfo() {}
public int getRssi() {
return mRssi;
}
public int getLqi() {
return mLqi;
}
public byte[] getBeaconAddress() {
return mBeaconAddress.clone();
}
public Collection<Integer> getFlags() {
return mFlags.clone();
}
public boolean isFlagSet(int flag) {
return mFlags.contains(flag);
}
@Override
void addToMap(Map<String, Object> parameters) {
super.addToMap(parameters);
}
@Override
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append(super.toString());
if (mRssi != UNKNOWN) {
sb.append(", RSSI: ").append(mRssi);
}
if (mLqi != UNKNOWN) {
sb.append(", LQI: ").append(mLqi);
}
if (mBeaconAddress != null) {
sb.append(", BeaconAddress: ").append(HexDump.toHexString(mBeaconAddress));
}
for (Integer flag : mFlags) {
switch (flag.intValue()) {
case FLAG_CAN_ASSIST:
sb.append(", CAN_ASSIST");
break;
default:
sb.append(", FLAG_").append(Integer.toHexString(flag));
break;
}
}
return sb.toString();
}
}

View File

@@ -0,0 +1,87 @@
/*
* 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;
/** Provides detailed information about a given channel. */
//@SystemApi
public class LowpanChannelInfo {
public static final int UNKNOWN_POWER = Integer.MAX_VALUE;
//////////////////////////////////////////////////////////////////////////
// Instance Variables
private String mName = null;
private int mIndex = 0;
private boolean mIsMaskedByRegulatoryDomain = false;
private float mSpectrumCenterFrequency = 0.0f;
private float mSpectrumBandwidth = 0.0f;
private int mMaxTransmitPower = UNKNOWN_POWER;
//////////////////////////////////////////////////////////////////////////
// Public Getters and Setters
public String getName() {
return mName;
}
public int getIndex() {
return mIndex;
}
public int getMaxTransmitPower() {
return mMaxTransmitPower;
}
public boolean isMaskedByRegulatoryDomain() {
return mIsMaskedByRegulatoryDomain;
}
public float getSpectrumCenterFrequency() {
return mSpectrumCenterFrequency;
}
public float getSpectrumBandwidth() {
return mSpectrumBandwidth;
}
@Override
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append("Channel ").append(mIndex);
if (mName != null) {
sb.append(" (").append(mName).append(")");
}
if (mSpectrumCenterFrequency > 0.0f) {
sb.append(", SpectrumCenterFrequency: ").append(mSpectrumCenterFrequency).append("Hz");
}
if (mSpectrumBandwidth > 0.0f) {
sb.append(", SpectrumBandwidth: ").append(mSpectrumBandwidth).append("Hz");
}
if (mMaxTransmitPower != UNKNOWN_POWER) {
sb.append(", MaxTransmitPower: ").append(mMaxTransmitPower);
}
return sb.toString();
}
}

View File

@@ -0,0 +1,73 @@
/*
* 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.net.Network;
import android.os.Handler;
import java.net.InetSocketAddress;
/**
* Commissioning Session.
*
* <p>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()}.
*
* <p>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();
}

View File

@@ -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<String, Object> parameters) throws LowpanException {
if (isMasterKey()) {
LowpanProperties.KEY_NETWORK_MASTER_KEY.putInMap(parameters, getMasterKey());
LowpanProperties.KEY_NETWORK_MASTER_KEY_INDEX.putInMap(
parameters, getMasterKeyIndex());
} else {
throw new LowpanException("Unsupported Network Credential");
}
}
}

View File

@@ -0,0 +1,54 @@
/*
* 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;
/**
* Describes the result from one channel of an energy scan.
*
* @hide
*/
//@SystemApi
public class LowpanEnergyScanResult {
public static final int UNKNOWN = Integer.MAX_VALUE;
private int mChannel = UNKNOWN;
private int mMaxRssi = UNKNOWN;
public LowpanEnergyScanResult() {}
public int getChannel() {
return mChannel;
}
public int getMaxRssi() {
return mMaxRssi;
}
public void setChannel(int x) {
mChannel = x;
}
public void setMaxRssi(int x) {
mMaxRssi = x;
}
@Override
public String toString() {
return "LowpanEnergyScanResult(channel: " + mChannel + ", maxRssi:" + mMaxRssi + ")";
}
}

View File

@@ -0,0 +1,290 @@
/*
* 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.os.DeadObjectException;
import android.os.RemoteException;
import android.os.ServiceSpecificException;
import android.util.AndroidException;
/**
* <code>LowpanException</code> 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;
}
}

View File

@@ -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(Map<String, Object> parameters, LowpanIdentity networkInfo) {
if (networkInfo.getName() != null) {
LowpanProperties.KEY_NETWORK_NAME.putInMap(parameters, networkInfo.getName());
}
if (networkInfo.getPanid() != LowpanIdentity.UNKNOWN) {
LowpanProperties.KEY_NETWORK_PANID.putInMap(
parameters, networkInfo.getPanid());
}
if (networkInfo.getChannel() != LowpanIdentity.UNKNOWN) {
LowpanProperties.KEY_CHANNEL.putInMap(
parameters, networkInfo.getChannel());
}
if (networkInfo.getXpanid() != null) {
LowpanProperties.KEY_NETWORK_XPANID.putInMap(parameters, networkInfo.getXpanid());
}
}
void addToMap(Map<String, Object> parameters) {
addToMap(parameters, this);
}
@Override
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append("Name: ").append(mName == null ? "<none>" : mName);
if (mXpanid != null) {
sb.append(", XPANID: ").append(HexDump.toHexString(mXpanid));
}
if (mPanid != UNKNOWN) {
sb.append(", PANID: ").append(String.format("0x%04X", mPanid));
}
if (mChannel != UNKNOWN) {
sb.append(", Channel: ").append(mChannel);
}
return sb.toString();
}
}

View File

@@ -0,0 +1,824 @@
/*
* 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.net.IpPrefix;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceSpecificException;
import android.util.Log;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* Class for managing a specific Low-power Wireless Personal Area Network (LoWPAN) interface.
*
* @hide
*/
//@SystemApi
public class LowpanInterface {
private static final String TAG = LowpanInterface.class.getSimpleName();
/** Detached role. The interface is not currently attached to a network. */
public static final String ROLE_DETACHED = "detached";
/** End-device role. End devices do not route traffic for other nodes. */
public static final String ROLE_END_DEVICE = "end-device";
/** Router role. Routers help route traffic around the mesh network. */
public static final String ROLE_ROUTER = "router";
/**
* Sleepy End-Device role.
*
* <p>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.
*
* <p>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.
*
* <p>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.
*
* <p>This state can be explicitly entered by calling {@link #reset()}, {@link #leave()}, or
* <code>setUp(false)</code>, 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.
*
* <p>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.
*
* <p>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.
*
* <p>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.
*
* <p>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.
*
* <p>The interface will enter this state when the driver has detected some sort of problem from
* which it was not immediately able to recover.
*
* <p>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<Integer, ILowpanInterfaceListener> mListenerMap = new HashMap<>();
/** Map between IBinder identity hashes and LowpanInstance objects. */
private static final HashMap<Integer, LowpanInterface> sInstanceMap = new HashMap<>();
private LowpanInterface(IBinder binder) {
mBinder = ILowpanInterface.Stub.asInterface(binder);
}
/**
* Get the LowpanInterface object associated with this IBinder. Returns null if this IBinder
* does not implement the appropriate interface.
*
* @hide
*/
@NonNull
public static final LowpanInterface from(IBinder binder) {
Integer hashCode = Integer.valueOf(System.identityHashCode(binder));
LowpanInterface instance;
synchronized (sInstanceMap) {
instance = sInstanceMap.get(hashCode);
if (instance == null) {
instance = new LowpanInterface(binder);
sInstanceMap.put(hashCode, instance);
}
}
return instance;
}
/** {@hide} */
public static final LowpanInterface from(ILowpanInterface iface) {
return from(iface.asBinder());
}
/** {@hide} */
public static final LowpanInterface getInterfaceFromBinder(IBinder binder) {
return from(binder);
}
/**
* Returns the IBinder object associated with this interface.
*
* @hide
*/
public IBinder getBinder() {
return mBinder.asBinder();
}
private static void throwAsPublicException(Throwable t) throws LowpanException {
LowpanException.throwAsPublicException(t);
}
//////////////////////////////////////////////////////////////////////////
// Private Property Helpers
void setProperties(Map properties) throws LowpanException {
try {
mBinder.setProperties(properties);
} catch (RemoteException x) {
// Catch and ignore all binder exceptions
Log.e(TAG, x.toString());
} catch (ServiceSpecificException x) {
throwAsPublicException(x);
}
}
@NonNull
Map<String, Object> getProperties(String keys[]) throws LowpanException {
try {
return mBinder.getProperties(keys);
} catch (RemoteException x) {
// Catch and ignore all binder exceptions
Log.e(TAG, x.toString());
} catch (ServiceSpecificException x) {
throwAsPublicException(x);
}
return new HashMap();
}
/** @hide */
public <T> void setProperty(LowpanProperty<T> key, T value) throws LowpanException {
HashMap<String, T> prop = new HashMap<>();
prop.put(key.getName(), value);
setProperties(prop);
}
/** @hide */
@Nullable
public <T> T getProperty(LowpanProperty<T> key) throws LowpanException {
Map<String, Object> map = getProperties(new String[] {key.getName()});
if (map != null && !map.isEmpty()) {
// We know there is only one value.
return (T) map.values().iterator().next();
}
return null;
}
@Nullable
<T> String getPropertyAsString(LowpanProperty<T> key) throws LowpanException {
try {
return mBinder.getPropertyAsString(key.getName());
} catch (RemoteException x) {
// Catch and ignore all binder exceptions
Log.e(TAG, x.toString());
} catch (ServiceSpecificException x) {
throwAsPublicException(x);
}
return null;
}
int getPropertyAsInt(LowpanProperty<Integer> key) throws LowpanException {
Integer value = getProperty(key);
return (value != null) ? value : 0;
}
boolean getPropertyAsBoolean(LowpanProperty<Boolean> key) throws LowpanException {
Boolean value = getProperty(key);
return (value != null) ? value : 0;
}
//////////////////////////////////////////////////////////////////////////
// Public Actions
/**
* Form a new network with the given network information optional credential. Unspecified fields
* in the network information will be filled in with reasonable values. If the network
* credential is unspecified, one will be generated automatically.
*
* <p>This method will block until either the network was successfully formed or an error
* prevents the network form being formed.
*
* <p>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<String, Object> parameters = new HashMap();
provision.addToMap(parameters);
mBinder.form(parameters);
} catch (RemoteException x) {
throwAsPublicException(x);
} catch (ServiceSpecificException x) {
throwAsPublicException(x);
}
}
/**
* Attempts to join a new network with the given network information. This method will block
* until either the network was successfully joined or an error prevented the network from being
* formed. Upon success, the interface will be up and attached to the newly joined network.
*
* <p>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<String, Object> parameters = new HashMap();
provision.addToMap(parameters);
mBinder.join(parameters);
} catch (RemoteException x) {
throwAsPublicException(x);
} catch (ServiceSpecificException x) {
throwAsPublicException(x);
}
}
/**
* Attaches to the network described by identity and credential. This is similar to {@link
* #join}, except that (assuming the identity and credential are valid) it will always succeed
* and provision the interface, even if there are no peers nearby.
*
* <p>This method will block execution until the operation has completed.
*/
public void attach(@NonNull LowpanProvision provision) throws LowpanException {
if (ROLE_DETACHED.equals(getRole())) {
Map<String, Object> parameters = new HashMap();
provision.addToMap(parameters);
setProperties(parameters);
setUp(true);
} else {
throw new LowpanException(LowpanException.LOWPAN_ALREADY);
}
}
/**
* Bring down the network interface and forget all non-volatile details about the current
* network.
*
* <p>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.
*
* <p>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.
*
* <p>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.
*
* <p>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 <code>true</code> if we have at least one other peer in range, <code>false</code>
* 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
*
* <h3>State Diagram</h3>
*
* <img src="LowpanInterface-1.png" />
*
* @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 {
Map<String, Object> map = new HashMap();
LowpanIdentity.addToMap(map, network);
setProperties(map);
}
/** TODO: doc */
@NonNull
public String getRole() {
String role = null;
try {
role = getProperty(LowpanProperties.KEY_NETWORK_ROLE);
} catch (LowpanException x) {
// We ignore all LoWPAN-specitic exceptions here.
Log.e(TAG, x.toString());
}
if (role == null) {
role = ROLE_DETACHED;
}
return role;
}
/** TODO: doc */
@Nullable
public LowpanCredential getLowpanCredential() {
LowpanCredential credential = null;
try {
Integer keyIndex = getProperty(LowpanProperties.KEY_NETWORK_MASTER_KEY_INDEX);
if (keyIndex == null) {
credential =
LowpanCredential.createMasterKey(
getProperty(LowpanProperties.KEY_NETWORK_MASTER_KEY));
} else {
credential =
LowpanCredential.createMasterKey(
getProperty(LowpanProperties.KEY_NETWORK_MASTER_KEY),
keyIndex.intValue());
}
} catch (LowpanException x) {
// We ignore all LoWPAN-specitic exceptions here.
Log.e(TAG, x.toString());
}
return credential;
}
/**
* TODO: doc
*
* @hide
*/
public void setLowpanCredential(LowpanCredential networkCredential) throws LowpanException {
Map<String, Object> map = new HashMap();
networkCredential.addToMap(map);
setProperties(map);
}
//////////////////////////////////////////////////////////////////////////
// Listener Support
/**
* Registers a subclass of {@link LowpanInterface.Callback} to receive events.
*
* @param cb Subclass of {@link LowpanInterface.Callback} which will receive events.
* @param handler If not <code>null</code>, events will be dispatched via the given handler
* object. If <code>null</code>, 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<String, Object> properties) {
Runnable runnable =
new Runnable() {
@Override
public void run() {
for (String key : (Set<String>) properties.keySet()) {
Object value = properties.get(key);
switch (key) {
case ILowpanInterface.KEY_INTERFACE_ENABLED:
cb.onEnabledChanged(
((Boolean) value).booleanValue());
break;
case ILowpanInterface.KEY_INTERFACE_UP:
cb.onUpChanged(
((Boolean) value).booleanValue());
break;
case ILowpanInterface.KEY_INTERFACE_CONNECTED:
cb.onConnectedChanged(
((Boolean) value).booleanValue());
break;
case ILowpanInterface.KEY_INTERFACE_STATE:
cb.onStateChanged((String) value);
break;
case ILowpanInterface.KEY_NETWORK_NAME:
case ILowpanInterface.KEY_NETWORK_PANID:
case ILowpanInterface.KEY_NETWORK_XPANID:
case ILowpanInterface.KEY_CHANNEL:
cb.onLowpanIdentityChanged(getLowpanIdentity());
break;
case ILowpanInterface.KEY_NETWORK_ROLE:
cb.onRoleChanged(value.toString());
break;
}
}
cb.onPropertiesChanged(properties);
}
};
if (handler != null) {
handler.post(runnable);
} else {
runnable.run();
}
}
};
try {
mBinder.addListener(listenerBinder);
} catch (RemoteException x) {
// Log and ignore. If this happens, this interface
// is likely dead anyway.
Log.e(TAG, x.toString());
}
synchronized (mListenerMap) {
mListenerMap.put(System.identityHashCode(cb), listenerBinder);
}
}
/**
* Registers a subclass of {@link LowpanInterface.Callback} to receive events.
*
* <p>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.
*
* <p>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());
}
}
}

View File

@@ -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<Integer, ILowpanManagerListener> mListenerMap = new HashMap<>();
//////////////////////////////////////////////////////////////////////////
private static LowpanManager sSingletonInstance;
//////////////////////////////////////////////////////////////////////////
// Static Methods
/** Returns a reference to the LowpanManager object, allocating it if necessary. */
public static LowpanManager getManager() {
return from(null);
}
public static LowpanManager from(Context context) {
// TODO: Actually get this from the context!
if (sSingletonInstance == null) {
sSingletonInstance = new LowpanManager();
}
return sSingletonInstance;
}
//////////////////////////////////////////////////////////////////////////
// Constructors
/**
* Private LowpanManager constructor. Since we are a singleton, we do not allow external
* construction.
*/
private LowpanManager() {}
//////////////////////////////////////////////////////////////////////////
// Private Methods
/**
* Returns a reference to the ILowpanManager interface, provided by the LoWPAN Manager Service.
*/
@Nullable
private ILowpanManager getILowpanManager() {
ILowpanManager manager = mManager;
if (manager == null) {
IBinder serviceBinder =
new ServiceManager().getService(ILowpanManager.LOWPAN_SERVICE_NAME);
mManager = manager = ILowpanManager.Stub.asInterface(serviceBinder);
// Add any listeners
synchronized (mListenerMap) {
for (Integer hashObj : mListenerMap.keySet()) {
try {
manager.addListener(mListenerMap.get(hashObj));
} catch (RemoteException x) {
// Consider any failure here as implying the manager is defunct
mManager = manager = null;
}
}
}
}
return manager;
}
//////////////////////////////////////////////////////////////////////////
// Public Methods
/**
* Returns a reference to the requested LowpanInterface object. If the given interface doesn't
* exist, or it is not a LoWPAN interface, returns null.
*/
@Nullable
public LowpanInterface getInterface(@NonNull String name) {
LowpanInterface ret = null;
ILowpanManager manager = getILowpanManager();
// Maximum number of tries is two. We should only try
// more than once if our manager has died or there
// was some sort of AIDL buffer full event.
for (int i = 0; i < 2 && manager != null; i++) {
try {
ILowpanInterface iface = manager.getInterface(name);
if (iface != null) {
ret = LowpanInterface.getInterfaceFromBinder(iface.asBinder());
}
break;
} catch (RemoteException x) {
// In all of the cases when we get this exception, we reconnect and try again
mManager = null;
manager = getILowpanManager();
}
}
return ret;
}
/**
* Returns a reference to the first registered LowpanInterface object. If there are no LoWPAN
* interfaces registered, returns null.
*/
@Nullable
public LowpanInterface getInterface() {
String[] ifaceList = getInterfaceList();
if (ifaceList != null && ifaceList.length > 0) {
return getInterface(ifaceList[0]);
}
return null;
}
/**
* Returns a string array containing the names of LoWPAN interfaces. This list may contain fewer
* interfaces if the calling process does not have permissions to see individual interfaces.
*/
@NonNull
public String[] getInterfaceList() {
ILowpanManager manager = getILowpanManager();
if (manager != null) {
try {
return manager.getInterfaceList();
} catch (RemoteException x) {
// In all of the cases when we get this exception, we reconnect and try again
mManager = null;
try {
manager = getILowpanManager();
if (manager != null) {
return manager.getInterfaceList();
}
} catch (RemoteException ex) {
// Something weird is going on, so we log it
// and fall back thru to returning an empty array.
Log.e(TAG, ex.toString());
mManager = null;
}
}
}
// Return empty list if we have no service.
return new String[0];
}
/**
* Registers a callback object to receive notifications when LoWPAN interfaces are added or
* removed.
*
* @hide
*/
public void registerCallback(@NonNull Callback cb, @Nullable Handler handler)
throws LowpanException {
ILowpanManagerListener.Stub listenerBinder =
new ILowpanManagerListener.Stub() {
public void onInterfaceAdded(ILowpanInterface lowpan_interface) {
Runnable runnable =
new Runnable() {
@Override
public void run() {
cb.onInterfaceAdded(
LowpanInterface.getInterfaceFromBinder(
lowpan_interface.asBinder()));
}
};
if (handler != null) {
handler.post(runnable);
} else {
runnable.run();
}
}
public void onInterfaceRemoved(ILowpanInterface lowpan_interface) {
Runnable runnable =
new Runnable() {
@Override
public void run() {
cb.onInterfaceRemoved(
LowpanInterface.getInterfaceFromBinder(
lowpan_interface.asBinder()));
}
};
if (handler != null) {
handler.post(runnable);
} else {
runnable.run();
}
}
};
ILowpanManager manager = getILowpanManager();
if (manager != null) {
try {
manager.addListener(listenerBinder);
} catch (DeadObjectException x) {
mManager = null;
// Tickle the ILowpanManager instance, which might
// get us added back.
getILowpanManager();
} catch (Throwable x) {
LowpanException.throwAsPublicException(x);
}
}
synchronized (mListenerMap) {
mListenerMap.put(Integer.valueOf(System.identityHashCode(cb)), listenerBinder);
}
}
/** @hide */
public void registerCallback(@NonNull Callback cb) throws LowpanException {
registerCallback(cb, null);
}
/**
* Unregisters a previously registered {@link LowpanManager.Callback} object.
*
* @hide
*/
public void unregisterCallback(@NonNull Callback cb) throws AndroidException {
Integer hashCode = Integer.valueOf(System.identityHashCode(cb));
ILowpanManagerListener listenerBinder = mListenerMap.get(hashCode);
if (listenerBinder != null) {
synchronized (mListenerMap) {
mListenerMap.remove(hashCode);
}
if (getILowpanManager() != null) {
try {
mManager.removeListener(listenerBinder);
} catch (DeadObjectException x) {
mManager = null;
}
}
}
}
}

View File

@@ -0,0 +1,125 @@
/*
* 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.net.LinkAddress;
import android.net.RouteInfo;
import java.util.List;
/** {@hide} */
public final class LowpanProperties {
public static final LowpanProperty<Boolean> KEY_INTERFACE_ENABLED =
new LowpanStandardProperty(
"android.net.lowpan.property.INTERFACE_ENABLED", Boolean.class);
public static final LowpanProperty<Boolean> KEY_INTERFACE_COMMISSIONED =
new LowpanStandardProperty(
"android.net.lowpan.property.INTERFACE_COMMISSIONED", Boolean.class);
public static final LowpanProperty<Boolean> KEY_INTERFACE_CONNECTED =
new LowpanStandardProperty(
"android.net.lowpan.property.INTERFACE_CONNECTED", Boolean.class);
public static final LowpanProperty<Boolean> KEY_INTERFACE_UP =
new LowpanStandardProperty("android.net.lowpan.property.INTERFACE_UP", Boolean.class);
public static final LowpanProperty<String> KEY_INTERFACE_STATE =
new LowpanStandardProperty("android.net.lowpan.property.INTERFACE_STATE", String.class);
public static final LowpanProperty<String> KEY_NETWORK_NAME =
new LowpanStandardProperty("android.net.lowpan.property.NETWORK_NAME", Boolean.class);
public static final LowpanProperty<Integer> KEY_NETWORK_PANID =
new LowpanStandardProperty("android.net.lowpan.property.NETWORK_PANID", Integer.class);
public static final LowpanProperty<byte[]> KEY_NETWORK_XPANID =
new LowpanStandardProperty("android.net.lowpan.property.NETWORK_XPANID", byte[].class);
public static final LowpanProperty<byte[]> KEY_NETWORK_MASTER_KEY =
new LowpanStandardProperty(
"android.net.lowpan.property.NETWORK_MASTER_KEY", byte[].class);
public static final LowpanProperty<Integer> KEY_NETWORK_MASTER_KEY_INDEX =
new LowpanStandardProperty(
"android.net.lowpan.property.NETWORK_MASTER_KEY_INDEX", Integer.class);
public static final LowpanProperty<Integer> KEY_NETWORK_TYPE =
new LowpanStandardProperty("android.net.lowpan.property.NETWORK_TYPE", Integer.class);
public static final LowpanProperty<String> KEY_NETWORK_ROLE =
new LowpanStandardProperty("android.net.lowpan.property.NETWORK_ROLE", String.class);
public static final LowpanProperty<Integer> KEY_CHANNEL =
new LowpanStandardProperty("android.net.lowpan.property.CHANNEL", Integer.class);
public static final LowpanProperty<int[]> KEY_CHANNEL_MASK =
new LowpanStandardProperty("android.net.lowpan.property.CHANNEL_MASK", int[].class);
public static final LowpanProperty<Integer> KEY_MAX_TX_POWER =
new LowpanStandardProperty("android.net.lowpan.property.MAX_TX_POWER", Integer.class);
public static final LowpanProperty<Integer> KEY_RSSI =
new LowpanStandardProperty("android.net.lowpan.property.RSSI", Integer.class);
public static final LowpanProperty<Integer> KEY_LQI =
new LowpanStandardProperty("android.net.lowpan.property.LQI", Integer.class);
public static final LowpanProperty<byte[]> KEY_BEACON_ADDRESS =
new LowpanStandardProperty("android.net.lowpan.property.BEACON_ADDRESS", byte[].class);
public static final LowpanProperty<Boolean> KEY_BEACON_CAN_ASSIST =
new LowpanStandardProperty(
"android.net.lowpan.property.BEACON_CAN_ASSIST", Boolean.class);
public static final LowpanProperty<String> KEY_DRIVER_VERSION =
new LowpanStandardProperty("android.net.lowpan.property.DRIVER_VERSION", String.class);
public static final LowpanProperty<String> KEY_NCP_VERSION =
new LowpanStandardProperty("android.net.lowpan.property.NCP_VERSION", String.class);
public static final LowpanProperty<List<LinkAddress>> KEY_LINK_ADDRESS_ARRAY =
new LowpanStandardProperty(
"android.net.lowpan.property.LINK_ADDRESS_ARRAY", LinkAddress[].class);
public static final LowpanProperty<List<RouteInfo>> KEY_ROUTE_INFO_ARRAY =
new LowpanStandardProperty(
"android.net.lowpan.property.ROUTE_INFO_ARRAY", RouteInfo[].class);
/** @hide */
public static final LowpanProperty<byte[]> KEY_EXTENDED_ADDRESS =
new LowpanStandardProperty(
"android.net.lowpan.property.EXTENDED_ADDRESS", byte[].class);
/** @hide */
public static final LowpanProperty<byte[]> KEY_MAC_ADDRESS =
new LowpanStandardProperty("android.net.lowpan.property.MAC_ADDRESS", byte[].class);
/** @hide */
private LowpanProperties() {}
/** @hide */
static final class LowpanStandardProperty<T> extends LowpanProperty<T> {
private final String mName;
private final Class<T> mType;
LowpanStandardProperty(String name, Class<T> type) {
mName = name;
mType = type;
}
@Override
public String getName() {
return mName;
}
@Override
public Class<T> getType() {
return mType;
}
@Override
public String toString() {
return getName();
}
}
}

View File

@@ -0,0 +1,34 @@
/*
* 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;
/** {@hide} */
public abstract class LowpanProperty<T> {
public abstract String getName();
public abstract Class<T> getType();
public void putInMap(Map map, T value) {
map.put(getName(), value);
}
public T getFromMap(Map map) {
return (T) map.get(getName());
}
}

View File

@@ -0,0 +1,104 @@
/*
* 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 java.util.Map;
/**
* Describes the information needed to describe a network
*
* @hide
*/
//@SystemApi
public class LowpanProvision {
//////////////////////////////////////////////////////////////////////////
// Builder
/** @hide */
//@SystemApi
public static class Builder {
private final LowpanProvision provision = new LowpanProvision();
public Builder setLowpanIdentity(@NonNull LowpanIdentity identity) {
provision.mIdentity = identity;
return this;
}
public Builder setLowpanCredential(@NonNull LowpanCredential credential) {
provision.mCredential = credential;
return this;
}
public LowpanProvision build() {
return provision;
}
}
private LowpanProvision() {}
//////////////////////////////////////////////////////////////////////////
// Instance Variables
private LowpanIdentity mIdentity = new LowpanIdentity();
private LowpanCredential mCredential = null;
//////////////////////////////////////////////////////////////////////////
// Public Getters and Setters
@NonNull
public LowpanIdentity getLowpanIdentity() {
return mIdentity;
}
@Nullable
public LowpanCredential getLowpanCredential() {
return mCredential;
}
//////////////////////////////////////////////////////////////////////////
// LoWPAN-Internal Methods
static void addToMap(Map<String, Object> parameters, LowpanProvision provision)
throws LowpanException {
provision.mIdentity.addToMap(parameters);
if (provision.mCredential != null) {
provision.mCredential.addToMap(parameters);
}
}
void addToMap(Map<String, Object> parameters) throws LowpanException {
addToMap(parameters, this);
}
@Override
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append("LowpanProvision { identity => ").append(mIdentity.toString());
if (mCredential != null) {
sb.append(", credential: ").append(mCredential.toString());
}
sb.append("}");
return sb.toString();
}
};

View File

@@ -0,0 +1,317 @@
/*
* 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.os.Handler;
import android.os.RemoteException;
import android.os.ServiceSpecificException;
import android.util.Log;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* LoWPAN Scanner
*
* <p>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<Integer> mChannelMask = null;
private int mTxPower = Integer.MAX_VALUE;
//////////////////////////////////////////////////////////////////////////
// Constructors/Accessors and Exception Glue
LowpanScanner(@NonNull ILowpanInterface binder) {
mBinder = binder;
}
/** Sets an instance of {@link LowpanScanner.Callback} to receive events. */
public void setCallback(@Nullable Callback cb, @Nullable Handler handler) {
mCallback = cb;
mHandler = handler;
}
/** Sets an instance of {@link LowpanScanner.Callback} to receive events. */
public void setCallback(@Nullable Callback cb) {
setCallback(cb, null);
}
/**
* Sets the channel mask to use when scanning.
*
* @param mask The channel mask to use when scanning. If <code>null</code>, 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 Collection<Integer> mask) {
if (mask == null) {
mChannelMask = null;
} else {
if (mChannelMask == null) {
mChannelMask = new ArrayList<>();
} else {
mChannelMask.clear();
}
mChannelMask.addAll(mask);
}
}
/**
* Gets the current channel mask.
*
* @return the current channel mask, or <code>null</code> if no channel mask is currently set.
*/
public @Nullable Collection<Integer> getChannelMask() {
return mChannelMask.clone();
}
/**
* Adds a channel to the channel mask used for scanning.
*
* <p>If a channel mask was previously <code>null</code>, 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.
*
* <p>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<String, Object> createScanOptionMap() {
Map<String, Object> map = new HashMap();
if (mChannelMask != null) {
LowpanProperties.KEY_CHANNEL_MASK.putInMap(
map, mChannelMask.stream().mapToInt(i -> i).toArray());
}
if (mTxPower != Integer.MAX_VALUE) {
LowpanProperties.KEY_MAX_TX_POWER.putInMap(map, Integer.valueOf(mTxPower));
}
return map;
}
/**
* Start a network scan.
*
* <p>This method will return once the scan has started.
*
* @see #stopNetScan
*/
public void startNetScan() throws LowpanException {
Map<String, Object> map = createScanOptionMap();
ILowpanNetScanCallback binderListener =
new ILowpanNetScanCallback.Stub() {
public void onNetScanBeacon(Map parameters) {
Callback callback = mCallback;
Handler handler = mHandler;
if (callback == null) {
return;
}
Runnable runnable = () -> callback.onNetScanBeacon(
new LowpanBeaconInfo.Builder()
.updateFromMap(parameters)
.build());
if (handler != null) {
handler.post(runnable);
} else {
runnable.run();
}
}
public void onNetScanFinished() {
Callback callback = mCallback;
Handler handler = mHandler;
if (callback == null) {
return;
}
Runnable runnable = () -> callback.onScanFinished();
if (handler != null) {
handler.post(runnable);
} else {
runnable.run();
}
}
};
try {
mBinder.startNetScan(map, binderListener);
} catch (ServiceSpecificException|RemoteException x) {
LowpanException.throwAsPublicException(x);
}
}
/**
* Stop a network scan currently in progress.
*
* @see #startNetScan
*/
public void stopNetScan() {
try {
mBinder.stopNetScan();
} catch (RemoteException x) {
// Catch and ignore all binder exceptions
Log.e(TAG, x.toString());
}
}
/**
* Start an energy scan.
*
* <p>This method will return once the scan has started.
*
* @see #stopEnergyScan
*/
public void startEnergyScan() throws LowpanException {
Map<String, Object> map = createScanOptionMap();
ILowpanEnergyScanCallback binderListener =
new ILowpanEnergyScanCallback.Stub() {
public void onEnergyScanResult(int channel, int rssi) {
Callback callback = mCallback;
Handler handler = mHandler;
if (callback == null) {
return;
}
Runnable runnable = () -> {
if (callback != null) {
LowpanEnergyScanResult result =
new LowpanEnergyScanResult();
result.setChannel(channel);
result.setMaxRssi(rssi);
callback.onEnergyScanResult(result);
}
};
if (handler != null) {
handler.post(runnable);
} else {
runnable.run();
}
}
public void onEnergyScanFinished() {
Callback callback = mCallback;
Handler handler = mHandler;
if (callback == null) {
return;
}
Runnable runnable = () -> callback.onScanFinished();
if (handler != null) {
handler.post(runnable);
} else {
runnable.run();
}
}
};
try {
mBinder.startEnergyScan(map, binderListener);
} catch (RemoteException x) {
LowpanException.throwAsPublicException(x);
} catch (ServiceSpecificException x) {
LowpanException.throwAsPublicException(x);
}
}
/**
* Stop an energy scan currently in progress.
*
* @see #startEnergyScan
*/
public void stopEnergyScan() {
try {
mBinder.stopEnergyScan();
} catch (RemoteException x) {
// Catch and ignore all binder exceptions
Log.e(TAG, x.toString());
}
}
}

View File

@@ -0,0 +1,29 @@
<HTML>
<BODY>
<p>@SystemApi</p>
<!-- @hide -->
<p>Provides classes to manage Low-power Wireless Personal Area Network (LoWPAN) functionality on the device.
Examples of such network technologies include <a href="http://threadgroup.org/">Thread</a> and
<a href="http://www.zigbee.org/zigbee-for-developers/network-specifications/zigbeeip/">ZigBee IP</a>.</p>
<p>The LoWPAN APIs provide a means by which applications can communicate
with the lower-level wireless stack that provides LoWPAN network access.</p>
<p>Some APIs may require the following user permissions:</p>
<ul>
<li>{@link android.Manifest.permission#ACCESS_LOWPAN_STATE}</li>
<li>{@link android.Manifest.permission#CHANGE_LOWPAN_STATE}</li>
<li>TBD</li>
</ul>
<p class="note"><strong>Note:</strong> Not all Android-powered devices provide LoWPAN functionality.
If your application uses these APIs, declare so with a <a
href="{@docRoot}guide/topics/manifest/uses-feature-element.html">{@code <uses-feature>}</a>
element in the manifest file:</p>
<pre>
&lt;manifest ...>
&lt;uses-feature android:name="android.hardware.lowpan" />
...
&lt;/manifest>
</pre>
</BODY>
</HTML>