I'm working with stripe integration. To add and save card. For entering card details i'm using stripe's default AddPaymentMethodActivityStarter . After setup intent my card is not attached to the customer and it is not not displayed in stripe console as well.
Is there any way to automatically attach card after setup intent (stripe.confirmSetupIntent) ?
Also i'm adding a footer layout to AddPaymentMethodActivityStarter. and the footer layout has a checkbox. is there any way to get the checkbox checked,unchecked value. Even after initialization, i always get null
StripeActivity.java
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_stripe_latest);
initMethod();
findElements();
// Get ephemeralKey
CustomerSession.initCustomerSession(this, (s, ephemeralKeyUpdateListener) -> getEphemeralKey(ephemeralKeyUpdateListener, s));
// Use the publishable key from the server to initialize the Stripe instance.
stripe = new Stripe(getApplicationContext(), getString(R.string.stripe_publishable_key));
// launch stripe add card ui
new AddPaymentMethodActivityStarter(StripeAddCardActivityDup.this).startForResult(
new AddPaymentMethodActivityStarter.Args.Builder()
.setAddPaymentMethodFooter(R.layout.footer_layout) // --> get the value of checkbox
.build());
// initialize the checkbox, in footer layout
saveCard = findViewById(R.id.saveCard);
if(saveCard !=null){
if(saveCard.isChecked()){
Toast.makeText(this, "checkbox is checked", Toast.LENGTH_SHORT).show();
}else{
Toast.makeText(this, "checkbox is not checked", Toast.LENGTH_SHORT).show();
}
}else{
Toast.makeText(this, "checkbox is null", Toast.LENGTH_SHORT).show();
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, #Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
messageHandler.lock(StripeAddCardActivityDup.this);
if (requestCode == AddPaymentMethodActivityStarter.REQUEST_CODE) { // result of AddPaymentMethodActivityStarter. get payment id and send to setupintent
final AddPaymentMethodActivityStarter.Result result =
AddPaymentMethodActivityStarter.Result.fromIntent(data);
if (result instanceof AddPaymentMethodActivityStarter.Result.Success) {
final AddPaymentMethodActivityStarter.Result.Success successResult =
(AddPaymentMethodActivityStarter.Result.Success) result;
setUpIntent(successResult.getPaymentMethod().id);
}
} else if (requestCode == 50001) { // result of setup intent
WeakReference<Activity> weakActivity = new WeakReference<>(this);
// Handle the result of stripe.confirmSetupIntent
stripe.onSetupResult(requestCode, data, new ApiResultCallback<SetupIntentResult>() {
#Override
public void onSuccess(#NonNull SetupIntentResult result) {
SetupIntent setupIntent = result.getIntent();
SetupIntent.Status status = setupIntent.getStatus();
if (status == SetupIntent.Status.Succeeded) {
// Setup completed successfully
runOnUiThread(() -> {
if (weakActivity.get() != null) {
attachCustomer(setupIntent.getPaymentMethodId()); // --> manually attaching the card to customer after setup intent using "attachPaymentMethod"
}
});
} else if (status == SetupIntent.Status.RequiresPaymentMethod) {
// Setup failed – allow retrying using a different payment method
runOnUiThread(() -> {
Activity activity = weakActivity.get();
if (activity != null) {
stripeErrorAlert(setupIntent.getLastSetupError().getMessage());
}
});
}
}
#Override
public void onError(#NonNull Exception e) {
// Setup request failed – allow retrying using the same payment method
runOnUiThread(() -> {
Activity activity = weakActivity.get();
if (activity != null) {
stripeErrorAlert(e.toString());
}
});
}
});
}
}
// method to confirm setup intent
public void setUpIntent(String paymentMethodId) {
BackgroundExecutor.execute(new BackgroundExecutor.Task("", 0, "") {
#Override
public void execute() {
try {
messageHandler.lock(StripeAddCardActivityDup.this);
// retrofit WS to get client secret
SetupIntentModel intentModel = driverService.getSetupIntent(new StripeSetupIntentRequest(getString(R.string.stripe_customer_id)));
runOnUiThread(() -> {
ConfirmSetupIntentParams confirmParams = ConfirmSetupIntentParams.create(paymentMethodId, intentModel.getClientSecret(),"redirect://stripe");
stripe.confirmSetupIntent(StripeAddCardActivityDup.this, confirmParams);
});
} catch (Exception e) {
Logger.logError(AppConstants.GENERAL_TAG, e);
}
}
});
}
// attach card to customer
private void attachCustomer(String paymentId){
CustomerSession.getInstance().attachPaymentMethod(paymentId, new CustomerSession.PaymentMethodRetrievalListener() {
#Override
public void onPaymentMethodRetrieved(#NotNull PaymentMethod paymentMethod) {
messageHandler.showAlert(getString(R.string.card_was_successful_added), getString(R.string.ok), "", v -> finish(),null);
}
#Override
public void onError(int i, #NotNull String s, #org.jetbrains.annotations.Nullable StripeError stripeError) {
String errorMsg = getString(R.string.card_wasnt_successful_added)+"-"+stripeError.toString();
messageHandler.showAlert(errorMsg, getString(R.string.ok), "", v -> finish(),null);
}
});
}
footer_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:background="#color/white"
android:layout_height="wrap_content">
<CheckBox
android:id="#+id/saveCard"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:text="save card" />
</LinearLayout>
Related
I'd like to successfully run the code below (belonging to this library) when any of the buttons from this Rating Dialog are pressed. How can I do it?
public void goToPickerActivity() {
Intent intent = new com.sucho.placepicker.PlacePicker.IntentBuilder()
.onlyCoordinates(true) //Get only Coordinates from Place Picker
.showLatLong(true)
.setLatLong(40.71274, -74.005974) // Initial Latitude and Longitude the Map will load into (NYC coordinates)
.setMapZoom(2.5f) // Map Zoom Level. Default: 14.0
.build(this);
startActivityForResult(intent, Constants.PLACE_PICKER_REQUEST);
}
Edit: I want to execute goToPickerActivity() first and then execute the library's intended click code. For example, when Rate App button is clicked:
Step 1 is: execute goToPickerActivity().
Once that's complete, Step 2 is: run the usual Rate App clicked code.
You can try to add a OnRatingDialogListener using setRateButtonText, setRateLaterButtonText or setNeverRateButtonText methods of AppRatingDialog.Builder class:
final AppRatingDialog appRatingDialog = new AppRatingDialog.Builder(this)
// ... call another setup methods if need
.setRateButtonText("Rate App", new OnRatingDialogListener() {
#Override
public void onClick() {
goToPickerActivity();
}
})
.setRateLaterButtonText("Rate App Later", new OnRatingDialogListener() {
#Override
public void onClick() {
goToPickerActivity();
}
})
.setNeverRateButtonText("Never", new OnRatingDialogListener() {
#Override
public void onClick() {
goToPickerActivity();
}
})
.build();
appRatingDialog.show();
Using lambda it will look like this:
final AppRatingDialog appRatingDialog = new AppRatingDialog.Builder(this)
// ... call another setup methods if need
.setRateButtonText("Rate App", () -> goToPickerActivity())
.setRateLaterButtonText("Rate App Later", () -> goToPickerActivity())
.setNeverRateButtonText("Never", () -> goToPickerActivity())
.build();
appRatingDialog.show();
EDIT 1:
Method openPlayStore:
private void openPlayStore() {
final String storeLink = "market://details?id=" + context.getPackageName();
final Uri marketUri = Uri.parse(storeLink);
try {
mContext.startActivity(new Intent(Intent.ACTION_VIEW, marketUri));
} catch (android.content.ActivityNotFoundException ex) {
Toast.makeText(mContext, "Couldn't find PlayStore on this device", Toast.LENGTH_SHORT).show();
}
}
If you can edit the library try to make openPlayStore method public, save reference to AppRatingDialog instanse to some variable, e.g. appRatingDialog and call appRatingDialog.openPlayStore().
EDIT 2:
To have different listeners for buttons we need to add new listeners to AppRatingDialog and handle them:
public class AppRatingDialog extends AppCompatDialog implements View.OnClickListener {
//...
private OnRatingDialogListener onRatingDialogListener;
private OnRatingDialogListener onRateLaterDialogListener;
private OnRatingDialogListener onRateNeverDialogListener;
//...
#Override
public void onClick(View v) {
if (v.getId() == R.id.dialog_rating_button_never_rate) {
savedNeverShow();
dismiss();
if (onRateNeverDialogListener != null) {
onRateNeverDialogListener.onClick();
}
} else if (v.getId() == R.id.dialog_rating_button_rate_later) {
dismiss();
incrementLaunchCount(true);
if (onRateLaterDialogListener != null) {
onRateLaterDialogListener.onClick();
}
} else if (v.getId() == R.id.dialog_rating_button_rate) {
savedNeverShow();
dismiss();
if (onRatingDialogListener != null) {
onRatingDialogListener.onClick();
} else {
openPlayStore();
}
}
}
// ...
public static class Builder {
//...
#NonNull
public Builder setRateLaterButtonText(String rateLaterButtonText, #Nullable OnRatingDialogListener onRateLaterClickListener) {
appRatingDialog.mRateLaterButtonText = rateLaterButtonText;
appRatingDialog.onRateLaterDialogListener = onRateLaterClickListener;
return this;
}
#NonNull
public Builder setNeverRateButtonText(String neverRateButtonText, #Nullable OnRatingDialogListener onNeverRateClickListener) {
appRatingDialog.mNeverRateButtonText = neverRateButtonText;
appRatingDialog.onRateNeverDialogListener = onNeverRateClickListener;
return this;
}
// ...
}
}
EDIT 3:
To open Play Store and notify a listener simultaneously:
public class AppRatingDialog extends AppCompatDialog implements View.OnClickListener {
//...
private OnRatingDialogListener onRatingDialogListener;
private OnRatingDialogListener onRateLaterDialogListener;
private OnRatingDialogListener onRateNeverDialogListener;
//...
#Override
public void onClick(View v) {
if (v.getId() == R.id.dialog_rating_button_never_rate) {
savedNeverShow();
dismiss();
if (onRateNeverDialogListener != null) {
onRateNeverDialogListener.onClick();
}
} else if (v.getId() == R.id.dialog_rating_button_rate_later) {
dismiss();
incrementLaunchCount(true);
if (onRateLaterDialogListener != null) {
onRateLaterDialogListener.onClick();
}
} else if (v.getId() == R.id.dialog_rating_button_rate) {
savedNeverShow();
dismiss();
openPlayStore();
if (onRatingDialogListener != null) {
onRatingDialogListener.onClick();
}
}
}
// ...
}
Please follow these steps:
In the library module look for class called AppRatingDialog.java add YOURACTIVITY.goToPickerActivity(**boolean**); to each view of onClick (at line 171) method like this one:
#Override
public void onClick(View v) {
if (v.getId() == R.id.dialog_rating_button_never_rate) {
YOURACTIVITY.goToPickerActivity(false);
savedNeverShow();
dismiss();
if (onRatingDialogListener != null) {
onRatingDialogListener.onClick();
}
} else if (v.getId() == R.id.dialog_rating_button_rate_later) {
YOURACTIVITY.goToPickerActivity(false);
dismiss();
incrementLaunchCount(true);
if (onRatingDialogListener != null) {
onRatingDialogListener.onClick();
}
} else if (v.getId() == R.id.dialog_rating_button_rate) {
YOURACTIVITY.goToPickerActivity(true);
savedNeverShow();
dismiss();
if (onRatingDialogListener != null) {
onRatingDialogListener.onClick();
}
}
}
In your activity modify your method goToPickerActivity() to be something like this:
private static void goToPickerActivity(boolean isRate) {
Intent intent = new com.sucho.placepicker.PlacePicker.IntentBuilder()
.onlyCoordinates(true) //Get only Coordinates from Place Picker
.showLatLong(true)
.setLatLong(40.71274, -74.005974) // Initial Latitude and Longitude the Map will load into (NYC coordinates)
.setMapZoom(2.5f) // Map Zoom Level. Default: 14.0
.build(this);
if (isRate){
startActivityForResult(intent, Constants.PLACE_PICKER_REQUEST_RATE);
} else {
startActivityForResult(intent, Constants.PLACE_PICKER_REQUEST);
}
in method onActivityResult check the request code if it's equal to Constants.PLACE_PICKER_REQUEST_RATE then call method openStore():
#Override
protected void onActivityResult(int requestCode, int resultCode, #Nullable Intent data) {
if (requestCode == Constants.PLACE_PICKER_REQUEST_RATE) {
//other code ...
openStore();
}
}
}
private void openStore() {
final Uri storeUri = Uri.parse(mStoreLink); // your app store listing link
try {
startActivity(new Intent(Intent.ACTION_VIEW, storeUri));
} catch (ActivityNotFoundException e) {
e.printStackTrace();
}
}
You can add handler to openStore() if you want to wait for certain time before go to store page:
Handler mHandler = new Handler();
mHandler.postDelayed(() -> {
openStore();
}, 1000); // wait for 1 second
You can simply write a class and extend from AppRatingDialog. then by overriding onClick method you can do what you want. then by calling super.onClick you'll run the library onClick method.
#Override
public void onClick(View v) {
if (v.getId() == R.id.dialog_rating_button_rate) {
goToPickerActivity();
}
super.onClick(v);
}
As you are able to edit the library code, to match up your requirement, first of all, change appratingdialog library code. Go to AppRatingDialog.java and inside onClick(View v) modify the rating button condition like below:
if (v.getId() == R.id.dialog_rating_button_rate) {
savedNeverShow();
dismiss();
if (onRatingDialogListener != null) {
onRatingDialogListener.onClick();
openPlayStore(); // Just added this extra line here, others are kept in place
} else {
openPlayStore();
}
}
Now, inside your app activity, create custom click listener for rating button using setRateButtonText like below:
AppRatingDialog appRatingDialog = new AppRatingDialog.Builder(MainActivity.this)
.setTriggerCount(3)
.setRepeatCount(4)
.setRateButtonText("Rate Now", clickListener)
.build();
appRatingDialog.show();
Finally, implement the click listener inside your app activity having the PlacePicker intent inside onClick like below:
OnRatingDialogListener clickListener = new OnRatingDialogListener() {
#Override
public void onClick() {
goToPickerActivity();
}
};
You actually seem to have this already answered in your original post.
startActivityForResult(intent, Constants.PLACE_PICKER_REQUEST);
public void goToPickerActivity() {
Intent intent = new com.sucho.placepicker.PlacePicker.IntentBuilder()
.onlyCoordinates(true) //Get only Coordinates from Place Picker
.showLatLong(true)
.setLatLong(40.71274, -74.005974) // Initial Latitude and Longitude the Map will load into (NYC coordinates)
.setMapZoom(2.5f) // Map Zoom Level. Default: 14.0
.build(this);
startActivityForResult(intent, Constants.PLACE_PICKER_REQUEST);
}
So override onActivityResult() from within there you can determine if the activity was successful and then do what you need like below
#Override
protected void onActivityResult(int requestCode, int resultCode, #Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (!(requestCode == 0 && resultCode == RESULT_OK)){
onBackPressed();
}else{
goToPickerActivity()
}
}
Try to update these following dependencies in your build.gradle project level:
classpath 'com.android.tools.build:gradle:3.6.3'
classpath 'com.github.dcendents:android-maven-gradle-plugin:$the_latest_version'
I am trying to make a login into my android app. I have generated the google-services.json with the same package name of the class and copied into the app folder of my application. On attempting to login it shows a dim screeen and thereafter shows a white screen of the the page I am trying to login with.
This is the code snippet from my activity class
// Button click listeners
btnSignIn.setOnClickListener(this);
btnSignOut.setOnClickListener(this);
btnRevokeAccess.setOnClickListener(this);
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this).addApi(Plus.API)
.addScope(Plus.SCOPE_PLUS_LOGIN).build();
Log.e(TAG, "onCreate End!");
}
protected void onStart() {
Log.e(TAG, "onStart!");
super.onStart();
mGoogleApiClient.connect();
Log.e(TAG, "onStart end!");
}
protected void onStop() {
Log.e(TAG, "onStop!");
if (mGoogleApiClient.isConnected()) {
mGoogleApiClient.disconnect();
}
super.onStop();
}
/**
* Method to resolve any signin errors
* */
private void resolveSignInError() {
PendingIntent signInIntent = mConnectionResult.getResolution();
if (signInIntent != null) {
if (mConnectionResult.hasResolution()) {
try {
mIntentInProgress = true;
mConnectionResult.startResolutionForResult(this, RC_SIGN_IN);
} catch (SendIntentException e) {
mIntentInProgress = false;
mGoogleApiClient.connect();
}
}
} else {
showDialog(DIALOG_PLAY_SERVICES_ERROR);
}
}
#Override
protected Dialog onCreateDialog(int id) {
switch(id) {
case DIALOG_PLAY_SERVICES_ERROR:
if (GooglePlayServicesUtil.isUserRecoverableError(mConnectionResult.getErrorCode())) {
return GooglePlayServicesUtil.getErrorDialog(
mConnectionResult.getErrorCode(),
this,
RC_SIGN_IN,
new DialogInterface.OnCancelListener() {
#Override
public void onCancel(DialogInterface dialog) {
Log.e(TAG, "Google Play services resolution cancelled");
}
});
} else {
return new AlertDialog.Builder(this)
.setMessage(R.string.play_services_error)
.setPositiveButton(R.string.close,
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
Log.e(TAG, "Google Play services error could not be "
+ "resolved: " + mConnectionResult.getErrorCode());
}
}).create();
}
default:
return super.onCreateDialog(id);
}
}
#Override
public void onConnectionFailed(ConnectionResult result) {
Log.i(TAG, "onConnectionFailed: ConnectionResult.getErrorCode() = " + result.getErrorCode());
Log.i(TAG, "See error types in http://developer.android.com/reference/com/google/android/gms/common/ConnectionResult.html");
if (!result.hasResolution()) {
GooglePlayServicesUtil.getErrorDialog(result.getErrorCode(), this,
0).show();
return;
}
if (result.getErrorCode() == ConnectionResult.SIGN_IN_REQUIRED) {
Log.i(TAG, "Error type: SIGN_IN_REQUIRED");
}
if (result.getErrorCode() == ConnectionResult.NETWORK_ERROR ) {
Log.i(TAG, "Error type: NETWORK_ERROR ");
}
if (result.getErrorCode() == ConnectionResult.API_UNAVAILABLE) {
// An API requested for GoogleApiClient is not available. The device's current
// configuration might not be supported with the requested API or a required component
// may not be installed, such as the Android Wear application. You may need to use a
// second GoogleApiClient to manage the application's optional APIs.
} else if (!mIntentInProgress) {
Log.i(TAG, "not IntentInProgress!");
// Store the ConnectionResult for later usage
mConnectionResult = result;
if (mSignInClicked) {
Log.i(TAG, "signInAlreadyClicked! Resolving sign error...");
// The user has already clicked 'sign-in' so we attempt to
// resolve all
// errors until the user is signed in, or they cancel.
resolveSignInError();
}
}
Log.i(TAG, "onConnectionFailed end!");
//TODO: Sign OUT?
}
#Override
protected void onActivityResult(int requestCode, int responseCode,
Intent intent) {
if (requestCode == RC_SIGN_IN) {
if (responseCode != RESULT_OK) {
mSignInClicked = false;
}
mIntentInProgress = false;
if (!mGoogleApiClient.isConnecting()) {
mGoogleApiClient.connect();
}
}
}
#Override
public void onConnected(Bundle arg0) {
mSignInClicked = false;
Toast.makeText(this, "User is connected!", Toast.LENGTH_LONG).show();
// Get user's information
getProfileInformation();
// Update the UI after signin
updateUI(true);
}
/**
* Updating the UI, showing/hiding buttons and profile layout
* */
private void updateUI(boolean isSignedIn) {
if (isSignedIn) {
btnSignIn.setVisibility(View.GONE);
btnSignOut.setVisibility(View.VISIBLE);
btnRevokeAccess.setVisibility(View.VISIBLE);
llProfileLayout.setVisibility(View.VISIBLE);
} else {
btnSignIn.setVisibility(View.VISIBLE);
btnSignOut.setVisibility(View.GONE);
btnRevokeAccess.setVisibility(View.GONE);
llProfileLayout.setVisibility(View.GONE);
}
}
/**
* 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);
Log.i(TAG, "Name: " + personName + ", plusProfile: "
+ personGooglePlusProfile + ", email: " + email
+ ", Image: " + personPhotoUrl);
txtName.setText(personName);
txtEmail.setText(email);
// by default the profile url gives 50x50 px image only
// we can replace the value with whatever dimension we want by
// replacing sz=X
personPhotoUrl = personPhotoUrl.substring(0,
personPhotoUrl.length() - 2)
+ PROFILE_PIC_SIZE;
new LoadProfileImage(imgProfilePic).execute(personPhotoUrl);
} else {
Toast.makeText(getApplicationContext(),
"Person information is null", Toast.LENGTH_LONG).show();
}
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
public void onConnectionSuspended(int arg0) {
mGoogleApiClient.connect();
updateUI(false);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
/**
* Button on click listener
* */
#Override
public void onClick(View v) {
if (!mGoogleApiClient.isConnecting()) {
switch (v.getId()) {
case R.id.btn_sign_in:
// Signin button clicked
signInWithGplus();
break;
case R.id.btn_sign_out:
// Signout button clicked
signOutFromGplus();
break;
case R.id.btn_revoke_access:
// Revoke access button clicked
revokeGplusAccess();
break;
}
}
}
/**
* Sign-in into google
* */
private void signInWithGplus() {
if (!mGoogleApiClient.isConnecting()) {
// We only process button clicks when GoogleApiClient is not transitioning
// between connected and not connected.
mSignInClicked = true;
resolveSignInError();
}
}
/**
* Sign-out from google
* */
private void signOutFromGplus() {
if (mGoogleApiClient.isConnected()) {
Plus.AccountApi.clearDefaultAccount(mGoogleApiClient);
mGoogleApiClient.disconnect();
mGoogleApiClient.connect();
updateUI(false);
}
}
/**
* Revoking access from google
* */
private void revokeGplusAccess() {
if (mGoogleApiClient.isConnected()) {
Plus.AccountApi.clearDefaultAccount(mGoogleApiClient);
Plus.AccountApi.revokeAccessAndDisconnect(mGoogleApiClient)
.setResultCallback(new ResultCallback<Status>() {
#Override
public void onResult(Status arg0) {
Log.e(TAG, "User access revoked!");
mGoogleApiClient.disconnect();
mGoogleApiClient.connect();
updateUI(false);
}
});
}
}
/**
* Background Async task to load user profile picture from url
* */
private class LoadProfileImage extends AsyncTask<String, Void, Bitmap> {
ImageView bmImage;
public LoadProfileImage(ImageView bmImage) {
this.bmImage = bmImage;
}
protected Bitmap doInBackground(String... urls) {
String urldisplay = urls[0];
Bitmap mIcon11 = null;
try {
InputStream in = new java.net.URL(urldisplay).openStream();
mIcon11 = BitmapFactory.decodeStream(in);
} catch (Exception e) {
Log.e(TAG, e.getMessage());
e.printStackTrace();
}
return mIcon11;
}
protected void onPostExecute(Bitmap result) {
bmImage.setImageBitmap(result);
}
}
this is the login button from my page xml file calling the login function to authenticate with google plus
<com.google.android.gms.common.SignInButton
android:id="#+id/btn_sign_in"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="20dp"/>
Please why is my app not authenticating with google plus sign. Please assist
I'm trying to implment in app puchase/billing in my app so when the user buys the item i remove the ads. I have and example code that is working with SKU = "android.test.purchased". Now my question is how can I link the app to my items - I have uploaded new apk with billing enabled, created and published the item one hour ago, but when I try to buy the item I get this:
here is my code:
public class RemoveAds extends AthanBaseActivity implements OnClickListener {
private static final String TAG = "inappbilling";
IabHelper mHelper;
//ID from playstore 16xxxx15_removeads.
//android.test.purchased
static final String ITEM_SKU = "com.myapppackage.16xxxx15_removeads.";
#Override
protected void onCreate(Bundle arg0) {
super.onCreate(arg0);
setContentView(R.layout.remove_ads);
findViewById( R.id.remove_ads_).setOnClickListener(this);
setupInAppPurchase();
}
public void consumeItem() {
mHelper.queryInventoryAsync(mReceivedInventoryListener);
}
IabHelper.QueryInventoryFinishedListener mReceivedInventoryListener = new IabHelper.QueryInventoryFinishedListener() {
public void onQueryInventoryFinished(IabResult result,
Inventory inventory) {
if (result.isFailure()) {
// Handle failure
} else {
mHelper.consumeAsync(inventory.getPurchase(ITEM_SKU),
mConsumeFinishedListener);
}
}
};
#Override
public void onDestroy() {
super.onDestroy();
if (mHelper != null)
mHelper.dispose();
mHelper = null;
}
IabHelper.OnConsumeFinishedListener mConsumeFinishedListener = new IabHelper.OnConsumeFinishedListener() {
public void onConsumeFinished(Purchase purchase, IabResult result) {
if (result.isSuccess()) {
Toast.makeText(RemoveAds.this, "SUCCESS", Toast.LENGTH_LONG)
.show();
} else {
Toast.makeText(RemoveAds.this, "ERROR purchase",
Toast.LENGTH_LONG).show();
// handle error
}
}
};
IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener = new IabHelper.OnIabPurchaseFinishedListener() {
public void onIabPurchaseFinished(IabResult result, Purchase purchase) {
if (result.isFailure()) {
// Handle error
return;
} else if (purchase.getSku().equals(ITEM_SKU)) {
consumeItem();
// buyButton.setEnabled(false);
}
}
};
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (!mHelper.handleActivityResult(requestCode, resultCode, data)) {
super.onActivityResult(requestCode, resultCode, data);
}
}
private void setupInAppPurchase() {
String base64EncodedPublicKey = "MIIBIjANBgkqhkcccxxxxxdomr somelongstringdfsdfsdfsfsdofksdofkdsMXz0R4EJuw7YZkQ8jMPemymSbQGtLllH+fu85hfQIDAQAB";
mHelper = new IabHelper(this, base64EncodedPublicKey);
mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
public void onIabSetupFinished(IabResult result) {
if (!result.isSuccess()) {
Log.d(TAG, "In-app Billing setup failed: " + result);
} else {
Log.d(TAG, "In-app Billing is set up OK");
}
}
});
}
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.remove_ads_:
mHelper.launchPurchaseFlow(this, ITEM_SKU, 10001,
mPurchaseFinishedListener, "mypurchasetoken");
break;
}
}
}
You cannot make purchases if the primary account on your real android device is same as your developer account.
I am trying to give my users the option to sign in with either Google or Facebook. So far I found an example to implement a Google Sign in Flow, but I am confused if I can implement a similar Facebook Login Flow within the same Activity.
Anyone have an Idea as to handle the Logins? I was thinking about potentially defining a class to handle the Login Flows for both Google / Facebook, and perhaps just check to see which is being used when the app launches. Any Ideas?
public class MainActivity extends Activity implements ConnectionCallbacks,
OnConnectionFailedListener, OnClickListener, OnAccessRevokedListener {
private static final String TAG = "MainActivity";
// A magic number we will use to know that our sign-in error
// resolution activity has completed.
private static final int OUR_REQUEST_CODE = 49404;
// The core Google+ client.
private PlusClient mPlusClient;
// A flag to stop multiple dialogues appearing for the user.
private boolean mResolveOnFail;
// We can store the connection result from a failed connect()
// attempt in order to make the application feel a bit more
// responsive for the user.
private ConnectionResult mConnectionResult;
// A progress dialog to display when the user is connecting in
// case there is a delay in any of the dialogs being ready.
private ProgressDialog mConnectionProgressDialog;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
// We pass through this for all three arguments, specifying the:
// 1. Context
// 2. Object to call onConnected and onDisconnected on
// 3. Object to call onConnectionFailed on
mPlusClient = new PlusClient.Builder(this, this, this)
.setVisibleActivities("http://schemas.google.com/BuyActivity")
.build();
// We use mResolveOnFail as a flag to say whether we should trigger
// the resolution of a connectionFailed ConnectionResult.
mResolveOnFail = false;
// Connect our sign in, sign out and disconnect buttons.
findViewById(R.id.sign_in_button).setOnClickListener(this);
findViewById(R.id.sign_out_button).setOnClickListener(this);
findViewById(R.id.sign_out_button).setVisibility(View.GONE);
findViewById(R.id.authButton).setOnClickListener(this);
// Configure the ProgressDialog that will be shown if there is a
// delay in presenting the user with the next sign in step.
mConnectionProgressDialog = new ProgressDialog(this);
mConnectionProgressDialog.setMessage("Signing in...");
}
#Override
protected void onStart() {
super.onStart();
Log.v(TAG, "Start");
// Every time we start we want to try to connect. If it
// succeeds we'll get an onConnected() callback. If it
// fails we'll get onConnectionFailed(), with a result!
mPlusClient.connect();
}
#Override
protected void onStop() {
super.onStop();
Log.v(TAG, "Stop");
// It can be a little costly to keep the connection open
// to Google Play Services, so each time our activity is
// stopped we should disconnect.
mPlusClient.disconnect();
}
#Override
public void onConnectionFailed(ConnectionResult result) {
Log.v(TAG, "ConnectionFailed");
// Most of the time, the connection will fail with a
// user resolvable result. We can store that in our
// mConnectionResult property ready for to be used
// when the user clicks the sign-in button.
if (result.hasResolution()) {
mConnectionResult = result;
if (mResolveOnFail) {
// This is a local helper function that starts
// the resolution of the problem, which may be
// showing the user an account chooser or similar.
startResolution();
}
}
}
#Override
public void onConnected(Bundle bundle) {
// Yay! We can get the oAuth 2.0 access token we are using.
Log.v(TAG, "Connected. Yay!");
// Turn off the flag, so if the user signs out they'll have to
// tap to sign in again.
mResolveOnFail = false;
// Hide the progress dialog if its showing.
mConnectionProgressDialog.dismiss();
// Hide the sign in button, show the sign out buttons.
findViewById(R.id.sign_in_button).setVisibility(View.GONE);
findViewById(R.id.sign_out_button).setVisibility(View.VISIBLE);
// Retrieve the oAuth 2.0 access token.
final Context context = this.getApplicationContext();
AsyncTask task = new AsyncTask() {
#Override
protected Object doInBackground(Object... params) {
String scope = "oauth2:" + Scopes.PLUS_LOGIN;
try {
// We can retrieve the token to check via
// tokeninfo or to pass to a service-side
// application.
String token = GoogleAuthUtil.getToken(context,
mPlusClient.getAccountName(), scope);
} catch (UserRecoverableAuthException e) {
// This error is recoverable, so we could fix this
// by displaying the intent to the user.
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (GoogleAuthException e) {
e.printStackTrace();
}
return null;
}
};
task.execute((Void) null);
// THIS IS TO CONNECT TO NAVI ACTIVITY AFTER YOU CONNECT Also makes it
// so you cannot go back to main activity
/*
* if (mPlusClient.isConnected()) { Intent intent = new Intent(this,
* NaviActivity.class); startActivity(intent); } finish();
*/
}
#Override
public void onDisconnected() {
// Bye!
Log.v(TAG, "Disconnected. Bye!");
}
protected void onActivityResult(int requestCode, int responseCode,
Intent intent) {
Log.v(TAG, "ActivityResult: " + requestCode);
if (requestCode == OUR_REQUEST_CODE && responseCode == RESULT_OK) {
// If we have a successful result, we will want to be able to
// resolve any further errors, so turn on resolution with our
// flag.
mResolveOnFail = true;
// If we have a successful result, lets call connect() again. If
// there are any more errors to resolve we'll get our
// onConnectionFailed, but if not, we'll get onConnected.
mPlusClient.connect();
} else if (requestCode == OUR_REQUEST_CODE && responseCode != RESULT_OK) {
// If we've got an error we can't resolve, we're no
// longer in the midst of signing in, so we can stop
// the progress spinner.
mConnectionProgressDialog.dismiss();
}
}
#Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.sign_in_button:
Log.v(TAG, "Tapped sign in");
if (!mPlusClient.isConnected()) {
// Show the dialog as we are now signing in.
mConnectionProgressDialog.show();
// Make sure that we will start the resolution (e.g. fire the
// intent and pop up a dialog for the user) for any errors
// that come in.
mResolveOnFail = true;
// We should always have a connection result ready to resolve,
// so we can start that process.
if (mConnectionResult != null) {
startResolution();
} else {
// If we don't have one though, we can start connect in
// order to retrieve one.
mPlusClient.connect();
}
}
break;
case R.id.sign_out_button:
Log.v(TAG, "Tapped sign out");
// We only want to sign out if we're connected.
if (mPlusClient.isConnected()) {
// Clear the default account in order to allow the user
// to potentially choose a different account from the
// account chooser.
mPlusClient.clearDefaultAccount();
// Disconnect from Google Play Services, then reconnect in
// order to restart the process from scratch.
mPlusClient.disconnect();
mPlusClient.connect();
// Hide the sign out buttons, show the sign in button.
findViewById(R.id.sign_in_button).setVisibility(View.VISIBLE);
findViewById(R.id.sign_out_button).setVisibility(View.GONE);
}
break;
// THIS SHOULD NOT BE NEEDED, MUST SWITCH ACTIVITIES UPON AUTHORIZATION
case R.id.authButton:
Log.v(TAG, "Switch Activities");
if (mPlusClient.isConnected()) {
Intent intent = new Intent(view.getContext(),
NaviActivity.class);
view.getContext().startActivity(intent);
}
break;
default:
// Unknown id.
}
}
#Override
public void onAccessRevoked(ConnectionResult status) {
// mPlusClient is now disconnected and access has been revoked.
// We should now delete any data we need to comply with the
// developer properties. To reset ourselves to the original state,
// we should now connect again. We don't have to disconnect as that
// happens as part of the call.
mPlusClient.connect();
// Hide the sign out buttons, show the sign in button.
findViewById(R.id.sign_in_button).setVisibility(View.VISIBLE);
findViewById(R.id.sign_out_button).setVisibility(View.GONE);
}
/**
* A helper method to flip the mResolveOnFail flag and start the resolution
* of the ConnenctionResult from the failed connect() call.
*/
private void startResolution() {
try {
// Don't start another resolution now until we have a
// result from the activity we're about to start.
mResolveOnFail = false;
// If we can resolve the error, then call start resolution
// and pass it an integer tag we can use to track. This means
// that when we get the onActivityResult callback we'll know
// its from being started here.
mConnectionResult.startResolutionForResult(this, OUR_REQUEST_CODE);
} catch (SendIntentException e) {
// Any problems, just try to connect() again so we get a new
// ConnectionResult.
mPlusClient.connect();
}
}
}
set both fragments (facebook and google) in the layout that you use as login and in another to receive the session validated
<com.facebook.widget.LoginButton
android:id="#+id/authButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="30dp" />
<com.google.android.gms.common.SignInButton
android:id="#+id/sign_in_button"
android:layout_below="#id/authButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
then use al functions required by each one
public class MainActivity extends Activity implements ConnectionCallbacks,OnConnectionFailedListener {
//google
private PlusClient plusClient;
private SignInButton btnSignIn;
private ProgressDialog connectionProgressDialog;
private ConnectionResult connectionResult;
private static final int REQUEST_CODE_RESOLVE_ERR = 9000;
//face
private LoginButton buttonLoginLogout;
private UiLifecycleHelper uiHelper;
static Usuario appusuario;
static String urldelogin="algo";
private Session.StatusCallback callback = new Session.StatusCallback() {
#Override
public void call(Session session, SessionState state, Exception exception) {
onSessionStateChange(session, state, exception);
if (session.isOpened()) {
Log.e("usuario", "si hay sesion");
// make request to the /me API
Request.newMeRequest(session, new Request.GraphUserCallback() {
// callback after Graph API response with user object
#Override
public void onCompleted(GraphUser user, Response response) {
if (user != null) {
Log.e("usuario", "si hay usuario");
buildUserInfoDisplay(user);
//start another activity
}
}
}).executeAsync();
}
}
private void onSessionStateChange(Session session, SessionState state,
Exception exception) {
// TODO Auto-generated method stub
}
};
#Override
public void onResume() {
super.onResume();
uiHelper.onResume();
}
#Override
public void onPause() {
super.onPause();
uiHelper.onPause();
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
uiHelper.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_CODE_RESOLVE_ERR &&
resultCode == RESULT_OK)
{
connectionResult = null;
plusClient.connect();
}
}
#Override
public void onDestroy() {
super.onDestroy();
uiHelper.onDestroy();
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
uiHelper.onSaveInstanceState(outState);
}
public static void buildUserInfoDisplay(GraphUser user) {
appusuario=new Usuario(user.getName(),user.getUsername());
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
uiHelper = new UiLifecycleHelper(this, callback);
uiHelper.onCreate(savedInstanceState);
buttonLoginLogout = (LoginButton)findViewById(R.id.authButton);
buttonLoginLogout.setReadPermissions(Arrays.asList("user_status"));
btnSignIn = (SignInButton)findViewById(R.id.sign_in_button);
buttonLoginLogout.setVisibility(View.VISIBLE);
btnSignIn.setVisibility(View.VISIBLE);
plusClient = new PlusClient.Builder(this, this, this).setActions("http://schemas.google.com/AddActivity", "http://schemas.google.com/BuyActivity")
.build();
connectionProgressDialog = new ProgressDialog(this);
connectionProgressDialog.setMessage("Conectando...");
btnSignIn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View view)
{
if (!plusClient.isConnected())
{
if (connectionResult == null)
{
connectionProgressDialog.show();
}
else
{
try
{
connectionResult.startResolutionForResult(
MainActivity.this,
REQUEST_CODE_RESOLVE_ERR);
}
catch (SendIntentException e)
{
connectionResult = null;
plusClient.connect();
}
}
}
}
});
}
#Override
protected void onStart()
{
super.onStart();
plusClient.connect();
}
#Override
protected void onStop()
{
super.onStop();
plusClient.disconnect();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
#Override
public void onConnected(Bundle connectionHint)
{
connectionProgressDialog.dismiss();
//nombre
String accountName = plusClient.getAccountName();
//cuenta con mail
Person accountperson=plusClient.getCurrentPerson();
String personName = accountperson.getDisplayName();
Log.e("Google +", "Conectado");
//start another activity
}
#Override
public void onDisconnected()
{
Log.e("Google +", "Desconectado");
}
#Override
public void onConnectionFailed(ConnectionResult result) {
// TODO Auto-generated method stub
if (connectionProgressDialog.isShowing())
{
if (result.hasResolution())
{
try
{
result.startResolutionForResult(this,
REQUEST_CODE_RESOLVE_ERR);
}
catch (SendIntentException e)
{
plusClient.connect();
}
}
}
connectionResult = result;
}
}
in the new activity place the same functions to validate the sesion and use
if (session.isOpened()) { }
to hide google login button or
public void onConnected(Bundle connectionHint)
{
}
to hide facebook login button
I have this code.. The only working here is the Login... I want to achieve the Publish to wall or feed dialog.. I have here the code for the wall post but It still not working.. Any help will be appreciated... I followed this link for my Login
[a link] http://www.kpbird.com/2013/03/android-login-using-facebook-sdk-30.html
I am trying to embed the post status in this Login..
public class FacebookActivity extends FragmentActivity {
private Button publishButton;
private String TAG = "FacebookActivity";
private TextView lblEmail;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.facebook_activity);
lblEmail = (TextView) findViewById(R.id.lblEmail);
LoginButton authButton = (LoginButton) findViewById(R.id.authButton);
authButton.setOnErrorListener(new OnErrorListener(){
#Override
public void onError(FacebookException error) {
Log.i(TAG, "Error " + error.getMessage());
}
// TODO Auto-generated method stub
});
// set permission list, Don't forget to add email
authButton.setReadPermissions(Arrays.asList("basic_info","email"));
// session state call back event
authButton.setSessionStatusCallback(new Session.StatusCallback() {
#Override
public void call(Session session, SessionState state, Exception exception) {
if (session.isOpened()) {
Log.i(TAG,"Access Token"+ session.getAccessToken());
Request.executeMeRequestAsync(session,
new Request.GraphUserCallback() {
#Override
public void onCompleted(GraphUser user,Response response) {
if (user != null) {
Log.i(TAG,"User ID "+ user.getId());
Log.i(TAG,"Email "+ user.asMap().get("email"));
lblEmail.setText(user.asMap().get("email").toString());
}
}
});
publishButton.setVisibility(View.VISIBLE);
}
else if (state.isClosed()) {
publishButton.setVisibility(View.INVISIBLE);
}
}
});
publishButton = (Button) findViewById(R.id.publishButton);
publishButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
publishFeedDialog();
}
});
}
private void publishFeedDialog() {
Bundle params = new Bundle();
params.putString("name", "Facebook SDK for Android");
params.putString("caption", "Build great social apps and get more installs.");
params.putString("description", "The Facebook SDK for Android makes it easier and faster to develop Facebook integrated Android apps.");
params.putString("link", "https://developers.facebook.com/android");
params.putString("picture", "https://raw.github.com/fbsamples/ios-3.x-howtos/master/Images/iossdk_logo.png");
WebDialog feedDialog = (
new WebDialog.FeedDialogBuilder(getActivity(),
Session.getActiveSession(),
params))
.setOnCompleteListener(new OnCompleteListener() {
#Override
public void onComplete(Bundle values,
FacebookException error) {
if (error == null) {
// When the story is posted, echo the success
// and the post Id.
final String postId = values.getString("post_id");
if (postId != null) {
Toast.makeText(getActivity(),
"Posted story, id: "+postId,
Toast.LENGTH_SHORT).show();
} else {
// User clicked the Cancel button
Toast.makeText(getActivity().getApplicationContext(),
"Publish cancelled",
Toast.LENGTH_SHORT).show();
}
} else if (error instanceof FacebookOperationCanceledException) {
// User clicked the "x" button
Toast.makeText(getActivity().getApplicationContext(),
"Publish cancelled",
Toast.LENGTH_SHORT).show();
} else {
// Generic, ex: network error
Toast.makeText(getActivity().getApplicationContext(),
"Error posting story",
Toast.LENGTH_SHORT).show();
}
}
})
.build();
feedDialog.show();
}
protected ContextWrapper getActivity() {
// TODO Auto-generated method stub
return null;
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
Session.getActiveSession().onActivityResult(this, requestCode, resultCode, data);
}
}