I am implementing Inapp billing for the products in my app for that i refered dungeons example and implementing from that!! But now i am not about to display checkout dialog box in my application and i even not getting any error in logcat..The application showing result as ERROR in a dialog box with NO CONNECTION MESSAGE IN IT
I am tracing the problem using logs.The code that i am using to display checkout dialog box is
In My Main Class::::::::::
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Intent j = getIntent();
int position = j.getExtras().getInt("BId");
System.err.println("Bid="+position);
Log.i("J","gf");
mHandler = new Handler();
mBooksPurchaseObserver = new BooksPurchaseObserver(mHandler);
mBillingService = new BillingService();
mBillingService.setContext(this);
mItemName = getString(CATALOG[position].nameId);
mSku = CATALOG[position].sku;
System.err.println("mSku_______="+mSku);
System.err.println("mItemName____="+mItemName);
System.err.println("Consts.DEBUG=="+Consts.DEBUG);
ResponseHandler.register(mBooksPurchaseObserver);
if (mBillingService.checkBillingSupported()) {
Log.i("ds","bsc_checkconnection");
}
if (Consts.DEBUG!=true) {
Log.d(TAG, "buying: " + mItemName + " sku: " + mSku);
Log.i("x","x");
}
mPurchaseDatabase = new PurchaseDatabase(this);
if(!mBillingService.requestPurchase(mItemName, mSku)){
Log.e("this is exp","request purchase______________");
showDialog(DIALOG_BILLING_NOT_SUPPORTED_ID);
}
setupWidgets();
Log.i("ga","Request purchaseeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee");
// Check if billing is supported.
Log.i("ga","Request purchaseeeeeeeeeee");
}
In Billing Service Class::::
class RequestPurchase extends BillingRequest {
public final String mProductId;
public final String mDeveloperPayload;
public RequestPurchase(String itemId) {
this(itemId, null);
Log.i("ga","Request purchase");
}
public RequestPurchase(String itemId, String developerPayload) {
// This object is never created as a side effect of starting this
// service so we pass -1 as the startId to indicate that we should
// not stop this service after executing this request.
super(-1);
System.err.println("itemId="+itemId);
Log.i("fads","request only");
mProductId = itemId;
mDeveloperPayload = developerPayload;
}
#Override
protected long run() throws RemoteException {
Log.i("gaaaaaaaaa","Request purchase");
Bundle request = makeRequestBundle("REQUEST_PURCHASE");
request.putString(Consts.BILLING_REQUEST_ITEM_ID, mProductId);
// Note that the developer payload is optional.
if (mDeveloperPayload != null) {
request.putString(Consts.BILLING_REQUEST_DEVELOPER_PAYLOAD, mDeveloperPayload);
}
System.err.println("mService===="+mService);
Bundle response = mService.sendBillingRequest(request);
System.err.println("response__"+response);
System.err.println("response__!!!!!!!!!!!!"+Consts.BILLING_RESPONSE_PURCHASE_INTENT);
PendingIntent pendingIntent
= response.getParcelable(Consts.BILLING_RESPONSE_PURCHASE_INTENT);
System.err.println("Pending Intent==="+pendingIntent);
Log.i("12","12");
if (pendingIntent == null) {
Log.e(TAG, "Error with requestPurchase");
return Consts.BILLING_RESPONSE_INVALID_REQUEST_ID;
}
Log.i("2","2");
Intent intent = new Intent();
Log.i("222222","11111");
System.err.println("Intent is equals to__"+intent);
System.err.println("pendingIntent is equals to__"+pendingIntent);
// System.err.printf("fsd",ResponseHandler.buyPageIntentResponse(pendingIntent, intent));
ResponseHandler.buyPageIntentResponse(pendingIntent, intent);
Log.i("f","fdas");
return response.getLong(Consts.BILLING_RESPONSE_REQUEST_ID,
Consts.BILLING_RESPONSE_INVALID_REQUEST_ID);
}
#Override
protected void responseCodeReceived(ResponseCode responseCode) {
Log.i("response code","response code");
ResponseHandler.responseCodeReceived(BillingService.this, this, responseCode);
}
}
My CheckbillingSupporting class
class CheckBillingSupported extends BillingRequest {
public CheckBillingSupported() {
// This object is never created as a side effect of starting this
// service so we pass -1 as the startId to indicate that we should
// not stop this service after executing this request.
super(-1);
}
#Override
protected long run() throws RemoteException {
Bundle request = makeRequestBundle("CHECK_BILLING_SUPPORTED");
Bundle response = mService.sendBillingRequest(request);
System.err.println("response code____"+Consts.BILLING_RESPONSE_RESPONSE_CODE);
int responseCode = response.containsKey(Consts.BILLING_RESPONSE_RESPONSE_CODE)
? response.getInt(Consts.BILLING_RESPONSE_RESPONSE_CODE)
: ResponseCode.RESULT_BILLING_UNAVAILABLE.ordinal();
if (Consts.DEBUG) {
Log.i(TAG, "CheckBillingSupported response code: " +
ResponseCode.valueOf(responseCode));
}
boolean billingSupported = (responseCode == ResponseCode.RESULT_OK.ordinal());
ResponseHandler.checkBillingSupportedResponse(billingSupported);
return Consts.BILLING_RESPONSE_INVALID_REQUEST_ID;
}
}
Could any one tell me were i went wrong?
Related
I am starter at Android and now I want to transfer data using intent from one activity to another.
First activity will collect datas and give it to second. but on second the data returns null. So have some errors on there. Here are my code.
public void previewStack(final Context context, final CreateStackNewActivity createStackNewActivity, final Stack stackDetails) {
Map<String, String> options = new HashMap<String, String>();
if(stackDetails.getStackId() != -1){
options.put("stack_id", String.valueOf(stackDetails.getStackId()));
}
int index = 1;
for(StackLineNew stackLine : stackDetails.getLines()){
options.put("title" + index, stackLine.getTitle());
options.put("line_type" + index, Integer.toString(stackLine.getLineType().intValue));
options.put("title" + index, stackLine.getTitle());
if (stackLine.getBody().indexOf("file:/") == -1 && stackLine.getBody().indexOf("content:") == -1) {
options.put("description" + index, stackLine.getBody());
if (stackLine.getLineId() != -1) {
options.put("line_id" + index, Integer.toString(stackLine.getLineId()));
}
}
index++;
}
Call<GenericAPIResponse> call = Hype4DAPI.previewStack(stackDetails.getName(), stackDetails.getCategory(), Integer.toString(stackDetails.getLines().size()), options, "");
call.enqueue(new Callback<GenericAPIResponse>() {
#Override
public void onResponse(Call<GenericAPIResponse> call, Response<GenericAPIResponse> response) {
if(response.isSuccessful()) {
GenericAPIResponse saveStackResponse = response.body();
System.out.println(saveStackResponse);
Toast.makeText(context, saveStackResponse.toString(), Toast.LENGTH_SHORT).show();
createStackNewActivity.saveInProgress = false;
createStackNewActivity.somethingHasChanged = false;
createStackNewActivity.updatePostButtonState();
Intent itnt = new Intent(createStackNewActivity, StackDetailsPage.class);
itnt.putExtra("stackId", stackDetails.getStackId());
itnt.putExtra("isPreview", "true");
itnt.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
createStackNewActivity.startActivity(itnt);
} else {
System.out.println(response.errorBody());
Toast.makeText(context, response.errorBody().toString(), Toast.LENGTH_SHORT).show();
}
}
#Override
public void onFailure(Call<GenericAPIResponse> call, Throwable t) {
t.printStackTrace();
}
});
}
And the code of second activity
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_stack_details);
final Intent intent = getIntent();
final String stackId;
if (intent != null) { //Null Checking
stackId = intent.getStringExtra("stackId");
isPreview = intent.getStringExtra("isPreview");
stackTitleStr = intent.getStringExtra("stackTitle");
saveLine = (HashMap<String, Object>)intent.getSerializableExtra("saveLine");
}
else{
stackId = null;
}
On second activity, I have all variables are null. isPreview, stackTitleStr, saveLine are all null.
So anyone please help me quickly.
first you should not create the intent in the onResponse callBack method but create a static method in your StackDetailsPage activity that return the intent it needs. With that, this activity "said" to the other ones whats it needs, and it avoid duplicate string extra keys. use this :
//in StackDetailsPage activity
public static Intent getIntent(Context context, String stackId, String...)
{
Intent intent = new Intent(context, StackDetailsPage.class);
intent.putExtra("stackId", stackId);
...
return intent;
}
and then in onResponse method do that :
startActivity(StackDetailsPage.getIntent(context,stackDetails.getStackId(), ...))
I created a class for working with subscriptions in the store.
In the beginning I receive from the server the list of subscriptions with the prices
The code is working and on most devices there is no problem.
But some users do not recive prices. It's like there's no response from the server. I've studied examples of implementation in Google documentation, but I can not understand where I can have problems in the code.
Part of my code:
public class BillingActivity extends AppCompatActivity {
RelativeLayout imageLayout;
View payButton;
// WebView payWebView;
// TextView useCodeButton;
ProgressBar progress1;
ProgressBar progress2;
ProgressBar progress3;
IInAppBillingService inAppBillingService;
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_billing_subscription);
price_1monthTextView = (TextView) findViewById(R.id.price_1monthTextView);
relative_1month = (RelativeLayout) findViewById(R.id.relative_1month);
relative_1month.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (MainActivity.myAccount == null) return;
if (MainActivity.myAccount.getUniqid() == null) return;
if (subscription1m != null) {
try {
Log.d("my", "purchase..." + subscription1m.storeName);
purchaseProduct(subscription1m);
} catch (Exception e) {
e.printStackTrace();
Log.d("my", "purchase error = " + e.toString());
}
}
}
});
progress1 = (ProgressBar) findViewById(R.id.progress1);
startGoogleBilling();
}
private void startGoogleBilling() {
if (serviceConnection != null) {
unbindService(serviceConnection);
}
progress1.setVisibility(View.VISIBLE);
serviceConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
inAppBillingService = IInAppBillingService.Stub.asInterface(service);
getSubscribtionsList();
}
#Override
public void onServiceDisconnected(ComponentName name) {
inAppBillingService = null;
}
};
Intent serviceIntent =
new Intent("com.android.vending.billing.InAppBillingService.BIND");
serviceIntent.setPackage("com.android.vending");
bindService(serviceIntent, serviceConnection, Context.BIND_AUTO_CREATE);
}
private static final int PR_CNT = 3;
List<InAppProduct> subscriptions = null;
InAppProduct subscription1m = null;
InAppProduct subscription3m = null;
InAppProduct subscription1y = null;
String[] productIds = {"eq.subscription.1m", "eq.subscription.3m.2", "eq.subscription.1y"};
private void getSubscribtionsList() {
mSwipeRefreshLayout.setRefreshing(false);
progress1.setVisibility(View.GONE);
try {
subscriptions =
getInAppPurchases("subs", productIds[0], productIds[1], productIds[2]);
if (subscriptions.size() == PR_CNT) {
for (InAppProduct inAppProduct : subscriptions) {
String productId = inAppProduct.productId;
Log.d("my", "productId= " + productId);
if (productId.contains(productIds[0])) subscription1m = inAppProduct;
if (productId.contains(productIds[1])) subscription3m = inAppProduct;
if (productId.contains(productIds[2])) subscription1y = inAppProduct;
}
Log.d("my", "1m= " + subscription1m.storeName + " pr=" + subscription1m.price + "\\n\\r " +
"3m= " + subscription3m.storeName + " pr=" + subscription3m.price + "\\n\\r " +
"1y= " + subscription1y.storeName + " pr=" + subscription1y.price + "\\n\\r ");
///----------------------!!!!
// purchaseProduct(inAppProduct);
}
updatePrices();
} catch (Exception e) {
Log.d("my", "exc = " + e.toString());
if (e.toString().contains("Attempt to invoke interface method 'android.os.Bundle com.android.vending.billing.IInAppBillingService.getSkuDetails")) {
if (attempt < 4) {
//getSubscribtionsList();
// startGoogleBilling();
} else {
}
}
// Toast.makeText(this, "Google inApp connection error", Toast.LENGTH_SHORT).show();
// refreshButton.setVisibility(View.VISIBLE);
startGoogleBilling();
}
}
private int attempt = 0;
#Override
public void onDestroy() {
super.onDestroy();
if (serviceConnection != null) {
unbindService(serviceConnection);
}
}
class InAppProduct {
public String productId;
public String storeName;
public String storeDescription;
public String price;
public boolean isSubscription;
public int priceAmountMicros;
public String currencyIsoCode;
public String getSku() {
return productId;
}
String getType() {
return isSubscription ? "subs" : "inapp";
}
}
List<InAppProduct> getInAppPurchases(String type, String... productIds) throws Exception {
ArrayList<String> skuList = new ArrayList<>(Arrays.asList(productIds));
Bundle query = new Bundle();
query.putStringArrayList("ITEM_ID_LIST", skuList);
Bundle skuDetails = inAppBillingService.getSkuDetails(
3, getPackageName(), type, query);
ArrayList<String> responseList = skuDetails.getStringArrayList("DETAILS_LIST");
List<InAppProduct> result = new ArrayList<>();
for (String responseItem : responseList) {
JSONObject jsonObject = new JSONObject(responseItem);
InAppProduct product = new InAppProduct();
// "com.example.myapp_testing_inapp1"
product.productId = jsonObject.getString("productId");
// Покупка
product.storeName = jsonObject.getString("title");
// Детали покупки
product.storeDescription = jsonObject.getString("description");
// "0.99USD"
product.price = jsonObject.getString("price");
// "true/false"
product.isSubscription = jsonObject.getString("type").equals("subs");
// "990000" = цена x 1000000
product.priceAmountMicros =
Integer.parseInt(jsonObject.getString("price_amount_micros"));
// USD
product.currencyIsoCode = jsonObject.getString("price_currency_code");
result.add(product);
}
return result;
}
private void updatePrices() {
if (subscriptions.size() == PR_CNT) {
price_1monthTextView.setText(subscription1m.price);
price_3monthTextView.setText(subscription3m.price);
price_1yearTextView.setText(subscription1y.price);
}
}
}
my problem was the bit depth of the X variable priceAmountMicros
The price from playmarket is multiplied by a 1000000 , and Kazakh tenge has exchange rate = 1 USD= 331,3 KZT.
And if i have price 18 000 KTZ and * 1000 000.
For price variable I must use long type
I have a listView that is supposed to accept a shared message and image where the image is placed within the ImageView. This feature works for just the first message, but once an image is shared, each message received after that initial one becomes a copy of that same image even though the blank image placeholder was already set, which is just a one pixel black png:
holder.sharedSpecial.setImageResource(R.drawable.image_share_empty_holder);
An example is below:
The green textbox is the recipient. They have recieved a shared image from the yellow textbox. The yellow textbox then simply sends a normal message and I have set another image as a placeholder for normal messages: holder.sharedSpecial.setImageResource(R.drawable.image_share_empty_holder);
The same previously shared image takes precedence. I have used notifyDataSetChanged() so as to allow for the updating the adapter so that it would recognize not to use the same image, but to no avail.
How can I reformulate this class so that the image shared is only displayed with the proper message and not copied into each subsequent message?
The ArrayAdapter class:
public class DiscussArrayAdapter extends ArrayAdapter<OneComment> {
class ViewHolder {
TextView countryName;
ImageView sharedSpecial;
LinearLayout wrapper;
}
private TextView countryName;
private ImageView sharedSpecial;
private MapView locationMap;
private GoogleMap map;
private List<OneComment> countries = new ArrayList<OneComment>();
private LinearLayout wrapper;
private JSONObject resultObject;
private JSONObject imageObject;
String getSharedSpecialURL = null;
String getSharedSpecialWithLocationURL = null;
String specialsActionURL = "http://" + Global.getIpAddress()
+ ":3000/getSharedSpecial/";
String specialsLocationActionURL = "http://" + Global.getIpAddress()
+ ":3000/getSharedSpecialWithLocation/";
String JSON = ".json";
#Override
public void add(OneComment object) {
countries.add(object);
super.add(object);
}
public DiscussArrayAdapter(Context context, int textViewResourceId) {
super(context, textViewResourceId);
}
public int getCount() {
return this.countries.size();
}
private OneComment comment = null;
public OneComment getItem(int index) {
return this.countries.get(index);
}
public View getView(int position, View convertView, ViewGroup parent) {
final ViewHolder holder;
View row = convertView;
if (row == null) {
LayoutInflater inflater = (LayoutInflater) this.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
row = inflater.inflate(R.layout.message_list_item, parent, false);
holder = new ViewHolder();
holder.wrapper = (LinearLayout) row.findViewById(R.id.wrapper);
holder.countryName = (TextView) row.findViewById(R.id.comment);
holder.sharedSpecial = (ImageView) row.findViewById(R.id.sharedSpecial);
// Store the ViewHolder as a tag.
row.setTag(holder);
} else {
holder = (ViewHolder) row.getTag();
}
Log.v("COMMENTING","Comment is " + countries.get(position).comment);
//OneComment comment = getItem(position);
holder.countryName.setText(countries.get(position).comment);
// Initiating Volley
final RequestQueue requestQueue = VolleySingleton.getsInstance().getRequestQueue();
// Check if message has campaign or campaign/location attached
if (countries.get(position).campaign_id == "0" && countries.get(position).location_id == "0") {
holder.sharedSpecial.setImageResource(R.drawable.image_share_empty_holder);
Log.v("TESTING", "It is working");
} else if (countries.get(position).campaign_id != "0" && countries.get(position).location_id != "0") {
// If both were shared
getSharedSpecialWithLocationURL = specialsLocationActionURL + countries.get(position).campaign_id + "/" + countries.get(position).location_id + JSON;
// Test Campaign id = 41
// Location id = 104
// GET JSON data and parse
JsonObjectRequest getCampaignLocationData = new JsonObjectRequest(Request.Method.GET, getSharedSpecialWithLocationURL, null,
new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
// Parse the JSON:
try {
resultObject = response.getJSONObject("shared");
} catch (JSONException e) {
e.printStackTrace();
}
// Get and set image
Picasso.with(getContext()).load("http://" + Global.getIpAddress() + ":3000" + adImageURL).into(holder.sharedSpecial);
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.d("Error.Response", error.toString());
}
}
);
requestQueue.add(getCampaignLocationData);
} else if (countries.get(position).campaign_id != "0" && countries.get(position).location_id == "0") {
// Just the campaign is shared
getSharedSpecialURL = specialsActionURL + countries.get(position).campaign_id + JSON;
// Test Campaign id = 41
// GET JSON data and parse
JsonObjectRequest getCampaignData = new JsonObjectRequest(Request.Method.GET, getSharedSpecialURL, null,
new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
// Parse the JSON:
try {
resultObject = response.getJSONObject("shared");
} catch (JSONException e) {
e.printStackTrace();
}
// Get and set image
Picasso.with(getContext()).load("http://" + Global.getIpAddress() + ":3000" + adImageURL).into(holder.sharedSpecial);
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.d("Error.Response", error.toString());
}
}
);
requestQueue.add(getCampaignData);
// Location set to empty
}
// If left is true, then yellow, if not then set to green bubble
holder.countryName.setBackgroundResource(countries.get(position).left ? R.drawable.bubble_yellow : R.drawable.bubble_green);
holder.wrapper.setGravity(countries.get(position).left ? Gravity.LEFT : Gravity.RIGHT);
return row;
}
}
The messaging class that sends normal messages only but can receive image messages and set to the adapter:
public class GroupMessaging extends Activity {
private static final int MESSAGE_CANNOT_BE_SENT = 0;
public String username;
public String groupname;
private Button sendMessageButton;
private Manager imService;
private InfoOfGroup group = new InfoOfGroup();
private InfoOfGroupMessage groupMsg = new InfoOfGroupMessage();
private StorageManipulater localstoragehandler;
private Cursor dbCursor;
private com.example.feastapp.ChatBoxUi.DiscussArrayAdapter adapter;
private ListView lv;
private EditText editText1;
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
imService = ((MessagingService.IMBinder) service).getService();
}
public void onServiceDisconnected(ComponentName className) {
imService = null;
Toast.makeText(GroupMessaging.this, R.string.local_service_stopped,
Toast.LENGTH_SHORT).show();
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.message_activity);
lv = (ListView) findViewById(R.id.listView1);
adapter = new DiscussArrayAdapter(getApplicationContext(), R.layout.message_list_item);
lv.setAdapter(adapter);
editText1 = (EditText) findViewById(R.id.editText1);
sendMessageButton = (Button) findViewById(R.id.sendMessageButton);
Bundle extras = this.getIntent().getExtras();
group.userName = extras.getString(InfoOfGroupMessage.FROM_USER);
group.groupName = extras.getString(InfoOfGroup.GROUPNAME);
group.groupId = extras.getString(InfoOfGroup.GROUPID);
String msg = extras.getString(InfoOfGroupMessage.GROUP_MESSAGE_TEXT);
setTitle("Group: " + group.groupName);
// Retrieve the information
localstoragehandler = new StorageManipulater(this);
dbCursor = localstoragehandler.groupGet(group.groupName);
if (dbCursor.getCount() > 0) {
// Probably where the magic happens, and keeps pulling the same
// thing
int noOfScorer = 0;
dbCursor.moveToFirst();
while ((!dbCursor.isAfterLast())
&& noOfScorer < dbCursor.getCount()) {
noOfScorer++;
}
}
localstoragehandler.close();
if (msg != null) {
// Then friends username and message, not equal to null, recieved
adapter.add(new OneComment(true, group.groupId + ": " + msg, "0", "0"));
adapter.notifyDataSetChanged();
((NotificationManager) getSystemService(NOTIFICATION_SERVICE))
.cancel((group.groupId + msg).hashCode());
}
// The send button
sendMessageButton.setOnClickListener(new OnClickListener() {
CharSequence message;
Handler handler = new Handler();
public void onClick(View arg0) {
message = editText1.getText();
if (message.length() > 0) {
// When general texting, the campaign and location will always be "0"
// Only through specials sharing is the user permitted to change the campaign and location to another value
adapter.add(new OneComment(false, imService.getUsername() + ": " + message.toString(), "0", "0"));
adapter.notifyDataSetChanged();
localstoragehandler.groupInsert(imService.getUsername(), group.groupName,
group.groupId, message.toString(), "0", "0");
// as msg sent, will blank out the text box so can write in
// again
editText1.setText("");
Thread thread = new Thread() {
public void run() {
try {
// JUST PUTTING "0" AS A PLACEHOLDER FOR CAMPAIGN AND LOCATION
// IN FUTURE WILL ACTUALLY ALLOW USER TO SHARE CAMPAIGNS
if (imService.sendGroupMessage(group.groupId,
group.groupName, message.toString(), "0", "0") == null) {
handler.post(new Runnable() {
public void run() {
Toast.makeText(
getApplicationContext(),
R.string.message_cannot_be_sent,
Toast.LENGTH_LONG).show();
// showDialog(MESSAGE_CANNOT_BE_SENT);
}
});
}
} catch (UnsupportedEncodingException e) {
Toast.makeText(getApplicationContext(),
R.string.message_cannot_be_sent,
Toast.LENGTH_LONG).show();
e.printStackTrace();
}
}
};
thread.start();
}
}
});
}
#Override
protected Dialog onCreateDialog(int id) {
int message = -1;
switch (id) {
case MESSAGE_CANNOT_BE_SENT:
message = R.string.message_cannot_be_sent;
break;
}
if (message == -1) {
return null;
} else {
return new AlertDialog.Builder(GroupMessaging.this)
.setMessage(message)
.setPositiveButton(R.string.OK,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,
int whichButton) {
/* User clicked OK so do some stuff */
}
}).create();
}
}
#Override
protected void onPause() {
super.onPause();
unregisterReceiver(groupMessageReceiver);
unbindService(mConnection);
ControllerOfGroup.setActiveGroup(null);
}
#Override
protected void onResume() {
super.onResume();
bindService(new Intent(GroupMessaging.this, MessagingService.class),
mConnection, Context.BIND_AUTO_CREATE);
IntentFilter i = new IntentFilter();
i.addAction(MessagingService.TAKE_GROUP_MESSAGE);
registerReceiver(groupMessageReceiver, i);
ControllerOfGroup.setActiveGroup(group.groupName);
}
// For receiving messages form other users...
public class GroupMessageReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Bundle extra = intent.getExtras();
//Log.i("GroupMessaging Receiver ", "received group message");
String username = extra.getString(InfoOfGroupMessage.FROM_USER);
String groupRId = extra.getString(InfoOfGroupMessage.TO_GROUP_ID);
String message = extra
.getString(InfoOfGroupMessage.GROUP_MESSAGE_TEXT);
// NEED TO PLACE INTO THE MESSAGE VIEW!!
String received_campaign_id = extra.getString(InfoOfGroupMessage.CAMPAIGN_SHARED);
String received_location_id = extra.getString(InfoOfGroupMessage.LOCATION_SHARED);
// NEED TO INTEGRATE THIS INTO LOGIC ABOVE, SO IT MAKES SENSE
if (username != null && message != null) {
if (group.groupId.equals(groupRId)) {
adapter.add(new OneComment(true, username + ": " + message, received_campaign_id, received_location_id));
localstoragehandler
.groupInsert(username, groupname, groupRId, message, received_campaign_id, received_location_id);
Toast.makeText(getApplicationContext(), "received_campaign: " + received_campaign_id +
" received_location:" + received_location_id, Toast.LENGTH_LONG).show();
received_campaign_id = "0";
received_location_id = "0";
} else {
if (message.length() > 15) {
message = message.substring(0, 15);
}
Toast.makeText(GroupMessaging.this,
username + " says '" + message + "'",
Toast.LENGTH_SHORT).show();
}
}
}
}
;
// Build receiver object to accept messages
public GroupMessageReceiver groupMessageReceiver = new GroupMessageReceiver();
#Override
protected void onDestroy() {
super.onDestroy();
if (localstoragehandler != null) {
localstoragehandler.close();
}
if (dbCursor != null) {
dbCursor.close();
}
}
}
I have gone through your code and this is common problem with listview that images starts repeating itself. In your case I think you have assigned image to Imageview every if and else if condition but if none of the condition satisfy it uses the previous image.
I would suggest to debug the getview method and put break points on the setImageResource. I use volley for these image loading and it has a method called defaultImage so that if no url is there the image is going to get the default one. So add that default case and see if it works.
If any of the above point is not clear feel free to comment.
I'm using the socialAuth plugin to connect a user to linkdin within my app. I have the connection set up correctly and retrieves data. However, I'm unsure how I can get my main activity to wait until the socialAuthListeners have fired and finished. I know a little about threading but I haven't used it with listeners before. Here's my code:
public class LinkdinAuth {
private static final String TAG = "TEST";
// SocialAuth Components
SocialAuthAdapter adapter;
ProgressDialog mDialog;
private Context context;
private boolean loggedIn = false;
private Bundle LinkdinData;
public LinkdinAuth(Context C){
this.context = C;
LinkdinData = new Bundle();
adapter = new SocialAuthAdapter(new ResponseListener());
}
public void adapterAuthorize(View v){
adapter.authorize(v.getContext(), Provider.LINKEDIN);
}
private final class ResponseListener implements DialogListener
{
public void onComplete(Bundle values) {
String providerName = values.getString(SocialAuthAdapter.PROVIDER);
Log.d("Main", "providername = " + providerName);
mDialog = new ProgressDialog(context);
mDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
mDialog.setMessage("Loading...");
//Get profile information
adapter.getUserProfileAsync(new ProfileDataListener());
// get Job and Education information
mDialog.show();
adapter.getCareerAsync(new CareerListener());
loggedIn = true;
Log.d("Main", "LOGGED IN = " + loggedIn );
Toast.makeText(context, providerName + " connected", Toast.LENGTH_SHORT).show();
}
#Override
public void onBack() {
Log.d("Main", "Dialog Closed by pressing Back Key");
}
#Override
public void onCancel() {
Log.d("Main", "Cancelled");
}
#Override
public void onError(SocialAuthError e) {
Log.d("Main", "Error");
e.printStackTrace();
}
}
// To receive the profile response after authentication
private final class ProfileDataListener implements SocialAuthListener<Profile> {
#Override
public void onExecute(String provider, Profile t) {
Log.d("Sign Up", "Receiving Data");
mDialog.dismiss();
Profile profileMap = t;
LinkdinData.putString("Validated ID", profileMap.getValidatedId() );
LinkdinData.putString("First Name", profileMap.getFirstName());
LinkdinData.putString("Last Name", profileMap.getLastName());
LinkdinData.putString("Email", profileMap.getEmail());
LinkdinData.putString("Country", profileMap.getCountry());
LinkdinData.putString("Language", profileMap.getLanguage());
LinkdinData.putString("Location", profileMap.getLocation());
LinkdinData.putString("Profile Image URL", profileMap.getProfileImageURL());
}
#Override
public void onError(SocialAuthError arg0) {
// TODO Auto-generated method stub
}
}
private final class CareerListener implements SocialAuthListener<Career> {
#Override
public void onExecute(String provider, Career t) {
Log.d("Custom-UI", "Receiving Data");
mDialog.dismiss();
Career careerMap = t;
//get education
Log.d("Main", "Education:");
if(careerMap.getEducations() != null){
for(Education E: careerMap.getEducations()){
Log.d("Main", "School = " +E.getSchoolName() );
Log.d("Main", "Major = " + E.getFieldOfStudy() );
Log.d("Main", "Degree = " + E.getDegree() );
Log.d("Main", "Start Date = " + E.getStartDate() );
Log.d("Main", "End Date = " + E.getEndDate() );
}
}
Log.d("SignUp", "Career");
if(careerMap.getPositions() != null){
for(Position P: careerMap.getPositions()){
LinkdinData.putString("Company Name", P.getCompanyName() );
LinkdinData.putString("Job Title", P.getTitle() );
Log.d("Main", "Industry = " + P.getIndustry() );
Log.d("Main", "Start Date = " + P.getStartDate() );
Log.d("Main", "End Date = " + P.getEndDate() );
}
}
}
#Override
public void onError(SocialAuthError e) {
}
}
public boolean isLoggedIn(){
return loggedIn;
}
public Bundle getLinkdinData(){
return LinkdinData;
}
So, as you can see. I have 2 listeners that get data after authorization goes through. And my main activity makes creates an instance, calls the adapterAuthroizeMethod and then if the user logs in a flag is set. Then getLinkedData is called. However I would like it to wait until I know the listeners have fired before calling getlinkdinData. Here's what my Main Activity does after a button press:
L.adapterAuthorize(v);
loggedInWithLinkdin = L.isLoggedIn();
Bundle B = L.getLinkdinData();
Intent i = new Intent(getBaseContext(), UserRegistration.class);
i.putExtra("linkdin bundle", B);
//startActivity(i);
Any ideas?
thanks
Well, not a recommend solution but more of a hack.
Here is what you can do.
Wrap the aync call around this construct :
AtomicBoolean done = new AtomicBoolean(false);
Global ans; // the return value holder
try{
result = someAsyncCall(query, new Thread()); // this new thread is for listener callback
result.setResultListener(result -> {
// do something with result.
ans = result.getAns() ; // set global ans
done.set(true);
synchronized (done) {
done.notifyAll(); // notify the main thread which is waiting
}
});
}
catch (Exception e ) {
Log(e);
}
synchronized (done) {
while (done.get() == false) {
done.wait(); // wait here until the listener fires
}
}
return ans; // return global ans
When the user presses the buy button, they get taken to the android play screen to buy the in-app item. But when they press back, they get this exception about not being able to start the billing service:
java.lang.RuntimeException: Unable to start service com.problemio.BillingService#405704f0 with Intent { act=com.android.vending.billing.RESPONSE_CODE cmp=com.problemio/.BillingService (has extras) }: java.lang.NullPointerException
at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:2387)
at android.app.ActivityThread.access$2800(ActivityThread.java:132)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1111)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:150)
at android.app.ActivityThread.main(ActivityThread.java:4293)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:507)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.NullPointerException
at com.problemio.ExtraHelpActivity.prependLogEntry(ExtraHelpActivity.java:561)
at com.problemio.ExtraHelpActivity.logProductActivity(ExtraHelpActivity.java:569)
at com.problemio.ExtraHelpActivity.access$4(ExtraHelpActivity.java:565)
at com.problemio.ExtraHelpActivity$ExtraHelpPurchaseObserver.onRequestPurchaseResponse(ExtraHelpActivity.java:187)
at com.problemio.ResponseHandler.responseCodeReceived(ResponseHandler.java:137)
at com.problemio.BillingService$RequestPurchase.responseCodeReceived(BillingService.java:285)
at com.problemio.BillingService.checkResponseCode(BillingService.java:582)
at com.problemio.BillingService.handleCommand(BillingService.java:427)
at com.problemio.BillingService.onStart(BillingService.java:398)
at android.app.Service.onStartCommand(Service.java:428)
at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:2370)
... 10 more
java.lang.NullPointerException
at com.problemio.ExtraHelpActivity.prependLogEntry(ExtraHelpActivity.java:561)
at com.problemio.ExtraHelpActivity.logProductActivity(ExtraHelpActivity.java:569)
at com.problemio.ExtraHelpActivity.access$4(ExtraHelpActivity.java:565)
at com.problemio.ExtraHelpActivity$ExtraHelpPurchaseObserver.onRequestPurchaseResponse(ExtraHelpActivity.java:187)
at com.problemio.ResponseHandler.responseCodeReceived(ResponseHandler.java:137)
at com.problemio.BillingService$RequestPurchase.responseCodeReceived(BillingService.java:285)
at com.problemio.BillingService.checkResponseCode(BillingService.java:582)
at com.problemio.BillingService.handleCommand(BillingService.java:427)
at com.problemio.BillingService.onStart(BillingService.java:398)
at android.app.Service.onStartCommand(Service.java:428)
at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:2370)
at android.app.ActivityThread.access$2800(ActivityThread.java:132)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1111)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:150)
at android.app.ActivityThread.main(ActivityThread.java:4293)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:507)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
at dalvik.system.NativeStart.main(Native Method)
It specifically mentions these lines in my class:
Caused by:
java.lang.NullPointerException
at com.problemio.ExtraHelpActivity.prependLogEntry(ExtraHelpActivity.java:561)
at com.problemio.ExtraHelpActivity.logProductActivity(ExtraHelpActivity.java:569)
at com.problemio.ExtraHelpActivity.access$4(ExtraHelpActivity.java:565)
at com.problemio.ExtraHelpActivity$ExtraHelpPurchaseObserver.onRequestPurchaseResponse(ExtraHelpActivity.java:187)
on line 561 I have this code:
private void prependLogEntry(CharSequence cs) {
SpannableStringBuilder contents = new SpannableStringBuilder(cs);
contents.append('\n');
contents.append(mLogTextView.getText()); // Line 561
mLogTextView.setText(contents);
}
on line 569 I have this code:
private void logProductActivity(String product, String activity) {
SpannableStringBuilder contents = new SpannableStringBuilder();
contents.append(Html.fromHtml("<b>" + product + "</b>: "));
contents.append(activity);
prependLogEntry(contents); // Line 569
}
By the way, which log is this? Is it really needed? Maybe its worthwhile to comment out these methods?
In any case, the other line the error points to is 187 and here is the code for that:
#Override
public void onRequestPurchaseResponse(RequestPurchase request,
ResponseCode responseCode) {
if (Consts.DEBUG) {
Log.d(TAG, request.mProductId + ": " + responseCode);
}
if (responseCode == ResponseCode.RESULT_OK) {
if (Consts.DEBUG) {
Log.i(TAG, "purchase was successfully sent to server");
}
logProductActivity(request.mProductId, "sending purchase request");
} else if (responseCode == ResponseCode.RESULT_USER_CANCELED) {
if (Consts.DEBUG) {
Log.i(TAG, "user canceled purchase");
}
logProductActivity(request.mProductId, "dismissed purchase dialog");
// This is line 187 right above this comment.
} else {
if (Consts.DEBUG) {
Log.i(TAG, "purchase failed");
}
logProductActivity(request.mProductId, "request purchase returned " + responseCode);
}
}
So you see, it keeps having a problem on this logging thing. What is this log? Where can I see it? How can I fix it so it doesn't make errors?
I am not certain, but maybe the bigger issue is that request is null. Why would the request possibly be null here?
Here is the entire ExtraHelpActivity class:
public class ExtraHelpActivity extends BaseActivity implements ServiceConnection
{
// , OnClickListener
private static final String TAG = "Pay";
String issueProductIdWebMarketing = "1";
String issueProductIdDonate = "2";
String issueProductIdPsych = "3";
/**
* The developer payload that is sent with subsequent
* purchase requests.
*/
private String payloadContents = null;
/**
* Used for storing the log text.
*/
private static final String LOG_TEXT_KEY = "DUNGEONS_LOG_TEXT";
/**
* The SharedPreferences key for recording whether we initialized the
* database. If false, then we perform a RestoreTransactions request
* to get all the purchases for this user.
*/
private static final String DB_INITIALIZED = "db_initialized";
private ExtraHelpPurchaseObserver mExtraHelpPurchaseObserver;
private Handler mHandler;
private Handler handler;
private BillingService mBillingService;
private Button mBuyButton;
private Button mEditPayloadButton;
private Button mEditSubscriptionsButton;
private TextView mLogTextView;
private Spinner mSelectItemSpinner;
private ListView mOwnedItemsTable;
private SimpleCursorAdapter mOwnedItemsAdapter;
private PurchaseDatabase mPurchaseDatabase;
private Cursor mOwnedItemsCursor;
private Set<String> mOwnedItems = new HashSet<String>();
/**
* The developer payload that is sent with subsequent
* purchase requests.
*/
private String mPayloadContents = null;
private static final int DIALOG_CANNOT_CONNECT_ID = 1;
private static final int DIALOG_BILLING_NOT_SUPPORTED_ID = 2;
private static final int DIALOG_SUBSCRIPTIONS_NOT_SUPPORTED_ID = 3;
/**
* Each product in the catalog can be MANAGED, UNMANAGED, or SUBSCRIPTION. MANAGED
* means that the product can be purchased only once per user (such as a new
* level in a game). The purchase is remembered by Android Market and
* can be restored if this application is uninstalled and then
* re-installed. UNMANAGED is used for products that can be used up and
* purchased multiple times (such as poker chips). It is up to the
* application to keep track of UNMANAGED products for the user.
* SUBSCRIPTION is just like MANAGED except that the user gets charged monthly
* or yearly.
*/
private enum Managed { MANAGED, UNMANAGED, SUBSCRIPTION }
/**
* A {#link PurchaseObserver} is used to get callbacks when Android Market sends
* messages to this application so that we can update the UI.
*/
private class ExtraHelpPurchaseObserver extends PurchaseObserver {
public ExtraHelpPurchaseObserver(Handler handler) {
super(ExtraHelpActivity.this, handler);
}
#Override
public void onBillingSupported(boolean supported, String type) {
if (Consts.DEBUG) {
Log.i(TAG, "supported: " + supported);
}
if (type == null || type.equals(Consts.ITEM_TYPE_INAPP)) {
if (supported) {
restoreDatabase();
mBuyButton.setEnabled(true);
mEditPayloadButton.setEnabled(true);
} else {
showDialog(DIALOG_BILLING_NOT_SUPPORTED_ID);
}
} else if (type.equals(Consts.ITEM_TYPE_SUBSCRIPTION)) {
mCatalogAdapter.setSubscriptionsSupported(supported);
} else {
showDialog(DIALOG_SUBSCRIPTIONS_NOT_SUPPORTED_ID);
}
}
#Override
public void onPurchaseStateChange(PurchaseState purchaseState, String itemId,
int quantity, long purchaseTime, String developerPayload) {
if (Consts.DEBUG) {
Log.i(TAG, "onPurchaseStateChange() itemId: " + itemId + " " + purchaseState);
}
if (developerPayload == null) {
logProductActivity(itemId, purchaseState.toString());
} else {
logProductActivity(itemId, purchaseState + "\n\t" + developerPayload);
}
if (purchaseState == PurchaseState.PURCHASED) {
mOwnedItems.add(itemId);
// If this is a subscription, then enable the "Edit
// Subscriptions" button.
for (CatalogEntry e : CATALOG) {
if (e.sku.equals(itemId) &&
e.managed.equals(Managed.SUBSCRIPTION)) {
mEditSubscriptionsButton.setVisibility(View.VISIBLE);
}
}
}
mCatalogAdapter.setOwnedItems(mOwnedItems);
mOwnedItemsCursor.requery();
}
#Override
public void onRequestPurchaseResponse(RequestPurchase request,
ResponseCode responseCode) {
if (Consts.DEBUG) {
Log.d(TAG, request.mProductId + ": " + responseCode);
}
if (responseCode == ResponseCode.RESULT_OK) {
if (Consts.DEBUG) {
Log.i(TAG, "purchase was successfully sent to server");
}
logProductActivity(request.mProductId, "sending purchase request");
} else if (responseCode == ResponseCode.RESULT_USER_CANCELED) {
if (Consts.DEBUG) {
Log.i(TAG, "user canceled purchase");
}
logProductActivity(request.mProductId, "dismissed purchase dialog");
} else {
if (Consts.DEBUG) {
Log.i(TAG, "purchase failed");
}
logProductActivity(request.mProductId, "request purchase returned " + responseCode);
}
}
#Override
public void onRestoreTransactionsResponse(RestoreTransactions request,
ResponseCode responseCode) {
if (responseCode == ResponseCode.RESULT_OK) {
if (Consts.DEBUG) {
Log.d(TAG, "completed RestoreTransactions request");
}
// Update the shared preferences so that we don't perform
// a RestoreTransactions again.
SharedPreferences prefs = getPreferences(Context.MODE_PRIVATE);
SharedPreferences.Editor edit = prefs.edit();
edit.putBoolean(DB_INITIALIZED, true);
edit.commit();
} else {
if (Consts.DEBUG) {
Log.d(TAG, "RestoreTransactions error: " + responseCode);
}
}
}
}
private static class CatalogEntry {
public String sku;
public int nameId;
public Managed managed;
public CatalogEntry(String sku, int nameId, Managed managed) {
this.sku = sku;
this.nameId = nameId;
this.managed = managed;
}
}
/** An array of product list entries for the products that can be purchased. */
private static final CatalogEntry[] CATALOG = new CatalogEntry[] {
new CatalogEntry("marketing_001", 1 , Managed.MANAGED),
new CatalogEntry("potion_001", 2 , Managed.UNMANAGED),
new CatalogEntry("subscription_monthly", 3,
Managed.SUBSCRIPTION),
new CatalogEntry("subscription_yearly", 4 ,
Managed.SUBSCRIPTION)
};
private String mItemName;
private String mSku;
private Managed mManagedType;
private CatalogAdapter mCatalogAdapter;
//outside onCreate() Within class
// 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()){
// //code here which is to be performed after successful purchase
// }
// };
//
// };
// TODO:
// TODO:
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.extra_help);
//Now setup the in-app billing</pre>
handler = new Handler();
mExtraHelpPurchaseObserver = new ExtraHelpPurchaseObserver(handler);
mBillingService = new BillingService();
mBillingService.setContext(this);
mPurchaseDatabase = new PurchaseDatabase(this);
ResponseHandler.register(mExtraHelpPurchaseObserver);
//Check if billing is supported. (Optional)
//boolean check = mBillingService.checkBillingSupported();
// startService(new Intent(mContext, BillingService.class));
// BillingHelper.setCompletedHandler(mTransactionHandler);
// Make sure the user is logged in
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences( ExtraHelpActivity.this);
final String user_id = prefs.getString( "user_id" , null );
Button donate = (Button)findViewById(R.id.donate);
donate.setOnClickListener(new Button.OnClickListener()
{
public void onClick(View v)
{
// Send me an email that a comment was submitted on a question.
// boolean val = mBillingService.requestPurchase(
// "android.test.purchased", payloadContents);
//Replace "android.test.purchased" with your product ID that you added to Google Play or make it a variable that is populated from a list.
//Place this code in a button event or where ever it fits in your process flow.
if (mBillingService.requestPurchase(issueProductIdDonate, Consts.ITEM_TYPE_INAPP , null))
{
}
else
{
Log.i("tag", "Can't purchase on this device");
}
}
});
try
{
boolean bindResult = bindService(
new Intent("com.android.vending.billing.MarketBillingService.BIND"),
this,
Context.BIND_AUTO_CREATE);
if (bindResult)
{
Log.i( "Err" , "Service bind successful.");
}
else
{
Log.e( "Err", "Could not bind to the MarketBillingService.");
}
}
catch (SecurityException e)
{
Log.e( "Err" , "Security exception: " + e);
}
}
/**
* Save the context of the log so simple things like rotation will not
* result in the log being cleared.
*/
#Override
protected void onSaveInstanceState(Bundle outState)
{
super.onSaveInstanceState(outState);
//outState.putString(LOG_TEXT_KEY, Html.toHtml((Spanned) mLogTextView.getText()));
}
/**
* Restore the contents of the log if it has previously been saved.
*/
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState)
{
super.onRestoreInstanceState(savedInstanceState);
if (savedInstanceState != null)
{
//mLogTextView.setText(Html.fromHtml(savedInstanceState.getString(LOG_TEXT_KEY)));
}
}
#Override
protected Dialog onCreateDialog(int id)
{
switch (id)
{
case DIALOG_CANNOT_CONNECT_ID:
return createDialog(1,1);
case DIALOG_BILLING_NOT_SUPPORTED_ID:
return createDialog(2,2);
case DIALOG_SUBSCRIPTIONS_NOT_SUPPORTED_ID:
return createDialog(3,3);
// case DIALOG_CANNOT_CONNECT_ID:
// return createDialog(R.string.cannot_connect_title,
// R.string.cannot_connect_message);
// case DIALOG_BILLING_NOT_SUPPORTED_ID:
// return createDialog(R.string.billing_not_supported_title,
// R.string.billing_not_supported_message);
// case DIALOG_SUBSCRIPTIONS_NOT_SUPPORTED_ID:
// return createDialog(R.string.subscriptions_not_supported_title,
// R.string.subscriptions_not_supported_message);
default:
return null;
}
}
private Dialog createDialog(int titleId, int messageId) {
String helpUrl = replaceLanguageAndRegion("help_url");
if (Consts.DEBUG) {
Log.i(TAG, helpUrl);
}
final Uri helpUri = Uri.parse(helpUrl);
// TODO: replace 1 with the thing its supposed to be - I think learn more url :)
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(titleId)
.setIcon(android.R.drawable.stat_sys_warning)
.setMessage(messageId)
.setCancelable(false)
.setPositiveButton(android.R.string.ok, null)
.setNegativeButton(1, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
Intent intent = new Intent(Intent.ACTION_VIEW, helpUri);
startActivity(intent);
}
});
return builder.create();
}
/**
* Replaces the language and/or country of the device into the given string.
* The pattern "%lang%" will be replaced by the device's language code and
* the pattern "%region%" will be replaced with the device's country code.
*
* #param str the string to replace the language/country within
* #return a string containing the local language and region codes
*/
private String replaceLanguageAndRegion(String str) {
// Substitute language and or region if present in string
if (str.contains("%lang%") || str.contains("%region%")) {
Locale locale = Locale.getDefault();
str = str.replace("%lang%", locale.getLanguage().toLowerCase());
str = str.replace("%region%", locale.getCountry().toLowerCase());
}
return str;
}
/**
* Sets up the UI.
*/
private void setupWidgets()
{
mOwnedItemsCursor = mPurchaseDatabase.queryAllPurchasedItems();
startManagingCursor(mOwnedItemsCursor);
String[] from = new String[] { PurchaseDatabase.PURCHASED_PRODUCT_ID_COL,
PurchaseDatabase.PURCHASED_QUANTITY_COL
};
// int[] to = new int[] { R.id.item_name, R.id.item_quantity };
// mOwnedItemsAdapter = new SimpleCursorAdapter(this, R.layout.item_row,
// mOwnedItemsCursor, from, to);
// mOwnedItemsTable = (ListView) findViewById(R.id.owned_items);
// mOwnedItemsTable.setAdapter(mOwnedItemsAdapter);
}
private void prependLogEntry(CharSequence cs) {
SpannableStringBuilder contents = new SpannableStringBuilder(cs);
contents.append('\n');
contents.append(mLogTextView.getText());
mLogTextView.setText(contents);
}
private void logProductActivity(String product, String activity) {
SpannableStringBuilder contents = new SpannableStringBuilder();
contents.append(Html.fromHtml("<b>" + product + "</b>: "));
contents.append(activity);
prependLogEntry(contents);
}
/**
* If the database has not been initialized, we send a
* RESTORE_TRANSACTIONS request to Android Market to get the list of purchased items
* for this user. This happens if the application has just been installed
* or the user wiped data. We do not want to do this on every startup, rather, we want to do
* only when the database needs to be initialized.
*/
private void restoreDatabase() {
SharedPreferences prefs = getPreferences(MODE_PRIVATE);
boolean initialized = prefs.getBoolean(DB_INITIALIZED, false);
if (!initialized) {
mBillingService.restoreTransactions();
Toast.makeText(this, 3, Toast.LENGTH_LONG).show();
// Used to be R.string.restoring_transactions instead of 3
}
}
/**
* Creates a background thread that reads the database and initializes the
* set of owned items.
*/
private void initializeOwnedItems() {
new Thread(new Runnable() {
public void run() {
doInitializeOwnedItems();
}
}).start();
}
/**
* Reads the set of purchased items from the database in a background thread
* and then adds those items to the set of owned items in the main UI
* thread.
*/
private void doInitializeOwnedItems() {
Cursor cursor = mPurchaseDatabase.queryAllPurchasedItems();
if (cursor == null) {
return;
}
final Set<String> ownedItems = new HashSet<String>();
try {
int productIdCol = cursor.getColumnIndexOrThrow(
PurchaseDatabase.PURCHASED_PRODUCT_ID_COL);
while (cursor.moveToNext()) {
String productId = cursor.getString(productIdCol);
ownedItems.add(productId);
}
} finally {
cursor.close();
}
// We will add the set of owned items in a new Runnable that runs on
// the UI thread so that we don't need to synchronize access to
// mOwnedItems.
mHandler.post(new Runnable() {
public void run() {
mOwnedItems.addAll(ownedItems);
mCatalogAdapter.setOwnedItems(mOwnedItems);
}
});
}
/**
* Called when a button is pressed.
*/
public void onClick(View v) {
if (v == mBuyButton) {
if (Consts.DEBUG) {
Log.d(TAG, "buying: " + mItemName + " sku: " + mSku);
}
if (mManagedType != Managed.SUBSCRIPTION &&
!mBillingService.requestPurchase(mSku, Consts.ITEM_TYPE_INAPP, mPayloadContents)) {
showDialog(DIALOG_BILLING_NOT_SUPPORTED_ID);
} else if (!mBillingService.requestPurchase(mSku, Consts.ITEM_TYPE_SUBSCRIPTION, mPayloadContents)) {
// Note: mManagedType == Managed.SUBSCRIPTION
showDialog(DIALOG_SUBSCRIPTIONS_NOT_SUPPORTED_ID);
}
} else if (v == mEditPayloadButton) {
showPayloadEditDialog();
} else if (v == mEditSubscriptionsButton) {
editSubscriptions();
}
}
/** List subscriptions for this package in Google Play
*
* This allows users to unsubscribe from this apps subscriptions.
*
* Subscriptions are listed on the Google Play app detail page, so this
* should only be called if subscriptions are known to be present.
*/
private void editSubscriptions() {
// Get current package name
String packageName = getPackageName();
// Open app detail in Google Play
Intent i = new Intent(Intent.ACTION_VIEW,
Uri.parse("market://details?id=" + packageName));
startActivity(i);
}
/**
* Displays the dialog used to edit the payload dialog.
*/
private void showPayloadEditDialog()
{
AlertDialog.Builder dialog = new AlertDialog.Builder(this);
final View view = View.inflate(this, R.layout.edit_payload, null);
final TextView payloadText = (TextView) view.findViewById(R.id.payload_text);
if (mPayloadContents != null) {
payloadText.setText(mPayloadContents);
}
dialog.setView(view);
dialog.setPositiveButton(
R.string.edit_payload_accept,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
mPayloadContents = payloadText.getText().toString();
}
});
dialog.setNegativeButton(
R.string.edit_payload_clear,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
if (dialog != null) {
mPayloadContents = null;
dialog.cancel();
}
}
});
dialog.setOnCancelListener(new DialogInterface.OnCancelListener(
oops.
mLogTextView is never initialised.
add mLogTextView = findViewById(R.id.blaaa);
I am sure you already know that
please tell me if i am wrong so that I delete this answer (:
Are you give permission in menifest file?
<uses-permission android:name="com.android.vending.BILLING" />
I am adding an answer because I reached the character limit in my original question since my class is so long.
This is the extra_help.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<include android:id="#+id/header"
layout="#layout/header"
android:layout_height="wrap_content"
android:layout_width="fill_parent"/>
<ScrollView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="5px">
<LinearLayout
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="5px"
>
<TextView
android:id="#+id/heading_1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textColor="#color/light_best_blue"
android:text="THE APP IS FREE TO HELP AS MANY PEOPLE AS POSSIBLE, PLEASE GIVE BACK"
/>
<Button
android:id="#+id/donate"
android:layout_marginTop ="10dp"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Donate $1.99 Since the App is Free"
/>
</LinearLayout>
</ScrollView>
</LinearLayout>