Merge "Address Robin's code review comments in initial FlpHal submission." into klp-dev

This commit is contained in:
destradaa
2013-08-10 00:31:58 +00:00
committed by Android (Google) Code Review
6 changed files with 158 additions and 56 deletions

View File

@@ -9,7 +9,7 @@
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIOS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
@@ -21,20 +21,26 @@ import android.hardware.location.IFusedLocationHardwareSink;
import android.location.Location; import android.location.Location;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException; import android.os.RemoteException;
import android.util.Log; import android.util.Log;
import java.util.ArrayList; import java.util.HashMap;
import java.util.Map;
/** /**
* Class that exposes IFusedLocationHardware functionality to unbundled services. * Class that exposes IFusedLocationHardware functionality to unbundled services.
* Namely this is used by GmsCore Fused Location Provider.
*/ */
public final class FusedLocationHardware { public final class FusedLocationHardware {
private final String TAG = "FusedLocationHardware"; private final String TAG = "FusedLocationHardware";
private IFusedLocationHardware mLocationHardware; private IFusedLocationHardware mLocationHardware;
ArrayList<FusedLocationHardwareSink> mSinkList = new ArrayList<FusedLocationHardwareSink>();
// the list uses a copy-on-write pattern to update its contents
HashMap<FusedLocationHardwareSink, DispatcherHandler> mSinkList =
new HashMap<FusedLocationHardwareSink, DispatcherHandler>();
private IFusedLocationHardwareSink mInternalSink = new IFusedLocationHardwareSink.Stub() { private IFusedLocationHardwareSink mInternalSink = new IFusedLocationHardwareSink.Stub() {
@Override @Override
@@ -48,6 +54,9 @@ public final class FusedLocationHardware {
} }
}; };
/**
* @hide
*/
public FusedLocationHardware(IFusedLocationHardware locationHardware) { public FusedLocationHardware(IFusedLocationHardware locationHardware) {
mLocationHardware = locationHardware; mLocationHardware = locationHardware;
} }
@@ -55,19 +64,24 @@ public final class FusedLocationHardware {
/* /*
* Methods to provide a Facade for IFusedLocationHardware * Methods to provide a Facade for IFusedLocationHardware
*/ */
public void registerSink(FusedLocationHardwareSink sink) { public void registerSink(FusedLocationHardwareSink sink, Looper looper) {
if(sink == null) { if(sink == null || looper == null) {
return; throw new IllegalArgumentException("Parameter sink and looper cannot be null.");
} }
boolean registerSink = false; boolean registerSink;
synchronized (mSinkList) { synchronized (mSinkList) {
// register only on first insertion // register only on first insertion
registerSink = mSinkList.size() == 0; registerSink = mSinkList.size() == 0;
// guarantee uniqueness // guarantee uniqueness
if(!mSinkList.contains(sink)) { if(mSinkList.containsKey(sink)) {
mSinkList.add(sink); return;
} }
HashMap<FusedLocationHardwareSink, DispatcherHandler> newSinkList =
new HashMap<FusedLocationHardwareSink, DispatcherHandler>(mSinkList);
newSinkList.put(sink, new DispatcherHandler(looper));
mSinkList = newSinkList;
} }
if(registerSink) { if(registerSink) {
@@ -81,14 +95,23 @@ public final class FusedLocationHardware {
public void unregisterSink(FusedLocationHardwareSink sink) { public void unregisterSink(FusedLocationHardwareSink sink) {
if(sink == null) { if(sink == null) {
throw new IllegalArgumentException("Parameter sink cannot be null.");
}
boolean unregisterSink;
synchronized(mSinkList) {
if(!mSinkList.containsKey(sink)) {
//done
return; return;
} }
boolean unregisterSink = false; HashMap<FusedLocationHardwareSink, DispatcherHandler> newSinkList =
synchronized(mSinkList) { new HashMap<FusedLocationHardwareSink, DispatcherHandler>(mSinkList);
mSinkList.remove(sink); newSinkList.remove(sink);
//unregister after the last sink //unregister after the last sink
unregisterSink = mSinkList.size() == 0; unregisterSink = newSinkList.size() == 0;
mSinkList = newSinkList;
} }
if(unregisterSink) { if(unregisterSink) {
@@ -176,27 +199,82 @@ public final class FusedLocationHardware {
} }
/* /*
* Helper methods * Helper methods and classes
*/ */
private void dispatchLocations(Location[] locations) { private class DispatcherHandler extends Handler {
ArrayList<FusedLocationHardwareSink> sinks = null; public static final int DISPATCH_LOCATION = 1;
synchronized (mSinkList) { public static final int DISPATCH_DIAGNOSTIC_DATA = 2;
sinks = new ArrayList<FusedLocationHardwareSink>(mSinkList);
public DispatcherHandler(Looper looper) {
super(looper, null /*callback*/ , true /*async*/);
} }
for(FusedLocationHardwareSink sink : sinks) { @Override
sink.onLocationAvailable(locations); public void handleMessage(Message message) {
MessageCommand command = (MessageCommand) message.obj;
switch(message.what) {
case DISPATCH_LOCATION:
command.dispatchLocation();
break;
case DISPATCH_DIAGNOSTIC_DATA:
command.dispatchDiagnosticData();
default:
Log.e(TAG, "Invalid dispatch message");
break;
}
}
}
private class MessageCommand {
private final FusedLocationHardwareSink mSink;
private final Location[] mLocations;
private final String mData;
public MessageCommand(
FusedLocationHardwareSink sink,
Location[] locations,
String data) {
mSink = sink;
mLocations = locations;
mData = data;
}
public void dispatchLocation() {
mSink.onLocationAvailable(mLocations);
}
public void dispatchDiagnosticData() {
mSink.onDiagnosticDataAvailable(mData);
}
}
private void dispatchLocations(Location[] locations) {
HashMap<FusedLocationHardwareSink, DispatcherHandler> sinks;
synchronized (mSinkList) {
sinks = mSinkList;
}
for(Map.Entry<FusedLocationHardwareSink, DispatcherHandler> entry : sinks.entrySet()) {
Message message = Message.obtain(
entry.getValue(),
DispatcherHandler.DISPATCH_LOCATION,
new MessageCommand(entry.getKey(), locations, null /*data*/));
message.sendToTarget();
} }
} }
private void dispatchDiagnosticData(String data) { private void dispatchDiagnosticData(String data) {
ArrayList<FusedLocationHardwareSink> sinks = null; HashMap<FusedLocationHardwareSink, DispatcherHandler> sinks;
synchronized(mSinkList) { synchronized(mSinkList) {
sinks = new ArrayList<FusedLocationHardwareSink>(mSinkList); sinks = mSinkList;
} }
for(FusedLocationHardwareSink sink : sinks) { for(Map.Entry<FusedLocationHardwareSink, DispatcherHandler> entry : sinks.entrySet()) {
sink.onDiagnosticDataAvailable(data); Message message = Message.obtain(
entry.getValue(),
DispatcherHandler.DISPATCH_DIAGNOSTIC_DATA,
new MessageCommand(entry.getKey(), null /*locations*/, data));
message.sendToTarget();
} }
} }
} }

View File

@@ -20,7 +20,6 @@ import android.location.Location;
/** /**
* Base class for sinks to interact with FusedLocationHardware. * Base class for sinks to interact with FusedLocationHardware.
* This is mainly used by GmsCore Fused Provider.
*/ */
public abstract class FusedLocationHardwareSink { public abstract class FusedLocationHardwareSink {
/* /*

View File

@@ -28,8 +28,6 @@ import android.os.IBinder;
* *
* <p>IMPORTANT: This class is effectively a public API for unbundled applications, and must remain * <p>IMPORTANT: This class is effectively a public API for unbundled applications, and must remain
* API stable. See README.txt in the root of this package for more information. * API stable. See README.txt in the root of this package for more information.
*
* @hide
*/ */
public abstract class FusedProvider { public abstract class FusedProvider {
private IFusedProvider.Stub mProvider = new IFusedProvider.Stub() { private IFusedProvider.Stub mProvider = new IFusedProvider.Stub() {

View File

@@ -437,7 +437,10 @@ public class LocationManagerService extends ILocationManager.Stub {
FusedProxy fusedProxy = FusedProxy.createAndBind( FusedProxy fusedProxy = FusedProxy.createAndBind(
mContext, mContext,
mLocationHandler, mLocationHandler,
flpHardwareProvider.getLocationHardware()); flpHardwareProvider.getLocationHardware(),
com.android.internal.R.bool.config_enableFusedLocationOverlay,
com.android.internal.R.string.config_fusedLocationProviderPackageName,
com.android.internal.R.array.config_locationProviderPackageNames);
if(fusedProxy == null) { if(fusedProxy == null) {
Slog.e(TAG, "No FusedProvider found."); Slog.e(TAG, "No FusedProvider found.");

View File

@@ -28,11 +28,10 @@ import android.location.LocationManager;
import android.content.Context; import android.content.Context;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Looper;
import android.os.RemoteException; import android.os.RemoteException;
import android.os.SystemClock; import android.os.SystemClock;
import android.util.Log; import android.util.Log;
import android.util.Slog;
/** /**
* This class is an interop layer for JVM types and the JNI code that interacts * This class is an interop layer for JVM types and the JNI code that interacts
@@ -48,6 +47,7 @@ public class FlpHardwareProvider {
private final static String TAG = "FlpHardwareProvider"; private final static String TAG = "FlpHardwareProvider";
private final Context mContext; private final Context mContext;
private final Object mLocationSinkLock = new Object();
public static FlpHardwareProvider getInstance(Context context) { public static FlpHardwareProvider getInstance(Context context) {
if (sSingletonInstance == null) { if (sSingletonInstance == null) {
@@ -61,7 +61,6 @@ public class FlpHardwareProvider {
mContext = context; mContext = context;
// register for listening for passive provider data // register for listening for passive provider data
Handler handler = new Handler();
LocationManager manager = (LocationManager) mContext.getSystemService( LocationManager manager = (LocationManager) mContext.getSystemService(
Context.LOCATION_SERVICE); Context.LOCATION_SERVICE);
manager.requestLocationUpdates( manager.requestLocationUpdates(
@@ -69,7 +68,7 @@ public class FlpHardwareProvider {
0 /* minTime */, 0 /* minTime */,
0 /* minDistance */, 0 /* minDistance */,
new NetworkLocationListener(), new NetworkLocationListener(),
handler.getLooper()); Looper.myLooper());
} }
public static boolean isSupported() { public static boolean isSupported() {
@@ -87,9 +86,13 @@ public class FlpHardwareProvider {
location.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos()); location.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
} }
IFusedLocationHardwareSink sink;
synchronized (mLocationSinkLock) {
sink = mLocationSink;
}
try { try {
if (mLocationSink != null) { if (sink != null) {
mLocationSink.onLocationAvailable(locations); sink.onLocationAvailable(locations);
} }
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(TAG, "RemoteException calling onLocationAvailable"); Log.e(TAG, "RemoteException calling onLocationAvailable");
@@ -98,9 +101,13 @@ public class FlpHardwareProvider {
// FlpDiagnosticCallbacks members // FlpDiagnosticCallbacks members
private void onDataReport(String data) { private void onDataReport(String data) {
IFusedLocationHardwareSink sink;
synchronized (mLocationSinkLock) {
sink = mLocationSink;
}
try { try {
if (mLocationSink != null) { if (mLocationSink != null) {
mLocationSink.onDiagnosticDataAvailable(data); sink.onDiagnosticDataAvailable(data);
} }
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(TAG, "RemoteException calling onDiagnosticDataAvailable"); Log.e(TAG, "RemoteException calling onDiagnosticDataAvailable");
@@ -199,21 +206,26 @@ public class FlpHardwareProvider {
private final IFusedLocationHardware mLocationHardware = new IFusedLocationHardware.Stub() { private final IFusedLocationHardware mLocationHardware = new IFusedLocationHardware.Stub() {
@Override @Override
public void registerSink(IFusedLocationHardwareSink eventSink) { public void registerSink(IFusedLocationHardwareSink eventSink) {
synchronized (mLocationSinkLock) {
// only one sink is allowed at the moment // only one sink is allowed at the moment
if (mLocationSink != null) { if (mLocationSink != null) {
throw new RuntimeException("IFusedLocationHardware does not support multiple sinks"); throw new RuntimeException(
"IFusedLocationHardware does not support multiple sinks");
} }
mLocationSink = eventSink; mLocationSink = eventSink;
} }
}
@Override @Override
public void unregisterSink(IFusedLocationHardwareSink eventSink) { public void unregisterSink(IFusedLocationHardwareSink eventSink) {
synchronized (mLocationSinkLock) {
// don't throw if the sink is not registered, simply make it a no-op // don't throw if the sink is not registered, simply make it a no-op
if (mLocationSink == eventSink) { if (mLocationSink == eventSink) {
mLocationSink = null; mLocationSink = null;
} }
} }
}
@Override @Override
public int getSupportedBatchSize() { public int getSupportedBatchSize() {

View File

@@ -33,10 +33,8 @@ import android.util.Log;
*/ */
public final class FusedProxy { public final class FusedProxy {
private final String TAG = "FusedProxy"; private final String TAG = "FusedProxy";
private final ServiceWatcher mServiceWatcher;
private ServiceWatcher mServiceWatcher; private final FusedLocationHardwareSecure mLocationHardware;
private FusedLocationHardwareSecure mLocationHardware;
/** /**
* Constructor of the class. * Constructor of the class.
@@ -46,7 +44,13 @@ public final class FusedProxy {
* @param handler The handler needed for construction. * @param handler The handler needed for construction.
* @param locationHardware The instance of the Fused location hardware assigned to the proxy. * @param locationHardware The instance of the Fused location hardware assigned to the proxy.
*/ */
private FusedProxy(Context context, Handler handler, IFusedLocationHardware locationHardware) { private FusedProxy(
Context context,
Handler handler,
IFusedLocationHardware locationHardware,
int overlaySwitchResId,
int defaultServicePackageNameResId,
int initialPackageNameResId) {
mLocationHardware = new FusedLocationHardwareSecure( mLocationHardware = new FusedLocationHardwareSecure(
locationHardware, locationHardware,
context, context,
@@ -63,9 +67,9 @@ public final class FusedProxy {
context, context,
TAG, TAG,
"com.android.location.service.FusedProvider", "com.android.location.service.FusedProvider",
com.android.internal.R.bool.config_enableFusedLocationOverlay, overlaySwitchResId,
com.android.internal.R.string.config_fusedLocationProviderPackageName, defaultServicePackageNameResId,
com.android.internal.R.array.config_locationProviderPackageNames, initialPackageNameResId,
newServiceWork, newServiceWork,
handler); handler);
} }
@@ -82,9 +86,17 @@ public final class FusedProxy {
public static FusedProxy createAndBind( public static FusedProxy createAndBind(
Context context, Context context,
Handler handler, Handler handler,
IFusedLocationHardware locationHardware IFusedLocationHardware locationHardware,
) { int overlaySwitchResId,
FusedProxy fusedProxy = new FusedProxy(context, handler, locationHardware); int defaultServicePackageNameResId,
int initialPackageNameResId) {
FusedProxy fusedProxy = new FusedProxy(
context,
handler,
locationHardware,
overlaySwitchResId,
defaultServicePackageNameResId,
initialPackageNameResId);
// try to bind the Fused provider // try to bind the Fused provider
if (!fusedProxy.mServiceWatcher.start()) { if (!fusedProxy.mServiceWatcher.start()) {