Home | History | Annotate | Download | only in provider
      1 /*
      2  * Copyright (C) 2013 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 com.android.location.provider;
     18 
     19 import android.hardware.location.IFusedLocationHardware;
     20 import android.hardware.location.IFusedLocationHardwareSink;
     21 
     22 import android.location.Location;
     23 
     24 import android.os.Handler;
     25 import android.os.Looper;
     26 import android.os.Message;
     27 import android.os.RemoteException;
     28 import android.util.Log;
     29 
     30 import java.util.HashMap;
     31 import java.util.Map;
     32 
     33 /**
     34  * Class that exposes IFusedLocationHardware functionality to unbundled services.
     35  */
     36 public final class FusedLocationHardware {
     37     private final String TAG = "FusedLocationHardware";
     38 
     39     private IFusedLocationHardware mLocationHardware;
     40 
     41     // the list uses a copy-on-write pattern to update its contents
     42     HashMap<FusedLocationHardwareSink, DispatcherHandler> mSinkList =
     43             new HashMap<FusedLocationHardwareSink, DispatcherHandler>();
     44 
     45     private IFusedLocationHardwareSink mInternalSink = new IFusedLocationHardwareSink.Stub() {
     46         @Override
     47         public void onLocationAvailable(Location[] locations) {
     48             dispatchLocations(locations);
     49         }
     50 
     51         @Override
     52         public void onDiagnosticDataAvailable(String data) {
     53             dispatchDiagnosticData(data);
     54         }
     55     };
     56 
     57     /**
     58      * @hide
     59      */
     60     public FusedLocationHardware(IFusedLocationHardware locationHardware) {
     61         mLocationHardware = locationHardware;
     62     }
     63 
     64     /*
     65      * Methods to provide a Facade for IFusedLocationHardware
     66      */
     67     public void registerSink(FusedLocationHardwareSink sink, Looper looper) {
     68         if(sink == null || looper == null) {
     69             throw new IllegalArgumentException("Parameter sink and looper cannot be null.");
     70         }
     71 
     72         boolean registerSink;
     73         synchronized (mSinkList) {
     74             // register only on first insertion
     75             registerSink = mSinkList.size() == 0;
     76             // guarantee uniqueness
     77             if(mSinkList.containsKey(sink)) {
     78                 return;
     79             }
     80 
     81             HashMap<FusedLocationHardwareSink, DispatcherHandler> newSinkList =
     82                     new HashMap<FusedLocationHardwareSink, DispatcherHandler>(mSinkList);
     83             newSinkList.put(sink, new DispatcherHandler(looper));
     84             mSinkList = newSinkList;
     85         }
     86 
     87         if(registerSink) {
     88             try {
     89                 mLocationHardware.registerSink(mInternalSink);
     90             } catch(RemoteException e) {
     91                 Log.e(TAG, "RemoteException at registerSink");
     92             }
     93         }
     94     }
     95 
     96     public void unregisterSink(FusedLocationHardwareSink sink) {
     97         if(sink == null) {
     98             throw new IllegalArgumentException("Parameter sink cannot be null.");
     99         }
    100 
    101         boolean unregisterSink;
    102         synchronized(mSinkList) {
    103             if(!mSinkList.containsKey(sink)) {
    104                 //done
    105                 return;
    106             }
    107 
    108             HashMap<FusedLocationHardwareSink, DispatcherHandler> newSinkList =
    109                     new HashMap<FusedLocationHardwareSink, DispatcherHandler>(mSinkList);
    110             newSinkList.remove(sink);
    111             //unregister after the last sink
    112             unregisterSink = newSinkList.size() == 0;
    113 
    114             mSinkList = newSinkList;
    115         }
    116 
    117         if(unregisterSink) {
    118             try {
    119                 mLocationHardware.unregisterSink(mInternalSink);
    120             } catch(RemoteException e) {
    121                 Log.e(TAG, "RemoteException at unregisterSink");
    122             }
    123         }
    124     }
    125 
    126     public int getSupportedBatchSize() {
    127         try {
    128             return mLocationHardware.getSupportedBatchSize();
    129         } catch(RemoteException e) {
    130             Log.e(TAG, "RemoteException at getSupportedBatchSize");
    131             return 0;
    132         }
    133     }
    134 
    135     public void startBatching(int id, GmsFusedBatchOptions batchOptions) {
    136         try {
    137             mLocationHardware.startBatching(id, batchOptions.getParcelableOptions());
    138         } catch(RemoteException e) {
    139             Log.e(TAG, "RemoteException at startBatching");
    140         }
    141     }
    142 
    143     public void stopBatching(int id) {
    144         try {
    145             mLocationHardware.stopBatching(id);
    146         } catch(RemoteException e) {
    147             Log.e(TAG, "RemoteException at stopBatching");
    148         }
    149     }
    150 
    151     public void updateBatchingOptions(int id, GmsFusedBatchOptions batchOptions) {
    152         try {
    153             mLocationHardware.updateBatchingOptions(id, batchOptions.getParcelableOptions());
    154         } catch(RemoteException e) {
    155             Log.e(TAG, "RemoteException at updateBatchingOptions");
    156         }
    157     }
    158 
    159     public void requestBatchOfLocations(int batchSizeRequest) {
    160         try {
    161             mLocationHardware.requestBatchOfLocations(batchSizeRequest);
    162         } catch(RemoteException e) {
    163             Log.e(TAG, "RemoteException at requestBatchOfLocations");
    164         }
    165     }
    166 
    167     public boolean supportsDiagnosticDataInjection() {
    168         try {
    169             return mLocationHardware.supportsDiagnosticDataInjection();
    170         } catch(RemoteException e) {
    171             Log.e(TAG, "RemoteException at supportsDiagnisticDataInjection");
    172             return false;
    173         }
    174     }
    175 
    176     public void injectDiagnosticData(String data) {
    177         try {
    178             mLocationHardware.injectDiagnosticData(data);
    179         } catch(RemoteException e) {
    180             Log.e(TAG, "RemoteException at injectDiagnosticData");
    181         }
    182     }
    183 
    184     public boolean supportsDeviceContextInjection() {
    185         try {
    186             return mLocationHardware.supportsDeviceContextInjection();
    187         } catch(RemoteException e) {
    188             Log.e(TAG, "RemoteException at supportsDeviceContextInjection");
    189             return false;
    190         }
    191     }
    192 
    193     public void injectDeviceContext(int deviceEnabledContext) {
    194         try {
    195             mLocationHardware.injectDeviceContext(deviceEnabledContext);
    196         } catch(RemoteException e) {
    197             Log.e(TAG, "RemoteException at injectDeviceContext");
    198         }
    199     }
    200 
    201     /*
    202      * Helper methods and classes
    203      */
    204     private class DispatcherHandler extends Handler {
    205         public static final int DISPATCH_LOCATION = 1;
    206         public static final int DISPATCH_DIAGNOSTIC_DATA = 2;
    207 
    208         public DispatcherHandler(Looper looper) {
    209             super(looper, null /*callback*/ , true /*async*/);
    210         }
    211 
    212         @Override
    213         public void handleMessage(Message message) {
    214             MessageCommand command = (MessageCommand) message.obj;
    215             switch(message.what) {
    216                 case DISPATCH_LOCATION:
    217                     command.dispatchLocation();
    218                     break;
    219                 case DISPATCH_DIAGNOSTIC_DATA:
    220                     command.dispatchDiagnosticData();
    221                 default:
    222                     Log.e(TAG, "Invalid dispatch message");
    223                     break;
    224             }
    225         }
    226     }
    227 
    228     private class MessageCommand {
    229         private final FusedLocationHardwareSink mSink;
    230         private final Location[] mLocations;
    231         private final String mData;
    232 
    233         public MessageCommand(
    234                 FusedLocationHardwareSink sink,
    235                 Location[] locations,
    236                 String data) {
    237             mSink = sink;
    238             mLocations = locations;
    239             mData = data;
    240         }
    241 
    242         public void dispatchLocation() {
    243             mSink.onLocationAvailable(mLocations);
    244         }
    245 
    246         public void dispatchDiagnosticData() {
    247             mSink.onDiagnosticDataAvailable(mData);
    248         }
    249     }
    250 
    251     private void dispatchLocations(Location[] locations) {
    252         HashMap<FusedLocationHardwareSink, DispatcherHandler> sinks;
    253         synchronized (mSinkList) {
    254             sinks = mSinkList;
    255         }
    256 
    257         for(Map.Entry<FusedLocationHardwareSink, DispatcherHandler> entry : sinks.entrySet()) {
    258             Message message = Message.obtain(
    259                     entry.getValue(),
    260                     DispatcherHandler.DISPATCH_LOCATION,
    261                     new MessageCommand(entry.getKey(), locations, null /*data*/));
    262             message.sendToTarget();
    263         }
    264     }
    265 
    266     private void dispatchDiagnosticData(String data) {
    267         HashMap<FusedLocationHardwareSink, DispatcherHandler> sinks;
    268         synchronized(mSinkList) {
    269             sinks = mSinkList;
    270         }
    271 
    272         for(Map.Entry<FusedLocationHardwareSink, DispatcherHandler> entry : sinks.entrySet()) {
    273             Message message = Message.obtain(
    274                     entry.getValue(),
    275                     DispatcherHandler.DISPATCH_DIAGNOSTIC_DATA,
    276                     new MessageCommand(entry.getKey(), null /*locations*/, data));
    277             message.sendToTarget();
    278         }
    279     }
    280 }
    281