• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.net.lowpan;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.net.IpPrefix;
22 import android.os.DeadObjectException;
23 import android.os.Handler;
24 import android.os.Looper;
25 import android.os.RemoteException;
26 
27 /**
28  * Commissioning Session.
29  *
30  * <p>This class enables a device to learn the credential needed to join a network using a technique
31  * called "in-band commissioning".
32  *
33  * @hide
34  */
35 // @SystemApi
36 public class LowpanCommissioningSession {
37 
38     private final ILowpanInterface mBinder;
39     private final LowpanBeaconInfo mBeaconInfo;
40     private final ILowpanInterfaceListener mInternalCallback = new InternalCallback();
41     private final Looper mLooper;
42     private Handler mHandler;
43     private Callback mCallback = null;
44     private volatile boolean mIsClosed = false;
45 
46     /**
47      * Callback base class for {@link LowpanCommissioningSession}
48      *
49      * @hide
50      */
51     // @SystemApi
52     public abstract static class Callback {
onReceiveFromCommissioner(@onNull byte[] packet)53         public void onReceiveFromCommissioner(@NonNull byte[] packet) {};
54 
onClosed()55         public void onClosed() {};
56     }
57 
58     private class InternalCallback extends ILowpanInterfaceListener.Stub {
59         @Override
onStateChanged(String value)60         public void onStateChanged(String value) {
61             if (!mIsClosed) {
62                 switch (value) {
63                     case ILowpanInterface.STATE_OFFLINE:
64                     case ILowpanInterface.STATE_FAULT:
65                         synchronized (LowpanCommissioningSession.this) {
66                             lockedCleanup();
67                         }
68                 }
69             }
70         }
71 
72         @Override
onReceiveFromCommissioner(byte[] packet)73         public void onReceiveFromCommissioner(byte[] packet) {
74             mHandler.post(
75                     () -> {
76                         synchronized (LowpanCommissioningSession.this) {
77                             if (!mIsClosed && (mCallback != null)) {
78                                 mCallback.onReceiveFromCommissioner(packet);
79                             }
80                         }
81                     });
82         }
83 
84         // We ignore all other callbacks.
85         @Override
onEnabledChanged(boolean value)86         public void onEnabledChanged(boolean value) {}
87 
88         @Override
onConnectedChanged(boolean value)89         public void onConnectedChanged(boolean value) {}
90 
91         @Override
onUpChanged(boolean value)92         public void onUpChanged(boolean value) {}
93 
94         @Override
onRoleChanged(String value)95         public void onRoleChanged(String value) {}
96 
97         @Override
onLowpanIdentityChanged(LowpanIdentity value)98         public void onLowpanIdentityChanged(LowpanIdentity value) {}
99 
100         @Override
onLinkNetworkAdded(IpPrefix value)101         public void onLinkNetworkAdded(IpPrefix value) {}
102 
103         @Override
onLinkNetworkRemoved(IpPrefix value)104         public void onLinkNetworkRemoved(IpPrefix value) {}
105 
106         @Override
onLinkAddressAdded(String value)107         public void onLinkAddressAdded(String value) {}
108 
109         @Override
onLinkAddressRemoved(String value)110         public void onLinkAddressRemoved(String value) {}
111     }
112 
LowpanCommissioningSession( ILowpanInterface binder, LowpanBeaconInfo beaconInfo, Looper looper)113     LowpanCommissioningSession(
114             ILowpanInterface binder, LowpanBeaconInfo beaconInfo, Looper looper) {
115         mBinder = binder;
116         mBeaconInfo = beaconInfo;
117         mLooper = looper;
118 
119         if (mLooper != null) {
120             mHandler = new Handler(mLooper);
121         } else {
122             mHandler = new Handler();
123         }
124 
125         try {
126             mBinder.addListener(mInternalCallback);
127 
128         } catch (RemoteException x) {
129             throw x.rethrowAsRuntimeException();
130         }
131     }
132 
lockedCleanup()133     private void lockedCleanup() {
134         // Note: this method is only called from synchronized contexts.
135 
136         if (!mIsClosed) {
137             try {
138                 mBinder.removeListener(mInternalCallback);
139 
140             } catch (DeadObjectException x) {
141                 /* We don't care if we receive a DOE at this point.
142                  * DOE is as good as success as far as we are concerned.
143                  */
144 
145             } catch (RemoteException x) {
146                 throw x.rethrowAsRuntimeException();
147             }
148 
149             if (mCallback != null) {
150                 mHandler.post(() -> mCallback.onClosed());
151             }
152         }
153 
154         mCallback = null;
155         mIsClosed = true;
156     }
157 
158     /** TODO: doc */
159     @NonNull
getBeaconInfo()160     public LowpanBeaconInfo getBeaconInfo() {
161         return mBeaconInfo;
162     }
163 
164     /** TODO: doc */
sendToCommissioner(@onNull byte[] packet)165     public void sendToCommissioner(@NonNull byte[] packet) {
166         if (!mIsClosed) {
167             try {
168                 mBinder.sendToCommissioner(packet);
169 
170             } catch (DeadObjectException x) {
171                 /* This method is a best-effort delivery.
172                  * We don't care if we receive a DOE at this point.
173                  */
174 
175             } catch (RemoteException x) {
176                 throw x.rethrowAsRuntimeException();
177             }
178         }
179     }
180 
181     /** TODO: doc */
setCallback(@ullable Callback cb, @Nullable Handler handler)182     public synchronized void setCallback(@Nullable Callback cb, @Nullable Handler handler) {
183         if (!mIsClosed) {
184             /* This class can be created with or without a default looper.
185              * Also, this method can be called with or without a specific
186              * handler. If a handler is specified, it is to always be used.
187              * Otherwise, if there was a Looper specified when this object
188              * was created, we create a new handle based on that looper.
189              * Otherwise we just create a default handler object. Since we
190              * don't really know how the previous handler was created, we
191              * end up always replacing it here. This isn't a huge problem
192              * because this method should be called infrequently.
193              */
194             if (handler != null) {
195                 mHandler = handler;
196             } else if (mLooper != null) {
197                 mHandler = new Handler(mLooper);
198             } else {
199                 mHandler = new Handler();
200             }
201             mCallback = cb;
202         }
203     }
204 
205     /** TODO: doc */
close()206     public synchronized void close() {
207         if (!mIsClosed) {
208             try {
209                 mBinder.closeCommissioningSession();
210 
211                 lockedCleanup();
212 
213             } catch (DeadObjectException x) {
214                 /* We don't care if we receive a DOE at this point.
215                  * DOE is as good as success as far as we are concerned.
216                  */
217 
218             } catch (RemoteException x) {
219                 throw x.rethrowAsRuntimeException();
220             }
221         }
222     }
223 }
224