ApiException: 9003: PLACES_API_ACCESS_NOT_CONFIGURED

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:

  1. Enabling the Places API in the developers console
  2. Using the migration guide : Migrating to the New Places SDK Client #New methods for the new Places SDK as this tutorial was using a deprecated Places SDK, i.e adding the new dependency.
  3. Adding the following code in my Android Manifest File
<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" />
  1. Regenerated my 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'

}

Solution 1:

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 .

  1. Using Intent
  2. 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.-----

    Using Intent

     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.
                }
            }
        }
    

    Using Fregment

    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 .