Mock GPS location issue - java

I'm developing an APP that get user specified latitude,longitude, and altitude, then fake this GPS location on the phone, and show that I am at that location in google map. I have the required permission on manifest file and mocked location is enabled in developer settings.
LocationManager lm = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
//lm.clearTestProviderEnabled(mocLocationProvider);
lm.addTestProvider(mocLocationProvider, false, false, false, false, false, false, false, 0, 10);
lm.setTestProviderEnabled(mocLocationProvider, true);
mockLocation = new Location(mocLocationProvider); // a string
mockLocation.setLatitude(Integer.parseInt(latitude.getText().toString())); // double
mockLocation.setLongitude(Integer.parseInt(longitude.getText().toString()));
mockLocation.setAltitude(Integer.parseInt(altitude.getText().toString()));
mockLocation.setTime(System.currentTimeMillis());
lm.setTestProviderLocation( mocLocationProvider, mockLocation);
But looks like my GPS location is not changed at all on google map, what is the problem?
Update: I just installed an app called "fake GPS location" on my phone and that app works fine, but I still don't know what's wrong with my code, but I think mine is a formal way to achieve this.
Update #2: Although some of similar applications can run on my phone, but I found some exceptions, http://www.cowlumbus.nl/forum/MockGpsProvider.zip, this app is not working on my phone. can someone help me with this issue? millions of thanks! I'm not getting any error message when setting the location each time.
Update#3 : I noticed that this app is fairly old, so it does not run on 4.1. if so, how to do the same thing in the new version? my phone is samsung galaxy s3, hope it helps.
Update#4: for your info, the code from app in my update#2 is:
package nl.cowlumbus.android.mockgps;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import android.app.Activity;
import android.content.Context;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
public class MockGpsProviderActivity extends Activity implements LocationListener {
public static final String LOG_TAG = "MockGpsProviderActivity";
private static final String MOCK_GPS_PROVIDER_INDEX = "GpsMockProviderIndex";
private MockGpsProvider mMockGpsProviderTask = null;
private Integer mMockGpsProviderIndex = 0;
/** Called when the activity is first created. */
/* (non-Javadoc)
* #see android.app.Activity#onCreate(android.os.Bundle)
*/
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
/** Use saved instance state if necessary. */
if(savedInstanceState instanceof Bundle) {
/** Let's find out where we were. */
mMockGpsProviderIndex = savedInstanceState.getInt(MOCK_GPS_PROVIDER_INDEX, 0);
}
/** Setup GPS. */
LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
if(locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)){
// use real GPS provider if enabled on the device
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this);
}
else if(!locationManager.isProviderEnabled(MockGpsProvider.GPS_MOCK_PROVIDER)) {
// otherwise enable the mock GPS provider
locationManager.addTestProvider(MockGpsProvider.GPS_MOCK_PROVIDER, false, false,
false, false, true, false, false, 0, 5);
locationManager.setTestProviderEnabled(MockGpsProvider.GPS_MOCK_PROVIDER, true);
}
if(locationManager.isProviderEnabled(MockGpsProvider.GPS_MOCK_PROVIDER)) {
locationManager.requestLocationUpdates(MockGpsProvider.GPS_MOCK_PROVIDER, 0, 0, this);
/** Load mock GPS data from file and create mock GPS provider. */
try {
// create a list of Strings that can dynamically grow
List<String> data = new ArrayList<String>();
/** read a CSV file containing WGS84 coordinates from the 'assets' folder
* (The website http://www.gpsies.com offers downloadable tracks. Select
* a track and download it as a CSV file. Then add it to your assets folder.)
*/
InputStream is = getAssets().open("mock_gps_data.csv");
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
// add each line in the file to the list
String line = null;
while ((line = reader.readLine()) != null) {
data.add(line);
}
// convert to a simple array so we can pass it to the AsyncTask
String[] coordinates = new String[data.size()];
data.toArray(coordinates);
// create new AsyncTask and pass the list of GPS coordinates
mMockGpsProviderTask = new MockGpsProvider();
mMockGpsProviderTask.execute(coordinates);
}
catch (Exception e) {}
}
}
#Override
public void onDestroy() {
super.onDestroy();
// stop the mock GPS provider by calling the 'cancel(true)' method
try {
mMockGpsProviderTask.cancel(true);
mMockGpsProviderTask = null;
}
catch (Exception e) {}
// remove it from the location manager
try {
LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
locationManager.removeTestProvider(MockGpsProvider.GPS_MOCK_PROVIDER);
}
catch (Exception e) {}
}
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
// store where we are before closing the app, so we can skip to the location right away when restarting
savedInstanceState.putInt(MOCK_GPS_PROVIDER_INDEX, mMockGpsProviderIndex);
super.onSaveInstanceState(savedInstanceState);
}
#Override
public void onLocationChanged(Location location) {
// show the received location in the view
TextView view = (TextView) findViewById(R.id.text);
view.setText( "index:" + mMockGpsProviderIndex
+ "\nlongitude:" + location.getLongitude()
+ "\nlatitude:" + location.getLatitude()
+ "\naltitude:" + location.getAltitude() );
}
#Override
public void onProviderDisabled(String provider) {
// TODO Auto-generated method stub
}
#Override
public void onProviderEnabled(String provider) {
// TODO Auto-generated method stub
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
// TODO Auto-generated method stub
}
/** Define a mock GPS provider as an asynchronous task of this Activity. */
private class MockGpsProvider extends AsyncTask<String, Integer, Void> {
public static final String LOG_TAG = "GpsMockProvider";
public static final String GPS_MOCK_PROVIDER = "GpsMockProvider";
/** Keeps track of the currently processed coordinate. */
public Integer index = 0;
#Override
protected Void doInBackground(String... data) {
// process data
for (String str : data) {
// skip data if needed (see the Activity's savedInstanceState functionality)
if(index < mMockGpsProviderIndex) {
index++;
continue;
}
// let UI Thread know which coordinate we are processing
publishProgress(index);
// retrieve data from the current line of text
Double latitude = null;
Double longitude = null;
Double altitude= null;
try {
String[] parts = str.split(",");
latitude = Double.valueOf(parts[0]);
longitude = Double.valueOf(parts[1]);
altitude = Double.valueOf(parts[2]);
}
catch(NullPointerException e) { break; } // no data available
catch(Exception e) { continue; } // empty or invalid line
// translate to actual GPS location
Location location = new Location(GPS_MOCK_PROVIDER);
location.setLatitude(latitude);
location.setLongitude(longitude);
location.setAltitude(altitude);
location.setTime(System.currentTimeMillis());
location.setLatitude(latitude);
location.setLongitude(longitude);
location.setAccuracy(16F);
location.setAltitude(0D);
location.setTime(System.currentTimeMillis());
location.setBearing(0F);
// show debug message in log
Log.d(LOG_TAG, location.toString());
// provide the new location
LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
locationManager.setTestProviderLocation(GPS_MOCK_PROVIDER, location);
// sleep for a while before providing next location
try {
Thread.sleep(200);
// gracefully handle Thread interruption (important!)
if(Thread.currentThread().isInterrupted())
throw new InterruptedException("");
} catch (InterruptedException e) {
break;
}
// keep track of processed locations
index++;
}
return null;
}
#Override
protected void onProgressUpdate(Integer... values) {
Log.d(LOG_TAG, "onProgressUpdate():"+values[0]);
mMockGpsProviderIndex = values[0];
}
}
}

Problem solved: I added the following code to set my current location and it can successfully show up in google map application.
location.setLatitude(latitude);
location.setLongitude(longitude);
location.setBearing(bearing);
location.setSpeed(speed);
location.setAltitude(altitude);
location.setTime(new Date().getTime());
location.setProvider(LocationManager.GPS_PROVIDER);
location.setAccuracy(1);
Conclusion: If you want to use mock location service in the new version of android, you have to set every attribute by yourself.

Related

Getting Current Location on Android - Currently crashing only on first app launch [Broadcast error]

So I am trying to add a some functionality to my app so that it can allow the user to get his location in a editbox instead of having to type it.
At the moment I have a "working example" but there is a strange bug in it: The first time you launch the app and click the button to get the location, the app crashes. It doesn't happen ever again, unless you reinstall the app and again it will crash only once ever. This seems to only be happening to Android 6.0 + devices (doesn't crash at all on 4.4 and 5.0).
Also sometimes it doesn't really get the location, just keeps returning null.
I suppose there is a better way to get Location, but this is my first time trying to get user's location so I don't know it.
So my question is essentially 2 questions - is there a better way to get location that will work on Android 4.4+ and why is my application crashing with pretty strange error.
The error:
system_process E/ActivityManager: Sending non-protected broadcast projekt.substratum.APP_CRASHED from system 820:system/1000 pkg android
java.lang.Throwable
at com.android.server.am.ActivityManagerService.checkBroadcastFromSystem(ActivityManagerService.java:17973)
at com.android.server.am.ActivityManagerService.broadcastIntentLocked(ActivityManagerService.java:18545)
at com.android.server.am.ActivityManagerService.broadcastIntent(ActivityManagerService.java:18636)
at android.app.ContextImpl.sendBroadcast(ContextImpl.java:881)
at com.android.server.am.AppErrors.crashApplicationInner(AppErrors.java:370)
at com.android.server.am.AppErrors.crashApplication(AppErrors.java:305)
at com.android.server.am.ActivityManagerService.handleApplicationCrashInner(ActivityManagerService.java:13554)
at com.android.server.am.ActivityManagerService.handleApplicationCrash(ActivityManagerService.java:13536)
at android.app.ActivityManagerNative.onTransact(ActivityManagerNative.java:1660)
at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:2813)
at android.os.Binder.execTransact(Binder.java:565)
The Location class that I'm using (not written by me, only minor edits done)
import android.content.Context;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
public class ProviderLocationTracker implements LocationListener,LocationTracker {
// The minimum distance to change Updates in meters
private static final long MIN_UPDATE_DISTANCE = 10;
// The minimum time between updates in milliseconds
private static final long MIN_UPDATE_TIME = 1000 * 60;
private LocationManager lm;
public enum ProviderType{
NETWORK,
GPS
};
private String provider;
private Location lastLocation;
private long lastTime;
private boolean isRunning;
private LocationUpdateListener listener;
public ProviderLocationTracker(Context context, ProviderType type) {
lm = (LocationManager)context.getSystemService(Context.LOCATION_SERVICE);
Criteria crit = new Criteria();
crit.setAccuracy(Criteria.ACCURACY_FINE);
if(type == ProviderType.NETWORK){
provider = LocationManager.NETWORK_PROVIDER;
}
else{
provider = LocationManager.GPS_PROVIDER;
}
provider = lm.getBestProvider(crit, true);
}
public String returnProvider(){
return provider;
}
public void start(){
if(isRunning){
//Already running, do nothing
return;
}
//The provider is on, so start getting updates. Update current location
isRunning = true;
lm.requestLocationUpdates(provider, MIN_UPDATE_TIME,MIN_UPDATE_DISTANCE, this);
lastLocation = null;
lastTime = 0;
return;
}
public void start(LocationUpdateListener update) {
start();
listener = update;
}
public void stop(){
if(isRunning){
lm.removeUpdates(this);
isRunning = false;
listener = null;
}
}
public boolean hasLocation(){
if(lastLocation == null){
return false;
}
if(System.currentTimeMillis() - lastTime > 5 * MIN_UPDATE_TIME){
return false; //stale
}
return true;
}
public boolean hasPossiblyStaleLocation(){
if(lastLocation != null){
return true;
}
return lm.getLastKnownLocation(provider)!= null;
}
public Location getLocation(){
if(lastLocation == null){
return null;
}
if(System.currentTimeMillis() - lastTime > 5 * MIN_UPDATE_TIME){
return null; //stale
}
return lastLocation;
}
public Location getPossiblyStaleLocation(){
if(lastLocation != null) {
return lastLocation;
}
return lm.getLastKnownLocation(provider);
}
public void onLocationChanged(Location newLoc) {
long now = System.currentTimeMillis();
if(listener != null){
listener.onUpdate(lastLocation, lastTime, newLoc, now);
}
lastLocation = newLoc;
lastTime = now;
}
public void onProviderDisabled(String arg0) {
}
public void onProviderEnabled(String arg0) {
}
public void onStatusChanged(String arg0, int arg1, Bundle arg2) {
}
}
Getting the location on button click listener:
if (checkLocationPermission()) {
if (ContextCompat.checkSelfPermission(getContext(),
Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
//Request location updates:
getLocation();
}
}
getLocation method:
public void getLocation(){
//In case we havent started it somehow, just returns if we did
location.start();
double alti;
double longti;
if(location.hasLocation()){
if (location.getLocation() != null) {
alti = location.getLocation().getLatitude();
longti = location.getLocation().getLongitude();
locationText.setText(alti +","+longti);
}else{
locationText.setText("1Couldn't get location, check your GPS/NETWORK");
}
}else{
if (location.getPossiblyStaleLocation() != null) {
alti = location.getPossiblyStaleLocation().getLatitude();
longti = location.getPossiblyStaleLocation().getLongitude();
locationText.setText(alti + "," + longti);
}else{
locationText.setText("2Couldn't get location, check your GPS/NETWORK");
}
}
}
Solved the crash, as #Giovanni Terlingen suggested, it was caused by the theme engine that I had on my phone. The problem that remains is that the GPS location getting is not always working - For older phones it doesn't get the location via GPS but the Criteria assigns GPS as provider anyway.
Is there a better way to get locations for devices from KitKat to possibly Oreo?
This seems to only be happening to Android 6.0 + device
Since Android 6.0, permissions has been introduced. Make sure that your app has location access on Android 6.0+. You should inform the user that your want to access his/her location. See this useful link:
https://developer.android.com/training/permissions/requesting.html

FusedLocationApi method getLastLocation() always null during first call

Looking for some help with a problem in my app concerning getting the current device location. Below is the GPSLocationListener class I am using.
import android.Manifest;
import android.app.Activity;
import android.content.pm.PackageManager;
import android.location.Location;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.util.Log;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
/**
* This class takes care of capturing the location of the device.
*/
public class GPSLocationListener implements GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener, LocationListener,
ActivityCompat.OnRequestPermissionsResultCallback {
protected static final String TAG = "location-updates-sample";
public static final int LOCATION_RESQUEST = 1;
/**
* The desired interval for location updates. Inexact. Updates may be more or less frequent.
*/
public static final long UPDATE_INTERVAL_IN_MILLISECONDS = 10000;
/**
* The fastest rate for active location updates. Exact. Updates will never be more frequent
* than this value.
*/
public static final long FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS =
UPDATE_INTERVAL_IN_MILLISECONDS / 2;
/**
* Provides the entry point to Google Play services.
*/
protected GoogleApiClient mGoogleApiClient;
/**
* Stores parameters for requests to the FusedLocationProviderApi.
*/
protected LocationRequest mLocationRequest;
/**
* Represents a geographical location.
*/
protected Location mCurrentLocation;
private Activity mActivity;
public double lat;
public double lon;
public GPSLocationListener(Activity activity) {
this.mActivity = activity;
// Kick off the process of building a GoogleApiClient and requesting the LocationServices API.
buildGoogleApiClient();
}
/**
* Builds a GoogleApiClient. Uses the {#code #addApi} method to request the
* LocationServices API.
*/
protected synchronized void buildGoogleApiClient() {
Log.i(TAG, "Building GoogleApiClient");
mGoogleApiClient = new GoogleApiClient.Builder(mActivity)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
createLocationRequest();
}
/**
* Sets up the location request. Android has two location request settings:
* {#code ACCESS_COARSE_LOCATION} and {#code ACCESS_FINE_LOCATION}. These settings control
* the accuracy of the current location. This sample uses ACCESS_FINE_LOCATION, as defined in
* the AndroidManifest.xml.
* <p/>
* When the ACCESS_FINE_LOCATION setting is specified, combined with a fast update
* interval (5 seconds), the Fused Navigation Provider API returns location updates that are
* accurate to within a few feet.
* <p/>
* These settings are appropriate for mapping applications that show real-time location
* updates.
*/
protected void createLocationRequest() {
mLocationRequest = new LocationRequest();
// Sets the desired interval for active location updates. This interval is
// inexact. You may not receive updates at all if no location sources are available, or
// you may receive them slower than requested. You may also receive updates faster than
// requested if other applications are requesting location at a faster interval.
mLocationRequest.setInterval(UPDATE_INTERVAL_IN_MILLISECONDS);
// Sets the fastest rate for active location updates. This interval is exact, and your
// application will never receive updates faster than this value.
mLocationRequest.setFastestInterval(FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
}
/**
* Requests location updates from the FusedLocationApi.
*/
public void startLocationUpdates(){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (ContextCompat.checkSelfPermission(this.mActivity, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this.mActivity, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this.mActivity, Manifest.permission.INTERNET) != PackageManager.PERMISSION_GRANTED) {
//return;
}else {
try {
ActivityCompat.requestPermissions(this.mActivity, new String[]{Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.INTERNET},
LOCATION_RESQUEST);
}catch (Exception e){
e.printStackTrace();
}
}
// If the initial location was never previously requested, we use
// FusedLocationApi.getLastLocation() to get it. If it was previously requested, we store
// its value in the Bundle and check for it in onCreate().
LocationServices.FusedLocationApi.requestLocationUpdates(
mGoogleApiClient, mLocationRequest, this);
}
}
/**
* Removes location updates from the FusedLocationApi.
*/
protected void stopLocationUpdates() {
// It is a good practice to remove location requests when the activity is in a paused or
// stopped state. Doing so helps battery performance and is especially
// recommended in applications that request frequent location updates.
// The final argument to {#code requestLocationUpdates()} is a LocationListener
// (http://developer.android.com/reference/com/google/android/gms/location/LocationListener.html).
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
}
public void onStart() {
mGoogleApiClient.connect();
//createLocationRequest();
// Within {#code onPause()}, we pause location updates, but leave the
// connection to GoogleApiClient intact. Here, we resume receiving
// location updates if the user has requested them.
}
public void onStop() {
// Stop location updates to save battery, but don't disconnect the GoogleApiClient object.
if (mGoogleApiClient.isConnected()) {
stopLocationUpdates();
mGoogleApiClient.disconnect();
}
}
/**
* Runs when a GoogleApiClient object successfully connects.
*/
#Override
public void onConnected(Bundle connectionHint) {
Log.i(TAG, "Connected to GoogleApiClient");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (ContextCompat.checkSelfPermission(this.mActivity, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this.mActivity, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this.mActivity, Manifest.permission.INTERNET) != PackageManager.PERMISSION_GRANTED) {
Log.i(TAG, "onConnected: Just empty if statement");
}else {
try {
ActivityCompat.requestPermissions(this.mActivity, new String[]{Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.INTERNET},
LOCATION_RESQUEST);
}catch (Exception e){
e.printStackTrace();
}
}
mCurrentLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
if (mCurrentLocation == null) {
mCurrentLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
Log.i(TAG, "onConnected " + String.valueOf(mCurrentLocation));
}
}
}
/**
* Callback that fires when the location changes.
*/
#Override
public void onLocationChanged(Location location) {
mCurrentLocation = location;
Log.i(TAG, "onLocationChanged: " + String.valueOf(mCurrentLocation.getLatitude()));
Log.i(TAG, "onLocationChanged: " + String.valueOf(mCurrentLocation.getLongitude()));
}
#Override
public void onConnectionSuspended(int cause) {
// The connection to Google Play services was lost for some reason. We call connect() to
// attempt to re-establish the connection.
Log.i(TAG, "Connection suspended");
mGoogleApiClient.connect();
}
#Override
public void onConnectionFailed(ConnectionResult result) {
// Refer to the javadoc for ConnectionResult to see what error codes might be returned in
// onConnectionFailed.
Log.i(TAG, "Connection failed: ConnectionResult.getErrorCode() = " + result.getErrorCode());
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
mActivity.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
switch (requestCode){
case LOCATION_RESQUEST:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){
startLocationUpdates(); // Calling this here is the only place that does not make the app crash
getCurrentLocation();
}else {
Log.i(TAG, "onRequestPermissionsResult: Need Permissions");
return;
}
break;
default:
break;
}
return;
}
public void getCurrentLocation(){
if (mCurrentLocation != null){
lat = mCurrentLocation.getLatitude();
lon = mCurrentLocation.getLongitude();
Log.i(TAG, "getCurrentLocation(): " + String.valueOf(mCurrentLocation.getLatitude()));
Log.i(TAG, "getCurrentLocation(): " + String.valueOf(mCurrentLocation.getLongitude()));
}
}
public GoogleApiClient getGoogleApiClient(){
return mGoogleApiClient;
}
}
Trying this out on my actual device with the GPS already enabled in the settings, I get some odd behavior. If I do not at all, call the startLocationUpdates() method or I call it in the onRequestPermissionsResult() method, the app launches fine and when I grant Device Location Permissions, the mCurrentLocation object is null, but does not crash. I stop the app and then launch again, and the mCurrentLocation has latitude and longitude coordinates that I can see in the logcat, which is what I am wanting in the first place, but they only hold any values, after the second launch. Now if I uninstall the app and try to call the startLocationUpdates() method anywhere, the app crashes upon launch with the error:
Client must have ACCESS_FINE_LOCATION permission to request PRIORITY_HIGH_ACCURACY locations.
But I am checking for permissions in the onConnected() method and also in the startLocationUpdates() method as well, although I do not think this is correct but this is the only way that I can get Android Studio to not underline the
LocationServices.FusedLocationApi.requestLocationUpdates(
mGoogleApiClient, mLocationRequest, this);
statement in red with a Permissions warning.
Here is the Activity where I am trying to get the location updates with the mapItBtnRespond() method.
package com.example.bigdaddy.as_built_weldmapper;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.Toast;
import com.example.bigdaddy.as_built_weldmapper.utilities.BendHelper;
import com.example.bigdaddy.as_built_weldmapper.utilities.GPSLocationListener;
public class SagActivity extends AppCompatActivity implements AdapterView.OnItemSelectedListener,
MajorButtonFragment.OnFragmentInteractionListener, Communicator{
/* Using this to insert into the Bend Direction field. */
public static String SAG_DIRECTION = "SAG";
/* This spinner holds the bend types */
Spinner mSagBendTypesSpinner;
/* Using this string to collect what was selected for the spinner type */
private String mBendTypeSpinnerVal;
/* All the EditText for the Activity */
private EditText mSagGpsShotEt;
private EditText mSagExistingGpsEt;
private EditText mSagCoverEt;
private EditText mSagDegreeEt;
private EditText mSagDistanceFromEt;
private EditText mSagNotesEt;
private EditText mSagOccupyIdEt;
private EditText mSagStationNumEt;
private GPSLocationListener mGPSLocationListener;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sag);
mGPSLocationListener = new GPSLocationListener(SagActivity.this);
/* checking if the MajorButtonFragment is null */
if (findViewById(R.id.majorButtonFragment) != null) {
if (savedInstanceState != null) {
return;
}
}
/* Referencing the spinner and setting the itemsSelectedListener */
mSagBendTypesSpinner = (Spinner) findViewById(R.id.bend_types_spinner);
mSagBendTypesSpinner.setOnItemSelectedListener((AdapterView.OnItemSelectedListener) this);
/* Create an ArrayAdapter using the string array and a default spinner layout */
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this,
R.array.bend_types_array, android.R.layout.simple_spinner_item);
/* Specify the layout to use when the list of choices appears */
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
/* Apply the adapter to the spinner */
mSagBendTypesSpinner.setAdapter(adapter);
/* Referencing and calling all the EditText for the Activity */
mSagGpsShotEt = (EditText) findViewById(R.id.eTextGpsShotForSag);
mSagExistingGpsEt = (EditText) findViewById(R.id.eTextExistGradeForSag);
mSagCoverEt = (EditText) findViewById(R.id.eTextCoverForSag);
mSagDegreeEt = (EditText) findViewById(R.id.eTextDegreeForSag);
mSagDistanceFromEt = (EditText) findViewById(R.id.eTextDistanceFromForSag);
mSagNotesEt = (EditText) findViewById(R.id.eTextNotesForSagActivity);
mSagOccupyIdEt = (EditText) findViewById(R.id.eTextJointIdSagActivity);
mSagStationNumEt = (EditText) findViewById(R.id.eTextStationNumSagActivity);
} /*onCreate() ends here.*/
#Override
protected void onStart() {
super.onStart();
Log.i("SagActivity", "onStart: ");
/* Starting the location listener here (GoogleApiClient) */
if (mGPSLocationListener != null){
mGPSLocationListener.onStart();
}
}
#Override
protected void onStop() {
super.onStop();
Log.i("SagActivity", "onStop: ");
/* Stopping the location listener here (GoogleApiClient) */
if (mGPSLocationListener != null){
mGPSLocationListener.onStop();
}
}
#Override
public void onLocalVoiceInteractionStopped() {
super.onLocalVoiceInteractionStopped();
}
#Override
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
mBendTypeSpinnerVal = mSagBendTypesSpinner.getSelectedItem().toString();
}
#Override
public void onNothingSelected(AdapterView<?> adapterView) {
}
#Override
public void exitBtnRespond() {
}
/**
* This overridden method comes from the Communicator Interface and is used globally in all
* Activities that implement it to Store (write) a transaction to the database.
* The utility class saveAndInsertBend() method is invoked here.
*/
#Override
public void storeBtnRespond() {
BendHelper.saveAndInsertBend(SagActivity.this, SAG_DIRECTION, mBendTypeSpinnerVal, mSagStationNumEt,
mSagOccupyIdEt, mSagDegreeEt, mSagDistanceFromEt, mSagGpsShotEt, mSagExistingGpsEt,
mSagCoverEt, mSagNotesEt);
}
#Override
public void mapItBtnRespond() {
Toast.makeText(this, "MapItBtn clicked in SagActivity",Toast.LENGTH_LONG).show();
mGPSLocationListener.getCurrentLocation();
Log.i("SagActivity", "mapItBtnRespond: " + String.valueOf(mGPSLocationListener.lat));
Log.i("SagActivity", "mapItBtnRespond: " + String.valueOf(mGPSLocationListener.lon));
}
#Override
public void onFragmentInteraction() {
}
}
What am I doing wrong here with all of this? Any help would be greatly appreciated as I am confused with the Permissions apparently. Thanks so much for any guidance.
You are asking for FINE_LOCATION permission in onConnected(), but onConnected is called when GPS is connected. That's the reason you are getting permission error.
You should remove this:
mCurrentLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
From onConnected(). Add this to getCurrentLocation() with permission request:
public void getCurrentLocation(){
//Request permission here
mCurrentLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
if (mCurrentLocation != null){
lat = mCurrentLocation.getLatitude();
lon = mCurrentLocation.getLongitude();
Log.i(TAG, "getCurrentLocation(): " + String.valueOf(mCurrentLocation.getLatitude()));
Log.i(TAG, "getCurrentLocation(): " + String.valueOf(mCurrentLocation.getLongitude()));
}
}
Then also call this method in onConnected():
#Override
public void onConnected(Bundle connectionHint) {
Log.i(TAG, "Connected to GoogleApiClient");
getCurrentLocation();
}

Google Drive API and Android Studio - Uploading Video File from Android Phone to Users Google Drive

I am trying to develop an app where the user takes a photo and uploads it to Google Drive automatically (The image is not saved on the phone). I figured out the code for that thanks to a Google Drive tutorial, but I have no idea how I would do that when it comes to upload videoes?
Here is the code for photo uploading:
package com.google.android.gms.drive.sample.quickstart;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import android.app.Activity;
import android.content.Intent;
import android.content.IntentSender;
import android.content.IntentSender.SendIntentException;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.provider.MediaStore;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GoogleApiAvailability;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.GoogleApiClient.ConnectionCallbacks;
import com.google.android.gms.common.api.GoogleApiClient.OnConnectionFailedListener;
import com.google.android.gms.common.api.ResultCallback;
import com.google.android.gms.drive.Drive;
import com.google.android.gms.drive.DriveApi.DriveContentsResult;
import com.google.android.gms.drive.MetadataChangeSet;
/**
* Android Drive Quickstart activity. This activity takes a photo and saves it
* in Google Drive. The user is prompted with a pre-made dialog which allows
* them to choose the file location.
*/
public class VideoCapture extends Activity implements ConnectionCallbacks,
OnConnectionFailedListener {
private static final String TAG = "drive-quickstart";
private static final int REQUEST_CODE_CAPTURE_VIDEO = 1;
private static final int REQUEST_CODE_CREATOR = 2;
private static final int REQUEST_CODE_RESOLUTION = 3;
private GoogleApiClient mGoogleApiClient;
private Byte mVideoToSave;
/**
* Create a new file and save it to Drive.
*/
private void saveFileToDrive() {
// Start by creating a new contents, and setting a callback.
Log.i(TAG, "Creating new contents.");
final Byte video = mVideoToSave;
Drive.DriveApi.newDriveContents(mGoogleApiClient)
.setResultCallback(new ResultCallback<DriveContentsResult>() {
#Override
public void onResult(DriveContentsResult result) {
// If the operation was not successful, we cannot do anything
// and must
// fail.
if (!result.getStatus().isSuccess()) {
Log.i(TAG, "Failed to create new contents.");
return;
}
// Otherwise, we can write our data to the new contents.
Log.i(TAG, "New contents created.");
// Get an output stream for the contents.
OutputStream outputStream = result.getDriveContents().getOutputStream();
// Write the bitmap data from it.
ByteArrayOutputStream mBAOS = new ByteArrayOutputStream();
byte[] mByte = new byte[1024];
try {
outputStream.write(mBAOS.toByteArray());
} catch (IOException e1) {
Log.i(TAG, "Unable to write file contents.");
}
// Create the initial metadata - MIME type and title.
// Note that the user will be able to change the title later.
MetadataChangeSet metadataChangeSet = new MetadataChangeSet.Builder()
.setMimeType("video/mp4").setTitle("Android Video.mp4").build();
// Create an intent for the file chooser, and start it.
IntentSender intentSender = Drive.DriveApi
.newCreateFileActivityBuilder()
.setInitialMetadata(metadataChangeSet)
.setInitialDriveContents(result.getDriveContents())
.build(mGoogleApiClient);
try {
startIntentSenderForResult(
intentSender, REQUEST_CODE_CREATOR, null, 0, 0, 0);
} catch (SendIntentException e) {
Log.i(TAG, "Failed to launch file chooser.");
}
}
});
}
#Override
protected void onResume() {
super.onResume();
if (mGoogleApiClient == null) {
// Create the API client and bind it to an instance variable.
// We use this instance as the callback for connection and connection
// failures.
// Since no account name is passed, the user is prompted to choose.
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addApi(Drive.API)
.addScope(Drive.SCOPE_FILE)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
}
// Connect the client. Once connected, the camera is launched.
mGoogleApiClient.connect();
}
#Override
protected void onPause() {
if (mGoogleApiClient != null) {
mGoogleApiClient.disconnect();
}
super.onPause();
}
#Override
protected void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
switch (requestCode) {
case REQUEST_CODE_CAPTURE_VIDEO:
// Called after a photo has been taken.
if (resultCode == Activity.RESULT_OK) {
// Store the image data as a bitmap for writing later.
mVideoToSave = (Byte) data.getExtras().get("data");
}
break;
case REQUEST_CODE_CREATOR:
// Called after a file is saved to Drive.
if (resultCode == RESULT_OK) {
Log.i(TAG, "Image successfully saved.");
mVideoToSave = null;
// Just start the camera again for another photo.
startActivityForResult(new Intent(MediaStore.ACTION_VIDEO_CAPTURE),
REQUEST_CODE_CAPTURE_VIDEO);
}
break;
}
}
#Override
public void onConnectionFailed(ConnectionResult result) {
// Called whenever the API client fails to connect.
Log.i(TAG, "GoogleApiClient connection failed: " + result.toString());
if (!result.hasResolution()) {
// show the localized error dialog.
GoogleApiAvailability.getInstance().getErrorDialog(this, result.getErrorCode(), 0).show();
return;
}
// The failure has a resolution. Resolve it.
// Called typically when the app is not yet authorized, and an
// authorization
// dialog is displayed to the user.
try {
result.startResolutionForResult(this, REQUEST_CODE_RESOLUTION);
} catch (SendIntentException e) {
Log.e(TAG, "Exception while starting resolution activity", e);
}
}
#Override
public void onConnected(Bundle connectionHint) {
Log.i(TAG, "API client connected.");
if (mVideoToSave == null) {
// This activity has no UI of its own. Just start the camera.
startActivityForResult(new Intent(MediaStore.ACTION_VIDEO_CAPTURE),
REQUEST_CODE_CAPTURE_VIDEO);
return;
}
saveFileToDrive();
}
#Override
public void onConnectionSuspended(int cause) {
Log.i(TAG, "GoogleApiClient connection suspended");
}
}

Getting longitude and latitude takes a very long time

I am getting the longitude and latitude of my device, but it takes at 30 seconds to a minute to do so. Any suggestions to cut the time down?
public class MainActivity extends Activity
{
public String zipcode;
public double latG;
public double lonG;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
LocationManager service = (LocationManager) getSystemService(LOCATION_SERVICE);
boolean enabled = service.isProviderEnabled(LocationManager.GPS_PROVIDER);
if (!enabled)
{
Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
startActivity(intent);
}
LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
locationManager.getLastKnownLocation(Context.LOCATION_SERVICE);
LocationListener locationListener = new LocationListener()
{
public void onLocationChanged(Location location)
{
if (location != null)
{
latG = location.getLatitude();
lonG = location.getLongitude();
Toast.makeText(MainActivity.this,
latG + " " + lonG,
Toast.LENGTH_LONG).show();
}
}
public void onProviderDisabled(String provider)
{
}
public void onProviderEnabled(String provider)
{
}
public void onStatusChanged(String provider, int status, Bundle extras)
{
}
};
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListener);
Geocoder geocoder = new Geocoder(this, Locale.getDefault());
List<Address> addresses = null;
try
{
addresses = geocoder.getFromLocation(latG, lonG, 1);
}
catch (IOException e)
{
Context context = this;
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(context);
alertDialogBuilder.setTitle("Error");
alertDialogBuilder.setMessage("Error in getting address information.");
alertDialogBuilder.setCancelable(true);
}
for (Address address : addresses)
{
if(address.getPostalCode() != null)
{
zipcode = address.getPostalCode();
Toast.makeText(MainActivity.this, zipcode, Toast.LENGTH_LONG).show();
break;
}
}
}
}
You are using GPS_PROVIDER for fetching the GPS data. GPS_PROVIDER fetches details directly from the satellite so it takes time for the first time you load this. Moreover GPS_PROVIDER takes more than 30 seconds if your are not below the open sky. GPS_PROVIDER may return NULL when you are inside the office or in basement.
There is an alternative way for this is to use NETWORK_PROVIDER. This provider will give you GPS details based on your current Network state. This will not be much accurate like GPS_PROVIDER but it works faster.
hi you are using GPS PROVIDER which can take some time as it depends on several constraints like yours building position, physical position, weather as gps data is available from the satellite so use a network provider which may faster in yours case please have a look on the given code snippet at
http://www.androidhive.info/2012/07/android-gps-location-manager-tutorial/
Best option is to use Google Play Services and its LocationClient.
http://developer.android.com/google/play-services/location.html
This gives you a provider that automatically picks the best available information from all the provider types and can return the location immediately in some cases using getLastLocation()
try to run it in device rather than running it in the emulator.
try this
try {
gps_enabled = locManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
} catch (Exception ex) {
}
try {
network_enabled = locManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
} catch (Exception ex) {}
if (gps_enabled) {
locManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locListener);
}
if (network_enabled) {
locManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locListener);
It will give the response what ever the service is available.Even you can place your priority
Use this code to fetch faster,
String provider;
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
Criteria criteria = new Criteria();
provider = locationManager.getBestProvider(criteria, false);
if (provider != null && !provider.equals("")) {
Location location = locationManager.getLastKnownLocation(provider);
locationManager.requestLocationUpdates(provider, 20000, 1, this);
if (location != null)
{
onLocationChanged(location);
//your remaining code
}

Android requestLocationUpdates without minDistance

I have a need to get the gps location every 20 seconds or so, but ignoring the need to have the user move a certain number of meters, I tried setting the minDistance to zero but still no luck, its only when I manually send the location using the location control from DDMS that this gets activated and the location gets updated.
Note - This is run and tested from the emulator and not a real device, for now at least
private final static Long INTERVAL_TIME = new Long(20);
private final static Float METERS_MOVED_VALUE = 0f;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.journey);
Bundle dataBundle = this.getIntent().getExtras();
try {
driverData = new JSONObject(dataBundle.getString("driverData"));
} catch (JSONException e) {
e.printStackTrace();
}
//Set the UI elements into variables
journeyDescription = (TextView)findViewById(R.id.journeyDescription);
journeyText = (TextView)findViewById(R.id.journeyText);
confirmButton = (Button)findViewById(R.id.btnCheck);
//Acquire a reference to the system Location Manager
locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
LocationListener locationListener = new LocationListener() {
public void onLocationChanged(Location location) {
try{
//Until requests are found keep broadcasting the drivers location and checking for requests
if(!foundRequest){
updateDriverLocationAndCheckForNewDriverRequests(location);
}
//Always keep updating the drivers location
Double latitude = location.getLatitude()*1E6;
Double longitude = location.getLongitude()*1E6;
geoPoint = new GeoPoint(latitude.intValue(), longitude.intValue());
}catch(JSONException e){
Toast.makeText(JourneyActivity.this, "An unexpected error occurred", Toast.LENGTH_LONG).show();
e.printStackTrace();
}
}
public void onStatusChanged(String provider, int status, Bundle extras) {}
public void onProviderEnabled(String provider) {}
public void onProviderDisabled(String provider) {}
};
//Register the listener with the Location Manager to receive location updates can be either gps provider
if (!locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)){
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, INTERVAL_TIME, METERS_MOVED_VALUE, locationListener);
}
else {
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, INTERVAL_TIME, METERS_MOVED_VALUE, locationListener);
}
}
Here is the related code fragment, any ideas on how to trigger the listener without having the user move or me having to send information from the DDMS Location Controls woild be greatly appreciated
Regards,
Milinda
requestLocationUpdates takes milliseconds, not seconds.
You should change:
private final static Long INTERVAL_TIME = new Long(20);
private final static Float METERS_MOVED_VALUE = 0f;
to:
private final static int INTERVAL_TIME_SECONDS = 20 * 1000; // 20 seconds
private final static float INTERVAL_DISTANCE_METERS = 0f; // 0 meters
As far as testing on the emulator goes. I think your limited to manually pushing GPS locations or creating a few automated simulators:
Testing GPS in Android

Categories

Resources