Home | History | Annotate | Download | only in lowpan
      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.os.Handler;
     22 import android.os.RemoteException;
     23 import android.os.ServiceSpecificException;
     24 import java.util.ArrayList;
     25 import java.util.Collection;
     26 import java.util.HashMap;
     27 import java.util.Map;
     28 
     29 /**
     30  * LoWPAN Scanner
     31  *
     32  * <p>This class allows performing network (active) scans and energy (passive) scans.
     33  *
     34  * @see LowpanInterface
     35  * @hide
     36  */
     37 // @SystemApi
     38 public class LowpanScanner {
     39     private static final String TAG = LowpanScanner.class.getSimpleName();
     40 
     41     // Public Classes
     42 
     43     /**
     44      * Callback base class for LowpanScanner
     45      *
     46      * @hide
     47      */
     48     // @SystemApi
     49     public abstract static class Callback {
     50         public void onNetScanBeacon(LowpanBeaconInfo beacon) {}
     51 
     52         public void onEnergyScanResult(LowpanEnergyScanResult result) {}
     53 
     54         public void onScanFinished() {}
     55     }
     56 
     57     // Instance Variables
     58 
     59     private ILowpanInterface mBinder;
     60     private Callback mCallback = null;
     61     private Handler mHandler = null;
     62     private ArrayList<Integer> mChannelMask = null;
     63     private int mTxPower = Integer.MAX_VALUE;
     64 
     65     // Constructors/Accessors and Exception Glue
     66 
     67     LowpanScanner(@NonNull ILowpanInterface binder) {
     68         mBinder = binder;
     69     }
     70 
     71     /** Sets an instance of {@link LowpanScanner.Callback} to receive events. */
     72     public synchronized void setCallback(@Nullable Callback cb, @Nullable Handler handler) {
     73         mCallback = cb;
     74         mHandler = handler;
     75     }
     76 
     77     /** Sets an instance of {@link LowpanScanner.Callback} to receive events. */
     78     public void setCallback(@Nullable Callback cb) {
     79         setCallback(cb, null);
     80     }
     81 
     82     /**
     83      * Sets the channel mask to use when scanning.
     84      *
     85      * @param mask The channel mask to use when scanning. If <code>null</code>, any previously set
     86      *     channel mask will be cleared and all channels not masked by the current regulatory zone
     87      *     will be scanned.
     88      */
     89     public void setChannelMask(@Nullable Collection<Integer> mask) {
     90         if (mask == null) {
     91             mChannelMask = null;
     92         } else {
     93             if (mChannelMask == null) {
     94                 mChannelMask = new ArrayList<>();
     95             } else {
     96                 mChannelMask.clear();
     97             }
     98             mChannelMask.addAll(mask);
     99         }
    100     }
    101 
    102     /**
    103      * Gets the current channel mask.
    104      *
    105      * @return the current channel mask, or <code>null</code> if no channel mask is currently set.
    106      */
    107     public @Nullable Collection<Integer> getChannelMask() {
    108         return (Collection<Integer>) mChannelMask.clone();
    109     }
    110 
    111     /**
    112      * Adds a channel to the channel mask used for scanning.
    113      *
    114      * <p>If a channel mask was previously <code>null</code>, a new one is created containing only
    115      * this channel. May be called multiple times to add additional channels ot the channel mask.
    116      *
    117      * @see #setChannelMask
    118      * @see #getChannelMask
    119      * @see #getTxPower
    120      */
    121     public void addChannel(int channel) {
    122         if (mChannelMask == null) {
    123             mChannelMask = new ArrayList<>();
    124         }
    125         mChannelMask.add(Integer.valueOf(channel));
    126     }
    127 
    128     /**
    129      * Sets the maximum transmit power to be used for active scanning.
    130      *
    131      * <p>The actual transmit power used is the lesser of this value and the currently configured
    132      * maximum transmit power for the interface.
    133      *
    134      * @see #getTxPower
    135      */
    136     public void setTxPower(int txPower) {
    137         mTxPower = txPower;
    138     }
    139 
    140     /**
    141      * Gets the maximum transmit power used for active scanning.
    142      *
    143      * @see #setTxPower
    144      */
    145     public int getTxPower() {
    146         return mTxPower;
    147     }
    148 
    149     private Map<String, Object> createScanOptionMap() {
    150         Map<String, Object> map = new HashMap();
    151 
    152         if (mChannelMask != null) {
    153             LowpanProperties.KEY_CHANNEL_MASK.putInMap(
    154                     map, mChannelMask.stream().mapToInt(i -> i).toArray());
    155         }
    156 
    157         if (mTxPower != Integer.MAX_VALUE) {
    158             LowpanProperties.KEY_MAX_TX_POWER.putInMap(map, Integer.valueOf(mTxPower));
    159         }
    160 
    161         return map;
    162     }
    163 
    164     /**
    165      * Start a network scan.
    166      *
    167      * <p>This method will return once the scan has started.
    168      *
    169      * @see #stopNetScan
    170      */
    171     public void startNetScan() throws LowpanException {
    172         Map<String, Object> map = createScanOptionMap();
    173 
    174         ILowpanNetScanCallback binderListener =
    175                 new ILowpanNetScanCallback.Stub() {
    176                     public void onNetScanBeacon(LowpanBeaconInfo beaconInfo) {
    177                         Callback callback;
    178                         Handler handler;
    179 
    180                         synchronized (LowpanScanner.this) {
    181                             callback = mCallback;
    182                             handler = mHandler;
    183                         }
    184 
    185                         if (callback == null) {
    186                             return;
    187                         }
    188 
    189                         Runnable runnable = () -> callback.onNetScanBeacon(beaconInfo);
    190 
    191                         if (handler != null) {
    192                             handler.post(runnable);
    193                         } else {
    194                             runnable.run();
    195                         }
    196                     }
    197 
    198                     public void onNetScanFinished() {
    199                         Callback callback;
    200                         Handler handler;
    201 
    202                         synchronized (LowpanScanner.this) {
    203                             callback = mCallback;
    204                             handler = mHandler;
    205                         }
    206 
    207                         if (callback == null) {
    208                             return;
    209                         }
    210 
    211                         Runnable runnable = () -> callback.onScanFinished();
    212 
    213                         if (handler != null) {
    214                             handler.post(runnable);
    215                         } else {
    216                             runnable.run();
    217                         }
    218                     }
    219                 };
    220 
    221         try {
    222             mBinder.startNetScan(map, binderListener);
    223 
    224         } catch (RemoteException x) {
    225             throw x.rethrowAsRuntimeException();
    226 
    227         } catch (ServiceSpecificException x) {
    228             throw LowpanException.rethrowFromServiceSpecificException(x);
    229         }
    230     }
    231 
    232     /**
    233      * Stop a network scan currently in progress.
    234      *
    235      * @see #startNetScan
    236      */
    237     public void stopNetScan() {
    238         try {
    239             mBinder.stopNetScan();
    240 
    241         } catch (RemoteException x) {
    242             throw x.rethrowAsRuntimeException();
    243         }
    244     }
    245 
    246     /**
    247      * Start an energy scan.
    248      *
    249      * <p>This method will return once the scan has started.
    250      *
    251      * @see #stopEnergyScan
    252      */
    253     public void startEnergyScan() throws LowpanException {
    254         Map<String, Object> map = createScanOptionMap();
    255 
    256         ILowpanEnergyScanCallback binderListener =
    257                 new ILowpanEnergyScanCallback.Stub() {
    258                     public void onEnergyScanResult(int channel, int rssi) {
    259                         Callback callback = mCallback;
    260                         Handler handler = mHandler;
    261 
    262                         if (callback == null) {
    263                             return;
    264                         }
    265 
    266                         Runnable runnable =
    267                                 () -> {
    268                                     if (callback != null) {
    269                                         LowpanEnergyScanResult result =
    270                                                 new LowpanEnergyScanResult();
    271                                         result.setChannel(channel);
    272                                         result.setMaxRssi(rssi);
    273                                         callback.onEnergyScanResult(result);
    274                                     }
    275                                 };
    276 
    277                         if (handler != null) {
    278                             handler.post(runnable);
    279                         } else {
    280                             runnable.run();
    281                         }
    282                     }
    283 
    284                     public void onEnergyScanFinished() {
    285                         Callback callback = mCallback;
    286                         Handler handler = mHandler;
    287 
    288                         if (callback == null) {
    289                             return;
    290                         }
    291 
    292                         Runnable runnable = () -> callback.onScanFinished();
    293 
    294                         if (handler != null) {
    295                             handler.post(runnable);
    296                         } else {
    297                             runnable.run();
    298                         }
    299                     }
    300                 };
    301 
    302         try {
    303             mBinder.startEnergyScan(map, binderListener);
    304 
    305         } catch (RemoteException x) {
    306             throw x.rethrowAsRuntimeException();
    307 
    308         } catch (ServiceSpecificException x) {
    309             throw LowpanException.rethrowFromServiceSpecificException(x);
    310         }
    311     }
    312 
    313     /**
    314      * Stop an energy scan currently in progress.
    315      *
    316      * @see #startEnergyScan
    317      */
    318     public void stopEnergyScan() {
    319         try {
    320             mBinder.stopEnergyScan();
    321 
    322         } catch (RemoteException x) {
    323             throw x.rethrowAsRuntimeException();
    324         }
    325     }
    326 }
    327