I am following the current place tutorial on : Select Current Place and Show Details on a Map
I keep getting the following runtime exception:
com.google.android.gms.common.api.ApiException: 9003: PLACES_API_ACCESS_NOT_CONFIGURED
I have tried the following steps:
<meta-data
android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version" />
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="@string/api_key" />
I am also using the Maps SDK which seems to be working fine. Both the Maps SDK and Places API are enabled on the developer console.
Even after trying all these steps, I keep getting the runtime error:
ApiException: 9003: PLACES_API_ACCESS_NOT_CONFIGURED error
My code:
package com.arnav.akapplications.mapfinder;
import android.Manifest;
import android.annotation.SuppressLint;
import android.app.PendingIntent;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.net.Uri;
import android.os.PersistableBundle;
import android.support.annotation.NonNull;
import android.support.design.widget.NavigationView;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import com.google.android.gms.auth.api.signin.GoogleSignIn;
import com.google.android.gms.auth.api.signin.GoogleSignInAccount;
import com.google.android.gms.auth.api.signin.GoogleSignInClient;
import com.google.android.gms.auth.api.signin.GoogleSignInOptions;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.location.FusedLocationProviderClient;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.location.places.GeoDataClient;
import com.google.android.gms.location.places.PlaceDetectionClient;
import com.google.android.gms.location.places.PlaceLikelihood;
import com.google.android.gms.location.places.PlaceLikelihoodBufferResponse;
import com.google.android.gms.location.places.Places;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.CameraPosition;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;
import com.squareup.picasso.Picasso;
public class MainActivity extends AppCompatActivity implements OnMapReadyCallback, LocationListener {
public static final String GOOGLE_ACCOUNT = "google_account";
private static final String TAG = MainActivity.class.getSimpleName();
public DrawerLayout drawerLayout;
public Toolbar toolbar;
TextView profileName,profileEmailID;
ImageView profilePhoto;
GoogleSignInAccount googleSignInAccount;
GoogleSignInClient googleSignInClient;
private GeoDataClient geoDataClient;
private PlaceDetectionClient placeDetectionClient;
private FusedLocationProviderClient fusedLocationProviderClient;
private GoogleMap mMap;
private Location lastKnownLocation;
private CameraPosition cameraPosition;
public LocationManager locationManager;
public Criteria criteria;
public String bestProvider;
public double latitude,longitude;
private boolean LocationPermissionGranted;
private static final int PERMISSION_REQUEST_ACCESS_LOCATION = 1;
private static final int DEFAULT_ZOOM = 15;
private final LatLng mDefaultLocation = new LatLng(-33.8523341, 151.2106085);
private static final int M_MAX_ENTRIES = 5;
private static final String KEY_CAMERA_POSITION = "camera_position";
private static final String KEY_LOCATION = "location";
private String[] likelyPlaceNames;
private String[] likelyPlaceAddresses;
private String[] likelyPlaceAttributions;
private LatLng[] likelyPlaceLatLng;
SupportMapFragment supportMapFragment;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(savedInstanceState!=null)
{
lastKnownLocation = savedInstanceState.getParcelable(KEY_LOCATION);
cameraPosition = savedInstanceState.getParcelable(KEY_CAMERA_POSITION);
}
setContentView(R.layout.activity_main);
// Places.initialize(getApplicationContext(), "AIzaSyCpmMHo0xQs-U_mXlGUOxFOReO0NlKv3CU");
//
// PlacesClient placesClient = Places.createClient(this);
googleSignInAccount = getIntent().getParcelableExtra(GOOGLE_ACCOUNT);
GoogleSignInOptions googleSignInOptions = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN).requestEmail().build();
googleSignInClient = GoogleSignIn.getClient(this,googleSignInOptions);
drawerLayout=findViewById(R.id.drawer_layout);
toolbar=findViewById(R.id.toolbar);
ActionBar actionbar = getSupportActionBar();
actionbar.setDisplayHomeAsUpEnabled(true);
actionbar.setHomeButtonEnabled(true);
actionbar.setHomeAsUpIndicator(R.drawable.ic_menu_black_24dp);
geoDataClient = Places.getGeoDataClient(this);
placeDetectionClient = Places.getPlaceDetectionClient(this);
fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this);
supportMapFragment = (SupportMapFragment)getSupportFragmentManager().findFragmentById(R.id.map);
supportMapFragment.getMapAsync(this);
NavigationView navigationView=findViewById(R.id.navigation_view);
profileName = navigationView.getHeaderView(0).findViewById(R.id.profileName);
profileEmailID = navigationView.getHeaderView(0).findViewById(R.id.profileEmailID);
profilePhoto = navigationView.getHeaderView(0).findViewById(R.id.profilePhoto);
Uri photoUrl = googleSignInAccount.getPhotoUrl();
profileName.setText(googleSignInAccount.getDisplayName());
profileEmailID.setText(googleSignInAccount.getEmail());
Picasso.with(getApplicationContext())
.load(photoUrl.toString())
.placeholder(android.R.drawable.sym_def_app_icon)
.resize(100, 100)
.transform(new CircleTransform())
.centerCrop()
.into(profilePhoto);
navigationView.setNavigationItemSelectedListener( new NavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
// item.setChecked(true);
switch(item.getItemId())
{
case R.id.search_books: //do something
break;
case R.id.search_movie: //do something
break;
case R.id.logout:
googleSignInClient.signOut().addOnCompleteListener(new OnCompleteListener<Void>() {
@Override
public void onComplete(@NonNull Task<Void> task) {
Intent intent = new Intent(MainActivity.this,LoginActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
}
});
break;
case R.id.finish:
System.exit(0);
break;
}
drawerLayout.closeDrawers();
return true;
}
});
}
@Override
public void onSaveInstanceState(Bundle outState) {
if(mMap != null)
{
outState.putParcelable(KEY_CAMERA_POSITION,mMap.getCameraPosition());
outState.putParcelable(KEY_LOCATION,lastKnownLocation);
super.onSaveInstanceState(outState);
}
}
@Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
super.onBackPressed();
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu_items,menu);
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch(item.getItemId())
{
case R.id.aboutProfile:
Intent intent = new Intent(this,ProfileActivity.class);
intent.putExtra(ProfileActivity.GOOGLE_ACCOUNT,googleSignInAccount);
startActivity(intent);
break;
case android.R.id.home:
drawerLayout.openDrawer(GravityCompat.START);
break;
case R.id.option_get_place:
showCurrentPlace();
break;
}
return true;
}
private void updateLocationUI()
{
if(mMap == null)
return;
try
{
if(LocationPermissionGranted)
{
mMap.setMyLocationEnabled(true);
mMap.getUiSettings().setMyLocationButtonEnabled(true);
}
else
{
mMap.setMyLocationEnabled(false);
mMap.getUiSettings().setMyLocationButtonEnabled(false);
lastKnownLocation = null;
getLocationPermission();
}
}
catch (SecurityException e)
{
Log.e("Exception: %s",e.getMessage() );
}
}
private void getLocationPermission()
{
if(ContextCompat.checkSelfPermission(this.getApplicationContext(), Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED)
{
LocationPermissionGranted = true;
}
else
{
ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.ACCESS_FINE_LOCATION},PERMISSION_REQUEST_ACCESS_LOCATION);
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
LocationPermissionGranted = false;
switch(requestCode)
{
case PERMISSION_REQUEST_ACCESS_LOCATION:
{
if(grantResults.length>0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
LocationPermissionGranted = true;
}
}
}
updateLocationUI();
}
private void getDeviceLocation()
{
try
{
if(LocationPermissionGranted)
{
locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
criteria = new Criteria();
bestProvider = String.valueOf(locationManager.getBestProvider(criteria, true));
Location location = locationManager.getLastKnownLocation(bestProvider);
if(location != null)
{
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(location.getLatitude(),location.getLongitude()),DEFAULT_ZOOM));
}
else
{
locationManager.requestLocationUpdates(bestProvider,1000,0,this);
}
}
}
catch(SecurityException e)
{
Log.e("Exception : %s" , e.getMessage());
}
}
@Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
googleMap.setInfoWindowAdapter(new GoogleMap.InfoWindowAdapter() {
@Override
public View getInfoWindow(Marker marker) {
return null;
}
@Override
public View getInfoContents(Marker marker) {
View infoWindow = getLayoutInflater().inflate(R.layout.custom_info_contents,null);
TextView title = ((TextView) infoWindow.findViewById(R.id.title));
TextView snippet = ((TextView)infoWindow.findViewById(R.id.snippet));
title.setText(marker.getTitle());
snippet.setText(marker.getSnippet());
return infoWindow;
}
});
getLocationPermission();
updateLocationUI();
getDeviceLocation();
}
private void showCurrentPlace()
{
if(mMap == null) {
Toast.makeText(this, "hello", Toast.LENGTH_LONG).show();
}
if(LocationPermissionGranted)
{
@SuppressLint("MissingPermission") final Task<PlaceLikelihoodBufferResponse> placeResult = placeDetectionClient.getCurrentPlace(null);
placeResult.addOnCompleteListener(new OnCompleteListener<PlaceLikelihoodBufferResponse>() {
@Override
public void onComplete(@NonNull Task<PlaceLikelihoodBufferResponse> task) {
if(task.isSuccessful() && task.getResult()!= null) {
PlaceLikelihoodBufferResponse placeLikelihoodBufferResponse = task.getResult();
int count,i=0;
if(placeLikelihoodBufferResponse.getCount() < M_MAX_ENTRIES) {
count = placeLikelihoodBufferResponse.getCount();
}
else {
count = M_MAX_ENTRIES;
}
likelyPlaceNames = new String[count];
likelyPlaceAddresses = new String[count];
likelyPlaceAttributions = new String[count];
likelyPlaceLatLng = new LatLng[count];
for(PlaceLikelihood placeLikelihood : placeLikelihoodBufferResponse) {
likelyPlaceNames[i] = (String) placeLikelihood.getPlace().getName();
likelyPlaceAddresses[i] = (String) placeLikelihood.getPlace().getAddress();
likelyPlaceAttributions[i] = (String) placeLikelihood.getPlace().getAttributions();
likelyPlaceLatLng[i] = placeLikelihood.getPlace().getLatLng();
i++;
if (i > (count - 1)) {
break;
}
}
placeLikelihoodBufferResponse.release();
openPlacesDialog();
}
else
{
Log.e(TAG,"Exception :%s" + task.getException());
}
}
});
}
else
{
Log.i(TAG,"the user did not grant location permission");
mMap.addMarker(new MarkerOptions().title(getString(R.string.default_info_title)).position(mDefaultLocation).snippet(getString(R.string.default_info_snippet)));
getLocationPermission();
}
}
private void openPlacesDialog()
{
DialogInterface.OnClickListener dialogListener = new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
LatLng markerLatLng = likelyPlaceLatLng[which];
String markerSnippet = likelyPlaceAddresses[which];
if(likelyPlaceAttributions[which] != null)
{
markerSnippet = markerSnippet + "\n" + likelyPlaceAttributions[which];
}
mMap.addMarker(new MarkerOptions().title(likelyPlaceNames[which]).position(markerLatLng).snippet(markerSnippet));
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(markerLatLng,DEFAULT_ZOOM));
}
};
AlertDialog dialog = new AlertDialog.Builder(this).setTitle(R.string.pick_place).setItems(likelyPlaceNames,dialogListener).show();
dialog.create();
}
@Override
public void onLocationChanged(Location location) {
locationManager.removeUpdates(this);
//open the map:
latitude = location.getLatitude();
longitude = location.getLongitude();
Toast.makeText(MainActivity.this, "latitude:" + latitude + " longitude:" + longitude, Toast.LENGTH_SHORT).show();
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
@Override
public void onProviderEnabled(String provider) {
}
@Override
public void onProviderDisabled(String provider) {
}
}
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.arnav.akapplications.mapfinder">
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.AppCompat.Light.NoActionBar">
<meta-data
android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version" />
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="@string/api_key" />
<activity android:name=".ProfileActivity"/>
<activity android:name=".MainActivity"
android:theme="@style/AppTheme"/>
<activity android:name=".LoginActivity"
android:theme="@style/AppTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
app-level build.gradle file:
apply plugin: 'com.android.application'
android {
compileSdkVersion 27
defaultConfig {
applicationId "com.arnav.akapplications.mapfinder"
minSdkVersion 15
targetSdkVersion 27
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
resValue "string", "google_maps_key", (project.findProperty("GOOGLE_MAPS_API_KEY") ?: "")
resValue "string", "google_places_key", (project.findProperty("GOOGLE_PLACES_API_KEY") ?: "")
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
//noinspection GradleCompatible
implementation 'com.android.support:appcompat-v7:27.1.1'
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
implementation 'com.google.android.gms:play-services-auth:16.0.1'
implementation 'com.squareup.picasso:picasso:2.5.2'
implementation 'com.android.support:design:27.1.1'
implementation 'com.google.android.gms:play-services-location:16.0.0'
implementation 'com.google.android.libraries.places:places-compat:1.0.0'
}
Many friends suggested me to post how I have implemented this(AutoComplete) on my Project .So I am suggested you to see this migration guide and implement on your project step by step.
Migration Guide:-https://developers.google.com/places/android-sdk/client-migration
GO to this link to create API Key:
Follows this steps to implement AutoComplete in your project :-
There is two way to implement to AutoComplete .
Using AutocompleteFragment
In both case follow these steps:-
1. Add this line in build.gradle file
dependencies {
implementation 'com.google.android.libraries.places:places:2.1.0'
}
2. Add other dependencies (This is optional) .
dependencies {
implementation 'com.google.android.libraries.places:places-compat:1.0.0'
}
implementation 'com.google.android.gms:play-services-places:16.0.0'
3. // Add an import statement for the client library.
import com.google.android.libraries.places.api.Places;
// Initialize Places.
Places.initialize(getApplicationContext(), apiKey);
// Create a new Places client instance.
PlacesClient placesClient = Places.createClient(this);
----------Now Choose any of the method you want to implement in your project.-----
if (!Places.isInitialized()) {
Places.initialize(getApplicationContext(), "YOUR_API_KEY");
}
...
// Set the fields to specify which types of place data to return.
List<Place.Field> fields = Arrays.asList(Place.Field.ID, Place.Field.NAME);
// Start the autocomplete intent.
Intent intent = new Autocomplete.IntentBuilder(
AutocompleteActivityMode.FULLSCREEN, fields)
.build(this);
startActivityForResult(intent, AUTOCOMPLETE_REQUEST_CODE);
and OnActivityResult method-------
/**
* Override the activity's onActivityResult(), check the request code, and
* do something with the returned place data (in this example it's place name and place ID).
*/
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == AUTOCOMPLETE_REQUEST_CODE) {
if (resultCode == RESULT_OK) {
Place place = Autocomplete.getPlaceFromIntent(data);
Log.i(TAG, "Place: " + place.getName() + ", " + place.getId());
} else if (resultCode == AutocompleteActivity.RESULT_ERROR) {
// TODO: Handle the error.
Status status = Autocomplete.getStatusFromIntent(data);
Log.i(TAG, status.getStatusMessage());
} else if (resultCode == RESULT_CANCELED) {
// The user canceled the operation.
}
}
}
Initialize this Autocomplete Fregment on .xml file
<fragment
android:id="@+id/autocomplete_fragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:name=
"com.google.android.libraries.places.widget.AutocompleteSupportFragment"
/>
-------------- and on .class file--------------------------
Initialize Places, passing the application context and your API key. Initialize the AutocompleteSupportFragment. Call setPlaceFields() to indicate the types of place data that you want to get. Add a PlaceSelectionListener to do something with the result, as well as handle any errors that might occur. The following example shows adding an autocomplete widget to an activity:
if (!Places.isInitialized()) {
Places.initialize(getApplicationContext(), "YOUR_API_KEY");
}
// Initialize the AutocompleteSupportFragment.
AutocompleteSupportFragment autocompleteFragment = (AutocompleteSupportFragment)
getSupportFragmentManager().findFragmentById(R.id.autocomplete_fragment);
autocompleteFragment.setPlaceFields(Arrays.asList(Place.Field.ID, Place.Field.NAME));
autocompleteFragment.setOnPlaceSelectedListener(new PlaceSelectionListener() {
@Override
public void onPlaceSelected(Place place) {
// TODO: Get info about the selected place.
Log.i(TAG, "Place: " + place.getName() + ", " + place.getId());
}
@Override
public void onError(Status status) {
// TODO: Handle the error.
Log.i(TAG, "An error occurred: " + status);
}
});
And Get LATLONG from selected place like this:-
LatLng latLng = place.getLatLng();
String mStringLatitude = String.valueOf(latLng.latitude);
String mStringLongitude = String.valueOf(latLng.longitude);
Hope this will help you .