0

I realize this question has been asked many times before but I'm asking it now because the answers are quite old (compared to the new API).

I've used Location Manager before but I've found it very unreliable. For example in my app, using getLastKnownLocation and/or current location, it would instantly load with the camera on the user's current location. But say if I turned the location on my device right before I started my app, it wouldn't have the camera on the user's current location but rather somewhere near Nigera (default view, I believe).

Only if I used Google Maps app and pin pointed my location or if I waited some time, then my app would load with the user's location in the view (using moveCamera).

Sometimes it would work and sometimes it wouldn't. But I want to use Google Api Client, or perhaps something smoother, to retrieve the user's location.

I want to do it like this:

1.) If the user doesn't have their location on, prompt them to turn it on.

2.) After turning location on, start the Maps camera/view with the user's current location in the center.

3.) Finally, if the user decides to take off location or move from their location, do absolutely nothing.

I've read a lot of questions here but I can't find anything that could help me configure this functionality using Google Api Client or anything else. I've tried almost everything with Location Manager but I still can't get it to work smoothly. And out of frustration, I've deleted all my Location Manager code.

If you want to see what I had written down or tried, most of my sources came from this question (and related):

What is the simplest and most robust way to get the user's current location on Android?

Thank you for taking the time to read this.

Community
  • 1
  • 1
SaltySea
  • 700
  • 1
  • 7
  • 21

2 Answers2

0

Location Manager is working perfectly for me, But for API level 23 you need to do some workarounds. For getting permission on API level 23, you need to write permission logic in the main thread.

This is a example i have used in one of my code.

   /*Checking for permission if API level is more than 23 or 23, if condition match function calls*/
    if (Build.VERSION.SDK_INT >= 23) {
        requestMultiplePermissions();
    }

    /*Background Thread for splash screen with 2 seconds*/
    final Thread splashScreenThread = new Thread() {

        public void run() {

            try {
                Thread.sleep(2000);

            } catch (InterruptedException exception) {
                exception.printStackTrace();
            } finally {
                Intent homeScreen = new Intent(SplashScreen.this, MainActivity.class);
                startActivity(homeScreen);
                finish();

            }
        }
    };

    splashScreenThread.start();


}

/*Standar Permission chcking code for API level 23 or more*/
private void requestMultiplePermissions() {
    String locationPermission = Manifest.permission.ACCESS_FINE_LOCATION;
    int hasLocPermission = checkSelfPermission(locationPermission);
    List<String> permissions = new ArrayList<String>();
    if (hasLocPermission != PackageManager.PERMISSION_GRANTED) {
        permissions.add(locationPermission);
    }

    if (!permissions.isEmpty()) {
        String[] params = permissions.toArray(new String[permissions.size()]);
        requestPermissions(params, 1);
    } else {
        // We already have permission, so handle as normal

    }

}

/*This is function is used when permissions is granted by user, here we are firing a Intent after getting permission
* */
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions,
                                       int[] grantResults) {
    Toast.makeText(SplashScreen.this, " " + grantResults, Toast.LENGTH_SHORT).show();
    switch (requestCode) {
        case 1:
            if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                // Handle permission granted firing the Intent
                Intent intent = new Intent(SplashScreen.this, MainActivity.class);
                startActivity(intent);
                finish();

            } else {
                // Handle permission denied, giving Alertbox to user with some text
                new AlertDialog.Builder(this)
                        .setMessage("The app cannot continue without permissions")
                        .setCancelable(false)
                        .setPositiveButton("Ok", new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog, int id) {
                                SplashScreen.this.finish();
                            }
                        })
                        .show();


            }
            break;
        default:
            super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    }
    //

Type the above code in your Mainactivity or anywhere you want, i will prefer to ask for permission when the app starts.

Firdoesh
  • 73
  • 1
  • 2
  • 9
  • it's better to ask permission just before your app will use it, so the user will understand at that moment and why you need it. For me it's main reason why I'm not allow some permissions when I don't sure when it's used – Andrew V. Oct 30 '17 at 10:31
0

The following service is gracefully giving me location with accuracy and status of Location Service . This service is used before I login to the application, as application requires Location Service to be enabled.

Based on this service input you can

  1. Prompt user to turn on Location
  2. Once location is received, map's can be initiated
  3. If location is disconnected, take care of the rest logic

Important points to remember for location updates are that

  • Specify minimum distance change for receiving updates setSmallestDisplacement(API will get back data even if we stay in one location for a long time without moving)
  • Set FastestInterval to receive location updates
  • Set priority parameter setPriority according to your requirement

    public class AppLocationService extends Service implements GoogleApiClient.ConnectionCallbacks,
            GoogleApiClient.OnConnectionFailedListener,
            LocationListener{

        private LocationRequest locationRequest;
        private GoogleApiClient googleApiClient;
        private Context appContext;
        private boolean currentlyProcessingLocation = false;
        private int mInterval=0;
        private final int CONNTIMEOUT=50000;
        private static final long MIN_DISTANCE_CHANGE_FOR_UPDATES = 10; // 10 meters

    @Override
    public void onCreate() {
        super.onCreate();

    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        appContext=getBaseContext();
        Toast.makeText(getBaseContext(), "Location Service Started", Toast.LENGTH_SHORT)
                .show();
        if(intent != null){
            mInterval = intent.getIntExtra(Constants.REFRESHTIMETAG, 5);
            mIMEI = intent.getStringExtra(Constants.IMEITAG);
            Log.v(Constants.BLL_LOG, "AppLocationService onStartCommand , mInterval=" + mInterval + " | mIMEI=" + mIMEI);
        }
        if (!currentlyProcessingLocation) {
            currentlyProcessingLocation = true;
            startTracking();
        }

        return START_STICKY;
    }

    private void startTracking() {
        Log.v(Constants.BLL_LOG, "startTracking");
        if (GooglePlayServicesUtil.isGooglePlayServicesAvailable(this) == ConnectionResult.SUCCESS) {
            Log.v(Constants.BLL_LOG, "ConnectionResult SUCCESS");
            googleApiClient = new GoogleApiClient.Builder(this)
                    .addApi(LocationServices.API)
                    .addConnectionCallbacks(this)
                    .addOnConnectionFailedListener(this)
                    .build();

            if (!googleApiClient.isConnected() || !googleApiClient.isConnecting()) {
                googleApiClient.connect();
                Log.v(Constants.BLL_LOG, "googleApiClient.connect()");
            }else{
                Log.v(Constants.BLL_LOG, "NOT connected googleApiClient.connect()");
                //
                //INTIMATE UI WITH EITHER HANDLER OR RUNONUI THREAD
                //
            }
        } else {
            Log.v(Constants.BLL_LOG, "unable to connect to google play services.");
        }
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
    public AppLocationService() {
    }

    @Override
    public void onConnected(Bundle bundle) {
        Log.v(Constants.BLL_LOG, "onConnected");
        locationRequest = LocationRequest.create();
        locationRequest.setInterval(mInterval * 1000); // milliseconds
        locationRequest.setFastestInterval(mInterval * 1000);
        locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
        locationRequest.setSmallestDisplacement(MIN_DISTANCE_CHANGE_FOR_UPDATES);//distance change
        int permissionCheck = ContextCompat.checkSelfPermission(appContext, Manifest.permission.ACCESS_COARSE_LOCATION);
        if (permissionCheck!= PackageManager.PERMISSION_DENIED)
        {    LocationServices.FusedLocationApi.requestLocationUpdates(googleApiClient, locationRequest, this);}

        Handler handler = new Handler(Looper.getMainLooper());
        handler.post(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(appContext, "Location Service got connected", Toast.LENGTH_SHORT)
                        .show();
            }
        });
    }

    @Override
    public void onConnectionSuspended(int i) {
        Log.v(Constants.BLL_LOG, "onConnectionSuspended");
        //INTIMATE UI ABOUT DISCONNECTION STATUS
    }

    @Override
    public void onLocationChanged(Location location) {
        Log.v(Constants.BLL_LOG, "onLocationChanged position: " + location.getLatitude() + ", " + location.getLongitude() + " accuracy: " + location.getAccuracy());
        //if (location.getAccuracy() < 500.0f) 
        Log.v(Constants.BLL_LOG, "onLocationChanged position: location.getAccuracy()= "+location.getAccuracy());

        //DO YOUR BUSINESS LOGIC, FOR ME THE SAME WAS TO SEND TO SERVER
        sendLocationDataToWebsite(location);        

    }

    @Override
    public void onConnectionFailed(ConnectionResult connectionResult) {
        Log.v(Constants.BLL_LOG, "onConnectionFailed");
        Handler handler = new Handler(Looper.getMainLooper());
        handler.post(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(appContext, "Location Service got disconnected temporarily", Toast.LENGTH_SHORT)
                        .show();
            }
        });
    }

    /**
     * Send details to server
     * @param location
     */
    void sendLocationDataToWebsite(Location location){


    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        if (googleApiClient != null && googleApiClient.isConnected()) {
            googleApiClient.disconnect();
        }
        this.unregisterReceiver(this.batteryInfoReceiver);
    }
}

NOTE: This service needs to be still tested in updated version

Sreehari
  • 5,621
  • 2
  • 25
  • 59
  • how do you use this service...do you have to put some intent filter on the manifest or something??...how do you get the values from another activity? – John Oct 15 '16 at 19:30
  • @Juan This is out of context, Still i am posting this https://developer.android.com/guide/components/bound-services.html – Sreehari Oct 17 '16 at 06:17