I'm using the new google-places api, calling the autocompleteactivity intent from a fragment, the autocomplete can't load any results when I set minifyEnabled to true in the gradle file. It does working if set the properties to false. Need help. Thanks.
try {
/*
* Initialize Places
*/
if (!Places.isInitialized()) {
Log.d(TAG, "initialized places api");
Places.initialize(getActivity().getApplicationContext(),
getResources().getString(R.string.places_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, Place.Field.ADDRESS, Place.Field.LAT_LNG);
// Start the autocomplete intent.
Intent intent = new Autocomplete.IntentBuilder(
AutocompleteActivityMode.FULLSCREEN, fields)
.build(getActivity());
startActivityForResult(intent, REQUEST_PICK_PLACE);
} catch (Exception e) {
Log.e(TAG, "exception", e);
}
When check back the logcat, I get this kind of message: "Error while autocompleting: ERROR"
Related
I am working on google maps and search.
The only option to search on the map is the Google Places API.
https://developers.google.com/places/android-sdk/intro
Which also states that you play service version of SDK is deprecated.
So I was trying to implement it with the new SDK.
Now what I want is instead of Autocomplete to Open a new Activity I want it to be displayed as a list on my autocomplete.
So I tried to implement this : https://github.com/googlesamples/android-play-places/blob/master/PlaceCompleteAdapter/Application/src/main/java/com/example/google/playservices/placecomplete/PlaceAutocompleteAdapter.java
But the issue is it works with Play service version but not with Compat version because the classes and imports are different.
This is the part of the code that I am having trouble with :
// Submit the query to the autocomplete API and retrieve a PendingResult that will
// contain the results when the query completes.
PendingResult<AutocompletePredictionBuffer> results =
Places.GeoDataApi
.getAutocompletePredictions(mGoogleApiClient, constraint.toString(),
mBounds, mPlaceFilter);
// This method should have been called off the main UI thread. Block and wait for at most 60s
// for a result from the API.
AutocompletePredictionBuffer autocompletePredictions = results
.await(60, TimeUnit.SECONDS);
// Confirm that the query completed successfully, otherwise return null
final Status status = autocompletePredictions.getStatus();
if (!status.isSuccess()) {
Toast.makeText(getContext(), "Error contacting API: " + status.toString(),
Toast.LENGTH_SHORT).show();
Log.e(TAG, "Error getting autocomplete prediction API call: " + status.toString());
autocompletePredictions.release();
return null;
}
If anyone has implemented PlacesAutoCompleteAdapter with New Places API library. Please guide me with changing the above code.
Thank you.
Reference link:
https://developers.google.com/places/android-sdk/autocomplete#get_place_predictions_programmatically
Step 1. Intialize new PlaceClient
// Initialize Places.
Places.initialize(getApplicationContext(), apiKey);
// Create a new Places client instance.
PlacesClient placesClient = Places.createClient(this);
Step 2. Create request
// contain the results when the query completes.
FindAutocompletePredictionsRequest request = FindAutocompletePredictionsRequest.builder()
// similar to previous mBounds
// but you have to use Rectangular bounds (Check reference link)
.setLocationRestriction(mBounds)
.setQuery(constraint.toString()) // similar to previous constraint
.setTypeFilter(TypeFilter.ADDRESS) // similar to mPlaceFilter
.build();
Step 3. Send request object to response method
Task<FindAutocompletePredictionsResponse> task =
placeClient.findAutocompletePredictions(request);
Step 4. Handle OnSuccess code here
task.addOnSuccessListener(
(response) -> {
for (AutocompletePrediction prediction : response.getAutocompletePredictions()) {
Timber.d("prediction result: " + prediction);
// add result to your arraylist
}
// return your arraylist outside foreach loop
});
Step 5. Handle OnFailure code here
task.addOnFailureListener((exception) -> {
if (exception instanceof ApiException) {
ApiException apiException = (ApiException) exception;
// places not found exception code
Timber.i("error message %s", apiException.getMessage());
}
});
Step 6. Handle OnComplete code here
task.addOnCompleteListener((response) -> {
Exception e = task.getException();
if (e instanceof ApiException) {
ApiException apiException = (ApiException) e;
if (!task.isSuccessful()) {
// your code
}
}
});
}
I'm trying to find out why some of our users are getting the error "Required parameter: part" when trying to upload a video into YouTube using YouTube API v3. Below you can see the code that we use for uploading videos. The method params are valid strings that aren't short or too long.
int shareYoutube(#NonNull Uri mediaUri, String mime, String mediaTitle, String postMessage, String accountName)
{
int error = ERR_NO_ERROR;
try {
// Developer tags not supported yet
//https://code.google.com/p/gdata-issues/issues/detail?id=5012
// Authorize the request.
GoogleAccountCredential credential = GoogleAccountCredential.usingOAuth2(getApplicationContext(), Arrays.asList(YouTubeScopes.YOUTUBE_UPLOAD));
credential.setSelectedAccountName(accountName);
// This object is used to make YouTube Data API requests.
YouTube.Builder builder = new YouTube.Builder(HTTP_TRANSPORT, JSON_FACTORY, credential);
builder.setApplicationName("TEST APP");
YouTube youtube = builder.build();
// Add extra information to the video before uploading.
Video video = new Video();
// set privacy
VideoStatus status = new VideoStatus();
status.setPrivacyStatus("public");
video.setStatus(status);
// Most of the video's metadata is set on the VideoSnippet object.
VideoSnippet snippet = new VideoSnippet();
snippet.setTitle(mediaTitle);
snippet.setDescription(postMessage);
// Film & Animation https://gist.github.com/dgp/1b24bf2961521bd75d6c
snippet.setCategoryId("1");
// Set the keyword tags that you want to associate with the video.
List<String> tags = new ArrayList<>();
tags.add("animation");
tags.add("cartoon");
tags.add("2d animation");
tags.add("drawing");
snippet.setTags(tags);
// Add the completed snippet object to the video resource.
video.setSnippet(snippet);
String fileFormat = "video/*";
InputStreamContent mediaContent = new InputStreamContent(fileFormat, getContentResolver().openInputStream(mediaUri));
// Insert the video. The command sends three arguments. The first
// specifies which information the API request is setting and which
// information the API response should return. The second argument
// is the video resource that contains metadata about the new video.
// The third argument is the actual video content.
YouTube.Videos.Insert videoInsert = youtube.videos().insert("snippet,statistics,status", video, mediaContent);
// Insert to a channel
//videoInsert.setOnBehalfOfContentOwnerChannel();
// Set the upload type and add an event listener.
MediaHttpUploader uploader = videoInsert.getMediaHttpUploader();
// Indicate whether direct media upload is enabled. A value of
// "True" indicates that direct media upload is enabled and that
// the entire media content will be uploaded in a single request.
// A value of "False," which is the default, indicates that the
// request will use the resumable media upload protocol, which
// supports the ability to resume an upload operation after a
// network interruption or other transmission failure, saving
// time and bandwidth in the event of network failures.
uploader.setDirectUploadEnabled(false);
YouTubeCallbackListener callback = new YouTubeCallbackListener();
uploader.setProgressListener(callback);
// Call the API and upload the video.
Video returnedVideo = videoInsert.execute();
synchronized (callback) {
if (!callback.hasCallbackResult()) {
try {
callback.wait();
error = callback.error;
} catch (InterruptedException e) {
e.printStackTrace();
error = ERR_POST_CANCELED;
}
} else {
error = callback.error;
}
}
if (ERR_NO_ERROR == error && null != returnedVideo)
{
Intent notificationIntent = new Intent(
Intent.ACTION_VIEW,
Uri.parse("http://www.youtube.com/watch?v="+returnedVideo.getId()));
mPendingIntent = PendingIntent.getActivity(getBaseContext(), 0, notificationIntent, 0);
}
}
catch (UserRecoverableAuthIOException userRecoverableException)
{
error = ERR_UNABLE_TO_AUTH_ACCOUNT;
try {
GoogleAuthUtil.getTokenWithNotification(
getApplicationContext(), accountName, "oauth2:" + YouTubeScopes.YOUTUBE_UPLOAD, null);
} catch (IOException e) {
} catch (GoogleAuthException e) {
}
} catch (GoogleJsonResponseException e) {
error = ERR_POST_ERROR;
Crashlytics.logException(e);
} catch (IOException e) {
error = ERR_POST_ERROR;
Crashlytics.logException(e);
} catch (Throwable t) {
error = ERR_POST_ERROR;
Crashlytics.logException(t);
}
return error;
}
Error:
400 Bad Request { "errors" : [ { "domain" : "global", "reason" : "required", "message" : "Required parameter: part", "locationType" : "parameter", "location" : "part" } ], "code" : 400, "message" : "Required parameter: part" }
Any thoughts on what could be happening here?
The problem was our proguard script. All we had to do was include the following line to it.
-keep class com.google.api.** { *; }
I followed the google play documentation for implementing autocomplete using "Use an intent to launch the autocomplete activity."
But sometimes the results are showing all mixed up and overlapped.
Below is the code that i am using :
try {
// The autocomplete activity requires Google Play Services to be available. The intent
// builder checks this and throws an exception if it is not the case.
AutocompleteFilter typeFilter = new AutocompleteFilter.Builder()
.setTypeFilter(AutocompleteFilter.TYPE_FILTER_CITIES)
.build();
Intent intent = new PlaceAutocomplete.IntentBuilder(PlaceAutocomplete.MODE_FULLSCREEN).setFilter(typeFilter)
.build(MainActivity.this);
startActivityForResult(intent, 111);
} catch (GooglePlayServicesRepairableException e) {
// Indicates that Google Play Services is either not installed or not up to date. Prompt
// the user to correct the issue.
GoogleApiAvailability.getInstance().getErrorDialog(MainActivity.this, e.getConnectionStatusCode(),
0 /* requestCode */).show();
} catch (GooglePlayServicesNotAvailableException e) {
// Indicates that Google Play Services is not available and the problem is not easily
// resolvable.
String message = "Google Play Services is not available: " +
GoogleApiAvailability.getInstance().getErrorString(e.errorCode);
Log.e("", message);
Toast.makeText(MainActivity.this, message, Toast.LENGTH_SHORT).show();
}
Is this a Google Play service SDK problem or code problem?
I want to enable server-side Calendar API access for my android app.
I have followed the steps given here .
I am getting a null value for the authorization code.
I think I am giving wrong values for 'scope' field and the 'server_client_id' field.
Please give me an example showing correct fields values for 'scope' and 'server_client_id' in the getToken() method.
Thanks for any help.
PS- I have used google+ sign in for android given here for connecting to a google account.
EDIT- Here is my code. I have given the OAuth 2.0 scope for the Google Calendar API in the scope field.
I have taken Client ID for Android application from Developers Console and put in 'serverClientID' field. This is probably where I am wrong. I don't know how to get Server's Client ID which is required by the
public class AsyncGetAuthToken extends AsyncTask<String, Void, String>{
#Override
protected String doInBackground(String... params) {
Bundle appActivities = new Bundle();
appActivities.putString(GoogleAuthUtil.KEY_REQUEST_VISIBLE_ACTIVITIES,
"MainActivity");
String scopeString = "https://www.googleapis.com/auth/calendar.readonly";
String serverClientID = CLIENT_ID;
String scopes = "oauth2:server:client_id:" + serverClientID + ":api_scope:" + scopeString;
String code = null;
try {
code = GoogleAuthUtil.getToken(
MainActivity.this, // Context context
Plus.AccountApi.getAccountName(mGoogleApiClient), // String accountName
scopes, // String scope
appActivities // Bundle bundle
);
} catch (IOException transientEx) {
// network or server error, the call is expected to succeed if you try again later.
// Don't attempt to call again immediately - the request is likely to
// fail, you'll hit quotas or back-off.
return null;
} catch (UserRecoverableAuthException e) {
// Requesting an authorization code will always throw
// UserRecoverableAuthException on the first call to GoogleAuthUtil.getToken
// because the user must consent to offline access to their data. After
// consent is granted control is returned to your activity in onActivityResult
// and the second call to GoogleAuthUtil.getToken will succeed.
startActivityForResult(e.getIntent(), AUTH_CODE_REQUEST_CODE);
return null;
} catch (GoogleAuthException authEx) {
// Failure. The call is not expected to ever succeed so it should not be
// retried.
return null;
} catch (Exception e) {
throw new RuntimeException(e);
}
return null;
}
}
And in my onActivityResult, I look for the Auth Code
if (requestCode == AUTH_CODE_REQUEST_CODE) {
if (responseCode == RESULT_OK){
Bundle extra = intent.getExtras();
String oneTimeToken = extra.getString("authtoken");
Log.d("LOG", "one time token" + oneTimeToken);
}
}
I'm trying to indicate the authentication / sync status of an account using the AccountAuthenticator and SyncAdapter. I've been through the samples, and can get it working alright.
How can I set the indicator to red just like the GMail account?
I'd also like to add additional status indicators on the sync adapter page. See picture below:
Answering my own question for future team knowledge...
Getting the indicator to change color was fairly easy after some experimentation. Start by creating a project based on thecode supplied in the SDK sample projects, modify as follows:
1) Fake the initial login from the server during the AuthenticationActivity. Once past the initial check, the system will start it's periodic sync attempts.
/**
* Called when the authentication process completes (see attemptLogin()).
*/
public void onAuthenticationResult(boolean result) {
Log.i(TAG, "onAuthenticationResult(" + result + ")");
// Hide the progress dialog
hideProgress();
// Override the result, we don't care right now....
result = true;
if (result) {
if (!mConfirmCredentials) {
finishLogin();
} else {
finishConfirmCredentials(true);
}
} else {
Log.e(TAG, "onAuthenticationResult: failed to authenticate");
if (mRequestNewAccount) {
// "Please enter a valid username/password.
mMessage.setText(getText(R.string.login_activity_loginfail_text_both));
} else {
// "Please enter a valid password." (Used when the
// account is already in the database but the password
// doesn't work.)
mMessage.setText(getText(R.string.login_activity_loginfail_text_pwonly));
}
}
}
2) Modify the "onPerformSync()" method within the SyncAdapter. The key here are the "syncResult.stats" fields. While modifying them, I found that inserting multiple errors didn't get the effect I wanted. Also noting that the counts didn't seem to be recorded across sync attempts (i.e. the fails always come in as zero). The "lifetimeSyncs" is a static variable that keeps count across sync attempts. This modified code will continue to alternate between green and red...
#Override
public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) {
List<User> users;
List<Status> statuses;
String authtoken = null;
try {
// use the account manager to request the credentials
authtoken = mAccountManager.blockingGetAuthToken(account, Constants.AUTHTOKEN_TYPE, true );
// fetch updates from the sample service over the cloud
//users = NetworkUtilities.fetchFriendUpdates(account, authtoken, mLastUpdated);
// update the last synced date.
mLastUpdated = new Date();
// update platform contacts.
Log.d(TAG, "Calling contactManager's sync contacts");
//ContactManager.syncContacts(mContext, account.name, users);
// fetch and update status messages for all the synced users.
//statuses = NetworkUtilities.fetchFriendStatuses(account, authtoken);
//ContactManager.insertStatuses(mContext, account.name, statuses);
if (SyncAdapter.lifetimeSyncs-- <= 0 ){
//mAccountManager.invalidateAuthToken(Constants.ACCOUNT_TYPE, authtoken);
syncResult.stats.numAuthExceptions++;
//syncResult.delayUntil = 60;
lifetimeSyncs = 5;
}
} catch (final AuthenticatorException e) {
syncResult.stats.numParseExceptions++;
Log.e(TAG, "AuthenticatorException", e);
} catch (final OperationCanceledException e) {
Log.e(TAG, "OperationCanceledExcetpion", e);
} catch (final IOException e) {
Log.e(TAG, "IOException", e);
Log.d(TAG, extras.toString());
syncResult.stats.numAuthExceptions++;
syncResult.delayUntil = 60;
//extras.putString(AccountManager.KEY_AUTH_FAILED_MESSAGE, "You're not registered");
} catch (final ParseException e) {
syncResult.stats.numParseExceptions++;
Log.e(TAG, "ParseException", e);
}
}
That's it, enjoy playing with the delays and other variables too...