Reputation: 707
When I start my Android application for the first time, it will trigger a dialog to ask location permissions. The problem is that onRequestPermissionsResult
is already being triggered before I had the chance to press allow or deny. Because of this, the application doesn't have the permissions on the first startup and the Geofences are not set. Of course, when I restart the application, all permissions are granted and the Geofences work like they should. How do I tackle this problem on the first startup?
public class MainActivity extends BaseActivity implements OnRetailerClickListener, NetworkListener, GoogleApiClient.ConnectionCallbacks {
public final int REQUEST_LOCATION_PERMISSION = 2222;
private GoogleApiClient googleApiClient;
private ViewPager mViewPager;
private PagerAdapter mPagerAdapter;
private OnBackPressedListener onBackPressedListener;
private List<Geofence> geofenceList;
private Intent intent;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
/* Setup custom toolbar for viewpager layout */
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
toolbar.setTitle("Overview");
setSupportActionBar(toolbar);
/* Setup TabLayout for viewpager tabs */
TabLayout tabLayout = (TabLayout) findViewById(R.id.tab_layout);
tabLayout.addTab(tabLayout.newTab().setText(R.string.tab_products));
tabLayout.addTab(tabLayout.newTab().setText(R.string.tab_map));
tabLayout.setTabGravity(TabLayout.GRAVITY_FILL);
/* register to the geofence observer */
AppClassWiring.geofenceDao().registerObserver(this);
/* build up GoogleApiClient and connect, used to set the geofences */
googleApiClient = new GoogleApiClient
.Builder(this)
.addConnectionCallbacks(this)
.addApi(LocationServices.API).build();
googleApiClient.connect();
/* create a viewpager for the fragments */
mViewPager = (ViewPager) findViewById(R.id.pager);
mPagerAdapter = new PagerAdapter(getSupportFragmentManager(), tabLayout.getTabCount());
mViewPager.setPageTransformer(true, new ZoomOutPageTransformer());
mViewPager.setAdapter(mPagerAdapter);
mViewPager.setOffscreenPageLimit(mPagerAdapter.getCount()); // all fragments are kept in memory because there are only 3
initViewPagerListeners(mViewPager, tabLayout);
}
@Override
protected void onResume() {
super.onResume();
if(!DeviceUtils.checkBluetooth())
askBluetooth();
}
/**
* The OnClickListener in the fragment will trigger this method.
* This way the app can switch to the correct page in the viewpager
*
* @param retailer object received from fragment
*/
@Override
public void onRetailerClick(Retailer retailer) {
mViewPager.setCurrentItem(PagerAdapter.FRAGMENT_MAP, true);
mPagerAdapter.getItemForPosition(1).onRetailerClick(retailer);
}
/**
* Init the ViewPagerListeners, used to add an onPageChangeLister for the TabLayout
* also closes the keyboard when changing pages
*
* @param viewPager instance of the used viewpager
* @param tabLayout instance of the used TabLayout above
*/
private void initViewPagerListeners(final ViewPager viewPager, TabLayout tabLayout) {
viewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
DeviceUtils.hideKeyboard(MainActivity.this);
}
@Override
public void onPageSelected(int position) {
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
@Override
public void onTabSelected(TabLayout.Tab tab) {
viewPager.setCurrentItem(tab.getPosition());
DeviceUtils.hideKeyboard(MainActivity.this);
}
@Override
public void onTabUnselected(TabLayout.Tab tab) {
}
@Override
public void onTabReselected(TabLayout.Tab tab) {
}
});
}
/**
* Builder method to build up a Geofencingrequest with the retrieved backend data
*
* @param geofences to provide the data, required for a geofence to be built. This can be:
* an Id, Latitude, Longitude, Radius, ExpirationDuration and TransitionTypes
* @return a new instance of a GeofencingRequest
*/
private GeofencingRequest buildGeofenceRequest(List<Geofence> geofences) {
GeofencingRequest.Builder builder = new GeofencingRequest.Builder();
builder.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER);
builder.addGeofences(geofences);
return builder.build();
}
@Override
public void onConnectionSuspended(int i) {
Toast.makeText(this, "Could not connect with the Google API", Toast.LENGTH_LONG).show();
}
private void askBluetooth() {
new AlertDialog.Builder(this)
.setTitle("Enable bluetooth")
.setMessage("Bluetooth should be enabled, Turn bluetooth on?")
.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
DeviceUtils.setBluetoothOn(true);
}
})
.setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
DeviceUtils.setBluetoothOn(false);
}
})
.setIcon(android.R.drawable.stat_sys_data_bluetooth)
.show();
}
/**
* When the GoogleApiClient is connected,
* the user is able to get all the geofences from the backend
*
* @param bundle null
*/
@Override
public void onConnected(@Nullable Bundle bundle) {
/* Trigger the network call to get all geofences.
The results can be shared with other classes that also listen to it */
AppClassWiring.geofenceDao().getAllGeofences();
}
/**
* Observable method that listens to the incoming results of the network call for geofences
*
* @param pointList recieved geofence/point objects from the API.
* Used to build up a GeofencingRequest. After building the GeofencingRequest,
* the data is provided to the GoogleApiClient to setup the geofences ready to trigger
*/
@Override
public void onResult(Object pointList) {
List<Point> points = (List<Point>) pointList;
geofenceList = new ArrayList<>();
for (int i = 0; i < points.size(); i++) {
geofenceList.add(new Geofence.Builder()
.setRequestId(points.get(i).getRetailer())
.setCircularRegion(
points.get(i).getValidLat(),
points.get(i).getValidLong(),
points.get(i).getValidRadius())
.setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER
| Geofence.GEOFENCE_TRANSITION_EXIT)
.setExpirationDuration(Geofence.NEVER_EXPIRE)
.build());
}
intent = new Intent(this, GeoFencingService.class);
// Permission check
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_LOCATION_PERMISSION);
} else {
LocationServices.GeofencingApi.addGeofences(
googleApiClient,
buildGeofenceRequest(geofenceList),
PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
);
}
}
@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case REQUEST_LOCATION_PERMISSION: {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
LocationServices.GeofencingApi.addGeofences(
googleApiClient,
buildGeofenceRequest(geofenceList),
PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT));
}
}
}
}
}
/**
* @param error provides the error that was thrown by the retrofit call.
*/
@Override
public void onError(NetworkException error) {
Toast.makeText(this, error.getMessage(), Toast.LENGTH_SHORT).show();
}
@Override
protected void onDestroy() {
onBackPressedListener = null;
/* unregister from the geofence observer */
AppClassWiring.geofenceDao().unregisterObserver(this);
super.onDestroy();
}
@Override
public void onBackPressed() {
if (onBackPressedListener != null)
onBackPressedListener.doBack();
else
super.onBackPressed();
}
public void setOnBackPressedListener(OnBackPressedListener onBackPressedListener) {
this.onBackPressedListener = onBackPressedListener;
}
}
Upvotes: 4
Views: 2654
Reputation: 3422
Use this method in onCreate() method:
requestStoragePermission();
and define this method outside onCreate() method:
private void requestStoragePermission() {
if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED)
return;
if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED)
return;
if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED)
return;
if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED)
return;
ActivityCompat.requestPermissions(this, new String[]
{
android.Manifest.permission.READ_EXTERNAL_STORAGE,
android.Manifest.permission.WRITE_EXTERNAL_STORAGE,
android.Manifest.permission.CAMERA,
android.Manifest.permission.READ_PHONE_STATE,
}, STORAGE_PERMISSION_CODE);
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
//Checking the request code of our request
if (requestCode == STORAGE_PERMISSION_CODE) {
//If permission is granted
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
//Displaying a toast
} else {
//Displaying another toast if permission is not granted
Toast.makeText(this, "Oops you just denied the permission", Toast.LENGTH_LONG).show();
}
}
}
Upvotes: 2
Reputation: 1006584
The problem is that onRequestPermissionsResult is already being triggered before I had the chance to press alow or deny.
The only way that will happen is if you have already granted the permission, and so the dialog does not appear. Or, if you decide to call onRequestPermissionsResult()
yourself, which would be very strange.
Upvotes: 1