blob: e25fb7d35ebc2798c5d39b687656025a97c38a52 [file] [log] [blame]
// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package io.v.location;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationManager;
import android.os.IBinder;
import android.util.Log;
import android.widget.Toast;
import com.google.common.collect.Lists;
import java.util.Arrays;
import java.util.List;
import io.v.android.v23.V;
import io.v.v23.context.VContext;
import io.v.v23.rpc.ListenSpec;
import io.v.v23.rpc.Server;
import io.v.v23.rpc.ServerCall;
import io.v.v23.security.BlessingPattern;
import io.v.v23.security.Blessings;
import io.v.v23.security.VCertificate;
import io.v.v23.security.VPrincipal;
import io.v.v23.security.VSecurity;
import io.v.v23.verror.VException;
import io.v.v23.vom.VomUtil;
public class LocationService extends Service {
private static final String TAG = "LocationService";
VContext mBaseContext;
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
mBaseContext = V.init(this);
String blessingsVom = intent.getStringExtra(LocationActivity.BLESSINGS_KEY);
if (blessingsVom == null || blessingsVom.isEmpty()) {
String msg = "Couldn't start LocationService: null or empty encoded blessings.";
Toast.makeText(this, msg, Toast.LENGTH_LONG).show();
Log.i(TAG, msg);
return START_REDELIVER_INTENT;
}
try {
Blessings blessings =
(Blessings) VomUtil.decodeFromString(blessingsVom, Blessings.class);
if (blessings == null) {
String msg = "Couldn't start LocationService: null blessings.";
Toast.makeText(this, msg, Toast.LENGTH_LONG).show();
Log.i(TAG, msg);
return START_REDELIVER_INTENT;
}
storeBlessings(blessings);
startLocationService(determineMountPoint(blessings));
} catch (VException e) {
String msg = "Couldn't start LocationService: " + e.getMessage();
Toast.makeText(this, msg, Toast.LENGTH_LONG).show();
Log.i(TAG, msg);
}
return START_REDELIVER_INTENT;
}
private void startLocationService(String mountPoint) throws VException {
VeyronLocationService locationService = new VeyronLocationService(
(LocationManager) getSystemService(Context.LOCATION_SERVICE));
ListenSpec spec = V.getListenSpec(mBaseContext).withProxy("proxy");
Log.i(TAG, "Mounting server at " + mountPoint);
VContext ctx = V.withNewServer(
V.withListenSpec(mBaseContext, spec), mountPoint, locationService, null);
Server server = V.getServer(ctx);
Log.i(TAG, "Listening on endpoints: " + Arrays.toString(
server.getStatus().getEndpoints()));
Toast.makeText(this, "Success", Toast.LENGTH_SHORT).show();
}
// Update vanadium state with the new blessings.
private void storeBlessings(Blessings blessings) throws VException {
VPrincipal p = V.getPrincipal(mBaseContext);
p.blessingStore().setDefaultBlessings(blessings);
p.blessingStore().set(blessings, new BlessingPattern("..."));
VSecurity.addToRoots(p, blessings);
}
@Override
public IBinder onBind(Intent intent) {
// Binding not allowed.
return null;
}
private static class VeyronLocationService implements LocationServer {
private final LocationManager manager;
private VeyronLocationService(LocationManager manager) {
this.manager = manager;
}
@Override
public LatLng get(VContext context, ServerCall call) throws VException {
Criteria criteria = new Criteria();
criteria.setAccuracy(Criteria.NO_REQUIREMENT);
String provider = manager.getBestProvider(criteria, true);
if (provider == null || provider.isEmpty()) {
throw new VException("Couldn't find any location providers on the device.");
}
Location location = manager.getLastKnownLocation(provider);
if (location == null) {
throw new VException("Got null location.");
}
return new LatLng(location.getLatitude(), location.getLongitude());
}
}
private static String determineMountPoint(Blessings blessings) {
String name = userEmailFromBlessings(blessings);
return name.isEmpty() ? "" : "users/" + name + "/location";
}
private static String userEmailFromBlessings(Blessings blessings) {
for (List<VCertificate> chain : blessings.getCertificateChains()) {
for (VCertificate certificate : Lists.reverse(chain)) {
if (certificate.getExtension().contains("@")) {
return certificate.getExtension();
}
}
}
Log.w(TAG, "Could not determine name from blessings '" + blessings + "'");
return "";
}
}