Google maps fragment into a viewpager activity [duplicate] - android

I managed to implement a TabLayout. Within one of the tabs is a Google Maps Fragment. I want to ask permission to access the user's location and then place a marker on the current location. As of right now, the dialog box does not show up and I do not know why. Can anyone help me?
public class MapsFragment extends Fragment implements OnMapReadyCallback{
GoogleMap mGoogleMap;
MapView mMapView;
View mView;
LocationManager locationManager;
static final int REQUEST_LOCATION = 1;
public MapsFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
mView = inflater.inflate(R.layout.fragment_maps,container,false);
return mView;
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState){
super.onViewCreated(view, savedInstanceState);
mMapView = (MapView) mView.findViewById(R.id.googleMap);
if(mMapView != null){
mMapView.onCreate(null);
mMapView.onResume();
mMapView.getMapAsync(this);
}
}
#Override
public void onMapReady(GoogleMap googleMap) {
mGoogleMap = googleMap;
googleMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
//Initialize Google PLay Services
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
if(ContextCompat.checkSelfPermission(getContext(),
Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED){
//Location Permission is gratned
MapsInitializer.initialize(getContext());
mGoogleMap.setMyLocationEnabled(true);
}
}
googleMap.addMarker(new MarkerOptions().position(new LatLng(36.652527, -121.797277)).title("CSUMB"));
CameraPosition CSUMB = CameraPosition.builder().target(new LatLng(36.6538, -121.797277)).zoom(16).bearing(0).tilt(45).build();
googleMap.moveCamera(CameraUpdateFactory.newCameraPosition(CSUMB));
}
void getLocation(){
locationManager = (LocationManager)getActivity()
.getSystemService(Context.LOCATION_SERVICE);
getLocation();
if(ActivityCompat.checkSelfPermission(getContext(), Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(getContext(),
Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED){
}else{
Location location = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
if(location!= null){
double latti = location.getLatitude();
double longi = location.getLongitude();
Toast.makeText(getActivity(),"Location is " + String.valueOf(latti) + ", " + String.valueOf(longi),Toast.LENGTH_LONG);
Log.e("Maps Fragment", "Location is: " + String.valueOf(latti) + ", " + String.valueOf(longi));
}
else{
Log.e("Maps fragment", "Unable to find current location.");
}
}
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case REQUEST_LOCATION:
getLocation();
break;
}
}
#Override
public void onResume() {
super.onResume();
mMapView.onResume();
}
#Override
public void onPause() {
super.onPause();
mMapView.onPause();
}
#Override
public void onDestroy() {
super.onDestroy();
mMapView.onDestroy();
}
#Override
public void onLowMemory() {
super.onLowMemory();
mMapView.onLowMemory();
}
}

This is very close to my other answer here, however, that answer doesn't explain how to do it using a ViewPager with a TabLayout.
First, the piece that sets this apart from the other answer, you'll need to keep a reference to the current Fragment in the FragmentPagerAdapter using the instantiateItem() override.
Also, note that the onRequestPermissionsResult() method is needed here in the Activity in order to route the user's permission request response to the Fragment.
Here is the full Activity code:
public class MainActivity extends AppCompatActivity {
ViewPager viewPager;
PagerAdapter pagerAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
// Get the ViewPager and set it's PagerAdapter so that it can display items
viewPager = (ViewPager) findViewById(R.id.viewpager);
pagerAdapter = new PagerAdapter(getSupportFragmentManager(), MainActivity.this);
viewPager.setAdapter(pagerAdapter);
// Give the TabLayout the ViewPager
TabLayout tabLayout = (TabLayout) findViewById(R.id.tab_layout);
tabLayout.setupWithViewPager(viewPager);
// Iterate over all tabs and set the custom view
for (int i = 0; i < tabLayout.getTabCount(); i++) {
TabLayout.Tab tab = tabLayout.getTabAt(i);
tab.setCustomView(pagerAdapter.getTabView(i));
}
}
class PagerAdapter extends FragmentPagerAdapter {
String tabTitles[] = new String[] { "Tab One", "Tab Two", "Tab Three", };
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 MapFragment();
case 1:
return new BlankFragment();
case 2:
return new BlankFragment();
}
return null;
}
#Override
public CharSequence getPageTitle(int position) {
// Generate title based on item position
return tabTitles[position];
}
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;
}
//This populates your Fragment reference array:
#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 == MapFragment.MY_PERMISSIONS_REQUEST_LOCATION){
MapFragment mapFragment = (MapFragment) pagerAdapter.fragments[0];
if (mapFragment != null) {
mapFragment.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
else {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
}
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context=".MainActivity">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/AppTheme.AppBarOverlay"
android:elevation="6dp">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:popupTheme="#style/ThemeOverlay.AppCompat.Light"
android:elevation="0dp" />
<android.support.design.widget.TabLayout
android:id="#+id/tab_layout"
app:tabMode="fixed"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/toolbar"
android:background="?attr/colorPrimary"
android:elevation="0dp"
app:tabTextColor="#d3d3d3"
app:tabSelectedTextColor="#ffffff"
app:tabIndicatorColor="#ff00ff"
android:minHeight="?attr/actionBarSize"
/>
</android.support.design.widget.AppBarLayout>
<android.support.v4.view.ViewPager
android:id="#+id/viewpager"
android:layout_width="match_parent"
android:layout_height="fill_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
/>
</android.support.design.widget.CoordinatorLayout>
custom_tab.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/custom_text"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:background="?attr/selectableItemBackground"
android:gravity="center"
android:textSize="16dip"
android:textColor="#ffffff"
android:maxLines="1"
/>
</LinearLayout>
For the Map Fragment, use essentially the same code as the other answer:
public class MapFragment extends SupportMapFragment
implements OnMapReadyCallback,
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener,
LocationListener {
GoogleMap mGoogleMap;
LocationRequest mLocationRequest;
GoogleApiClient mGoogleApiClient;
Location mLastLocation;
Marker mCurrLocationMarker;
#Override
public void onResume() {
super.onResume();
setUpMapIfNeeded();
}
private void setUpMapIfNeeded() {
if (mGoogleMap == null) {
getMapAsync(this);
}
}
#Override
public void onPause() {
super.onPause();
//stop location updates when Activity is no longer active
if (mGoogleApiClient != null) {
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
}
}
#Override
public void onMapReady(GoogleMap googleMap)
{
mGoogleMap=googleMap;
mGoogleMap.setMapType(GoogleMap.MAP_TYPE_HYBRID);
//Initialize Google Play Services
if (android.os.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);
}
}
protected synchronized void buildGoogleApiClient() {
mGoogleApiClient = new GoogleApiClient.Builder(getActivity())
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
mGoogleApiClient.connect();
}
#Override
public void onConnected(Bundle bundle) {
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(ConnectionResult connectionResult) {}
#Override
public void onLocationChanged(Location location)
{
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.zoomTo(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() {
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 *asynchronously* -- don't 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 dialogInterface, int i) {
//Prompt the user once 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) {
switch (requestCode) {
case MY_PERMISSIONS_REQUEST_LOCATION: {
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// permission was granted, yay! 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 {
// permission denied, boo! Disable the
// functionality that depends on this permission.
Toast.makeText(getActivity(), "permission denied", Toast.LENGTH_LONG).show();
}
return;
}
// other 'case' lines to check for other
// permissions this app might request
}
}
}
Result
First, the location permission prompt:
Once the user has accepted the permission at runtime, show the user's current location:

Related

My map shows but my markers dosnt in google maps [duplicate]

I managed to implement a TabLayout. Within one of the tabs is a Google Maps Fragment. I want to ask permission to access the user's location and then place a marker on the current location. As of right now, the dialog box does not show up and I do not know why. Can anyone help me?
public class MapsFragment extends Fragment implements OnMapReadyCallback{
GoogleMap mGoogleMap;
MapView mMapView;
View mView;
LocationManager locationManager;
static final int REQUEST_LOCATION = 1;
public MapsFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
mView = inflater.inflate(R.layout.fragment_maps,container,false);
return mView;
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState){
super.onViewCreated(view, savedInstanceState);
mMapView = (MapView) mView.findViewById(R.id.googleMap);
if(mMapView != null){
mMapView.onCreate(null);
mMapView.onResume();
mMapView.getMapAsync(this);
}
}
#Override
public void onMapReady(GoogleMap googleMap) {
mGoogleMap = googleMap;
googleMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
//Initialize Google PLay Services
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
if(ContextCompat.checkSelfPermission(getContext(),
Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED){
//Location Permission is gratned
MapsInitializer.initialize(getContext());
mGoogleMap.setMyLocationEnabled(true);
}
}
googleMap.addMarker(new MarkerOptions().position(new LatLng(36.652527, -121.797277)).title("CSUMB"));
CameraPosition CSUMB = CameraPosition.builder().target(new LatLng(36.6538, -121.797277)).zoom(16).bearing(0).tilt(45).build();
googleMap.moveCamera(CameraUpdateFactory.newCameraPosition(CSUMB));
}
void getLocation(){
locationManager = (LocationManager)getActivity()
.getSystemService(Context.LOCATION_SERVICE);
getLocation();
if(ActivityCompat.checkSelfPermission(getContext(), Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(getContext(),
Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED){
}else{
Location location = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
if(location!= null){
double latti = location.getLatitude();
double longi = location.getLongitude();
Toast.makeText(getActivity(),"Location is " + String.valueOf(latti) + ", " + String.valueOf(longi),Toast.LENGTH_LONG);
Log.e("Maps Fragment", "Location is: " + String.valueOf(latti) + ", " + String.valueOf(longi));
}
else{
Log.e("Maps fragment", "Unable to find current location.");
}
}
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case REQUEST_LOCATION:
getLocation();
break;
}
}
#Override
public void onResume() {
super.onResume();
mMapView.onResume();
}
#Override
public void onPause() {
super.onPause();
mMapView.onPause();
}
#Override
public void onDestroy() {
super.onDestroy();
mMapView.onDestroy();
}
#Override
public void onLowMemory() {
super.onLowMemory();
mMapView.onLowMemory();
}
}
This is very close to my other answer here, however, that answer doesn't explain how to do it using a ViewPager with a TabLayout.
First, the piece that sets this apart from the other answer, you'll need to keep a reference to the current Fragment in the FragmentPagerAdapter using the instantiateItem() override.
Also, note that the onRequestPermissionsResult() method is needed here in the Activity in order to route the user's permission request response to the Fragment.
Here is the full Activity code:
public class MainActivity extends AppCompatActivity {
ViewPager viewPager;
PagerAdapter pagerAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
// Get the ViewPager and set it's PagerAdapter so that it can display items
viewPager = (ViewPager) findViewById(R.id.viewpager);
pagerAdapter = new PagerAdapter(getSupportFragmentManager(), MainActivity.this);
viewPager.setAdapter(pagerAdapter);
// Give the TabLayout the ViewPager
TabLayout tabLayout = (TabLayout) findViewById(R.id.tab_layout);
tabLayout.setupWithViewPager(viewPager);
// Iterate over all tabs and set the custom view
for (int i = 0; i < tabLayout.getTabCount(); i++) {
TabLayout.Tab tab = tabLayout.getTabAt(i);
tab.setCustomView(pagerAdapter.getTabView(i));
}
}
class PagerAdapter extends FragmentPagerAdapter {
String tabTitles[] = new String[] { "Tab One", "Tab Two", "Tab Three", };
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 MapFragment();
case 1:
return new BlankFragment();
case 2:
return new BlankFragment();
}
return null;
}
#Override
public CharSequence getPageTitle(int position) {
// Generate title based on item position
return tabTitles[position];
}
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;
}
//This populates your Fragment reference array:
#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 == MapFragment.MY_PERMISSIONS_REQUEST_LOCATION){
MapFragment mapFragment = (MapFragment) pagerAdapter.fragments[0];
if (mapFragment != null) {
mapFragment.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
else {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
}
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context=".MainActivity">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/AppTheme.AppBarOverlay"
android:elevation="6dp">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:popupTheme="#style/ThemeOverlay.AppCompat.Light"
android:elevation="0dp" />
<android.support.design.widget.TabLayout
android:id="#+id/tab_layout"
app:tabMode="fixed"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/toolbar"
android:background="?attr/colorPrimary"
android:elevation="0dp"
app:tabTextColor="#d3d3d3"
app:tabSelectedTextColor="#ffffff"
app:tabIndicatorColor="#ff00ff"
android:minHeight="?attr/actionBarSize"
/>
</android.support.design.widget.AppBarLayout>
<android.support.v4.view.ViewPager
android:id="#+id/viewpager"
android:layout_width="match_parent"
android:layout_height="fill_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
/>
</android.support.design.widget.CoordinatorLayout>
custom_tab.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/custom_text"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:background="?attr/selectableItemBackground"
android:gravity="center"
android:textSize="16dip"
android:textColor="#ffffff"
android:maxLines="1"
/>
</LinearLayout>
For the Map Fragment, use essentially the same code as the other answer:
public class MapFragment extends SupportMapFragment
implements OnMapReadyCallback,
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener,
LocationListener {
GoogleMap mGoogleMap;
LocationRequest mLocationRequest;
GoogleApiClient mGoogleApiClient;
Location mLastLocation;
Marker mCurrLocationMarker;
#Override
public void onResume() {
super.onResume();
setUpMapIfNeeded();
}
private void setUpMapIfNeeded() {
if (mGoogleMap == null) {
getMapAsync(this);
}
}
#Override
public void onPause() {
super.onPause();
//stop location updates when Activity is no longer active
if (mGoogleApiClient != null) {
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
}
}
#Override
public void onMapReady(GoogleMap googleMap)
{
mGoogleMap=googleMap;
mGoogleMap.setMapType(GoogleMap.MAP_TYPE_HYBRID);
//Initialize Google Play Services
if (android.os.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);
}
}
protected synchronized void buildGoogleApiClient() {
mGoogleApiClient = new GoogleApiClient.Builder(getActivity())
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
mGoogleApiClient.connect();
}
#Override
public void onConnected(Bundle bundle) {
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(ConnectionResult connectionResult) {}
#Override
public void onLocationChanged(Location location)
{
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.zoomTo(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() {
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 *asynchronously* -- don't 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 dialogInterface, int i) {
//Prompt the user once 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) {
switch (requestCode) {
case MY_PERMISSIONS_REQUEST_LOCATION: {
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// permission was granted, yay! 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 {
// permission denied, boo! Disable the
// functionality that depends on this permission.
Toast.makeText(getActivity(), "permission denied", Toast.LENGTH_LONG).show();
}
return;
}
// other 'case' lines to check for other
// permissions this app might request
}
}
}
Result
First, the location permission prompt:
Once the user has accepted the permission at runtime, show the user's current location:

Have tabs preload their Fragments when app starts and have tabs save state

I have 3 tabs:
Home
Google Map
Settings
I have a main activity which has a TabLayout to show the 3 tabs:
public class MainActivity extends AppCompatActivity implements MyMapFragment.OnFragmentInteractionListener, SettingsFragment.OnFragmentInteractionListener {
private static final int INDEX_HOME_FRAGMENT = 0;
private static final int INDEX_MAP_FRAGMENT = 1;
private static final int INDEX_SETTINGS_FRAGMENT = 2;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TabLayout tabLayout = (TabLayout) findViewById(R.id.tab_layout);
tabLayout.addTab(tabLayout.newTab().setText("Home"));
tabLayout.addTab(tabLayout.newTab().setText("Map"));
tabLayout.addTab(tabLayout.newTab().setText("Settings"));
tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
#Override
public void onTabSelected(TabLayout.Tab tab) {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
switch(tab.getPosition()) {
case INDEX_HOME_FRAGMENT:
HomeFragment homeFragment = new HomeFragment();
transaction.replace(R.id.frame_layout, homeFragment);
// Commit the transaction
transaction.commit();
break;
case INDEX_MAP_FRAGMENT:
MyMapFragment myMapFragment = new MyMapFragment();
transaction.replace(R.id.frame_layout, myMapFragment);
// Commit the transaction
transaction.commit();
break;
case INDEX_SETTINGS_FRAGMENT:
SettingsFragment settingsFragment = new SettingsFragment();
transaction.replace(R.id.frame_layout, settingsFragment);
// Commit the transaction
transaction.commit();
break;
default:
//error occured here
Log.e("Error occured = ", " TAB_ERROR");
break;
}
}
});
// Check that the activity is using the layout version with
// the fragment_container FrameLayout
if (findViewById(R.id.frame_layout) != null) {
if (savedInstanceState != null) {
return;
}
HomeFragment homeFragment = new HomeFragment();
// Add the fragment to the 'fragment_container' FrameLayout
getSupportFragmentManager().beginTransaction()
.add(R.id.frame_layout, homeFragment ).commit();
}
}
#Override
public void onFragmentInteraction(Uri uri) {
//do nothing
}
}
This Activity also handles when a tab gets clicked. When a tab gets clicked it should show the Fragment in the FrameLayout.
This all works fine. The only problem is when I click the Maps tab, Google maps always refreshes.
I want the map to preload when the app starts so when the user clicks the map tab the map shoudl already be loaded. As well when the user goes away from the map tab and comes back it should save the map as it was previously. Currently when the user goes back to the map tab the map is reloaded and it takes again some time for it to load.
This is my map Fragment:
public class MyMapFragment extends SupportMapFragment
implements OnMapReadyCallback,
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener,
LocationListener {
public static final int MY_PERMISSIONS_REQUEST_LOCATION = 99;
GoogleMap mGoogleMap;
LocationRequest mLocationRequest;
GoogleApiClient mGoogleApiClient;
Marker lastOpenned = null;
#Override
public void onResume() {
super.onResume();
setUpMapIfNeeded();
}
private void setUpMapIfNeeded() {
if (mGoogleMap == null) {
getMapAsync(this);
}
}
#Override
public void onPause() {
super.onPause();
//stop location updates when Activity is no longer active
if (mGoogleApiClient != null) {
//LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient,this);
}
}
#Override
public void onMapReady(GoogleMap googleMap) {
mGoogleMap = googleMap;
LatLngBounds.Builder builder = new LatLngBounds.Builder();
mGoogleMap.addMarker(new MarkerOptions()
.position(new LatLng(40.76793169992044, -73.98180484771729))
.title("San Francisco"));
mGoogleMap.addMarker(new MarkerOptions()
.position(new LatLng(41.76793169992044, -72.98180484771729))
.title("Las Vegas"));
builder.include(new LatLng(40.76793169992044, -73.98180484771729));
builder.include(new LatLng(41.76793169992044, -72.98180484771729));
LatLngBounds bounds = builder.build();
mGoogleMap.animateCamera(CameraUpdateFactory.newLatLngBounds(bounds, 200));
mGoogleMap.setOnMarkerClickListener(new GoogleMap.OnMarkerClickListener() {
public boolean onMarkerClick(Marker marker) {
return true;
}
});
//Initialize Google Play Services
if (android.os.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);
}
}
protected synchronized void buildGoogleApiClient() {
mGoogleApiClient = new GoogleApiClient.Builder(getActivity())
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
mGoogleApiClient.connect();
}
#Override
public void onConnected(Bundle bundle) {
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 onLocationChanged(Location location) {
}
private void 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 *asynchronously* -- don't 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 dialogInterface, int i) {
//Prompt the user once 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) {
switch (requestCode) {
case MY_PERMISSIONS_REQUEST_LOCATION: {
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// permission was granted, yay! 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 {
// permission denied, boo! Disable the
// functionality that depends on this permission.
Toast.makeText(getActivity(), "permission denied", Toast.LENGTH_LONG).show();
}
return;
}
// other 'case' lines to check for other
// permissions this app might request
}
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
}
public interface OnFragmentInteractionListener {
// TODO: Update argument type and name
void onFragmentInteraction(Uri uri);
}
}
I would suggest not making new MyMapFragment() every time you click the tab if you don't want the map to reload.
A simple way to do that is a simple wrapper Fragment holder class.
public class MainActivity extends AppCompatActivity
implements MyMapFragment.OnFragmentInteractionListener, SettingsFragment.OnFragmentInteractionListener {
static class FragmentTab {
String name;
Fragment frag;
public FragmentTab(String name, Fragment f) {
this.name = name;
this.frag = f;
}
}
// These are only created once, not per-click
private List<FragmentTab> tabs = Arrays.asList(
new FragmentTab("Home", new HomeFragment()),
new FragmentTab("Map", new MyMapFragment()),
new FragmentTab("Settings", new SettingsFragment()),
);
Then, you can iterate and index that list to clean up the rest of your code
for (FragmentTab tab : tabs) {
tabLayout.addTab(tabLayout.newTab().setText(tab.name));
}
tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
#Override
public void onTabSelected(TabLayout.Tab tab) {
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.frame_layout, tabs.get(tab.getPosition()).frag)
.commit();
}
};
A LinkedHashMap<String, Fragment> would also work, but replacing tab.getPosition() for tab.getTitle() (I think)

Requesting location permissions

My app is using API 23 and I'm using my Samsung Galaxy S5 to test it. I am using the GoogleMaps API as well.
In the onConnected() method I want to retrieve the user's current location so I have this:
mLastLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
but with only that, it is underlined red with the following error:
Call requires permission which may be rejected by the user: code should explicitly check to see if permission is available (with CheckPermission)...
and it gives me the option to 'add permission check' which inserts some code and I add something to it, so the onConnected() method is like this
#Override
public void onConnected(Bundle bundle) {
Log.i(TAG, "oOnConnected() called");
boolean r = ActivityCompat.checkSelfPermission(this,
android.Manifest.permission.ACCESS_FINE_LOCATION) !=
PackageManager.PERMISSION_GRANTED;
Log.i(TAG, "result = : " + r );
if (ActivityCompat.checkSelfPermission(this,
android.Manifest.permission.ACCESS_FINE_LOCATION) !=
PackageManager.PERMISSION_GRANTED ) {
Log.i(TAG, "PERMISSIONS NOT SET");
requestPermissions(new String[] { android.Manifest.permission.ACCESS_FINE_LOCATION }, 100);
return;
}
mLastLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
String s = String.valueOf(mLastLocation.getLatitude()) + " " +
String.valueOf(mLastLocation.getLongitude());
Log.i(TAG, "CURRENT LOCATION: " + s);
}
There is a problem when I run the code:
(1) When I have location on my device enabled it works fine, I see my current location in the terminal. I check the value of r and it's false...
(2) When location is disabled, when I run the app it crashes and the "stop working" message appears. I check the terminal and it crashed because of the mLastLocation object is null or something. But those lines shouldn't be executed, it should be asking for permissions. I checked the value of r and it's false as well.
Why is r false in both cases? How do I fix this to get permissions to pop up when location is disabled?
my solution would be
in the manifest file
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<meta-data
android:name="com.google.android.maps.v2.API_KEY"
android:value="YOUR_KEY" />
i created a fragment that will hold the map
public class BlankFragment extends Fragment implements OnMapReadyCallback, GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener {
private GoogleApiClient googleApiClient = null;
FusedLocationProviderApi fusedLocationProviderApi;
LocationRequest locationRequest;
final int PERMISSIONS_REQUEST = 900;
private static final LatLng STUTTGART = new LatLng(48.792925, 9.204344);
private static final float STUTTGART_ZOOM = 16;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_blank, container, false);
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getLocation();
}
private void getLocation() {
locationRequest = LocationRequest.create();
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
locationRequest.setInterval(10000);
locationRequest.setFastestInterval(5000);
fusedLocationProviderApi = LocationServices.FusedLocationApi;
googleApiClient = new GoogleApiClient.Builder(getContext())
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
googleApiClient.connect();
}
#Override
public void onConnected(Bundle arg0) {
if (ActivityCompat.checkSelfPermission(getContext(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
&& ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(getActivity(),
new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION},
PERMISSIONS_REQUEST);
return;
}
fusedLocationProviderApi.requestLocationUpdates(googleApiClient, locationRequest, this);
}
#Override
public void onLocationChanged(Location location) {
Toast.makeText(getContext(), "location :"+location.getLatitude()+" , "+location.getLongitude(), Toast.LENGTH_SHORT).show();
}
#Override
public void onPause() {
super.onPause();
if (googleApiClient.isConnected()) {
googleApiClient.disconnect();
}
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
SupportMapFragment mapFragment = (SupportMapFragment) this.getChildFragmentManager()
.findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
}
#Override
public void onMapReady(GoogleMap googleMap) {
googleMap.clear();
googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(STUTTGART, STUTTGART_ZOOM));
googleMap.getUiSettings().setMapToolbarEnabled(false);
}
#Override
public void onConnectionSuspended(int i) {
}
#Override
public void onRequestPermissionsResult(int requestCode,
#NonNull String permissions[], #NonNull int[] grantResults) {
switch (requestCode) {
case PERMISSIONS_REQUEST: {
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// permission was granted, yay!
fusedLocationProviderApi.requestLocationUpdates(googleApiClient, locationRequest, this);
}
}
}
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
}
}
the xml file looks like this
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.bemaxnet.test.maps.fragment.BlankFragment">
<fragment
android:id="#+id/map"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<Button
android:id="#+id/currentLocation"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="current location"
android:drawableLeft="#android:drawable/ic_menu_add"/>
</FrameLayout>
and finally added those dependencies in the app gradle
compile 'com.google.android.gms:play-services-maps:9.6.1'
compile 'com.google.android.gms:play-services-location:9.6.1'

Android Runtime Permissions: catching the user's press on "Allow"

In my app I've a MapFragment with the classic "MyLocationButton".
On older APIs I don't have any kind of issue, but since Google asked developers to use Runtime Permissions, I'm facing this problem: when the user clicks ALLOW, the already said button is not appearing, at least not until the user refreshes this fragment. Is there a way to catch the user's press to make the fragment refresh as soon as he's given permissions?
EDIT:
I'm using nested fragments, and I've found out my problem is the same you can see at this page of the AOSP Issue Tracker. I've solved it using the last version of Android APIs (v24).
I'll post my MapFragment:
public class MapFragment extends Fragment implements OnMapReadyCallback, GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener, PetrolStationsArray.PetrolStationsListener {
private GoogleMap mGoogleMap;
private int mMapType;
private static LatLng mPosition;
private static float mZoom;
private CoordinatorLayout mCoordinatorLayout;
private View mLocationButton;
private AppCompatImageButton mTurnGPSOn;
private FragmentManager mFragmentManager;
private FragmentTransaction mFragmentTransaction;
private SupportMapFragment mSupportMapFragment;
private SupportPlaceAutocompleteFragment mSupportPlaceAutocompleteFragment;
private LocalBroadcastManager mLocalBroadcastManager;
private PetrolStationsArray mPetrolStationsArray;
protected LocationRequest mLocationRequest;
protected GoogleApiClient mGoogleApiClient;
Marker mCurrLocationMarker;
private CountDownTimer mDragTimer;
private boolean mTimerIsRunning = false;
// Design pattern to instantiate a new fragment.
public static MapFragment newInstance() {
MapFragment fragment = new MapFragment();
return fragment;
}
/********************************************************/
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Since API 23, Android requests you check for Location Permissions.
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
checkLocationPermission();
}
mMapType = Integer.parseInt(loadPreferences(SETTINGS_PREFERENCES, MAP_KEY));
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_map, container, false);
mLocalBroadcastManager = LocalBroadcastManager.getInstance(getContext());
mPetrolStationsArray = PetrolStationsArray.get();
mDragTimer = new CountDownTimer(DRAG_TIMER_INTERVAL, DRAG_TIMER_INTERVAL + 1) {
#Override
public void onTick(long l) {
}
#Override
public void onFinish() {
mTimerIsRunning = false;
mPetrolStationsArray.setPosition(mPosition);
}
};
return view;
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
// Initialise a new fragment inside of this one.
mFragmentManager = getChildFragmentManager();
mSupportMapFragment = (SupportMapFragment) mFragmentManager.findFragmentByTag(MAP_FRAGMENT_TAG);
mSupportPlaceAutocompleteFragment = (SupportPlaceAutocompleteFragment) mFragmentManager.findFragmentByTag(AUTOCOMPLETE_FRAGMENT_TAG);
mCoordinatorLayout = (CoordinatorLayout) view.findViewById(R.id.coordinator_layout);
/*
** Never inflate fragments inside other fragments in a layout.xml!
** Do it programmatically.
** See here for reference: http://stackoverflow.com/a/19815266/4938112.
*/
if (mSupportMapFragment == null) {
mSupportMapFragment = new SupportMapFragment();
fragmentTransaction(mFragmentManager, mSupportMapFragment, R.id.map_fragment_container, MAP_FRAGMENT_TAG);
}
// Asynchronous thread to load map.
mSupportMapFragment.getMapAsync(this);
if (mSupportPlaceAutocompleteFragment == null) {
mSupportPlaceAutocompleteFragment = new SupportPlaceAutocompleteFragment();
fragmentTransaction(mFragmentManager, mSupportPlaceAutocompleteFragment, R.id.card_view, AUTOCOMPLETE_FRAGMENT_TAG);
}
// Filter for a specific place type.
AutocompleteFilter typeFilter = new AutocompleteFilter.Builder()
.setTypeFilter(AutocompleteFilter.TYPE_FILTER_CITIES | AutocompleteFilter.TYPE_FILTER_ADDRESS)
.build();
mSupportPlaceAutocompleteFragment.setFilter(typeFilter);
mSupportPlaceAutocompleteFragment.setOnPlaceSelectedListener(new PlaceSelectionListener() {
#Override
public void onPlaceSelected(Place place) {
LatLng position = place.getLatLng();
CameraUpdate centre = CameraUpdateFactory.newLatLng(position);
CameraUpdate zoom = CameraUpdateFactory.zoomTo(ZOOM_LEVEL);
mGoogleMap.moveCamera(centre);
mGoogleMap.animateCamera(zoom);
}
#Override
public void onError(Status status) {
Log.d("PLACE_ERROR", "An error occurred: " + status);
}
});
mTurnGPSOn = ((AppCompatImageButton) view.findViewById(R.id.turn_gps_on));
mTurnGPSOn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// Ask if the user wants to open the GPS - settings.
displayPromptToEnableGPS(getActivity());
}
});
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
}
#Override
public void onMapReady(GoogleMap googleMap) {
this.mGoogleMap = googleMap;
mGoogleMap.setMapType(mMapType);
if (mPosition != null) {
CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngZoom(mPosition, mZoom);
mGoogleMap.moveCamera(cameraUpdate);
}
mGoogleMap.setTrafficEnabled(true);
mGoogleMap.getUiSettings().setMapToolbarEnabled(false);
mGoogleMap.setOnCameraChangeListener(new GoogleMap.OnCameraChangeListener() {
#Override
public void onCameraChange(CameraPosition cameraPosition) {
mPosition = cameraPosition.target;
mZoom = cameraPosition.zoom;
if (mTimerIsRunning) {
mDragTimer.cancel();
}
mDragTimer.start();
mTimerIsRunning = true;
}
});
// Get the "My Position" button.
mLocationButton = ((View) mSupportMapFragment.getView().findViewById(Integer.parseInt("1")).getParent()).findViewById(Integer.parseInt("2"));
RelativeLayout.LayoutParams rlp = (RelativeLayout.LayoutParams) mLocationButton.getLayoutParams();
Resources r = getActivity().getResources();
int px = (int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
10,
r.getDisplayMetrics()
);
// Position on right bottom.
rlp.addRule(RelativeLayout.ALIGN_PARENT_TOP, 0);
rlp.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, RelativeLayout.TRUE);
rlp.setMargins(0, 0, px, px);
turnOnMyLocation();
}
#Override
public void onPause() {
super.onPause();
// Stop location updates when Activity is no longer active.
if (mGoogleApiClient != null && mGoogleApiClient.isConnected()) {
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
}
mPetrolStationsArray.removePetrolStationListener(this);
}
#Override
public void onResume() {
super.onResume();
mPetrolStationsArray.setPetrolStationsListener(this);
}
#Override
public void onListUpdated() {
// Cleaning all the markers.
if (mGoogleMap != null) {
mGoogleMap.clear();
}
List<PetrolStation> petrolStationList = mPetrolStationsArray.getList();
for (PetrolStation petrolStation : petrolStationList) {
double lat = petrolStation.getLat();
double lon = petrolStation.getLon();
String name = petrolStation.getName();
if (mGoogleMap != null) {
mGoogleMap.addMarker(new MarkerOptions()
.position(new LatLng(lat, lon))
.title(name));
}
}
}
#Override
public void onServerRequest() {
}
#Override
public void onConnected(Bundle bundle) {
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(1000);
mLocationRequest.setFastestInterval(1000);
mLocationRequest.setPriority(LocationRequest.PRIORITY_LOW_POWER);
if (ContextCompat.checkSelfPermission(getContext(), Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
}
}
#Override
public void onConnectionSuspended(int i) {
// TODO
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
// TODO
}
#Override
public void onLocationChanged(Location location) {
if (mCurrLocationMarker != null) {
mCurrLocationMarker.remove();
}
// Just a check to overtake the
// 'java.lang.IllegalStateException: Fragment MapFragment{42f519d0} not attached to Activity'
// exception I've encountered.
if (!isAdded()) {
return;
}
// Stop location updates.
if (mGoogleApiClient != null) {
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
}
}
// Start the transaction between different fragments.
private void fragmentTransaction(FragmentManager mFragmentManager, Fragment fragment, int id, String tag) {
mFragmentTransaction = mFragmentManager.beginTransaction();
mFragmentTransaction.add(id, fragment, tag);
mFragmentTransaction.commit();
mFragmentManager.executePendingTransactions();
}
/*********************************************
************ LOCATION PERMISSIONS ************
*********************************************/
#Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case MY_PERMISSIONS_REQUEST_LOCATION: {
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
turnOnMyLocation();
} else {
// Permission denied, boo! Disable the functionality that depends on this permission.
String message = getResources().getString(R.string.permission_denied);
Snackbar snackbar = Snackbar
.make(mCoordinatorLayout, message, Snackbar.LENGTH_LONG)
.setAction(R.string.close_snack_bar, new View.OnClickListener() {
#Override
public void onClick(View view) {
}
});
snackbar.show();
}
}
}
}
// Ask for permission (START DIALOG) in Android APIs >= 23.
public boolean checkLocationPermission() {
if (ContextCompat.checkSelfPermission(getContext(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// Should we show an explanation?
if (shouldShowRequestPermissionRationale(Manifest.permission.ACCESS_FINE_LOCATION)) {
// Prompt the user once explanation has been shown.
requestPermissions(new String[] {
Manifest.permission.ACCESS_FINE_LOCATION
}, MY_PERMISSIONS_REQUEST_LOCATION);
} else {
// No explanation needed, we can request the permission.
requestPermissions(new String[] {
Manifest.permission.ACCESS_FINE_LOCATION
}, MY_PERMISSIONS_REQUEST_LOCATION);
}
return false;
} else {
return true;
}
}
public void turnOnMyLocation() {
// Initialise Google Play Services.
if (mGoogleApiClient == null) {
buildGoogleApiClient();
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (ContextCompat.checkSelfPermission(getContext(), Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
mGoogleMap.setMyLocationEnabled(true);
}
} else {
mGoogleMap.setMyLocationEnabled(true);
}
}
// Let's build our Location Services API Client.
protected synchronized void buildGoogleApiClient() {
mGoogleApiClient = new GoogleApiClient
.Builder(getContext())
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
mGoogleApiClient.connect();
}
public static void displayPromptToEnableGPS(final Activity activity) {
final AlertDialog.Builder builder = new AlertDialog.Builder(activity);
final String action = Settings.ACTION_LOCATION_SOURCE_SETTINGS;
final String message = MyFuelApp.getAppContext().getResources().getString(R.string.open_gps_settings);
builder.setMessage(message)
.setPositiveButton(MyFuelApp.getAppContext().getResources().getString(R.string.confirm_ok),
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface d, int id) {
activity.startActivity(new Intent(action));
d.dismiss();
}
})
.setNegativeButton(MyFuelApp.getAppContext().getResources().getString(R.string.deny_no),
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface d, int id) {
d.cancel();
}
});
builder.create().show();
}
}
One way to solve is to ask before open your MapFragment. This way you only have to check if you have the permission or not at your fragment to load one view or another.
The other way, is to add the button at your method turnOnMyLocation().
You can use
onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults)
within this callback you should check the equality of the request code that you passed while requesting permission with the one in the parameter. If it matches, you can get the user result.
If user allow the permission, then you can simply detach and attach your fragment as follow:
Fragment currentFragment = getFragmentManager().findFragmentByTag("FRAGMENT");
FragmentTransaction fragTransaction = getFragmentManager().beginTransaction();
fragTransaction.detach(currentFragment);
fragTransaction.attach(currentFragment);
fragTransaction.commit();
This is how your fragment will be reloaded and also your views gets refreshed. I hope by this you can address your problem.

Android onCameraChange in Fragment is never called

I'm trying to set a listener to catch camera moves but it doesn't work. The method onCameraChange, implemented by the Fragment that host the SupportMapFragment, is never called also if I set up all right. This similar question didn't help me.
Here's the code of the Fragment:
public class MapFragment extends Fragment implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener,
OnMapReadyCallback, GoogleMap.OnCameraChangeListener {
private static final String TAG = MapFragment.class.getSimpleName();
private static final int MY_LOCATION_REQUEST_PERMISSION = 100;
private static final int ENABLE_LOCATION_REQUEST_PERMISSION = 200;
private int mShortAnimationDuration;
private ImageButton checkin;
private LinearLayout big_checkin;
private GoogleMap mMap;
private GoogleApiClient mGoogleApiClient;
private double mLatitude, mLongitude;
private SupportPlaceAutocompleteFragment autocompleteFragment;
public MapFragment() {
// Required empty public constructor
}
#Override
public void onCreate(Bundle savedInstanceState) {
if (BuildConfig.DEBUG) {
Log.d(TAG, "onCreate");
}
super.onCreate(savedInstanceState);
buildGoogleApiClient();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if (BuildConfig.DEBUG) {
Log.d(TAG, "onCreateView");
}
// Inflate the layout for this fragment
final View view = inflater.inflate(R.layout.fragment_map, container, false);
final SupportMapFragment mapFragment = (SupportMapFragment) getChildFragmentManager().findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
final DrawerLayout drawer = (DrawerLayout) getActivity().findViewById(R.id.drawer_layout);
final Toolbar toolbar = (Toolbar) view.findViewById(R.id.map_toolbar);
((AppCompatActivity) getActivity()).setSupportActionBar(toolbar);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
getActivity(), drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawer.addDrawerListener(toggle);
toggle.syncState();
autocompleteFragment = (SupportPlaceAutocompleteFragment)
getChildFragmentManager().findFragmentById(R.id.place_autocomplete_fragment);
return view;
}
protected synchronized void buildGoogleApiClient() {
mGoogleApiClient = new GoogleApiClient.Builder(getContext())
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
}
private void getMyLocation() {
if (ContextCompat.checkSelfPermission(getContext(),
Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
PermissionUtils.requestPermission((AppCompatActivity) getActivity(), MY_LOCATION_REQUEST_PERMISSION, Manifest.permission.ACCESS_FINE_LOCATION, false);
} else {
final Location lastLocation = LocationServices.FusedLocationApi.getLastLocation(
mGoogleApiClient);
if (lastLocation != null) {
mLatitude = lastLocation.getLatitude();
mLongitude = lastLocation.getLongitude();
LatLng latLng = new LatLng(mLatitude, mLongitude);
CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngZoom(latLng, 17);
if (mMap != null) {
mMap.animateCamera(cameraUpdate);
mClusterManager.clearItems();
addItems();
}
} else {
if (mMap != null) {
mMap.setMyLocationEnabled(false);
}
final ImageButton myLocation = (ImageButton) getView().findViewById(R.id.my_location); //TODO migliorare
myLocation.setVisibility(View.GONE);
}
}
}
#Override
public void onDestroy() {
if (BuildConfig.DEBUG) {
Log.d(TAG, "onDestroy");
}
super.onDestroy();
}
#Override
public void onDestroyView() {
if (BuildConfig.DEBUG) {
Log.d(TAG, "onDestroyView");
}
super.onDestroyView();
mMap = null;
mGoogleApiClient = null;
autocompleteFragment = null;
}
#Override
public void onStart() {
if (BuildConfig.DEBUG) {
Log.d(TAG, "onStart");
}
super.onStart();
if (mGoogleApiClient != null)
mGoogleApiClient.connect();
}
#Override
public void onStop() {
if (BuildConfig.DEBUG) {
Log.d(TAG, "onStop");
}
mGoogleApiClient.disconnect();
super.onStop();
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
if (requestCode == MY_LOCATION_REQUEST_PERMISSION) {
if (PermissionUtils.isPermissionGranted(permissions, grantResults,
Manifest.permission.ACCESS_FINE_LOCATION)) {
// Enable the my location layer if the permission has been granted.
getMyLocation();
} else {
//TODO avvisare che si devono dare i permessi?
// Display the missing permission error dialog when the fragments resume.
}
} else if (requestCode == ENABLE_LOCATION_REQUEST_PERMISSION) {
if (PermissionUtils.isPermissionGranted(permissions, grantResults,
Manifest.permission.ACCESS_FINE_LOCATION)) {
// Enable the my location layer if the permission has been granted.
enableMyLocation();
} else {
//TODO avvisare che si devono dare i permessi?
// Display the missing permission error dialog when the fragments resume.
}
}
}
private void enableMyLocation() {
if (ContextCompat.checkSelfPermission(getContext(),
Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
PermissionUtils.requestPermission((AppCompatActivity) getActivity(), ENABLE_LOCATION_REQUEST_PERMISSION, Manifest.permission.ACCESS_FINE_LOCATION, false);
} else {
if (mMap != null) {
// Access to the location has been granted to the app.
mMap.setMyLocationEnabled(true);
//getMyLocation();
}
}
}
#Override
public void onMapReady(GoogleMap googleMap) {
if (BuildConfig.DEBUG) {
Log.d(TAG, "mapReady");
}
mMap = googleMap;
mMap.setOnCameraChangeListener(this);
enableMyLocation();
setUpClusterer();
}
#Override
public void onConnected(#Nullable Bundle bundle) {
if (BuildConfig.DEBUG) {
Log.d(TAG, "onConnected");
}
if (ContextCompat.checkSelfPermission(getContext(),
Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
PermissionUtils.requestPermission((AppCompatActivity) getActivity(), MY_LOCATION_REQUEST_PERMISSION, Manifest.permission.ACCESS_FINE_LOCATION, false);
} else {
final Location lastLocation = LocationServices.FusedLocationApi.getLastLocation(
mGoogleApiClient);
if (lastLocation != null) {
mLatitude = lastLocation.getLatitude();
mLongitude = lastLocation.getLongitude();
CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngZoom(new LatLng(mLatitude, mLongitude), 17);
if (mMap != null) {
mMap.moveCamera(cameraUpdate);
mClusterManager.clearItems();
addItems();
}
} else {
if (mMap != null) {
mMap.setMyLocationEnabled(false);
}
final ImageButton myLocation = (ImageButton) getView().findViewById(R.id.my_location); //TODO migliorare
myLocation.setVisibility(View.GONE);
}
}
}
#Override
public void onConnectionSuspended(int i) {
Log.i("GOOGLE API CLIENT", "Connection suspended");
mGoogleApiClient.connect();
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
}
#Override
public void onCameraChange(CameraPosition cameraPosition) {
if (BuildConfig.DEBUG) {
Log.d(TAG, "onCameraChange");
}
LatLng center = cameraPosition.target;
Snackbar.make(getView(), center.latitude + " - " + center.longitude, Snackbar.LENGTH_SHORT);
}
}
Here's the layout:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="me.grinworld.grinpark.MapFragment">
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/map"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<android.support.v7.widget.Toolbar
android:id="#+id/map_toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:layout_margin="8dp"
android:background="#drawable/map_bar"
android:elevation="3dp"
android:padding="3dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:background="#drawable/map_bar_search">
<ImageView
android:id="#+id/fav_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:layout_marginEnd="5dp"
android:layout_centerVertical="true"
android:layout_alignParentEnd="true"
android:src="#drawable/ic_favorite_idle"/>
<fragment
android:id="#+id/place_autocomplete_fragment"
android:name="com.google.android.gms.location.places.ui.SupportPlaceAutocompleteFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_toStartOf="#id/fav_icon"
android:layout_gravity="center" />
</RelativeLayout>
</android.support.v7.widget.Toolbar>
RESOLVED.
I just noticed that, since I was using ClusterManager, I set up as onCameraChangeListener this manager, that obviously overrode my custom method.

Categories

Resources