Skip to content

Commit

Permalink
Merge branch 'dev'
Browse files Browse the repository at this point in the history
  • Loading branch information
neuberoliveira committed Dec 7, 2018
2 parents bcc905f + 24182a1 commit 4d62c08
Show file tree
Hide file tree
Showing 5 changed files with 188 additions and 77 deletions.
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,13 @@ protected List<ReactPackage> getPackages() {


#### Methods
Open the system Settings to enable user to toggle Location on.

The parameter `openInDetails` (android only) is used to open app details screen (android M+ only), so the user can toggle the permission in `Permissions` tab.

```javascript
//Open the system Settings to enable user to toggle Location on
GPSState.openSettings();
//openInDetails defaults to true
GPSState.openSettings(openInDetails:boolean);
```

```javascript
Expand Down
164 changes: 100 additions & 64 deletions android/src/main/java/br/com/dopaminamob/gpsstate/GPSStateModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.provider.Settings;
import android.support.annotation.Nullable;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.PermissionChecker;
Expand All @@ -33,10 +35,12 @@
import java.util.HashMap;
import java.util.Map;


/**
* Created by neuber on 14/08/17.
*/
public class GPSStateModule extends ReactContextBaseJavaModule implements ActivityCompat.OnRequestPermissionsResultCallback/*, ActivityEventListener, LocationListener, GpsStatus.Listener*/ {

public class GPSStateModule extends ReactContextBaseJavaModule implements ActivityCompat.OnRequestPermissionsResultCallback /*, ActivityEventListener, LocationListener, GpsStatus.Listener*/ {
private static final int STATUS_NOT_DETERMINED = 0;
private static final int STATUS_RESTRICTED = 1;
private static final int STATUS_DENIED = 2;
Expand All @@ -47,12 +51,14 @@ public class GPSStateModule extends ReactContextBaseJavaModule implements Activi
private static final int REQUEST_CODE_AUTHORIZATION = 1;

private static final String EVENT_STATUS_CHANGE = "OnStatusChange";

private boolean isListen = false;
private int targetSdkVersion = -1;
private BroadcastReceiver mGpsSwitchStateReceiver = null;
private LocationManager locationManager;

private int currentStatus = STATUS_NOT_DETERMINED;

private BroadcastReceiver mGpsSwitchStateReceiver = null;
private LocationManager locationManager;

public GPSStateModule(ReactApplicationContext reactContext) {
super(reactContext);
locationManager = (LocationManager) reactContext.getSystemService(reactContext.LOCATION_SERVICE);
Expand Down Expand Up @@ -82,8 +88,22 @@ public Map<String, Object> getConstants() {
constants.put("AUTHORIZED_WHENINUSE", STATUS_AUTHORIZED_WHENINUSE);
return constants;
}



@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults){
if(requestCode==REQUEST_CODE_AUTHORIZATION){
int status = STATUS_NOT_DETERMINED;

if(grantResults.length>0) {
int result = grantResults[0];
status = (result == PackageManager.PERMISSION_GRANTED) ? STATUS_AUTHORIZED : STATUS_DENIED;
}
sendEvent(status);
}
}



@ReactMethod
public void _startListen() {
_stopListen();
Expand Down Expand Up @@ -112,8 +132,20 @@ public void _getStatus(Promise promise) {
}

@ReactMethod
public void _openSettings(){
Intent callGPSSettingIntent = new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS);
public void _openSettings(boolean openDetails){
Intent callGPSSettingIntent = new Intent();
String packageName = getReactApplicationContext().getPackageName();
String intentAction = Settings.ACTION_APPLICATION_DETAILS_SETTINGS;
if(openDetails && isMarshmallowOrAbove()){
intentAction = android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS;

Uri uri = Uri.fromParts("package", packageName, null);
callGPSSettingIntent.setData(uri);

waitForPermissionBecomeGranted();
}

callGPSSettingIntent.setAction(intentAction);
getCurrentActivity().startActivityForResult(callGPSSettingIntent, 0);
}

Expand All @@ -125,13 +157,12 @@ public void _requestAuthorization(){


int getGpsState(){
int status = STATUS_NOT_DETERMINED;
boolean enabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);

//TODO check permission to inform the correct status
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M || targetSdkVersion >= Build.VERSION_CODES.M) {
int permission = ActivityCompat.checkSelfPermission(getReactApplicationContext(), Manifest.permission.ACCESS_FINE_LOCATION);
boolean isGranted = permission == PackageManager.PERMISSION_GRANTED;
int status;
boolean enabled = isGpsEnabled();

if(isMarshmallowOrAbove()) {
boolean isGranted = isPermissionGranted();

if(enabled) {
if(isGranted){
status = STATUS_AUTHORIZED;
Expand All @@ -144,9 +175,23 @@ int getGpsState(){
}else{
status = (enabled ? STATUS_AUTHORIZED : STATUS_RESTRICTED);
}


currentStatus = status;
return status;
}

int getPermission(){
return ActivityCompat.checkSelfPermission(getReactApplicationContext(), Manifest.permission.ACCESS_FINE_LOCATION);
}

boolean isPermissionGranted(){
int permission = getPermission();
return permission == PackageManager.PERMISSION_GRANTED;
}

boolean isGpsEnabled(){
return locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
}


void sendEvent(int status){
Expand All @@ -156,54 +201,45 @@ void sendEvent(int status){

reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit(EVENT_STATUS_CHANGE, params);
}

/*
@Override
public void onLocationChanged(Location location) {}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
Toast.makeText(getReactApplicationContext(), "onStatusChanged: ["+provider+"]"+status, Toast.LENGTH_LONG).show();
}
@Override
public void onGpsStatusChanged(int event) {
Toast.makeText(getReactApplicationContext(), "onGpsStatusChanged: "+event, Toast.LENGTH_LONG).show();
}
@Override
public void onProviderEnabled(String provider) {
Toast.makeText(getReactApplicationContext(), "onProviderEnabled: "+provider, Toast.LENGTH_LONG).show();
}
@Override
public void onProviderDisabled(String provider) {
Toast.makeText(getReactApplicationContext(), "onProviderDisabled: "+provider, Toast.LENGTH_LONG).show();
}
@Override
public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data) {
int rc = resultCode;
Toast.makeText(getReactApplicationContext(), "onActivityResult: "+rc, Toast.LENGTH_LONG).show();
}
@Override
public void onNewIntent(Intent intent) {}
*/

@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults){
if(requestCode==REQUEST_CODE_AUTHORIZATION){
int status = STATUS_NOT_DETERMINED;

if(grantResults.length>0) {
int result = grantResults[0];
status = (result == PackageManager.PERMISSION_GRANTED) ? STATUS_AUTHORIZED : STATUS_DENIED;
}
sendEvent(status);
}

boolean isMarshmallowOrAbove(){
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M || targetSdkVersion >= Build.VERSION_CODES.M;
}


boolean isPermissionEquals(int expectedPerm){
return currentStatus == expectedPerm;
}

boolean isAuthorized(){
return isPermissionEquals(STATUS_AUTHORIZED);
}

boolean isDenied(){
return isPermissionEquals(STATUS_DENIED);
}

boolean isUnknow(){
return isPermissionEquals(STATUS_NOT_DETERMINED);
}

void waitForPermissionBecomeGranted(){
final Ticker ticker = new Ticker();
ticker.setInterval(3000);
ticker.setMaxTicks(30);
ticker.startTick(new TickerCallBack() {
@Override
public void tick() {
if(isPermissionGranted()){
ticker.stopTick();
sendEvent(getGpsState());
}
}
});
}




private final class GPSProvideChangeReceiver extends BroadcastReceiver {

@Override
Expand Down
72 changes: 72 additions & 0 deletions android/src/main/java/br/com/dopaminamob/gpsstate/Ticker.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package br.com.dopaminamob.gpsstate;

public class Ticker {
private int maxTicks = 10;
private int interval = 1;
private int ticksCount = 0;
private boolean running = false;
private TickerCallBack callBack;

public void startTick(TickerCallBack cb){
running = true;
callBack = cb;
tick();
}

public void stopTick(){
running = false;
ticksCount = 0;
}

private void tick(){
if(!reachedMaxTicks() && hasCallback() && isRunning()){
new java.util.Timer().schedule(
new java.util.TimerTask() {
@Override
public void run() {
callBack.tick();
ticksCount ++;

tick();
}
},
getInterval()
);
}else{
stopTick();
}
}


public int getMaxTicks() {
return maxTicks;
}

public void setMaxTicks(int maxTicks) {
this.maxTicks = maxTicks;
}

public int getInterval() {
return interval;
}

public void setInterval(int interval) {
this.interval = interval;
}

public boolean isRunning(){
return running;
}

public boolean hasCallback(){
return callBack!=null;
}

public boolean reachedMaxTicks(){
return ticksCount >= getMaxTicks();
}
}

interface TickerCallBack {
void tick();
}
19 changes: 9 additions & 10 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@
const {NativeModules, NativeEventEmitter, Platform} = require('react-native');
const {GPSState} = NativeModules;

const isDroid = Platform.OS=='android';
const isIOS = Platform.OS=='ios';
const gpsStateEmitter = new NativeEventEmitter(GPSState);
var subscription = null;
var listener = null;
const isDroid = Platform.OS=='android';
const isIOS = Platform.OS=='ios';
var isListening = true;

subscription = gpsStateEmitter.addListener('OnStatusChange', (response)=>{
if(listener){
Expand All @@ -18,32 +19,30 @@ subscription = gpsStateEmitter.addListener('OnStatusChange', (response)=>{
status = response.status;
}

if(status)
if(status && isListening)
listener.apply(this, [status]);
}
});

GPSState.addListener = (callback)=>{
if(typeof callback == 'function'){
isListening = true;
listener = callback;
GPSState._startListen();
}
}

GPSState.removeListener = (callback)=>{
if(subscription){
GPSState._stopListen();
subscription.remove();
subscription = null;
}
isListening = false
GPSState._stopListen();
}

GPSState.getStatus = ()=>{
return GPSState._getStatus();
}

GPSState.openSettings = ()=>{
GPSState._openSettings();
GPSState.openSettings = (openInDetails=true)=>{
GPSState._openSettings(openInDetails);
}

GPSState.requestAuthorization = (authType)=>{
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "react-native-gps-state",
"description": "React Native Listener for GPS status changes",
"version": "0.0.2",
"version": "1.2.0",
"main": "index.js",
"repository": {
"type": "git",
Expand Down

0 comments on commit 4d62c08

Please sign in to comment.