Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to programmatically enable and disable GPS in Ionic Framework or Cordova

My problem is simple. I need a way to turn on and off GPS using a button inside an Ionic app. I've check the docs and read this ng-cordova plugin http://ngcordova.com/docs/plugins/geolocation/ but they don't seem have this funcction. Am I just missing something or is this even possible in Ionic Framework? Thanks!

like image 578
balfonso Avatar asked Feb 08 '23 01:02

balfonso


2 Answers

I wanna open GPS automatically according to my requirements.
So I used cordova-plugin-request-location-accuracy
When GPS is off, it request user to open GPS..It's very helpful for me..
Ionic1
https://github.com/dpa99c/cordova-plugin-request-location-accuracy

Ionic2
https://ionicframework.com/docs/native/location-accuracy/
Best Regards....

like image 137
Saw Pyae Avatar answered May 16 '23 06:05

Saw Pyae


As far as I know controlling the device location is not possible as there isn't any Ionic or Cordova plugin available for this purpose. One can get the device position using the Geolocation plugin. But this doesn't work in case the device GPS is off. I have managed a work around to enable device location using a JSInterface bridge. This solution is valid only for the ionic android platform and honestly I would recommend using this only if turning on the device GPS is extremely crucial to your application.

Explanation: Google LocationServices gives us a provision of enabling device location. I have created a bridge between ionic and native platform. My ionic page requests for the device location using this bridge. ex: NativeBridge.functionNameInActivity

Native function requesting device position<----->JSInterface Bridge<---->Ionic function

1. Below is the code for the MainActivity which extends CordovaActivity:

public class MainActivity extends CordovaActivity implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, ResultCallback<LocationSettingsResult> {

    public static Context mContext;
    private Intent mIntent;
    private final int REQUEST_CODE_LOCATION = 101;
    private final int REQUEST_CODE_LOCATION_SETTINGS = 102;

    protected GoogleApiClient mGoogleApiClient;
    protected LocationRequest locationRequest;
    public static double LATITUDE, LONGITUDE;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mContext = getApplicationContext();
        loadUrl(launchUrl);
        mIntent = new Intent(this, LocationService.class);
        final WebView webView = (WebView) appView.getEngine().getView();
        webView.addJavascriptInterface(this.getJavaScriptHandler(), "NativeBridge");
    }


    @Override
    public void onDestroy() {
        super.onDestroy();
        stopService(mIntent);
    }


    public void configureLocationClient() {
        final int intervalInSecs = 30;
        final int fastestIntervalInSecs = 5;
        final int milliSecondMultiplier = 1000;
        mGoogleApiClient = new GoogleApiClient.Builder(this)
                .addApi(LocationServices.API)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this).build();
        mGoogleApiClient.connect();
        locationRequest = LocationRequest.create();
        locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
        locationRequest.setInterval(intervalInSecs * milliSecondMultiplier);
        locationRequest.setFastestInterval(fastestIntervalInSecs * milliSecondMultiplier);
    }

    public void checkLocationPermission() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_CODE_LOCATION);
        } else {
            configureLocationClient();
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == REQUEST_CODE_LOCATION_SETTINGS) {
            if (resultCode == RESULT_OK) {
                startService(mIntent);
            } else {
                //Display a message requesting location access for further operations
            }
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);

        Map<String, Integer> perms;
        switch (requestCode) {
            case REQUEST_CODE_LOCATION:
                perms = new HashMap<String, Integer>();
                perms.put(Manifest.permission.ACCESS_FINE_LOCATION, PackageManager.PERMISSION_GRANTED);

                for (int i = 0; i < permissions.length; i++) {
                    perms.put(permissions[i], grantResults[i]);
                }

                if (perms.get(Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
                    //Start location fetching service
                    configureLocationClient();
                } else {
                    // Location Permission Denied
                    DisplayUtils.displayToast(mContext, AppConstants.MSG_PERMISSIONS_LOCATION);
                    return;
                }

                break;

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

    @Override
    public void onConnected(@Nullable Bundle bundle) {

        LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder()
                .addLocationRequest(locationRequest);
        builder.setAlwaysShow(true);
        PendingResult<LocationSettingsResult> result =
                LocationServices.SettingsApi.checkLocationSettings(
                        mGoogleApiClient,
                        builder.build()
                );

        result.setResultCallback(this);

    }

    @Override
    public void onConnectionSuspended(int i) {
    }

    @Override
    public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
    }

    @Override
    public void onResult(@NonNull LocationSettingsResult locationSettingsResult) {
        final Status status = locationSettingsResult.getStatus();
        switch (status.getStatusCode()) {
            case LocationSettingsStatusCodes.SUCCESS:
                /*Start location fetching service*/
                startService(mIntent);
                break;

            case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
                /*Location settings are not satisfied. Show the user a dialog by calling startResolutionForResult(), and check the result in onActivityResult().*/
                try {
                    status.startResolutionForResult(MainActivity.this, REQUEST_CODE_LOCATION_SETTINGS);
                } catch (IntentSender.SendIntentException e) {
                    e.printStackTrace();
                }
                break;

            case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
                /*Location settings unavailable*/
                break;
            default:
                break;
        }
    }

    public JavaScriptHandler getJavaScriptHandler() {
        return new JavaScriptHandler(this.getApplicationContext());
    }

    /***
     * Javascript handler
     ***/
    public class JavaScriptHandler {
        CordovaActivity parentActivity;
        private Context mContext;

        public JavaScriptHandler(final CordovaActivity activity) {
            this.parentActivity = activity;
        }

        public JavaScriptHandler(final Context context) {
            this.mContext = context;
        }

        @JavascriptInterface
        public boolean ifLocationPermissionGranted() {
            return ContextCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED;
        }

        @JavascriptInterface
        public boolean ifLocationAccessible() {
            LocationManager mLocationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
            return mLocationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
        }

        @JavascriptInterface
        public void startLocationService() {
            checkLocationPermission();
        }

        @JavascriptInterface
        public String getLatitude() {
            return String.valueOf(LATITUDE);
        }

        @JavascriptInterface
        public String getLongitude() {
            return String.valueOf(LONGITUDE);
        }
    }
}

2. Location Service class:

public class LocationService extends Service {
    private static String TAG = "TAG-LocationService";
    private LocationManager mLocationManager;
    private static final int LOCATION_INTERVAL = 2000;
    private static final float LOCATION_DISTANCE = 0f;

    private class LocationListener implements android.location.LocationListener {
        Location mLastLocation;

        public LocationListener(String provider) {
            mLastLocation = new Location(provider);
        }

        @Override
        public void onLocationChanged(Location location) {
            mLastLocation.set(location);
            if (location != null) {
                MainActivity.LATITUDE = mLastLocation.getLatitude();
                MainActivity.LONGITUDE = mLastLocation.getLongitude();
            }
        }

        @Override
        public void onProviderDisabled(String provider) {
        }

        @Override
        public void onProviderEnabled(String provider) {
        }

        @Override
        public void onStatusChanged(String provider, int status, Bundle extras) {
        }
    }

    LocationListener[] mLocationListeners = new LocationListener[]{
            new LocationListener(LocationManager.GPS_PROVIDER), new LocationListener(LocationManager.NETWORK_PROVIDER),
    };

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


    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        super.onStartCommand(intent, flags, startId);
        return START_STICKY;
    }

    @Override
    public void onCreate() {
        initializeLocationManager();
        try {
            mLocationManager.requestLocationUpdates(
                    LocationManager.NETWORK_PROVIDER, LOCATION_INTERVAL, LOCATION_DISTANCE,
                    mLocationListeners[1]);

        } catch (SecurityException ex) {
            ex.printStackTrace();
        } catch (IllegalArgumentException ex) {
            ex.printStackTrace();
        }
        try {
            mLocationManager.requestLocationUpdates(
                    LocationManager.GPS_PROVIDER, LOCATION_INTERVAL, LOCATION_DISTANCE,
                    mLocationListeners[0]);
        } catch (SecurityException ex) {
            ex.printStackTrace();
        } catch (IllegalArgumentException ex) {
            ex.printStackTrace();
        }
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        if (mLocationManager != null) {
            for (int i = 0; i < mLocationListeners.length; i++) {
                if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
                    mLocationManager.removeUpdates(mLocationListeners[i]);
                }
            }
        }
    }

    private void initializeLocationManager() {
        if (mLocationManager == null) {
            mLocationManager = (LocationManager) getApplicationContext().getSystemService(Context.LOCATION_SERVICE);
        }
    }
}

3. Code for your JS controller file:

MyDemoApp.controller('LocationController', function ($scope, $cordovaToast, $ionicPopup) {
$scope.goForIt = function () {
    if (NativeBridge.ifLocationPermissionGranted()) {
        if (NativeBridge.ifLocationAccessible()) {
            $scope.getDevicePosition();
        } else {
            $scope.showLocationAlert();
        }
    } else {
        $scope.showLocationAlert();
    }
}

$scope.getDevicePosition = function () {
    var positionLatitude = parseFloat(NativeBridge.getLatitude());
    var positionLongitude = parseFloat(NativeBridge.getLongitude());
}

$scope.showLocationAlert = function () {
    var confirmPopup = $ionicPopup.confirm({
        title: 'Location Service required for further operation',
        template: 'Grant permission to access Location?'
    });
    confirmPopup.then(function (res) {
        if (res) {
            NativeBridge.startLocationService();
        } else {
            $cordovaToast.showShortCenter("Location access required");
        }
    });
};

});

4. Add below line in the dependencies of your build.gradle:

compile 'com.google.android.gms:play-services-location:10.0.1'

5. Add permission to your manifest

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />    
<uses-feature android:name="android.hardware.location.gps" />

6. Declare Service in your manifest:

<service android:name=".LocationService"></service>

On calling this function, you will see a similar dialog asking to enable device location.

enter image description here

Again, I would recommend using this only if enabling the user location is extremely important to your app functionality because its a lot of work. Feel free to criticize :-)

like image 31
Sanket Mendon Avatar answered May 16 '23 08:05

Sanket Mendon