After doing a considerable amount of thinking on the subject,
I decided that attempting to directly port wpantund's property-based
API over to Binder was a mistake, so this commit contains the required
changes to abandon that approach and go with a more traditional
Binder interface.
Bug: b/63708348
Change-Id: I685cd066fabe8470ef4bb456aea7d3bb515c3969
Test: Compiled and ran unit tests, manually confirmed lowpanctl
and lowpan-service (with related changes) appeared to be
working properly.
224 lines
6.7 KiB
Java
224 lines
6.7 KiB
Java
/*
|
|
* 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.DeadObjectException;
|
|
import android.os.Handler;
|
|
import android.os.Looper;
|
|
import android.os.RemoteException;
|
|
|
|
/**
|
|
* 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 class LowpanCommissioningSession {
|
|
|
|
private final ILowpanInterface mBinder;
|
|
private final LowpanBeaconInfo mBeaconInfo;
|
|
private final ILowpanInterfaceListener mInternalCallback = new InternalCallback();
|
|
private final Looper mLooper;
|
|
private Handler mHandler;
|
|
private Callback mCallback = null;
|
|
private volatile boolean mIsClosed = false;
|
|
|
|
/**
|
|
* Callback base class for {@link LowpanCommissioningSession}
|
|
*
|
|
* @hide
|
|
*/
|
|
// @SystemApi
|
|
public abstract static class Callback {
|
|
public void onReceiveFromCommissioner(@NonNull byte[] packet) {};
|
|
|
|
public void onClosed() {};
|
|
}
|
|
|
|
private class InternalCallback extends ILowpanInterfaceListener.Stub {
|
|
@Override
|
|
public void onStateChanged(String value) {
|
|
if (!mIsClosed) {
|
|
switch (value) {
|
|
case ILowpanInterface.STATE_OFFLINE:
|
|
case ILowpanInterface.STATE_FAULT:
|
|
synchronized (LowpanCommissioningSession.this) {
|
|
lockedCleanup();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onReceiveFromCommissioner(byte[] packet) {
|
|
mHandler.post(
|
|
() -> {
|
|
synchronized (LowpanCommissioningSession.this) {
|
|
if (!mIsClosed && (mCallback != null)) {
|
|
mCallback.onReceiveFromCommissioner(packet);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
// We ignore all other callbacks.
|
|
@Override
|
|
public void onEnabledChanged(boolean value) {}
|
|
|
|
@Override
|
|
public void onConnectedChanged(boolean value) {}
|
|
|
|
@Override
|
|
public void onUpChanged(boolean value) {}
|
|
|
|
@Override
|
|
public void onRoleChanged(String value) {}
|
|
|
|
@Override
|
|
public void onLowpanIdentityChanged(LowpanIdentity value) {}
|
|
|
|
@Override
|
|
public void onLinkNetworkAdded(IpPrefix value) {}
|
|
|
|
@Override
|
|
public void onLinkNetworkRemoved(IpPrefix value) {}
|
|
|
|
@Override
|
|
public void onLinkAddressAdded(String value) {}
|
|
|
|
@Override
|
|
public void onLinkAddressRemoved(String value) {}
|
|
}
|
|
|
|
LowpanCommissioningSession(
|
|
ILowpanInterface binder, LowpanBeaconInfo beaconInfo, Looper looper) {
|
|
mBinder = binder;
|
|
mBeaconInfo = beaconInfo;
|
|
mLooper = looper;
|
|
|
|
if (mLooper != null) {
|
|
mHandler = new Handler(mLooper);
|
|
} else {
|
|
mHandler = new Handler();
|
|
}
|
|
|
|
try {
|
|
mBinder.addListener(mInternalCallback);
|
|
|
|
} catch (RemoteException x) {
|
|
throw x.rethrowAsRuntimeException();
|
|
}
|
|
}
|
|
|
|
private void lockedCleanup() {
|
|
// Note: this method is only called from synchronized contexts.
|
|
|
|
if (!mIsClosed) {
|
|
try {
|
|
mBinder.removeListener(mInternalCallback);
|
|
|
|
} catch (DeadObjectException x) {
|
|
/* We don't care if we receive a DOE at this point.
|
|
* DOE is as good as success as far as we are concerned.
|
|
*/
|
|
|
|
} catch (RemoteException x) {
|
|
throw x.rethrowAsRuntimeException();
|
|
}
|
|
|
|
if (mCallback != null) {
|
|
mHandler.post(() -> mCallback.onClosed());
|
|
}
|
|
}
|
|
|
|
mCallback = null;
|
|
mIsClosed = true;
|
|
}
|
|
|
|
/** TODO: doc */
|
|
@NonNull
|
|
public LowpanBeaconInfo getBeaconInfo() {
|
|
return mBeaconInfo;
|
|
}
|
|
|
|
/** TODO: doc */
|
|
public void sendToCommissioner(@NonNull byte[] packet) {
|
|
if (!mIsClosed) {
|
|
try {
|
|
mBinder.sendToCommissioner(packet);
|
|
|
|
} catch (DeadObjectException x) {
|
|
/* This method is a best-effort delivery.
|
|
* We don't care if we receive a DOE at this point.
|
|
*/
|
|
|
|
} catch (RemoteException x) {
|
|
throw x.rethrowAsRuntimeException();
|
|
}
|
|
}
|
|
}
|
|
|
|
/** TODO: doc */
|
|
public synchronized void setCallback(@Nullable Callback cb, @Nullable Handler handler) {
|
|
if (!mIsClosed) {
|
|
/* This class can be created with or without a default looper.
|
|
* Also, this method can be called with or without a specific
|
|
* handler. If a handler is specified, it is to always be used.
|
|
* Otherwise, if there was a Looper specified when this object
|
|
* was created, we create a new handle based on that looper.
|
|
* Otherwise we just create a default handler object. Since we
|
|
* don't really know how the previous handler was created, we
|
|
* end up always replacing it here. This isn't a huge problem
|
|
* because this method should be called infrequently.
|
|
*/
|
|
if (handler != null) {
|
|
mHandler = handler;
|
|
} else if (mLooper != null) {
|
|
mHandler = new Handler(mLooper);
|
|
} else {
|
|
mHandler = new Handler();
|
|
}
|
|
mCallback = cb;
|
|
}
|
|
}
|
|
|
|
/** TODO: doc */
|
|
public synchronized void close() {
|
|
if (!mIsClosed) {
|
|
try {
|
|
mBinder.closeCommissioningSession();
|
|
|
|
lockedCleanup();
|
|
|
|
} catch (DeadObjectException x) {
|
|
/* We don't care if we receive a DOE at this point.
|
|
* DOE is as good as success as far as we are concerned.
|
|
*/
|
|
|
|
} catch (RemoteException x) {
|
|
throw x.rethrowAsRuntimeException();
|
|
}
|
|
}
|
|
}
|
|
}
|