Android IAB - Activity destroyed after successful purchase - android

I am pulling my hair out! At one point in the last week, I had this working.
I have an Android app that I am trying to add in-ap billing to. I followed the sample TrivialDrive, and my code worked a few times. Now it doesn't.
I am creating a simple trivia game that has a number of free questions, and the option to upgrade to get more questions. When the user completes the list of free questions, they are taken to a "Game Over" screen where they can erase their answers and start again, or upgrade.
When I click the "Upgrade" button, I can make a successful purchase, but as soon as the Google "Payment Successful" dialog goes away, my activity is destroyed and I am sent back to my main activity.
When I try to go back and do my purchase again, my code catches the error ("You already own this item") and handles it appropriately. My code explains to the user that they already own the upgrade, and allows them to click a button to continue playing. So it looks like the OnIabPurchaseFinishedListener is firing at this point.
I have updated the Google helper code with the latest files.
Any help or suggestions as to where to look for answers is much appreciated.
Thanks.
This is the relevant code for my activity:
public class GameOverActivity extends BaseActivity
{
private IabHelper mHelper;
private String m_base64EncodedPublicKey;
private static String THE_UPGRADE_SKU = "upgrade52";
public static int BILLING_RESPONSE_RESULT_ITEM_ALREADY_OWNED = 7;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_game_over);
setTitle("Game Over");
Button butPlay = (Button) findViewById(R.id.buttonPlay);
butPlay.setVisibility(View.INVISIBLE);
PrepareIAB();
}
#Override
protected void onResume()
{
super.onResume();
CURRENT_ACTIVITY = ACTIVITY_GAME_OVER;
SetMainText();
}
#Override
protected void onDestroy()
{
super.onDestroy();
try
{
if (mHelper != null)
{
mHelper.dispose();
mHelper = null;
}
}
catch (Exception e)
{
}
}
private void PrepareIAB()
{
m_base64EncodedPublicKey = "MyKey";
// compute your public key and store it in base64EncodedPublicKey
mHelper = new IabHelper(this, m_base64EncodedPublicKey);
mHelper.enableDebugLogging( true, TAG);
mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener()
{
public void onIabSetupFinished(IabResult result)
{
if (!result.isSuccess())
{
ShowMessage("There was an error connecting to the Google Play Store.");
}
}
});
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
try
{
// Pass on the activity result to the helper for handling
if (!mHelper.handleActivityResult(requestCode, resultCode, data))
{
// not handled, so handle it ourselves (here's where you'd
// perform any handling of activity results not related to in-app
// billing...
super.onActivityResult(requestCode, resultCode, data);
}
else
{
// Log.d(TAG, "onActivityResult handled by IABUtil.");
}
}
catch (Exception e)
{
super.onActivityResult(requestCode, resultCode, data);
}
}
IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener =
new IabHelper.OnIabPurchaseFinishedListener()
{
public void onIabPurchaseFinished(IabResult result, Purchase purchase)
{
try
{
if (result.isFailure())
{
if (result.mResponse==7)
{
UpgradeComplete();
ShowMessage("Thank you for upgrading.\r\n\r\nThis version has 400 more questions.");
}
else
{
ShowMessage("Error purchasing: " + String.valueOf(result.mResponse));
UpgradeError();
return;
}
}
else if (purchase.getSku().equals(THE_UPGRADE_SKU))
{
UpgradeComplete();
ShowMessage("Thank you for upgrading.\r\n\r\nThis version has 400 more questions.");
}
else
{
ShowMessage("Something else happened. ");
}
}
catch (Exception e)
{
Log.e(TAG, e.getLocalizedMessage());
}
}
};
private void HideUpgrade()
{
try
{
Button btnUpgrade = (Button) findViewById(R.id.buttonUpgrade);
if (btnUpgrade != null)
{
btnUpgrade.setVisibility(View.INVISIBLE);
}
TextView txtMessage = (TextView) findViewById(R.id.txtUpgradeFromGameOver);
if (txtMessage!=null)
{
txtMessage.setVisibility(View.INVISIBLE);
}
}
catch (Exception e)
{
}
}
public void onQuitButtonClick(View view)
{
finish();
}
public void onResetDBButtonClick(View view)
{
ConfirmResetDatabase();
}
private void ConfirmResetDatabase()
{
DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener()
{
#Override
public void onClick(DialogInterface dialog, int which)
{
switch (which)
{
case DialogInterface.BUTTON_POSITIVE:
ResetDatabase();
Intent gameActivity = new Intent(getApplicationContext(), GameActivity.class);
gameActivity.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
// startActivityForResult(gameActivity, ACTIVITY_GAME);
startActivity(gameActivity);
break;
case DialogInterface.BUTTON_NEGATIVE:
// No button clicked
break;
}
}
};
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage("Do you want to erase your score and start over?").setPositiveButton("Yes", dialogClickListener).setNegativeButton("No", dialogClickListener).show();
}
public void onUpgradeButtonClick(View view)
{
try
{
if (mHelper != null)
{
mHelper.launchPurchaseFlow(this, THE_UPGRADE_SKU, 10001, mPurchaseFinishedListener, m_TriviaAppInstance.AppInstallID());
}
else
{
ShowMessage("Unable to connect to Google Play Store.");
}
}
catch (Exception e)
{
ShowMessage("Unable to connect to Google Play Store.");
SendErrorMessage(e.getLocalizedMessage());
}
}
private void UpgradeComplete()
{
try
{
HideUpgrade();
Button butPlay = (Button) findViewById(R.id.buttonPlay);
if (butPlay!=null)
{
butPlay.setVisibility(View.VISIBLE);
}
TextView txtReset = (TextView) findViewById(R.id.txtGameOverRestDB);
if (txtReset!=null)
{
txtReset.setVisibility(View.INVISIBLE);
}
Button btnReset = (Button)findViewById(R.id.buttonResetDB);
if (btnReset!=null)
{
btnReset.setVisibility(View.INVISIBLE);
}
m_TriviaAppInstance.SetUpgradedStatus(true);
}
catch (Exception e)
{
}
//
}
private void UpgradeError()
{
try
{
Button butUpgrade;
butUpgrade = (Button) findViewById(R.id.buttonUpgrade);
butUpgrade.setVisibility(View.INVISIBLE);
TextView txtMessage = (TextView) findViewById(R.id.txtUpgradeScreen);
txtMessage.setText(R.string.upgradeScreenTextError);
}
catch (Exception e)
{
}
}
public void onPlayButtonClick(View view)
{
Intent myIntent = new Intent(view.getContext(), GameActivity.class);
myIntent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
startActivityForResult(myIntent, ACTIVITY_GAME);
}
public void SetMainText()
{
TextView txt = (TextView) findViewById(R.id.txtScoreGlobal);
txt.setText(Integer.toString(m_TriviaAppInstance.getGlobal()) + "%");
SetPlayerScore(1);
if (m_TriviaAppInstance.getUpgradedStatus() == true)
{
HideUpgrade();
}
}
}

FYI: I think I have this figured out - for anyone else that may come across it.
The activity that I was using to launch "In App Billing" was called with a "FLAG_ACTIVITY_NO_HISTORY". I did this because I didn't want the user to be able to click to go back to this "Game Over" activity.
BUT, this causes grief with "In App Billing". So, make sure you don't try to launch "In App Billing" from an activity that has had the "FLAG_ACTIVITY_NO_HISTORY" set.
My original code:
private void GameOver()
{
m_TriviaAppInstance.setGameOver(true);
Intent gameOver = new Intent(getApplicationContext(), GameOverActivity.class);
gameOver.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
startActivity(gameOver);
}
Updated code:
private void GameOver()
{
m_TriviaAppInstance.setGameOver(true);
Intent gameOver = new Intent(getApplicationContext(), GameOverActivity.class);
startActivity(gameOver);
}
Peace

I'm not high enough to comment, but bless you. I had
android:noHistory="true"
set in AndroidManifest.xml for my activity and was experiencing the same problem.
Took it out and IAB is working. Yay!

Do not forget that your IabHelper.OnIabPurchaseFinishedListener is called on a different thread and before onResume() is called on your Activity!
So your UpgradeComplete() or UpgradeError() can cause a crash on older devices (Crashed every time on my Gingerbread Sony Xperia Mini Pro and worked without any trouble on Samsung Galaxy S4 (Android 4.2.2)
Caused a 3 day delay on my game..

Related

Cannot send sms verification code using with the SMS User Consent API on android

I am trying to make a phone number verification on android studio using java. I followed the instructions from the documentation here https://developers.google.com/identity/sms-retriever/user-consent/overview but sadly it isn't sending me an SMS code, and I am not getting any error. Below is my code:
public class OTPSMSActivity extends AppCompatActivity {
private ImageView blur;
private TextView resend;
private CustomEditText editText;
private FirebaseFirestore db = FirebaseFirestore.getInstance();
private KProgressHUD loadingBar;
private static final int SMS_CONSENT_REQUEST = 2;
// Set to an unused request code
private final BroadcastReceiver smsVerificationReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if (SmsRetriever.SMS_RETRIEVED_ACTION.equals(intent.getAction())) {
Bundle extras = intent.getExtras();
Status smsRetrieverStatus = (Status) extras.get(SmsRetriever.EXTRA_STATUS);
switch (smsRetrieverStatus.getStatusCode()) {
case CommonStatusCodes.SUCCESS:
// Get consent intent
Intent consentIntent = extras.getParcelable(SmsRetriever.EXTRA_CONSENT_INTENT);
try {
/*Start activity to show consent dialog to user within
*5 minutes, otherwise you'll receive another TIMEOUT intent
*/
startActivityForResult(consentIntent, SMS_CONSENT_REQUEST);
Log.d("life", "Intent to send image");
} catch (ActivityNotFoundException e) {
Log.e("life", "Exception: " + e.toString());
}
break;
case CommonStatusCodes.TIMEOUT:
Log.d("life", "Timeout!");
break;
}
} else {
Log.d("life", "SmsRetriever don't matched");
}
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_otpsms);
blur = findViewById(R.id.blur);
editText = findViewById(R.id.number);
Button verify = findViewById(R.id.verify);
TextView change = findViewById(R.id.textView42);
resend = findViewById(R.id.resend);
Paper.init(this);
getBackgroundImage();
change.setOnClickListener(view -> {
finish();
});
String phoneNumber = getIntent().getStringExtra("phone");
loadingBar = KProgressHUD.create(OTPSMSActivity.this)
.setStyle(KProgressHUD.Style.SPIN_INDETERMINATE)
.setLabel("Please wait")
.setDetailsLabel("Sending sms code to your phone number.")
.setCancellable(true)
.setAnimationSpeed(2)
.setDimAmount(0.5f)
.show();
verify.setOnClickListener(view -> {
loadingBar = KProgressHUD.create(OTPSMSActivity.this)
.setStyle(KProgressHUD.Style.SPIN_INDETERMINATE)
.setLabel("Loading")
.setDetailsLabel("Verifying code")
.setCancellable(true)
.setAnimationSpeed(2)
.setDimAmount(0.5f)
.show();
String theCode = editText.getText().toString();
if (theCode.length() != 6){
new StyleableToast
.Builder(OTPSMSActivity.this)
.text("Invalid code.")
.iconStart(R.drawable.error)
.textColor(Color.WHITE)
.backgroundColor(getResources().getColor(R.color.error))
.show();
editText.setError("Invalid phone number.");
editText.requestFocus();
loadingBar.dismiss();
return;
}
verifyCode(theCode);
});
resend.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
}
});
String phone = "+63" + phoneNumber.substring(1);
Log.d("life", phone);
Task<Void> task = SmsRetriever.getClient(this).startSmsUserConsent(phone);
task.addOnCompleteListener(listener -> {
if (listener.isSuccessful()) {
Log.d("life", "Success");
loadingBar.dismiss();
IntentFilter intentFilter = new IntentFilter(SmsRetriever.SMS_RETRIEVED_ACTION);
registerReceiver(smsVerificationReceiver, intentFilter);
} else {
Exception exception = listener.getException();
exception.printStackTrace();
}
});
}
private void verifyCode(String code) {
if (code.equals(editText.getText().toString())) {
String phoneNumber = getIntent().getStringExtra("phone");
String userID = Paper.book().read("userID");
loadingBar.setDetailsLabel("Uploading number to database");
db.collection("Buyers").document(userID)
.update("phone", "+63" + phoneNumber.substring(1))
.addOnCompleteListener(task11 -> {
if (task11.isSuccessful()){
loadingBar.dismiss();
StyleableToast.makeText(OTPSMSActivity.this, "Success! Phone number updated.", Toast.LENGTH_LONG, R.style.successtoast).show();
finish();
}
});
} else {
new StyleableToast
.Builder(OTPSMSActivity.this)
.text("Code does not matched.")
.iconStart(R.drawable.error)
.textColor(Color.WHITE)
.backgroundColor(getResources().getColor(R.color.error))
.show();
loadingBar.dismiss();
}
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == SMS_CONSENT_REQUEST) {
if (resultCode == RESULT_OK) {
// Get SMS message content
String message = data.getStringExtra(SmsRetriever.EXTRA_SMS_MESSAGE);
// Extract one-time code from the message and complete verification
String oneTimeCode = parseOneTimeCode(message);
Log.d("life", "oneTimeCode: " + oneTimeCode);
//for this demo we will display it instead
editText.setText(oneTimeCode);
} else {
Log.d("life", "Error2");
}
} else {
Log.d("life", "Error1");
}
}
private String parseOneTimeCode(String message) {
//simple number extractor
return message.replaceAll("[^0-9]", "");
}
#Override
protected void onDestroy() {
super.onDestroy();
//to prevent IntentReceiver leakage unregister
unregisterReceiver(smsVerificationReceiver);
}
I want to know what am I doing wrong here.
Calling this API won't be sending you an SMS. This API listens to the SMS that you will receive on your device, ask for your permission and then retrieve it.
You should not wait for the task to complete. It is there to listen to the SMS you receive. So the first thing that you need to correct in your onCreate function:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_otpsms);
...
Task<Void> task = SmsRetriever.getClient(this).startSmsUserConsent(null);
IntentFilter intentFilter = new IntentFilter(SmsRetriever.SMS_RETRIEVED_ACTION);
registerReceiver(smsVerificationReceiver, intentFilter);
...
}
The phone number you are passing to SmsRetriever.getClient(this).startSmsUserConsent is the phone number of the sender. So if you know which number will send you an SMS, then pass it to this function. But if you don't know the number of the sender, keep it null.
And note that the sender phone number should not be in the phone's contacts list as mentioned in the documentation: https://developers.google.com/identity/sms-retriever/choose-an-api
So first call create this task instruction above, have it wait for your sms and then request an SMS. You could use third party platforms to send SMS messages. To test that you can send an SMS using your emulator to the emulator device.

How can I solve this race condition involving PlacePicker?

I have a race condition between the PlacePicker activity and my own activity that I want to start immediately after PlacePicker ends.
Here is how my app works:
It begins in PlaceActivity. In PlaceActivity's onStart, I connect to the GoogleAPI. In onConnected, I use Places to determine the user's location. If the location has a probability of less than .8, it invokes the PlacePicker (which is it's own activity). The Placepicker is created with startActivityForResult. Within the corresponding onActivityResult, RatingsActivity is started and is passed the place from the PlacePicker. The problem is that there is a race between PlaceActivity restarting after PlacePicker stops, and the start of RatingsActivity. How do I fix this? I know I could require the user to press another button to find their location, but I would much rather it happen automatically in onStart.
#Override
public void onStart() {
super.onStart();
mGoogleApiClient.connect();
}
#Override
public void onConnected(Bundle bundle) {
detectCurrentPlace();
}
public void detectCurrentPlace() {
PendingResult<PlaceLikelihoodBuffer> result = Places.PlaceDetectionApi.getCurrentPlace(mGoogleApiClient, null);
//Find the most probable place
//If prob is greater than threshold, assume this is the correct place.
//Otherwise, open placepicker
final double thresh = .8;
//intent.putExtra("com.parse.starter.name", mostProbPlace.getName());
//intent.putExtra("com.parse.starter.address", mostProbPlace.getAddress());
result.setResultCallback(new ResultCallback<PlaceLikelihoodBuffer>() {
#Override
public void onResult(PlaceLikelihoodBuffer placeLikelihoods) {
double highestProb = 0;
PlaceLikelihood mostProbPlace = null;
for(PlaceLikelihood p : placeLikelihoods) {
if(p.getLikelihood() > highestProb) {
highestProb = p.getLikelihood();
mostProbPlace = p;
}
StringBuffer types = new StringBuffer();
for (int type : p.getPlace().getPlaceTypes()) {
types.append(", " + type);
}
Log.i(TAG, String.format("Place '%s' has liklihood: %g", p.getPlace().getName(), p.getLikelihood()));
Log.i(TAG, String.format("Website: '%s; Types: %s", p.getPlace().getWebsiteUri(), types));
}
placeLikelihoods.release();
//Log.i(TAG, "Probability of place: " + mostProbPlace.getLikelihood());
if(highestProb > thresh) {
//I'm not sure if this line is right
Intent intent = new Intent(getApplicationContext(), RatingActivity.class);
intent.putExtra("com.parse.starter.name", mostProbPlace.getPlace().getName());
intent.putExtra("com.parse.starter.address", mostProbPlace.getPlace().getAddress());
startActivity(intent);
}
else {
createPlacePicker();
}
placeLikelihoods.release();
}
});
}
public void createPlacePicker() {
PlacePicker.IntentBuilder builder = new PlacePicker.IntentBuilder();
Context context = getApplicationContext();
try {
startActivityForResult(builder.build(context), PLACE_PICKER_REQUEST);
} catch(GooglePlayServicesRepairableException e) {
e.printStackTrace();
Log.d(TAG, "REPAIRABLE_SERVICES");
} catch(GooglePlayServicesNotAvailableException e) {
e.printStackTrace();
Log.d(TAG, "NOTAVAILABLE_SERVICES");
}
}
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if(requestCode == PLACE_PICKER_REQUEST) {
if(resultCode == RESULT_OK) {
Place place = PlacePicker.getPlace(data, this);
String toastMsg = String.format("Place: %s", place.getName());
Toast.makeText(this, toastMsg, Toast.LENGTH_LONG).show();
Intent intent = new Intent(this, RatingActivity.class);
intent.putExtra("com.parse.starter.name", place.getName());
intent.putExtra("com.parse.starter.address", place.getAddress());
startActivity(intent);
}
}
}
From what I can tell, the race condition is caused by the fact you are running detectCurrentPlace every time onStart is called.
I think you just need to store the state of your PlaceActivity when the activity is started, so you can modify the behaviour of onStart depending upon whether it is being called from the launch, or as a result of the return from PlacePicker.
class PlaceActivity {
boolean mRunningPlacePicker;
#Override
public void onStart() {
super.onStart();
if (mRunningPlacePicker) {
// we've returned from placepicker - don't run the detectCurrentPlace again
// because RatingsActivity has already launched from onActivityResult
...
} else {
mGoogleApiClient.connect();
}
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
// save the state in case Android destroys our activity
outState.putBoolean("mRunningPlacePicker", mRunningPlacePicker);
}
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
// restore the state
if (savedInstanceState != null) {
mRunningPlacePicker = savedInstanceState.getBoolean("mRunningPlacePicker");
}
}
#Override
public void onConnected(Bundle bundle) {
detectCurrentPlace();
}
public void detectCurrentPlace() {
// do your deciding...
result.setResultCallback(new ResultCallback<PlaceLikelihoodBuffer>() {
#Override
public void onResult(PlaceLikelihoodBuffer placeLikelihoods) {
...
if (highestProb > thresh) {
...
} else {
// save the fact we are running the place picker
mRunningPlacePicker = true;
createPlacePicker();
}
}
}

Implement barge-in for Android TTS

I am having difficulty figuring out how to resolve this issue, I am not sure if I am not setting up threads correctly or if it is even possible to resolve things properly.
This is an Android app that reads certain strings out as TTS (using the native Android TTS) at certain timings. During this TTS reading, the user should be able to barge-in with instructions such as "Stop" or "Pause." This recognition is done by using the iSpeech API.
Our current solution is to have the TTS running as a Thread that will output the proper strings. Once the user presses a button to begin the voice recognition (using an Intent), the app does voice recognition and handles it perfectly, but then TTS never again outputs anything. Logcat shows the following error:
11-28 02:18:57.072: W/TextToSpeech(16383): speak failed: not bound to TTS engine
I have thought about making the voice recognition a thread of its own that pauses the TTS, but the problem would then be that the timer controlling the TTS would become unsynced with what it should be.
Any advice or help would be appreciated.
Relevant code regarding the thread and the intent are below:
Thread
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Prevent device from sleeping mid build.
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
setContentView(R.layout.activity_build_order);
mPlayer = MediaPlayer.create(BuildOrderActivity.this, R.raw.bing);
params.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID,"stringId");
tts = new TextToSpeech(BuildOrderActivity.this, new TextToSpeech.OnInitListener() {
#SuppressWarnings("deprecation")
public void onInit(int status) {
if(status != TextToSpeech.ERROR)
{
tts.setLanguage(Locale.US);
tts.setOnUtteranceCompletedListener(new OnUtteranceCompletedListener() {
public void onUtteranceCompleted(String utteranceId) {
mPlayer.start();
}
});
}
}
});
buttonStart = (Button) findViewById(R.id.buttonStartBuild);
buttonStart.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
startBuild = new StartBuildRunnable();
Thread t = new Thread(startBuild);
t.start();
}
});
...//code continues oncreate setup for the view}
public class StartBuildRunnable implements Runnable {
public void run() {
double delay;
buildActions = parseBuildXMLAction();
buildTimes = parseBuildXMLTime();
say("Build has started");
delayForNextAction((getSeconds(buildTimes.get(0)) * 1000));
say(buildActions.get(0));
for (int i = 1; i < buildActions.size(); i++)
{
delay = calcDelayUntilNextAction(buildTimes.get(i - 1), buildTimes.get(i));
delayForNextAction((long) (delay * 1000));
say(buildActions.get(i));
//listViewBuildItems.setSelection(i);
}
say("Build has completed");
}
}
Intent
/**
* Fire an intent to start the speech recognition activity.
* #throws InvalidApiKeyException
*/
private void startRecognition() {
setupFreeFormDictation();
try {
recognizer.startRecord(new SpeechRecognizerEvent() {
#Override
public void onRecordingComplete() {
updateInfoMessage("Recording completed.");
}
#Override
public void onRecognitionComplete(SpeechResult result) {
Log.v(TAG, "Recognition complete");
//TODO: Once something is recognized, tie it to an action and continue recognizing.
// currently recognizes something in the grammar and then stops listening until
// the next button press.
if (result != null) {
Log.d(TAG, "Text Result:" + result.getText());
Log.d(TAG, "Text Conf:" + result.getConfidence());
updateInfoMessage("Result: " + result.getText() + "\n\nconfidence: " + result.getConfidence());
} else
Log.d(TAG, "Result is null...");
}
#Override
public void onRecordingCancelled() {
updateInfoMessage("Recording cancelled.");
}
#Override
public void onError(Exception exception) {
updateInfoMessage("ERROR: " + exception.getMessage());
exception.printStackTrace();
}
});
} catch (BusyException e) {
e.printStackTrace();
} catch (NoNetworkException e) {
e.printStackTrace();
}
}

how to start an inapp billing activity

I got a code from internet for inapp billing and I want to use that code in my application but I am getting an error that when I click the the buy button of my app it redirect me to the another layout of the code where I get an another Button and after that click my in-app billing starts.
I want that when I click my buy button then the in-app billing should start. without any another button clicks.
This is the code from where the the in-app billing start.
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mSP = PreferenceManager.getDefaultSharedPreferences(this);
Log.i("BillingService", "Starting");
setContentView(R.layout.contact_market);
mContext = this;
mPurchaseButton = (Button) findViewById(R.id.main_purchase_yes);
mPurchaseButton.setOnClickListener(this);
mPreview = (TextView) findViewById(R.id.chakkde);
startService(new Intent(mContext, BillingService.class));
BillingHelper.setCompletedHandler(mTransactionHandler);
}
public Handler mTransactionHandler = new Handler() {
public void handleMessage(android.os.Message msg) {
Log.i(TAG, "Transaction complete");
Log.i(TAG, "Transaction status: "
+ BillingHelper.latestPurchase.purchaseState);
Log.i(TAG, "Item purchased is: "
+ BillingHelper.latestPurchase.productId);
if (BillingHelper.latestPurchase.isPurchased()) {
showItem();
}
};
};
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.main_purchase_yes:
if (BillingHelper.isBillingSupported()) {
BillingHelper.requestPurchase(mContext,
"android.test.purchased");
} else {
Log.i(TAG, "Can't purchase on this device");
mPurchaseButton.setEnabled(false);
}
break;
default:
Log.i(TAG, "default. ID: " + v.getId());
break;
}
}
private void showItem() {
mPreview.setVisibility(View.VISIBLE);
SharedPreferences.Editor prefEditor = mSP.edit();
prefEditor.putBoolean(DroidSugarPreference.KEY_ENABLE,
true);
prefEditor.commit();
startActivity(new Intent(InAppMain.this, Setup.class));
InAppMain.this.finish();
}
#Override
protected void onPause() {
Log.i(TAG, "onPause())");
super.onPause();
}
#Override
protected void onDestroy() {
BillingHelper.stopService();
super.onDestroy();
}
}
this if from where I call the above class
public void onClick(View v) {
// TODO Auto-generated method stub
switch (v.getId()) {
case R.id.gtask_button:
startActivity(new Intent(getActivity(), InAppMain.class));
default:
break;
}
but now i want that from case R.id.gtask_button: i should start the in-app billing activity that i was starting from R.id.main_purchase_yes.
thnx in advance...
From what i see, this is called when you click the button
BillingHelper.requestPurchase(mContext, "android.test.purchased");
So maybe thats where it changes your layout to something else...
Post the method so we can take a look.
EDIT:
Ok, here's the code
protected static void requestPurchase(Context activityContext, String itemId){
if (amIDead()) {
return;
}
Log.i(TAG, "requestPurchase()");
Bundle request = makeRequestBundle("REQUEST_PURCHASE");
request.putString("ITEM_ID", itemId);
try {
Bundle response = mService.sendBillingRequest(request);
//The RESPONSE_CODE key provides you with the status of the request
Integer responseCodeIndex = (Integer) response.get("RESPONSE_CODE");
//The PURCHASE_INTENT key provides you with a PendingIntent, which you can use to launch the checkout UI
PendingIntent pendingIntent = (PendingIntent) response.get("PURCHASE_INTENT");
//The REQUEST_ID key provides you with a unique request identifier for the request
Long requestIndentifier = (Long) response.get("REQUEST_ID");
Log.i(TAG, "current request is:" + requestIndentifier);
C.ResponseCode responseCode = C.ResponseCode.valueOf(responseCodeIndex);
Log.i(TAG, "REQUEST_PURCHASE Sync Response code: "+responseCode.toString());
startBuyPageActivity(pendingIntent, new Intent(), activityContext);
} catch (RemoteException e) {
Log.e(TAG, "Failed, internet error maybe", e);
Log.e(TAG, "Billing supported: "+isBillingSupported());
}
}
and we find the culprit -
startBuyPageActivity(pendingIntent, new Intent(), activityContext);

how to implement conversion text speech listen in audio file similar google translator in android

i am using google transalate api in my application,i have done in text conversion is ok
but translate-text to speech is pending
http://android-developers.blogspot.com/2009/09/introduction-to-text-to-speech-in.html
this code i am using how can implement translate text voice in android.
http://www.freeimagehosting.net/uploads/c382dd10f8.png
this above screenshot display text conversion is ok,click audiobutton image listen translate text in audioplayer how can implemented
my code
//audio button click event..........
submit = (ImageView) findViewById(R.id.ImageView01);
submit.setOnClickListener(new View.OnClickListener()
{ public void onClick(View v)
{
//speech code how can implemented
}
});
/////////////////// translate button code//////////////////////
((Button)findViewById(R.id.Button01)).setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
try {
String fromLan=spineFrom.getSelectedItem().toString();
String toLan=spineTo.getSelectedItem().toString();
Log.v("check",fromLan+" :"+toLan);
translatedText = Translate.execute(((EditText)findViewById(R.id.EditText01)).getText().toString(),converStrtoLan(fromLan),converStrtoLan(toLan));
((TextView)findViewById(R.id.TextView02)).setText(translatedText);
Intent checkIntent = new Intent();
checkIntent.setAction(TextToSpeech.Engine.ACTION_CHECK_TTS_DATA);
startActivityForResult(checkIntent,1);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
}
private TextToSpeech mTts;
protected void onActivityResult(
int requestCode, int resultCode, Intent data) {
if (requestCode == 1) {
if (resultCode == TextToSpeech.Engine.CHECK_VOICE_DATA_PASS) {
// success, create the TTS instance
mTts = new TextToSpeech(this, null);
} else {
// missing data, install it
Intent installIntent = new Intent();
installIntent.setAction(
TextToSpeech.Engine.ACTION_INSTALL_TTS_DATA);
startActivity(installIntent);
}
}
mTts.setLanguage(Locale.US);
String myText1 = "Did you sleep well?";
String myText2 = "I hope so, because it's time to wake up.";
mTts.speak(myText1, TextToSpeech.QUEUE_FLUSH, null);
mTts.speak(myText2, TextToSpeech.QUEUE_ADD, null);
}
private Language converStrtoLan(String lan){
if(lan.equals("ENGLISH") || lan=="ENGLISH"){
return Language.ENGLISH;
}else if (lan.equals("SPANISH") || lan=="SPANISH"){
return Language.SPANISH;
}
return null;
}
}
how can add this audio code in audio click event ,
please forward some valuable response of this code this issue i am struggle for more number of days thanks in advance ..
In order to do Text To Speech with Android you can use eyes-free library

Categories

Resources