Photo size in getPhotoUrl() method Google Identity toolkit - android

I did the login using Google Identity Toolkit, I have noticed that the class GitkitUser.UserProfile retrieves the photo url, but is too small. The google documentation do not say anything about photo size.
https://developers.google.com/identity/toolkit/android/reference/com/google/identitytoolkit/GitkitUser.UserProfile.html#getPhotoUrl()
For example with Facebook login, the getPhotoUrl() method returns:
https://scontent.xx.fbcdn.net/hprofile-xap1/v/t1.0-1/p50x50/12651146_10208004779813340_3124516205553866664_n.jpg?oh=efa817d10aaf9d184a767bae81a71071&oe=576850AD
For example with Gmail login, the getPhotoUrl() method returns:
https://lh6.googleusercontent.com/-5XFRyKHh7Os/AAAAAAAAAAI/AAAAAAAABIo/Trf7GjTnFec/s96-c/photo.jpg
Deleting /s96-c (or replace to /s200-c) in the Gmail photo url appears big, but I need a workaround to Facebook photo.

The solution for android was obtain the federatedId and after that call:
http://graph.facebook.com/{federatedId}/picture?type=large
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.welcome);
client = GitkitClient.newBuilder(this, new GitkitClient.SignInCallbacks() {
#Override
public void onSignIn(IdToken idToken, GitkitUser user) {
DataStorage.getInstance().setLastToken(idToken.getTokenString());
Configuration config = Configuration.fromMetaData(AppInfo.getAppInfo(LoginActivity.this).metaData);
ApiClient apiClient = new ApiClient(config.getApiKey(), AppInfo.getAppInfo(LoginActivity.this), config.getServerWidgetUrl());
final GetAccountInfo.Request request = apiClient.newGetAccountInfoRequest(idToken);
new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... params) {
GetAccountInfo.Response accountInfo = request.execute();
JSONArray users = accountInfo.getJsonResponse().optJSONArray("users");
JSONObject user = users == null ? null : users.optJSONObject(0);
String email = user == null ? null : user.optString("email");
if (email != null) {
JSONArray providerUserInfo = user.optJSONArray("providerUserInfo");
if (providerUserInfo != null && providerUserInfo.length() != 0) {
for (int i = 0; i < providerUserInfo.length(); ++i) {
JSONObject userInfo = providerUserInfo.optJSONObject(i);
if (userInfo != null) {
try {
String userInfoString = userInfo.getString("federatedId");
if(userInfoString.contains("facebook.com")) {
int lastSlash = userInfoString.lastIndexOf("/");
if(lastSlash != -1) {
String federatedIdFacebook = userInfoString.substring(lastSlash + 1, userInfoString.length());
Log.i("federatedIdFacebook", federatedIdFacebook);
}
break;
}
} catch (JSONException e) {
Log.e("LoginActivity", e.getMessage());
}
}
}
}
}
return null;
}
}.execute();
}
#Override
public void onSignInFailed() {
Toast.makeText(LoginActivity.this, "Sign in failed", Toast.LENGTH_LONG).show();
}
}).build();
}

You could use the idToken to get the User's identifier at IDP (facebook id).
See users[].providerUserInfo[].federatedId at https://developers.google.com/identity/toolkit/web/reference/relyingparty/getAccountInfo
And then use the facebookId to get the large account picture, with
http://graph.facebook.com/{facebookId}/picture?type=large

Related

Can I access Fb user details even without requesting the user to sign-in for an android app that I am developing

Overall skeleton of the app goes like this,
The app opens, let's the new user to register or already existing user to login goes into SQLite. Later I want to fetch data from/through the user's profile. Is it possible?
I have been looking into this AccessToken stuff offered by Fb but everything flows over my head.
Let's say the user logs in initially by registering. Later I'll let the user to type in what to search and I want to fetch those search result from Facebook, those search results should also be from the user's profile. All these should happen even without the user manually entering his Fb details, rather he's going to get a pop up dialog box that says Continue with Fb login something of that sort.
Facebook user details only access with Access Token which is generated by facebook. First need to create developer account then create app over developer account. App ID and Key need to put on your android app which you can get from facebook developer account after creating an app there. For more details check out its official documentation.
I assume you question states that you want to get the user detail from facebook without getting logged in you app.if that is the case yes it is possible. because getting details from facebook is a different process and you getting logged in your app is a different one.
private Context context;
private Fragment mFragment;
private ShareDialog mShareDialog;
/**
* #param context
*/
public FacebookLoginManager(Context context, Fragment fragment) {
this.context = context;
this.mFragment = fragment;
}
/**
* #param context
*/
public FacebookLoginManager(Context context) {
this.context = context;
}
/**
* The purpose of this method is to initialize the facebook sdk
*
* #param callbackManager
*/
public void initializedFacebook(CallbackManager callbackManager) {
if (FacebookSdk.isInitialized()) {
performFacebookLogin(callbackManager);
} else {
FacebookSdk.sdkInitialize(getApplicationContext());
performFacebookLogin(callbackManager);
}
}
/**
* The purpose of this method is to initialize the facebook data from the server
*
* #param callbackManager
*/
private void performFacebookLogin(CallbackManager callbackManager) {
try {
LoginManager.getInstance().registerCallback(callbackManager,
new FacebookCallback<LoginResult>() {
#Override
public void onSuccess(LoginResult loginResult) {
final String accessToken = "" + loginResult.getAccessToken().getToken();
Log.e("accessToken", accessToken);
GraphRequest request = GraphRequest.newMeRequest(
AccessToken.getCurrentAccessToken(),
new GraphRequest.GraphJSONObjectCallback() {
#Override
public void onCompleted(
JSONObject object,
GraphResponse response) {
try {
final FacebookResponseBean mFacebookResponseBean = new FacebookResponseBean();
if (object != null) {
if (object.has(FacebookConstants.ID) && object.get(FacebookConstants.ID) != null) {
mFacebookResponseBean.setUserId(object.get(FacebookConstants.ID) + "");
}
if (object.has(FacebookConstants.NAME) && object.get(FacebookConstants.NAME) != null) {
mFacebookResponseBean.setName(object.get(FacebookConstants.NAME) + "");
}
if (object.has(FacebookConstants.EMAIL) && object.get(FacebookConstants.EMAIL) != null) {
mFacebookResponseBean.setEmail(object.get(FacebookConstants.EMAIL) + "");
}
if (object.has(FacebookConstants.GENDER) && object.get(FacebookConstants.GENDER) != null) {
mFacebookResponseBean.setGender(object.get(FacebookConstants.GENDER) + "");
}
if (object.has(FacebookConstants.BIRTHDAY) && object.get(FacebookConstants.BIRTHDAY) != null) {
mFacebookResponseBean.setBirthday(object.get(FacebookConstants.BIRTHDAY) + "");
}
if (object.has(FacebookConstants.AGE_RANGE) && object.get(FacebookConstants.AGE_RANGE) != null) {
mFacebookResponseBean.setAgerange(object.get(FacebookConstants.AGE_RANGE) + "");
}
if (object.has(FacebookConstants.TIMEZONE) && object.get(FacebookConstants.TIMEZONE) != null) {
mFacebookResponseBean.setTimezone(object.get(FacebookConstants.TIMEZONE) + "");
}
if (object.has(FacebookConstants.VERIFIED) && object.get(FacebookConstants.VERIFIED) != null) {
mFacebookResponseBean.setVerified(object.get(FacebookConstants.VERIFIED) + "");
}
if (object.has(FacebookConstants.UPDATED_TIME) && object.get(FacebookConstants.UPDATED_TIME) != null) {
mFacebookResponseBean.setUpdatedtime(object.get(FacebookConstants.UPDATED_TIME) + "");
}
if (object.has(FacebookConstants.LOCALE) && object.get(FacebookConstants.LOCALE) != null) {
mFacebookResponseBean.setLocale(object.get(FacebookConstants.LOCALE) + "");
}
if (object.has(FacebookConstants.FIRST_NAME) && object.get(FacebookConstants.FIRST_NAME) != null) {
mFacebookResponseBean.setFirstName(object.get(FacebookConstants.FIRST_NAME) + "");
}
if (object.has(FacebookConstants.LAST_NAME) && object.get(FacebookConstants.LAST_NAME) != null) {
mFacebookResponseBean.setLastName(object.get(FacebookConstants.LAST_NAME) + "");
}
if (object.has(FacebookConstants.PICTURE) && object.get(FacebookConstants.PICTURE) != null) {
JSONObject picture = object.getJSONObject(FacebookConstants.PICTURE);
JSONObject data = picture.getJSONObject("data");
if (data.has("url") && data.get("url") != null) {
mFacebookResponseBean.setPhotolink(data.get("url") + "");
Logger.error("image", data.get("url") + "");
}
}
}
if (context instanceof LoginActivity) {
((LoginActivity) context).setFaceBookResponse(mFacebookResponseBean);
} else if (context instanceof RegistrationActivity) {
((RegistrationActivity) context).setFaceBookResponse(mFacebookResponseBean);
} else if (context instanceof UserProfileActivity) {
((UserProfileActivity) context).setFaceBookResponse(mFacebookResponseBean);
} else if (mFragment != null && mFragment instanceof FragmentLinkAccounts) {
((FragmentLinkAccounts) mFragment).setFaceBookResponse(mFacebookResponseBean);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
});
Bundle parameters = new Bundle();
parameters.putString("fields", FacebookConstants.PERMISSION);
request.setParameters(parameters);
request.executeAsync();
}
#Override
public void onCancel() {
}
#Override
public void onError(FacebookException exception) {
exception.printStackTrace();
if (exception instanceof FacebookAuthorizationException) {
if (AccessToken.getCurrentAccessToken() != null) {
LoginManager.getInstance().logOut();
}
}
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* The purpose of this method is to share the image and content on facebook
*
* #param activity
* #param manager
* #param image
* #param isShareRequest
* #param id
*/
public void shareContent(final Activity activity, CallbackManager manager, View image, final boolean isShareRequest, int id) {
mShareDialog = new ShareDialog(activity);
String time = GlobalAcess.getDateTime();
mShareDialog.registerCallback(manager, new FacebookCallback<Sharer.Result>() {
#Override
public void onSuccess(Sharer.Result result) {
if (isShareRequest)
ToastMessage.getInstance(activity).showLongMessage(activity.getString(R.string.msg_request_posted));
else
ToastMessage.getInstance(activity).showLongMessage(activity.getString(R.string.msg_trip_posted));
}
#Override
public void onCancel() {
}
#Override
public void onError(FacebookException error) {
error.printStackTrace();
}
});
String url = "";
if (isShareRequest) {
url = NetworkConstants.SHARE_REQUEST_URL + "id=" + id + "?t=" + time;
} else {
url = NetworkConstants.SHARE_TRIP_URL + "id=" + id + "?t=" + time;
}
if (ShareDialog.canShow(ShareLinkContent.class)) {
ShareLinkContent content = new ShareLinkContent.Builder()
.setContentUrl(Uri.parse(url))
.build();
mShareDialog.show(content);
}
}
}
//

I want to refresh/recreate my activity programatically when getting response from server

I want when server sends some response in form of WebView then immediately my activity gets refreshed and so WebView in form of banner ad.
I write code for display banner ad but ad is showing only when my activity recreated i.e. when I rotate my screen then banner is showing but when it is in same static mode then banner is not showing.
So, please let me know what I will do so that when server gave some response immediately it will be shown on my activity.
void startDemo() {
//Set Http Client Options
final OptimusHTTP client = new OptimusHTTP();
client.enableDebugging();
client.setMethod(OptimusHTTP.METHOD_POST);
client.setMode(OptimusHTTP.MODE_SEQ);
FreqDetector_Goertzel.getInstance().startRecording(new FreqDetector_Goertzel.RecordTaskListener() {
private String urlRedirect = "";
private String imgSmallBanner = "";
#Override
public void onSuccess(int val)
{
String pSet = pVal.getPatternSet(val, 5);
if (pSet != null) {
FreqDetector_Goertzel.getInstance().stopRecording();
EasyDeviceInfo deviceInfo = new EasyDeviceInfo(MainActivity.this);
final HashMap<String, String> device_params = new HashMap<>();
device_params.put("aid", deviceInfo.getAndroidID());
device_params.put("pattern", pSet);
if (isNetworkAvailable(MainActivity.this)) {
try {
client.makeRequest(MainActivity.this, new HttpReq(), Defaults.MATCHINGSERVER, device_params, new OptimusHTTP.ResponseListener() {
#Override
public void onSuccess(String s) {
try {
if (s != null && !s.contains("No Match Found"))
{
JSONObject jsonObject = null;
jsonObject = new JSONObject(s);
imgSmallBanner = Uri.decode(jsonObject.optString("smallImgUrl", "NA"));
urlRedirect = Uri.decode(jsonObject.optString("redirectUrl", "NA"));
loadAdvertisement(urlRedirect, imgSmallBanner);
} else {
//Did not match
startDemo();
}
} catch (JSONException e) {
e.printStackTrace();
}
}
#Override
public void onFailure(String s) {
}
});
} catch (Exception e) {
e.printStackTrace();
}
} else {
//Internet not available. Do not do anything.
}
}
}
#Override
public void onFailure(String s) {
}
});
}
void loadAdvertisement(String clickUrl, String imgSmallName) {
String click_url;
String img_small_url;
stopDemo();
click_url = Uri.decode(Uri.encode(clickUrl));
img_small_url = imgSmallName;
StringBuilder htmlData2 = new StringBuilder();
htmlData2.append("<html><body style='margin:0;padding:0;background-color:black;'><a href='").append(click_url).append("' ><img src='").append(img_small_url).append("' height=50 style='margin:0 auto;display:block;' /></a></body></html>");
webView_img_small.loadDataWithBaseURL("file:///android_asset/", htmlData2.toString(), "text/html", "utf-8", null);
webView_img_small.setVisibility(View.VISIBLE);
/* What I will do here so when server sends response it will immediately being refreshed and shown on activity without recreating it.*/ }
here you can find some response: http://developer.android.com/guide/topics/ui/how-android-draws.html
for me a call to invalidate() only refresh the view and a call to requestLayout() refresh the view and compute the size of the view in the screen.
You can try to use Activity.recreate(). This method will destroy your current Activity and create a new Activity same way when you rotate device.
Hope this helps.

How exactly can I get friends profile info like birthday,gender etc using google plus API?

Can somebody please explain to me that what friends information I can get from google plus in android api in both worst and best case scenario.Some how I am not able to figure it out from google documentation.
I am using following code with scope and permission :-
mGoogleApiClient = new GoogleApiClient.Builder(this).addApi(Plus.API).addScope(Plus.SCOPE_PLUS_LOGIN).addScope(Plus.SCOPE_PLUS_PROFILE)
.addConnectionCallbacks(this).addOnConnectionFailedListener(this).build();
to retrieve people info I am calling
Plus.PeopleApi.loadVisible(mGoogleApiClient, null)
.setResultCallback(this);
Now is there any google api which I can use to get profile info of users and to what extent ?
In onConnected method call the method getProfileInformation() , in this method you can get all the profile info
#Override
public void onConnected(Bundle bundle) {
mSignInClicked = false;
Toast.makeText(this, "User is connected!", Toast.LENGTH_LONG).show();
// Get user's information
getProfileInformation();
/**
* Fetching user's information name, email, profile pic
* */
private void getProfileInformation() {
try {
if (Plus.PeopleApi.getCurrentPerson(mGoogleApiClient) != null) {
Person currentPerson = Plus.PeopleApi
.getCurrentPerson(mGoogleApiClient);
String personName = currentPerson.getDisplayName();
String personPhotoUrl = currentPerson.getImage().getUrl();
String personGooglePlusProfile = currentPerson.getUrl();
String email = Plus.AccountApi.getAccountName(mGoogleApiClient);
**currentPerson.getBirthday();
currentPerson.getGender();
currentPerson.getRelationshipStatus();**
} else {
Toast.makeText(getApplicationContext(),
"Person information is null", Toast.LENGTH_LONG).show();
}
} catch (Exception e) {
e.printStackTrace();
}
}
Try this, you can get any information with personBuffer.get(i) :
private static final int PROFILE_PIC_SIZE = 400;
public void getProfileInformation() {
try {
Plus.PeopleApi.loadVisible(mGoogleApiClient, null).setResultCallback(new ResultCallback<People.LoadPeopleResult>() {
#Override
public void onResult(People.LoadPeopleResult loadPeopleResult) {
if (loadPeopleResult.getStatus().getStatusCode() == CommonStatusCodes.SUCCESS) {
PersonBuffer personBuffer = loadPeopleResult.getPersonBuffer();
try {
int count = personBuffer.getCount();
for (int i = 0; i < count; i++) {
String name = personBuffer.get(i).getDisplayName();
String nickName = personBuffer.get(i).getNickname();
String gender = personBuffer.get(i).getGender();
String urlPhoto = personBuffer.get(i).getImage().getUrl().substring(0,
personBuffer.get(i).getImage().getUrl().length() - 2)
+ PROFILE_PIC_SIZE;
//And other things...
if(personBuffer.get(i).getPlacesLived() != null || personBuffer.get(i).hasPlacesLived()) {
for (Person.PlacesLived place : personBuffer.get(i).getPlacesLived()) {
if (place.isPrimary()) {
String placesLived = place.getValue();
}
}
}
}
} finally {
personBuffer.close();
}
} else {
}
}
});
}catch(Exception e)
{}
}

Facebook SDK on Unity cant get anything except first_name

so here is my code for connecting and getting the values:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using Facebook;
using SmartLocalization;
public class mainMenuFacebook : MonoBehaviour {
public string FBname;
public string FBsurname;
Dictionary<string, string> profile = new Dictionary<string, string>();
// Use this for initialization
void OnMouseDown()
{
FB.Login("publish_actions,public_profile", LoginCallback); // logine tıklama
}
void Awake() {
FB.Init(SetInit, OnHideUnity); //facebook başlangıcı
}
private void SetInit()
{
if (FB.IsLoggedIn)
{
// Util.Log("Already logged in");
OnLoggedIn();
}
}
private void OnHideUnity(bool isGameShown)
{
if (!isGameShown)
{
// pause the game - we will need to hide
Time.timeScale = 0;
}
else
{
// start the game back up - we're getting focus again
Time.timeScale = 1;
}
}
void LoginCallback(FBResult result)
{
Util.Log("LoginCallback");
if (FB.IsLoggedIn)
{ gameObject.guiTexture.enabled = false;
OnLoggedIn();
}
}
void OnLoggedIn()
{
FB.API("/me?fields=first_name,last_name,email", Facebook.HttpMethod.GET, APICallback); // adını ve idyi çekiyoruz.
}
void APICallback(FBResult result)
{
if (result.Error != null)
{
// Let's just try again
// FB.API("/me?fields=id,first_name,last_name,email,friends.limit(100).fields(first_name,last_name,id)", Facebook.HttpMethod.GET, APICallback);
return;
}
Debug.Log(result.Text);
profile = Util.DeserializeJSONProfile(result.Text);
FBname = profile["first_name"];
FBsurname = profile["last_name"]; // **IT GIVES ERROR**
Debug.Log(FBsurname + " " + FBname);
//PlayerPrefs.SetString("surname",profile["last_name"]);
//PlayerPrefs.SetString("email",profile["email"]);
gameObject.guiTexture.enabled = false;
GameObject.Find("Wellcome").guiText.enabled = true;
GameObject.Find("Wellcome").guiText.text = LanguageManager.Instance.GetTextValue("menu.hosgeldin") + " <b><color=#ffa500ff>" + FBname + "</color></b>, <i>" + LanguageManager.Instance.GetTextValue("menu.cikis") +"</i>";
PlayerPrefs.SetString("name",FBname);
}
}
when i only try to get first_name everything is okay. But i need to get last_name and email too. I think i cant serialize because when i try to Debug.Log(profile.Count); it shows 1.
How can i fix it?
Given error is:
KeyNotFoundException: The given key was not present in the dictionary.
System.Collections.Generic.Dictionary`2[System.String,System.String].get_Item (System.String key) (at /Users/builduser/buildslave/mono-runtime-and-classlibs/build/mcs/class/corlib/System.Collections.Generic/Dictionary.cs:150)
mainMenuFacebook.APICallback (.FBResult result) (at Assets/Scripts/mainMenuFacebook.cs:84)
Facebook.AsyncRequestString+<Start>c__Iterator0.MoveNext ()
Try this:
public void OnMouseDown()
{
List<string> permissions = new List<string>() { "public_profile", "email" };
FB.LogInWithReadPermissions(permissions,AuthCallback);
Debug.Log("Facebook Login");
}
In AuthCallback: if user logs in successfully, get info from FB api.
private void AuthCallback(ILoginResult result)
{
if(FB.IsLoggedIn)
{
GetInfo();
}
else
{
Debug.Log("User cancelled login");
}
}
FB API returns json result, so you will need FacebookUser class to deserialize it.
class FacebookUser
{
public string id;
public string first_name;
public string last_name;
public string email;
}
public void GetInfo()
{
FB.API("/me?fields=id,first_name,last_name,email", HttpMethod.GET, result =>
{
if(result.Error != null)
{
Debug.Log("Result error");
}
var facebookUser = Newtonsoft.Json.JsonConvert.DeserializeObject<FacebookUser>(result.RawResult);
Debug.Log(" facebook id - " + facebookUser.id);
Debug.Log(" facebook first name - " + facebookUser.first_name);
Debug.Log(" facebook last name - " + facebookUser.last_name);
Debug.Log(" facebook email - " + facebookUser.email);
});
}
NOTE: You should have Email permission from facebook to access it.
Check it in Graph API Explorer

InApp Purchase RESTORE_TRANSACTIONS, I am not able to figure the code out

I am adding a in app purchase in my coding, it's working well while purchase but gives error and application closes when I try to add Restore_Transaction code when application is removed and installed again, I have added below coding
in onCreate i wrote
startService(new Intent(mContext, BillingService.class));
BillingHelper.setCompletedHandler(mTransactionHandler);
if (BillingHelper.isBillingSupported()) {
BillingHelper.restoreTransactionInformation(BillingSecurity
.generateNonce());
}
and then i called handler using
public Handler mTransactionHandler = new Handler() {
public void handleMessage(android.os.Message msg) {
if (BillingHelper.latestPurchase.isPurchased()) {
showItem();
}
};
};
private void showItem() {
purchased = Purchased.getPurchaseInfo(getApplicationContext());
if (purchased == null) {
Date d = new Date();
Toast.makeText(getApplicationContext(), "--- Upgrated ---",
Toast.LENGTH_LONG).show();
purchased = new Purchased(getApplicationContext());
purchased.isPurchased = 1;
purchased.purchasedDate = d.getTime();
purchased.save();
Intent intent = new Intent(ActorGenieActivity.this,
SplashScreen.class);
startActivity(intent);
}
}
I found the answer to my question, thanx to anddev
You have to check for purchases not to be null
public static void verifyPurchase(String signedData, String signature) {
ArrayList<VerifiedPurchase> purchases = BillingSecurity.verifyPurchase(
signedData, signature);
if (purchases != null && !purchases.isEmpty()) {
latestPurchase = purchases.get(0);
confirmTransaction(new String[] { latestPurchase.notificationId });
if (mCompletedHandler != null) {
mCompletedHandler.sendEmptyMessage(0);
} else {
Log
.e(
TAG,
"verifyPurchase error. Handler not instantiated. Have you called setCompletedHandler()?");
}
}
}
and in Confirm_Notification u hav to check for
if (notifyIds[0] != null)
Follow this:
confirmTransaction(new String[] { latestPurchase.notificationId });
here and do this:
protected static void confirmTransaction(String[] notifyIds) {
if (amIDead()) {
return;
}
// there isn't a notifyid then this was the restore transaction call and this should be skipped
if (notifyIds[0] != null){
Log.i(TAG, "confirmTransaction()");
Bundle request = makeRequestBundle("CONFIRM_NOTIFICATIONS");
......
......
}
Works like a charm form me.. Thanks Guys...
You can use the below code to get purchase history:
public static ArrayList<VerifiedPurchase> verifyPurchase(String signedData,
String signature) {
if (signedData == null) {
//Log.e(TAG, "data is null");
return null;
}
if (Constans.DEBUG) {
//Log.i(TAG, "signedData: " + signedData);
}
boolean verified = false;
if (!TextUtils.isEmpty(signature)) {
/**
* Compute your public key (that you got from the Android Market
* publisher site).
*
* Instead of just storing the entire literal string here embedded
* in the program, construct the key at runtime from pieces or use
* bit manipulation (for example, XOR with some other string) to
* hide the actual key. The key itself is not secret information,
* but we don't want to make it easy for an adversary to replace the
* public key with one of their own and then fake messages from the
* server.
*
* Generally, encryption keys / passwords should only be kept in
* memory long enough to perform the operation they need to perform.
*/
String base64EncodedPublicKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuKgldGQPL/xV9WKLmY62UVgEm7gsPI/T/nQxRKpYN17m8Sq3gO9nWD17wXew4oNaHmMAmArS7s7eFi3Z+XiyWil1iZvEOdBOdZD502BzujPoBa4Fu9eITPBO9tzBEdvNLXf8amnsRj53TA4bcxB2O6OcXrQIv3t3n5Dg5Nn+rJpoKSNUv7NEzJagG/2NhyjIysAObbvQ5SBQ5NgRtZlvhsTeQJPMLhRAoRcTK/+47VkhrxM3PppeGjoNRryn6d+RhMjs/nydvoQtP2V76UcUu4m+daDnK3PxOnwLt50hNtQhNf3VgixVrSKfHUWp240uEz9MHstjj8BWPH9BFF/TewIDAQAB";
PublicKey key = Security.generatePublicKey(base64EncodedPublicKey);
verified = Security.verify(key, signedData, signature);
if (!verified) {
//Log.w(TAG, "signature does not match data.");
return null;
}
}
JSONObject jObject;
JSONArray jTransactionsArray = null;
int numTransactions = 0;
long nonce = 0L;
try {
jObject = new JSONObject(signedData);
// The nonce might be null if the user backed out of the buy page.
nonce = jObject.optLong("nonce");
jTransactionsArray = jObject.optJSONArray("orders");
if (jTransactionsArray != null) {
numTransactions = jTransactionsArray.length();
}
} catch (JSONException e) {
return null;
}
if (!Security.isNonceKnown(nonce)) {
//Log.w(TAG, "Nonce not found: " + nonce);
return null;
}
ArrayList<VerifiedPurchase> purchases = new ArrayList<VerifiedPurchase>();
try {
for (int i = 0; i < numTransactions; i++) {
JSONObject jElement = jTransactionsArray.getJSONObject(i);
int response = jElement.getInt("purchaseState");
PurchaseState purchaseState = PurchaseState.valueOf(response);
String productId = jElement.getString("productId");
String packageName = jElement.getString("packageName");
long purchaseTime = jElement.getLong("purchaseTime");
String orderId = jElement.optString("orderId", "");
String notifyId = null;
if (jElement.has("notificationId")) {
notifyId = jElement.getString("notificationId");
}
String developerPayload = jElement.optString(
"developerPayload", null);
// If the purchase state is PURCHASED, then we require a
// verified nonce.
if (purchaseState == PurchaseState.PURCHASED && !verified) {
continue;
}
purchases.add(new VerifiedPurchase(purchaseState, notifyId,
productId, orderId, purchaseTime, developerPayload));
}
} catch (JSONException e) {
//Log.e(TAG, "JSON exception: ", e);
return null;
}
removeNonce(nonce);
return purchases;
}
You can call this method from the below method in BillingService class:
private void purchaseStateChanged(int startId, String signedData,
String signature) {
ArrayList<Security.VerifiedPurchase> purchases;
purchases = Security.verifyPurchase(signedData, signature);
if (purchases == null) {
return;
}
ArrayList<String> notifyList = new ArrayList<String>();
for (VerifiedPurchase vp : purchases) {
if (vp.notificationId != null) {
notifyList.add(vp.notificationId);
}
ResponseHandler.purchaseResponse(this, vp.purchaseState,
vp.productId, vp.orderId, vp.purchaseTime,
vp.developerPayload);
}
if (!notifyList.isEmpty()) {
String[] notifyIds = notifyList.toArray(new String[notifyList
.size()]);
confirmNotifications(startId, notifyIds);
}
}

Categories

Resources