Android PlaceAutocomplete search result mixup - android

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?

Related

Android: Receiving wrong UTM from Google Ads

According to my boss, some of our applications have been invested on advertising of the app via Google Ads. In order for them to parse the data and analyze them correctly, they are using the UTM auto-tagging approach. It is my job from the client (Android Device) to send the UTM using Firebase Analytics and also a custom event to Firebase depending on this UTM.
However, our data shows that both Firebase SDK and our events are transferred incorrectly. The click numbers and the download numbers do not match. Since both of them are incorrect, I'm guessing the received UTM on the device itself is wrong, and this needs to be received correctly and I am unable to find an answer for this.
I'm using Install Referrer Library to track down what the UTM is after the app is downloaded to the device. I am guessing Firebase SDK also uses somewhat similar approach. On our end, the UTM is recorded to SharedPreferences and it is not queried again if the query was successful.
Here is the related code for it (the processReferrer method basically parses the UTM according to our needs):
/**
* Checks if the referrer information is recorded before, if not, creates
* a connection to Google Play and saves the data to shared preferences.
*/
private static void fetchReferrerInformation(Context context)
{
SharedPreferences preferences =
PreferenceManager.getDefaultSharedPreferences(context);
String utmData = preferences.getString(UTM_DATA, "");
// Only connect if utm is not recorded before.
if (TextUtils.isEmpty(utmData))
{
InstallReferrerClient client;
try
{
client = InstallReferrerClient.newBuilder(context).build();
client.startConnection(new InstallReferrerStateListener()
{
#Override
public void onInstallReferrerSetupFinished(int responseCode)
{
switch (responseCode)
{
case InstallReferrerClient.InstallReferrerResponse.OK:
{
ReferrerDetails response;
try
{
response = client.getInstallReferrer();
}
catch (Exception e)
{
Log.e(TAG, "Error while fetching referrer information.", e);
if (Fabric.isInitialized())
Crashlytics.logException(new IllegalStateException("Exception while fetching UTM information.", e));
return;
}
if (response != null)
{
processReferrer(context, response.getInstallReferrer());
}
break;
}
case InstallReferrerClient.InstallReferrerResponse.FEATURE_NOT_SUPPORTED:
{
Log.w(TAG, "Install referrer client: Feature is not supported.");
break;
}
case InstallReferrerClient.InstallReferrerResponse.SERVICE_UNAVAILABLE:
{
Log.w(TAG, "Install referrer client: Service is unavailable.");
break;
}
}
try
{
client.endConnection();
}
catch (Exception ignored){}
}
#Override
public void onInstallReferrerServiceDisconnected()
{
// Do nothing, we need to fetch the information once and
// it is not really necessary to try to reconnect.
// If app is opened once more, the attempt will be made anyway.
}
});
}
catch (Exception e)
{
if (Fabric.isInitialized())
Crashlytics.logException(new IllegalStateException("Exception while fetching UTM information.", e));
}
}
else
Log.i(TAG, "UTM is already recorded, skipping connection initialization. Value: " +
utmData);
}
The approach is pretty simple, however the data seems to be wrong. So, does it seem that the implementation is somewhat incorrect? If not, why is the data received from Google Ads is wrong? Any help is appreciated, thank you very much.
Edit: Upon some testing, here is what I've found:
Works:
An API 19 real device (GM Discovery II Mini) and in between API 25-29 emulators with Play Store installed. Edit: UTM can also be fetched with API 23 and 24 Genymotion Emulators, where Play Store is installed.
Doesn't work:
An API 24 Android Studio emulator with latest Google Play Services and Play Store installed (device is also logged in to my account), and a real device (General Mobile 4G Dual, API 23) cannot query the UTM information. The code below lands on the case of InstallReferrerResponse.FEATURE_NOT_SUPPORTED. So I am almost sure that the install referrer client is bugged on some API levels.
Edit: Opened an issue to the Google: https://issuetracker.google.com/issues/149342702
As I don't know how you are processing the resonse, I can show you the way we did it in our implementation.
ReferrerDetails response = referrerClient.getInstallReferrer();
if (response == null) {
break;
}
String[] installReferrer = response.getInstallReferrer().split("&");
if (installReferrer.length >= 1) {
utmSource = installReferrer[0].split("=")[1];
}
if (installReferrer.length >= 2) {
utmMedium = installReferrer[1].split("=")[1];
}
Compare this snippet with yours and check if anything differs.

Google Places API Autocomplete Error when enable minify

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"

Trying to get place from place picker but it open and closes

I am integrating place picker but I have already enable places api but it opens and close immediately.
I have created api key and puted it on manifest file
still it not working.in my logcat it gives me error
2019-03-08 10:31:41.640 2837-2358/? E/Places: Places API for Android does not seem to be enabled for your app. See https://developers.google.com/places/android/signup for more details.
2019-03-08 10:31:41.651 4713-4713/? E/Places: Place Picker closing due to PLACES_API_ACCESS_NOT_CONFIGURED
2019-03-08 10:31:41.775 2837-2358/? E/Places: Places API for Android does not seem to be enabled for your app. See https://developers.google.com/places/android/signup for more details.
2019-03-08 10:31:41.776 2837-2358/? E/AsyncOperation: serviceID=65, operation=SearchPlaces
OperationException[Status{statusCode=PLACES_API_ACCESS_NOT_CONFIGURED, resolution=null}]
here is my code
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="key" />
#SuppressLint("MissingPermission")
private void showPlacePicker() {
PlacePicker.IntentBuilder builder = new PlacePicker.IntentBuilder();
try {
startActivityForResult(builder.build(NewOrderActivity.this), PLACE_PICKER_REQUEST);
} catch (GooglePlayServicesRepairableException e) {
e.printStackTrace();
} catch (GooglePlayServicesNotAvailableException e) {
e.printStackTrace();
}
}
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == PLACE_PICKER_REQUEST) {
if (resultCode == RESULT_OK) {
Place place = PlacePicker.getPlace(data, NewOrderActivity.this);
edt_pickup_address.setText(place.getAddress());
Geocoder geocoder = new Geocoder(getApplicationContext(), Locale.getDefault());
try {
List<Address> listAddresses = geocoder.getFromLocation(place.getLatLng().latitude, place.getLatLng().longitude, 1);
if (null != listAddresses && listAddresses.size() > 0) {
/* post_area = listAddresses.get(0).getSubLocality();
post_city = listAddresses.get(0).getSubAdminArea();
post_state = listAddresses.get(0).getAdminArea();*/
}
} catch (IOException e) {
e.printStackTrace();
}
String place_phone_number = "" + place.getPhoneNumber();
if (!TextUtils.isEmpty(place_phone_number)) {
String[] phone_number = place_phone_number.split(" ");
String s = "";
for (int i = 0; i < phone_number.length; i++) {
if (i != 0) {
s = s + phone_number[i];
}
}
// et_contact_no_add_company.setText(s);
} else {
// et_contact_no_add_company.setText("");
}
if (place.getWebsiteUri() != null) {
// et_website_add_company.setText("" + place.getWebsiteUri());
} else {
// et_website_add_company.setText("");
}
}
}
}
As per Google new update the Place Picker Deprecate and it will not longer available in future, here is official statement
Deprecation notice: Place Picker
Notice: The Place Picker (Android, iOS) is deprecated as of January 29, 2019. This feature will be turned off on July 29, 2019,
and will no longer be available after that date. To continue using the
Place Picker with Places SDK for iOS v.2.7.0 through the deprecation
period, do NOT disable the Places SDK for iOS. Read the migration
guides (Android, iOS) to learn more.
So, the other side u can use the Place Autocomplete
But here is some limitation in new Place API you must enable the Billing account to use the Place Autocomplete.
Reminder: To use the Places API, you must get an API key and you must
enable billing. You can enable billing when you get your API key (see
the Quick guide) or as a separate process (see Usage and Billing).
Alternative solution: get the latLong from place name using Geocoder
Deprecation notice: Google Play Services version of the Places SDK for Android
Please refer this link
https://developers.google.com/places/android-sdk/autocomplete

Using YouTube Player API, play video as a specific user, applying YouTube Red subscription

I am able to play videos using the YouTube Player API 1.2.2 for Android. However, users always see pre-roll ads even if they have a YouTube Red subscription. I could not find any documentation surrounding video playback as a specific YouTube user, in order to take advantage of a YouTube Red subscription, which disables ads.
The javadoc for YouTubePlayerSupportFragment.initialize() says:
public void initialize (String developerKey, YouTubePlayer.OnInitializedListener listener)
Initialize a YouTubePlayer, which can be used to play videos and control video playback. One of the callbacks in listener will be invoked when the initialization succeeds or fails.
Parameters
developerKey A valid API key that is enabled to use the YouTube Data API v3 service. To generate a new key, visit the Google Developers Console.
listener The callbacks that will be invoked when the initialization succeeds or fails.
So it takes an API key, rather than a user's OAuth credentials. Is there any way to pass the OAuth credentials instead, to play a video as a specific user?
I saw this example app: https://github.com/youtube/yt-direct-lite-android -- It shows an example of using OAuth 2.0 to upload videos, but the playback uses a simple API key only.
There is not currently a way to play videos as a specific user, aside from using WebView. It is the same as the answer to Play private YouTube video using YoutubePlayerView from YoutubeAndroidPlayerAPI?:
This is not possible with the Android Player API. The only way to play private videos on a device is to implement a WebView in your app, have the user log into their YouTube account, and then play back the Private video in that specific browser session only.
As long as you app uses oath and is verified you can build and play private playlists as if you were the user of the account [for that account]. Using the youtube v3 api and the .player api. If not authenticated properly for whatever reason, you can run into situations where the api lets you create a private playlist as a user of the account but the list is empty within the player api.
also, you can actually play private video:
#SuppressLint("StaticFieldLeak")
private void loadUploadedVideos() {
if (mChosenAccountName == null) {
return;
}
Log.d(TAG, "loadUploads");
showProgressDialog();
new AsyncTask<Void, Void, List<VideoData>>() {
#Override
protected List<VideoData> doInBackground(Void... voids) {
try {
YouTube youtube = new YouTube.Builder(transport, jsonFactory,
credential).setApplicationName(Constants.APP_NAME)
.build();
/*
* Now that the user is authenticated, the app makes a
* channels list request to get the authenticated user's
* channel. Returned with that data is the playlist id for
* the uploaded videos.
* https://developers.google.com/youtube
* /v3/docs/channels/list
*/
ChannelListResponse clr = youtube.channels()
.list("contentDetails").setMine(true).execute();
// Get the user's uploads playlist's id from channel list
// response
String uploadsPlaylistId = clr.getItems().get(0)
.getContentDetails().getRelatedPlaylists()
.getUploads();
List<VideoData> videos = new ArrayList<VideoData>();
// Get videos from user's upload playlist with a playlist
// items list request
PlaylistItemListResponse pilr = youtube.playlistItems()
.list("id,contentDetails")
.setPlaylistId(uploadsPlaylistId)
.setMaxResults(50L).execute();
List<String> videoIds = new ArrayList<String>();
// Iterate over playlist item list response to get uploaded
// videos' ids.
for (PlaylistItem item : pilr.getItems()) {
videoIds.add(item.getContentDetails().getVideoId());
}
// Get details of uploaded videos with a videos list
// request.
VideoListResponse vlr = youtube.videos()
.list("id,snippet,status")
.setId(TextUtils.join(",", videoIds)).execute();
// Add only the public videos to the local videos list.
for (Video video : vlr.getItems()) {
//if ("public".equals(video.getStatus().getPrivacyStatus())) {
VideoData videoData = new VideoData();
videoData.setVideo(video);
videos.add(videoData);
//}
}
// Sort videos by title
Collections.sort(videos, new Comparator<VideoData>() {
#Override
public int compare(VideoData videoData,
VideoData videoData2) {
return videoData.getTitle().compareTo(
videoData2.getTitle());
}
});
return videos;
} catch (final GooglePlayServicesAvailabilityIOException availabilityException) {
showGooglePlayServicesAvailabilityErrorDialog(availabilityException
.getConnectionStatusCode());
} catch (UserRecoverableAuthIOException userRecoverableException) {
startActivityForResult(
userRecoverableException.getIntent(),
REQUEST_AUTHORIZATION);
} catch (IOException e) {
Utils.logAndShow(MainActivity.this, Constants.APP_NAME, e);
}
catch (Exception e) {
Log.e(TAG, e.getMessage());
}
return null;
}
#Override
protected void onPostExecute(List<VideoData> videos) {
if (videos == null) {
hideProgressDialog();
return;
}
if (mMyUploadsFragment != null)
mMyUploadsFragment.setUploads(videos);
hideProgressDialog();
}
}.execute((Void) null);
}
And finally this is the answer to the question, but it needed context:
Also once authenticated, youtube prime features are available in the player api. Nice. The trick seems to be to log the Youtube user into the youtube app on the phone as well as using the same creds in your own app.
anyway any playlist the app is authenticated to play on android can be played this way:
public void onPlaylistSelected(PlaylistData playlist) {
try {
mPlaylistData = playlist;
//Intent intent = YouTubeIntents.createPlayPlaylistIntent(this, playlist.getId());
Intent intent = YouTubeIntents.createOpenPlaylistIntent(this, playlist.getId());
startActivity(intent);
} catch (ActivityNotFoundException e) {
Log.w(TAG,e.getMessage());
Toast.makeText(this, R.string.warn_install_yt,Toast.LENGTH_LONG).show();
}
}

GoogleAccountCredential + Google Play Services + Refresh Token - how this works together?

I have published a pretty successful app about 2 weeks ago. But starting from yesterday, users keep sending me emails about Drive not being accessable anymore. After a quick debug, I found that requests to the Drive API now return "403 Forbidden" -> "Access Not Configured".
I think this might be an issue with the refresh token not being handled properly.
I'm using the following code (from the Android Drive SDK samples):
mCredentials = GoogleAccountCredential.usingOAuth2(this, DriveScopes.DRIVE);
String accountName = PreferenceManager.getDefaultSharedPreferences(this).getString(PREF_DRIVE_NAME, null);
if (accountName != null) {
setupDrive(accountName);
} else {
startActivityForResult(mCredentials.newChooseAccountIntent(), 0);
}
setupDrive(...) looks like this:
mCredentials.setSelectedAccountName(accountName);
try {
mCredentials.getToken();
} catch (Exception e) {
Log.w(AbstractDriveActivity.class.getSimpleName(), "Error getting auth token", e);
if (e instanceof UserRecoverableAuthException) {
Intent intent = ((UserRecoverableAuthException) e).getIntent();
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK).addFlags(Intent.FLAG_FROM_BACKGROUND);
startActivity(intent);
} else {
Toast.makeText(AbstractDriveActivity.this, getString(R.string.toast_drive_setup_error),
Toast.LENGTH_SHORT).show();
finish();
}
}
drive = new Drive.Builder(AndroidHttp.newCompatibleTransport(), new GsonFactory(),
mCredentials).build();
Any idea what might be wrong here?
From my understanding, GoogleAccountCredential uses the Google Play Services to manage the OAuth2 flow and all you need to provide is the username. Am I wrong? Did I miss something?
Btw: After clearing app data, selecting the Google Account again, everything works fine. That's why I think that it has something to do with the refresh token.
Goddchen
No guaranty, but the problem might come from here:
mCredentials = GoogleAccountCredential.usingOAuth2(this, DriveScopes.DRIVE);
This method appears as deprecated to me. You should upgrade your SDK and environment and change it to:
mCredentials = GoogleAccountCredential.usingOAuth2(this, Arrays.asList(DriveScopes.DRIVE));

Categories

Resources