0

I managed to incorporate Google Maps API within a TabLayout but it has 2 problems. One is that the app asks for the users location immediately and one the permission is granted it does not show the new updated location. Can anyone help me out?

MainActivity

public class MainActivity extends AppCompatActivity
        implements NavigationView.OnNavigationItemSelectedListener{

    private Toolbar toolbar;
    private TabLayout tabLayout;
    private ViewPager viewPager;
    private PagerAdapter pagerAdapter;
    private DrawerLayout drawerLayout;
    //private ViewPagerAdapter viewPagerAdapter;
    private String[] pageTitle = {"myPlanner", "News", "Parking"};
    private String studyRooms = "http://library2.csumb.edu/mrbs/mobilenow.php";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        drawerLayout = (DrawerLayout) findViewById(R.id.drawerLayout);
        setSupportActionBar(toolbar);

        //create default navigation drawer toggle
        ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, drawerLayout, toolbar,
                R.string.navigation_drawer_open, R.string.navigation_drawer_close);
        drawerLayout.addDrawerListener(toggle);
        toggle.syncState();


        tabLayout = (TabLayout) findViewById(R.id.tab_layout);
        tabLayout.setupWithViewPager(viewPager);
        for (int i = 0; i < 3; i++) {
            //TabLayout.Tab tab = tabLayout.getTabAt(i);
            //tab.setCustomView(pagerAdapter.getTabView(i));
            tabLayout.addTab(tabLayout.newTab().setText(pageTitle[i]));
        }

        //set gravity for tab bar
        tabLayout.setTabGravity(TabLayout.GRAVITY_FILL);
        //handling navigation view item event
        NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
        assert navigationView != null;
        navigationView.setNavigationItemSelectedListener(this);

        viewPager = (ViewPager)findViewById(R.id.view_pager);
        pagerAdapter = new PagerAdapter(getSupportFragmentManager(), MainActivity.this);
        viewPager.setAdapter(pagerAdapter);


        //setting Tab layout (number of Tabs = number of ViewPager pages)
        viewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));
        viewPager.setOffscreenPageLimit(3);
        tabLayout.addOnTabSelectedListener(new TabLayout.ViewPagerOnTabSelectedListener(viewPager));

    }

    class PagerAdapter extends FragmentPagerAdapter{

        String tabTitles[] = new String[]{"myPlanner", "News", "Parking"};
        public Fragment[] fragments = new Fragment[tabTitles.length];
        Context context;

        public PagerAdapter(FragmentManager fm, Context context){
            super(fm);
            this.context = context;
        }

        @Override
        public int getCount(){
            return tabTitles.length;
        }

        @Override
        public Fragment getItem(int position){
            switch (position){
                case 0:
                    return new myPlanner();
                case 1:
                    return new News();
                case 2:
                    return new MapsFragment();
            }
            return null;
        }

        public View getTabView(int position) {
            View tab = LayoutInflater.from(MainActivity.this).inflate(R.layout.custom_tab, null);
            TextView tv = (TextView) tab.findViewById(R.id.custom_text);
            tv.setText(tabTitles[position]);
            return tab;
        }


        @Override
        public CharSequence getPageTitle(int position){
            //Generate title based on item position
            return tabTitles[position];
        }

        @Override
        public Object instantiateItem(ViewGroup container, int position){
            Fragment createdFragment = (Fragment)super.instantiateItem(container,position);
            fragments[position] = createdFragment;
            return createdFragment;
        }

    }

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

        if(requestCode == MapsFragment.MY_PERMISSIONS_REQUEST_LOCATION){
            MapsFragment mapFragment = (MapsFragment) pagerAdapter.fragments[2];
            if(mapFragment != null){
                mapFragment.onRequestPermissionsResult(requestCode,permissions,grantResults);
            }
        }
        else{
            super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        }
    }



    /*
    Method for the navigation Drawer that takes in the id from the navigation drawer
    and based on the view, an action will be performed.
     */
    @Override
    public boolean onNavigationItemSelected(MenuItem item) {
        int id = item.getItemId();

        if (id == R.id.DinningCommonsItem) {
            viewPager.setCurrentItem(0);
        } else if (id == R.id.LibraryStudyRooms) {
            Uri uri = Uri.parse(studyRooms);
            Intent intent = new Intent(Intent.ACTION_VIEW, uri);
            startActivity(intent);
           // viewPager.setCurrentItem(1);
        } else if (id == R.id.MapYourRoute) {
            viewPager.setCurrentItem(2);
        } else if (id == R.id.CampusPD) {
            Intent i = new Intent(Intent.ACTION_DIAL, Uri.parse("tel:" + "18316550268"));
            i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            startActivity(i);

        } else if (id == R.id.close) {
            finish();
        }
        drawerLayout.closeDrawer(GravityCompat.START);
        return true;
    }

    @Override
    public void onBackPressed() {
        assert drawerLayout != null;
        if (drawerLayout.isDrawerOpen(GravityCompat.START)) {
            drawerLayout.closeDrawer(GravityCompat.START);
        } else {
            super.onBackPressed();
        }
    }

}

MapsFragment

public class MapsFragment extends SupportMapFragment implements OnMapReadyCallback,GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener, LocationListener{

    GoogleMap mGoogleMap;
    LocationRequest mLocationRequest;
    GoogleApiClient mGoogleApiClient;
    Location mLastLocation;
    Marker mCurrLocationMarker;

    MapView mMapView;
    View mView;
    LocationManager locationManager;
    static final int REQUEST_LOCATION = 1;

    @Override
    public void onResume() {
        super.onResume();
        Log.d("MapsFragment", "Inside onResume");
        setUpMapIfNeeded();
    }

    private void setUpMapIfNeeded() {
        Log.d("MapsFragment", "Inside setUpMapIfNeeded");

        if (mGoogleMap == null) {
            getMapAsync(this);
        }
    }

    //This method gets called when the activity's view is obstructed.
    @Override
    public void onPause() {
        super.onPause();
        Log.d("MapsFragment", "Inside onPause");

        //mMapView.onPause();
        //Stop location updates when Activity is no longer active
        if(mGoogleApiClient != null){
            LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient,this);
        }
    }

    //Call back method for when map is ready to be used.
    @Override
    public void onMapReady(GoogleMap googleMap){
        Log.d("MapsFragment", "Inside onMapReady");

        mGoogleMap =  googleMap;
        mGoogleMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);

        //Initialize Google Play Services
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
            if(ContextCompat.checkSelfPermission(getActivity(),
                    Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED){
                //Location Permission already granted
                buildGoogleApiClient();
                mGoogleMap.setMyLocationEnabled(true);
            }else{
                //Request location permission
                checkLocationPermission();
            }
        }
        else{
            buildGoogleApiClient();
            mGoogleMap.setMyLocationEnabled(true);
        }
    }


    private void buildGoogleApiClient() {
        Log.d("MapsFragment", "Inside buildGoogleApiClient");

        mGoogleApiClient = new GoogleApiClient.Builder(getActivity())
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .addApi(LocationServices.API)
                .build();
        mGoogleApiClient.connect();
    }

    //After calling connect(), this method will be invoked asynch when the
    //connect request has successfully completed.
    @Override
    public void onConnected(@Nullable Bundle bundle) {
        Log.d("MapsFragment", "Inside onConnected");

        mLocationRequest =  new LocationRequest();
        mLocationRequest.setInterval(1000);
        mLocationRequest.setFastestInterval(1000);
        mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);

        if(ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_FINE_LOCATION)
                == PackageManager.PERMISSION_GRANTED){
            LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient,
                    mLocationRequest, this);
        }
    }

    @Override
    public void onConnectionSuspended(int i) {

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

    }

    @Override
    public void onLocationChanged(Location location) {
        Log.d("MapsFragment", "Inside onLocationChanged");

        mLastLocation = location;
        if(mCurrLocationMarker != null){
            mCurrLocationMarker.remove();
        }

        //Place current location marker
        LatLng latLng = new LatLng(location.getLatitude(),location.getLongitude());
        MarkerOptions markerOptions = new MarkerOptions();
        markerOptions.position(latLng);
        markerOptions.title("Current Position");
        markerOptions.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_MAGENTA));
        mCurrLocationMarker = mGoogleMap.addMarker(markerOptions);

        //Move map Camera
        mGoogleMap.moveCamera(CameraUpdateFactory.newLatLng(latLng));
        mGoogleMap.animateCamera(CameraUpdateFactory.zoomBy(11));

        //Optionally, stop location updates if only current location is needed
        if(mGoogleApiClient != null){
            LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient,this);
        }
    }

    public static final int MY_PERMISSIONS_REQUEST_LOCATION = 99;

    private void checkLocationPermission() {
        Log.d("MapsFragment", "Inside checkLocationPermission");

        if(ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_FINE_LOCATION)
                != PackageManager.PERMISSION_GRANTED){
            //Should we show an explanation?
            if(ActivityCompat.shouldShowRequestPermissionRationale(getActivity(),
                    Manifest.permission.ACCESS_FINE_LOCATION)){

                //Show an explanation to the user *asyncly* -- dont block
                //this thread waiting for the user's response! After the user
                //sees the explanation try again to request the permission
                new AlertDialog.Builder(getActivity())
                        .setTitle("Location permission needed")
                        .setMessage("This app needs the Location permission, please accept to use location functionality")
                        .setPositiveButton("OK", new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int i) {
                                //prompt the user once the explanation has been shown
                                ActivityCompat.requestPermissions(getActivity(),
                                        new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
                                        MY_PERMISSIONS_REQUEST_LOCATION);
                            }
                        })
                        .create()
                        .show();
            }
            else{
                //NO explanation needed, we can request the permission.
                ActivityCompat.requestPermissions(getActivity(),
                        new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
                        MY_PERMISSIONS_REQUEST_LOCATION);
            }
        }
    }


    @Override
    public void onRequestPermissionsResult(int requestCode, String permissions[]
            , int[] grantResults){
        Log.d("MapsFragment", "Inside onRequestPermissionsResult");

        switch (requestCode){
            case MY_PERMISSIONS_REQUEST_LOCATION:{
                //If request is cancelled, the results arrays are empty
                if(grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){
                    //Permission was granted do the location-related task you need to do.
                    if(ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_FINE_LOCATION)
                            == PackageManager.PERMISSION_GRANTED){

                        if(mGoogleApiClient == null){
                            buildGoogleApiClient();
                        }
                        mGoogleMap.setMyLocationEnabled(true);
                    }
                }
                else{
                    //permissions were denied. Disable the functionality that depends onthis permission
                    Toast.makeText(getActivity(), "Permission denied",Toast.LENGTH_LONG).show();
                }
                return;
            }//Other case lines to check for other permissions this app might request
        }

    }
TheLearner
  • 312
  • 2
  • 20

1 Answers1

1

Please try this class, it is working fine.

public class MapsFragmentDemo extends com.google.android.gms.maps.MapFragment implements OnMapReadyCallback, GoogleApiClient.ConnectionCallbacks,
    GoogleApiClient.OnConnectionFailedListener, LocationListener {


private static final int REQUEST_LOCATION = 1;
private final int REQUEST_CHECK_SETTINGS = 300;
GoogleMap mGoogleMap;
LocationRequest mLocationRequest;
GoogleApiClient mGoogleApiClient;
Location mLastLocation;
Marker mCurrLocationMarker;
boolean isFragmentVisible = false;
private LocationSettingsRequest.Builder builder;
private PendingResult<LocationSettingsResult> result;

@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
    super.setUserVisibleHint(isVisibleToUser);
    if (isVisibleToUser) {
        isFragmentVisible = true;
        Log.d("MapsFragment", "Inside Visible");
        getMapAsync(this);
        createLocationRequest();
        buildGoogleApiClient();

    }
}


protected void createLocationRequest() {
    mLocationRequest = new LocationRequest();
    mLocationRequest.setInterval(1000);
    mLocationRequest.setFastestInterval(1000);
    mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
    mLocationRequest.setSmallestDisplacement(.5f);

}


@Override
public void onResume() {
    super.onResume();
    Log.d("MapsFragment", "Inside onResume");
    if (isFragmentVisible) {
        Log.d("MapsFragment", "Inside onResume true");
        if (mGoogleApiClient != null && mGoogleApiClient.isConnected()) {
            if (checkAccessPermission())
                startLocationUpdates();

            else
                askForPermission();
        }
    }
}

@Override
public void onPause() {
    super.onPause();
    Log.d("MapsFragment", "Inside onPause");
    stopLocationUpdates();
}

@Override
public void onStop() {
    super.onStop();
    Log.d("MapsFragment", "onStop fired ..............");
    if (mGoogleApiClient != null && !mGoogleApiClient.isConnected())
        mGoogleApiClient.disconnect();

}

protected void stopLocationUpdates() {
    if (mGoogleApiClient != null)
        LocationServices.FusedLocationApi.removeLocationUpdates(
                mGoogleApiClient, this);
}

protected void startLocationUpdates() {
    if (mGoogleApiClient != null) {

        accessLocation();
    }
}

private boolean checkAccessPermission() {
    return (ContextCompat.checkSelfPermission(getActivity(), android.Manifest.permission.ACCESS_FINE_LOCATION)
            == PackageManager.PERMISSION_GRANTED);
}

@SuppressWarnings("MissingPermission")
private void accessLocation() {
    LocationServices.FusedLocationApi.requestLocationUpdates(
            mGoogleApiClient, mLocationRequest, this);
    if (mGoogleMap != null)
        mGoogleMap.setMyLocationEnabled(true);
}

private void askForPermission() {
    // Should we show an explanation?
    if (android.support.v4.app.ActivityCompat.shouldShowRequestPermissionRationale(getActivity(),
            android.Manifest.permission.ACCESS_FINE_LOCATION)) {
        new AlertDialog.Builder(getActivity())
                .setTitle("Location permission needed")
                .setMessage("This app needs the Location permission, please accept to use location functionality")
                .setPositiveButton("OK", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int i) {
                        //prompt the user once the explanation has been shown
                        FragmentCompat.requestPermissions(MapsFragmentDemo.this,
                                new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION},
                                REQUEST_LOCATION);
                    }
                })
                .create()
                .show();
    } else
        FragmentCompat.requestPermissions(MapsFragmentDemo.this,
                new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION},
                REQUEST_LOCATION);
}


//Call back method for when map is ready to be used.
@Override
public void onMapReady(GoogleMap googleMap) {
    Log.d("MapsFragment", "Inside onMapReady");

    mGoogleMap = googleMap;
    mGoogleMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);


}

private void buildGoogleApiClient() {
    Log.d("MapsFragment", "Inside buildGoogleApiClient");

    mGoogleApiClient = new GoogleApiClient.Builder(getActivity())
            .addConnectionCallbacks(this)
            .addOnConnectionFailedListener(this)
            .addApi(LocationServices.API)
            .build();
    mGoogleApiClient.connect();
}


@Override
public void onConnected(@Nullable Bundle bundle) {
    Log.d("MapsFragment", "Inside onConnected");

    builder = new LocationSettingsRequest.Builder().addLocationRequest(mLocationRequest);
    result = LocationServices.SettingsApi.checkLocationSettings(mGoogleApiClient, builder.build());
    result.setResultCallback(new ResultCallback<LocationSettingsResult>() {
        @Override
        public void onResult(LocationSettingsResult result) {
            final Status status = result.getStatus();
            final LocationSettingsStates mState = result.getLocationSettingsStates();
            switch (status.getStatusCode()) {
                case LocationSettingsStatusCodes.SUCCESS:
                    if (!checkAccessPermission()) {

                        askForPermission();

                    } else
                        startLocationUpdates();
                    break;
                case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
                    try {
                        status.startResolutionForResult(getActivity(), REQUEST_CHECK_SETTINGS);
                    } catch (IntentSender.SendIntentException e) {
                    }
                    break;
                case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
                    break;
            }
        }
    });


}

public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    switch (requestCode) {
        case REQUEST_CHECK_SETTINGS:
            switch (resultCode) {
                case Activity.RESULT_OK:
                    if (!checkAccessPermission()) {

                        askForPermission();

                    } else
                        startLocationUpdates();
                    break;
                case Activity.RESULT_CANCELED:

                    break;
            }
            break;
    }
}

@Override
public void onConnectionSuspended(int i) {

}

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

}

@Override
public void onLocationChanged(Location location) {
    mGoogleMap.clear();
    Log.d("MapsFragment", "Inside onLocationChanged");
    LatLng latLng = new LatLng(location.getLatitude(), location.getLongitude());

    MarkerOptions markerOptions = new MarkerOptions();
    markerOptions.position(latLng);
    markerOptions.title("Current Position");
    markerOptions.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_MAGENTA));
    Marker currLocationMarker = mGoogleMap.addMarker(markerOptions);


    CameraPosition cameraPosition = new CameraPosition.Builder()
            .target(latLng).zoom(14).build();


    mGoogleMap.animateCamera(CameraUpdateFactory
            .newCameraPosition(cameraPosition));

    //Optionally, stop location updates if only current location is needed
    if (mGoogleApiClient != null) {
        stopLocationUpdates();
    }

}

@Override
public void onRequestPermissionsResult(int requestCode, String permissions[]
        , int[] grantResults) {
    Log.d("MapsFragment", "Inside onRequestPermissionsResult");

    switch (requestCode) {
        case REQUEST_LOCATION: {
            //If request is cancelled, the results arrays are empty
            if (grantResults.length > 0
                    && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                // permission was granted
                accessLocation();
            } else {
                // permission was denied
                Toast.makeText(getActivity(), "Permission denied", Toast.LENGTH_LONG).show();
            }
            return;
        }//Other case lines to check for other permissions this app might request
    }

}

}

Manish Jain
  • 2,139
  • 19
  • 15
  • Hi, I have a question: Why do we need the @SuppressedWarnings line within the accessLocation method? – TheLearner Mar 08 '17 at 18:22
  • Android lint gives false positive warning to check location permission but as we are calling it after checking permission so we don't need to check separately inside `accessLocation()` method. So we are using `@SuppressedWarning`. Check this [link](http://stackoverflow.com/questions/37642254/false-positive-lint-permission-error-even-after-asking-for-permission-at-runtime) – Manish Jain Mar 09 '17 at 04:43
  • FragmentCompact is available in v13 library. compile 'com.android.support:support-v13:25.1.1' – Manish Jain Mar 09 '17 at 04:44
  • Thank you for your answers. I am going to try it now. Also, As of right now I am not using an XML for the GoogleMap how can I resize the googlemap because it is the entire size of the screen minus the tablayout. I would like to add two buttons, one to save the user location and another to retrieve their saved location and display it on the map. – TheLearner Mar 09 '17 at 04:55
  • Please accept the answer if it working for you. Rest the layout issue is not a part of this question. – Manish Jain Mar 09 '17 at 05:12
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/137618/discussion-between-thelearner-and-manish-jain). – TheLearner Mar 09 '17 at 05:14
  • @TheLearner: accept the answer so it will benefit to others also. – Manish Jain Mar 09 '17 at 12:59