0

I have the following logic:

Server side making Place Search web service call and gets valid unique cross Google maps API's PlaceId string. Check: Constructing manually URL for Place Details from him (returned PlaceId) returns the expected Place indicating that he has photos in Google's places DB (photos[] in the result Json is not empty...).

So now the server sends to Android client this PlaceId and in android I make API call to Places Photos to get at least one image. It should work because PlaceId is unique place identifier across all Google Maps products. The workflow is pretty much straight forward based on official Google sample, and as seen in the comments in the code the connection part is succeeding and all API set up is good (in the dev console, manifest with API KEY etc.).

The problem is that it's not working: In dev console I see usage count increasing and in the place in the code where I expect to fetch the image nothing happens - The result is that any PlaceId I try (and as mentioned above should have photos) don't have any photos in Google's DB. Also ain't exceptions or something like this to debug. Where is the problem? Thanks,

//Under Activity extends FragmentActivity implements GoogleApiClient.OnConnectionFailedListener, GoogleApiClient.ConnectionCallbacks 

private GoogleApiClient mGoogleApiClient = null;
private boolean isConnected = false;
private ImageView mImageView;

@Override
protected void onCreate(Bundle savedInstanceState) {
    /* Regular code... */
    //Next 2 lines: I don't for what they are good - But in the official Google sample
    //they appears - So probably it's right...
    StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
    StrictMode.setThreadPolicy(policy);
    if (mGoogleApiClient == null) {  
        rebuildGoogleApiClient();
    }
    if (isConnected) {
        /* This is printed! */
        Log.e("TAG", "Start of API Call"); 
        String placeId = /* Call to my server, the result is 100% valid PlaceId that has photos*/
        placePhotosTask(placeId, 800, 400);  //Height, Width
    }
}

private void placePhotosTask(final String placeId, final int width, final int height) {
    new PhotoTask(width, height) {
        @Override
        protected void onPreExecute() {
            //TODO Display a temporary image to show while bitmap is loading.
            //mImageView.setImageResource(R.drawable.empty_photo);
        }

        @Override
        protected void onPostExecute(AttributedPhoto attributedPhoto) {
            if (attributedPhoto != null) {
                /* THIS IS NOT PRINTED */
                Log.e("TAG", "Success of API Call");
                mImageView.setImageBitmap(attributedPhoto.bitmap);
            }
        }
    }.execute(placeId);
}

private class PhotoTask extends AsyncTask<String, Void, PhotoTask.AttributedPhoto> {

    private int mHeight;
    private int mWidth;

    public PhotoTask(int width, int height) {
        mHeight = height;
        mWidth = width;
    }

    //Loads the first photo for a place id from the Geo Data API. The place id must be the first (and only) parameter.
    @Override
    protected AttributedPhoto doInBackground(String... params) {
        if (params.length != 1) {
            return null;
        }
        final String placeId = params[0];
        AttributedPhoto attributedPhoto = null;
        PlacePhotoMetadataResult result = Places.GeoDataApi.getPlacePhotos(mGoogleApiClient, placeId).await();
        if (result.getStatus().isSuccess()) {
            PlacePhotoMetadataBuffer photoMetadataBuffer = result.getPhotoMetadata();
            //BUG!: photoMetadataBuffer.getCount() == 0 Always!
            if (photoMetadataBuffer.getCount() > 0 && !isCancelled()) {
                //Get the first bitmap and its attributions.
                PlacePhotoMetadata photo = photoMetadataBuffer.get(0);
                CharSequence attribution = photo.getAttributions();
                //Load a scaled bitmap for this photo.
                Bitmap image = photo.getScaledPhoto(mGoogleApiClient, mWidth, mHeight).await().getBitmap();
                attributedPhoto = new AttributedPhoto(attribution, image);
            }
            //Release the PlacePhotoMetadataBuffer.
            photoMetadataBuffer.release();
        }
        return attributedPhoto;
    }

    //Holder for an image and its attribution.
    class AttributedPhoto {
        public final CharSequence attribution;
        public final Bitmap bitmap;
        public AttributedPhoto(CharSequence attribution, Bitmap bitmap) {
            this.attribution = attribution;
            this.bitmap = bitmap;
        }
    }

}

protected synchronized void rebuildGoogleApiClient() {
    mGoogleApiClient = new GoogleApiClient.Builder(this)
        .enableAutoManage(this, 0 /* clientId */, this)
        .addConnectionCallbacks(this)
        .addApi(Places.GEO_DATA_API)  
        .build();
}

@Override
public void onConnectionFailed(ConnectionResult connectionResult) {
    isConnected = false;
}

@Override
public void onConnected(Bundle bundle) {
    isConnected = true;
}

@Override
public void onConnectionSuspended(int i) {
    isConnected = false;
}
michael
  • 3,835
  • 14
  • 53
  • 90

1 Answers1

2

I disagree with the bug comment - photoMetadataBuffer.getCount() == 0 Always. Here is some code that shows loading photos successfully. Note, for context, this code was built inside the Android Studio Google Maps template app, to make it easier to get all the API Key configuration correctly inserted in the application, with the bonus of having a map for displaying results.

private GoogleMap mMap;
private GoogleApiClient mGoogleApiClient;
private final String placeId = "ChIJhSxoJzyuEmsR9gBDBR09ZrE";
private final static String TAG = "MapsActivity";

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_maps);
    // Obtain the SupportMapFragment and get notified when the map is ready to be used.
    SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
            .findFragmentById(R.id.map);
    mapFragment.getMapAsync(this);

    mGoogleApiClient = new GoogleApiClient
            .Builder(this)
            .addApi(Places.GEO_DATA_API)
            .addApi(Places.PLACE_DETECTION_API)
            .addConnectionCallbacks(this)
            .addOnConnectionFailedListener(this)
            .build();
}

@Override
protected void onStart() {
    super.onStart();
    mGoogleApiClient.connect();
}

@Override
protected void onStop() {
    mGoogleApiClient.disconnect();
    super.onStop();
}

@Override
public void onMapReady(GoogleMap googleMap) {
    mMap = googleMap;

    Places.GeoDataApi.getPlaceById(mGoogleApiClient, placeId).setResultCallback(new ResultCallback<PlaceBuffer>() {
        @Override
        public void onResult(PlaceBuffer places) {
            if (places.getStatus().isSuccess() && places.getCount() > 0) {
                    final Place myPlace = places.get(0);
                    Log.i(TAG, "Place found: " + myPlace.getName());
                    mMap.addMarker(new MarkerOptions()
                            .position(myPlace.getLatLng())
                            .title(myPlace.getName().toString())
                            .snippet(myPlace.getAddress().toString()));
                    mMap.moveCamera(CameraUpdateFactory.newLatLng(myPlace.getLatLng()));
            }
            places.release();
        }
    });

    Places.GeoDataApi.getPlacePhotos(mGoogleApiClient, placeId).setResultCallback(new ResultCallback<PlacePhotoMetadataResult>() {
        @Override
        public void onResult(PlacePhotoMetadataResult placePhotoMetadataResult) {
            if (placePhotoMetadataResult.getStatus().isSuccess()) {
                PlacePhotoMetadataBuffer photoMetadata = placePhotoMetadataResult.getPhotoMetadata();
                int photoCount = photoMetadata.getCount();
                for (int i = 0; i<photoCount; i++) {
                    PlacePhotoMetadata placePhotoMetadata = photoMetadata.get(i);
                    final String photoDetail = placePhotoMetadata.toString();
                    placePhotoMetadata.getScaledPhoto(mGoogleApiClient, 500, 500).setResultCallback(new ResultCallback<PlacePhotoResult>() {
                        @Override
                        public void onResult(PlacePhotoResult placePhotoResult) {
                            if (placePhotoResult.getStatus().isSuccess()) {
                                Log.i(TAG, "Photo "+photoDetail+" loaded");
                            } else {
                                Log.e(TAG, "Photo "+photoDetail+" failed to load");
                            }
                        }
                    });
                }
                photoMetadata.release();
            } else {
                Log.e(TAG, "No photos returned");
            }
        }
    });
}
Brett
  • 2,399
  • 1
  • 17
  • 23
  • Ok found the bug. The problem is the server return the place id as quoted string. Anyway In my method I used `Places.GeoDataApi.getPlacePhotos(mGoogleApiClient, placeId).await();`. Your implementation with anonymous result callback is better. – michael Oct 16 '15 at 06:40
  • Yup, using await() on android is bad if called from the UI thread. Callbacks are better. Thanks! – Brett Oct 18 '15 at 05:31
  • Thanks!! I could load bitImage to my Image. – Lay Leangsros Dec 27 '15 at 04:03