I am using: bp.isSubscribed(ID) to verify my subscription. But when I cancel a subscription the method bp.isSubscribed(ID) still returning true. What should I do?
transDetails.purchaseInfo.purchaseData.purchaseState.toString()
Always return PurchasedSuccessfully after i cancelled manually from play store manage subscription.
public void checkSubscriptionDetails(){
bp = new BillingProcessor(this, LICENSE_KEY, new BillingProcessor.IBillingHandler() {
#Override
public void onProductPurchased(#NonNull String productId, #Nullable TransactionDetails details) {
Common.printLog("InApp", ":onProductPurchased :" + productId);
}
#Override
public void onPurchaseHistoryRestored() {
}
#Override
public void onBillingError(int errorCode, #Nullable Throwable error) {
}
#Override
public void onBillingInitialized() {
}
});
boolean purchaseResult = bp.loadOwnedPurchasesFromGoogle();
// ## purchaseResult is always return FALSE
if (bp.isSubscribed(planID)) {
TransactionDetails transDetails = bp.getSubscriptionTransactionDetails(planID);
String strDetailsSubsMonth = "OrderID:" + transDetails.orderId +
"\nproductId: " + transDetails.productId +
"\npurchaseToken: " + transDetails.purchaseToken +
"\npurchaseTime: " + transDetails.purchaseTime +
"\npurchaseInfo.signature: " + transDetails.purchaseInfo.signature +
"\npurchaseInfo.responseData: " + transDetails.purchaseInfo.responseData +
"\npurchaseData.purchaseToken: " + transDetails.purchaseInfo.purchaseData.purchaseToken +
"\npurchaseData.autoRenewing: " + transDetails.purchaseInfo.purchaseData.autoRenewing +
"\npurchaseData.developerPayload: " + transDetails.purchaseInfo.purchaseData.developerPayload +
"\npurchaseData.purchaseState: " + transDetails.purchaseInfo.purchaseData.purchaseState.toString();
String strPurchaseState = transDetails.purchaseInfo.purchaseData.purchaseState.toString();
Common.printLog("InApp", "Details: " + planID + " >> " + strDetailsSubsMonth + " \n" + "Purchase State :" + strPurchaseState);
}
}
package com.anjlab.android.iab.v3;
public enum PurchaseState
{
PurchasedSuccessfully,
Canceled,
Refunded,
SubscriptionExpired
}
i need return "Canceled" when subscription canceled.
Initiate bp varibale in onCreate() and then call loadOwnedPurchasesFromGoogle().
In my case!
Don't know why we need to Call loadOwnedPurchasesFromGoogle() for multiple time. I always get false when I call in loadOwnedPurchasesFromGoogle() in onCreate(). But when I call in onPause() and onDestory(), I get true and my all values get update.
After getting loadOwnedPurchasesFromGoogle() true, I get update subscription value!
Best Solution from Server side get actual information for subscription or you can cross verify by Node.js configuration.
https://caster.io/lessons/verify-android-app-subscription-status-from-nodejs
Related
I have new requirement, I am creating REST API which has dynamic request (actions) and I want to convert that JSON request to POJO, I know how to convert JSON to POJO where key's are same, but not sure what to do when there are different content on objects.
My Json is as follow.
{
"name":"Workflow",
"actions": [
{
"name": "EDIT_PROPERTY",
"payload": {
"name": "city",
"value": "Pune"
}
},
{
"name":"SEND_EMAIL",
"payload":{
"from":"no-reply#yaho.com",
"to":"alpesh#yahoo.com",
"subject":"Try email",
"body":"content"
}
},
{
"name":"CREATE_TASK",
"payload":{
"user":1,
"type":"call",
"status":"open",
"note":"This is note content"
}
}
]
}
As you can see actions are set of Objects which has name and payload, now payload has different fields, I have predefined names. and each payload under action has predefined keys as you see.
I want to convert this to POJO something like
class Workflow{
String name;
Set<Action> actions;
}
class Action {
String name;
//What to add as payload
}
Thanks
Alpesh
This is what you can do :
JSON to POJO model :
#Data
#JsonInclude(JsonInclude.Include.NON_NULL)
public class Event {
public String name;
public List<Action> actions;
#Data
public static class Action {
public String name;
Map<String, Object> payload;
}
}
public class TestJson {
private static String json = "{\n" +
" \"name\":\"Workflow\",\n" +
" \"actions\": [\n" +
" {\n" +
" \"name\": \"EDIT_PROPERTY\",\n" +
" \"payload\": {\n" +
" \"name\": \"city\",\n" +
" \"value\": \"Pune\"\n" +
" }\n" +
" },\n" +
" {\n" +
" \"name\":\"SEND_EMAIL\",\n" +
" \"payload\":{\n" +
" \"from\":\"no-reply#yaho.com\",\n" +
" \"to\":\"alpesh#yahoo.com\",\n" +
" \"subject\":\"Try email\",\n" +
" \"body\":\"content\"\n" +
" }\n" +
" },\n" +
" {\n" +
" \"name\":\"CREATE_TASK\",\n" +
" \"payload\":{\n" +
" \"user\":1,\n" +
" \"type\":\"call\",\n" +
" \"status\":\"open\",\n" +
" \"note\":\"This is note content\"\n" +
" }\n" +
" }\n" +
" ]\n" +
"}";
#SneakyThrows
public static void main(String[] args) {
ObjectMapper objectMapper = new ObjectMapper();
Event event = objectMapper.readValue(json, Event.class);
System.out.println(event);
}
}
When debugging, you'll notice that our objects have been filled accordingly:
Well, generally, I prefer any solution that does not involve Component Annotations. This is my own personal preference because eliminating constructors and method parameters is usually a giant headache. This is based on 1999 - 2006 Java Programming experience. If you have a need to dynamically generate classes and constructors or getters, then you may easily ignore or delete this answer. For me, JSON Parsing is practice right now.
In this posted answer, I have used the older Java JSON Library whose JavaDoc may be viewed here: javax.json.*. Here is my solution. It requires / expects that you write:
Your own toString() methods for your JSON Data Classes
Your own retrieve operations
The following code has output, and that is included at the end of this post. Usually I include a lot of Code Documentation. However, when the code is strictly parsing data, the code itself is usually so legible that more comments would clutter the retrieve and the toString() operations, so I have left them as is.
import java.util.*;
import javax.json.*;
import java.io.*;
public class Messages
{
public abstract static class Action
{
public final String name;
public Action(String name) { this.name=name; }
}
public static class EditProperty extends Action
{
public final String propName, propValue;
public EditProperty(String name, String value)
{ super("EDIT_PROPERTY"); this.propName=name; this.propValue=value; }
public String toString()
{
return
"Action: " + name + '\n' +
"Name: " + propName + '\n' +
"Value: " + propValue + '\n';
}
}
public static class SendEmail extends Action
{
public final String from, to, subject, body;
public SendEmail(String from, String to, String subject, String body)
{ super("SEND_EMAIL"); this.from=from; this.to=to; this.subject=subject; this.body=body; }
public String toString()
{
return
"Action: " + name + '\n' +
"From: " + from + '\n' +
"To: " + to + '\n' +
"Subject: " + subject + '\n' +
"Body: " + body + '\n';
}
}
public static class CreateTask extends Action
{
public final int user;
public final String type, status, note;
public CreateTask(int user, String type, String status, String note)
{ super("CREATE_TASK"); this.user=user; this.type=type; this.status=status; this.note=note; }
public String toString()
{
return
"Action: " + name + '\n' +
"User: " + user + '\n' +
"Type: " + type + '\n' +
"Status: " + status + '\n' +
"Note: " + note + '\n';
}
}
public static void main(String[] argv) throws IOException
{
Vector<Action> actions = new Vector<>();
Reader r = new FileReader("in.json");
JsonArray actionList = Json
.createReader(r)
.readObject()
.getJsonArray("actions");
for (JsonObject actionObj : actionList.getValuesAs(JsonObject.class))
{
JsonObject payload = actionObj.getJsonObject("payload");
Action action = null;
switch (actionObj.getString("name"))
{
case "EDIT_PROPERTY" : action = new EditProperty(
payload.getString("name"),
payload.getString("value")
); break;
case "SEND_EMAIL" : action = new SendEmail(
payload.getString("from"),
payload.getString("to"),
payload.getString("subject"),
payload.getString("body")
); break;
case "CREATE_TASK" : action = new CreateTask(
payload.getInt("user"),
payload.getString("type"),
payload.getString("status"),
payload.getString("note")
); break;
}
actions.add(action);
}
for (Action action : actions) System.out.println(action);
}
}
The class and inner-classes above would produce this output when invoked at the command line:
#cloudshell:~$ java Messages
Action: EDIT_PROPERTY
Name: city
Value: Pune
Action: SEND_EMAIL
From: no-reply#yaho.com
To: alpesh#yahoo.com
Subject: Try email
Body: content
Action: CREATE_TASK
User: 1
Type: call
Status: open
Note: This is note content
The JSON you show is actually a list of one object type;
specifically, the payload is just a Map of String to Object.
Once you parse the JSON,
your code will need to process each "different" payload type
based on the payload type.
Here is some sample code:
public class BlamMessage
{
private String name;
private Map<String, Object> payload;
...
}
public class MessageHolder
{
#JsonProperty("actions")
private List<BlamMessage> messageList;
private String name;
...
}
Here is my json URL https://jsonplaceholder.typicode.com/todos I want to display only completed: true is to be strike through, how can I do that?
MainActivity.java
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://jsonplaceholder.typicode.com/")
.addConverterFactory(GsonConverterFactory.create())
.build();
JsonPlaceHolderApi jsonPlaceHolderApi = retrofit.create(JsonPlaceHolderApi.class);
Call<List<Post>> call = jsonPlaceHolderApi.getPosts();
call.enqueue(new Callback<List<Post>>() {
#Override
public void onResponse(Call<List<Post>> call, Response<List<Post>> response) {
if (!response.isSuccessful()) {
textresult.setText("Code: " + response.code());
return;
}
List<Post> posts = response.body();
for (Post post : posts) {
String content = "";
content += "User ID: " + post.getUserId() + "\n";
content += "ID: " + post.getId() + "\n";
content += " Title: " + post.getTitle() + "\n";
content += "Completed: " + post.getCompleted() + "\n\n";
textresult.append(content);
if (post.getCompleted().contains("true")) {
textresult.setPaintFlags(textresult.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
}
}
}
#Override
public void onFailure(Call<List<Post>> call, Throwable t) {
textresult.setText(t.getMessage());
}
});
JsonPlaceHolderApi.java
public interface JsonPlaceHolderApi {
#GET("todos")
Call<List<Post>> getPosts();
}
Post.java
public class Post {
private int userId;
private int id;
private String title;
private String completed;
public int getUserId() {
return userId;
}
public int getId() {
return id;
}
public String getTitle() {
return title;
}
public String getCompleted() {
return completed;
}
}
When I try to run the above code I got output as image, but I need if completed: true it should be strike.
it is not possible to do setPaintFlags() with custom text better use can use HTML text for your work for you don't need to check "post.complete()", just append all content in a single string and replace your target string (complete: true) with HTML text.
just do it like
String content = "";
for (Post post : posts) {
content += "User ID: " + post.getUserId() + "\n";
content += "ID: " + post.getId() + "\n";
content += " Title: " + post.getTitle() + "\n";
content += "Completed: " + post.getCompleted() + "\n\n";
}
String tempHtmlText = content.replaceAll("Completed: true","<strike>Completed: true</strike>");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
textresult.setText(Html.fromHtml(tempHtmlText , Html.FROM_HTML_MODE_LEGACY));
} else {
textresult.setText(Html.fromHtml(tempHtmlText));
}
or you can use Gson formmater
I'm trying to send a file from the phone to the wear app, on the phone I'm sending the file as follows with a successful status.
NodeApi.GetConnectedNodesResult nodesResult = Wearable.NodeApi.getConnectedNodes(mGoogleApiClient).await();
for (Node node : nodesResult.getNodes()) {
ChannelApi.OpenChannelResult result = Wearable.ChannelApi.openChannel(mGoogleApiClient, node.getId(), "/songs").await();
Channel channel = result.getChannel();
File file = new File(AppUtils.getDownloadsDir(getApplicationContext()),"lift.mp3");
Log.d(TAG, "call: " + file.canRead() + Uri.fromFile(file) + file.length());
channel.sendFile(mGoogleApiClient, Uri.fromFile(file)).setResultCallback(
new ResultCallback<Status>() {
#Override
public void onResult(#NonNull Status status) {
Log.d(TAG, "onResult: " + status.isSuccess() + " " + status.getStatusMessage());
}
}
);
Log.d(TAG, "Node " + node.getId() + node.getDisplayName() + node.isNearby());
}
On the wear side however, onChannelOpened is getting called with the correct path, I create a file, but when calling Channel.receiveFile I get a status code of 8 (INTERNAL_ERROR) in the resultCallback status.
public void onChannelOpened(final Channel channel) {
if (channel.getPath().equals("/songs")) {
try {
final File outFile = prepareFile("wild.mp3");
if (outFile == null || !outFile.exists()) {
Log.d(TAG, "Failed to create file ");
return;
}
Log.d(TAG, "onChannelOpened: " + mGoogleApiClient.isConnected());
channel.receiveFile(mGoogleApiClient, Uri.fromFile(outFile), false).setResultCallback(
new ResultCallback<Status>() {
#Override
public void onResult(#NonNull Status status) {
int statusCode = status.getStatusCode();
if (!status.isSuccess()) {
Log.e(TAG, "receiveFile(): Failed to receive file with "
+ "status code = " + statusCode
+ ", and status: " + status.getStatus());
...
Fixed. The application id was already the same when this was happening, however the key stores in signingConfigs were different in the wear module and the mobile module, making them the same solved the problem.
So I'm following the instructions for creating a Crosswalk extension on https://crosswalk-project.org/documentation/embedding_crosswalk/extensions.html. My question relates to extending the XWalkExtension class.
package org.crosswalkproject.sample;
import org.xwalk.core.XWalkExtension;
public class ExtensionEcho extends XWalkExtension {
private static String name = "echo";
private static String jsapi = "var echoListener = null;" +
"extension.setMessageListener(function(msg) {" +
" if (echoListener instanceof Function) {" +
" echoListener(msg);" + " };" + "});" +
"exports.echo = function (msg, callback) {" +
" echoListener = callback;" + " extension.postMessage(msg);" +
"};" + "exports.echoSync = function (msg) {" +
" return extension.internal.sendSyncMessage(msg);" + "};";
public ExtensionEcho() {
super(name, jsapi);
}
#Override
public void onMessage(int instanceID, String message) {
postMessage(instanceID, "From java: " + message);
}
#Override
public String onSyncMessage(int instanceID, String message) {
return "From java sync: " + message;
}
}
When extending the XWalkExtension class, how can you get the android application context? Hence, if I wanted to create a Toast message, I can pass in the context.
There isn't a publicly documented interface to get the Activity from XWalkExtension. You can modify the constructor to store a private reference to an Activity, then simply pass it in from where you instantiate the extension.
public class ExtensionEcho extends XWalkExtension {
private final Activity activity;
public ExtensionEcho(Activity activity) {
this.activity = activity;
}
...
}
When reading up on the play2 documentation I found this:
Because of the way Play 2.0 works, action code must be as fast as
possible (i.e. non blocking). So what should we return as result if we
are not yet able to compute it? The response should be a promise of a
result!
Wow! This of course made me interested in playakka and akka.
I'm currently building an autocomplete application that is integrating with elasticsearch,
so this would be a perfect fit!
Controller:
public class AutoComplete extends Controller {
#BodyParser.Of(value = BodyParser.Json.class)
public static Result complete(final String term) {
F.Promise<List<String>> list = Akka.future(new Callable<List<String>>() {
public List<String> call() throws Exception {
List<String> list = IndexService.find(term);
return list;
}
});
return async(list.map(new F.Function<List<String>, Result>() {
#Override
public Result apply(List<String> list) throws Throwable {
return ok(Json.toJson(list));
}
}));
}
Service:
public static List<String> find(final String term) {
IndexQuery < SearchWord > query = SearchWord.find.query();
query.setQuery("{\n" +
" \"bool\": {\n" +
" \"should\": [\n" +
" {\n" +
" \"text\": {\n" +
" \"search_word.ngrams\": {\n" +
" \"operator\": \"and\",\n" +
" \"query\": \""+term+"\"\n" +
" }\n" +
" }\n" +
" },\n" +
" {\n" +
" \"text\": {\n" +
" \"search_word.full\": {\n" +
" \"boost\": 1,\n" +
" \"query\": \""+term+"\"\n" +
" }\n" +
" }\n" +
" }\n" +
" ]\n" +
" }\n" +
"}");
IndexResults<SearchWord> indexResults = SearchWord.find.search(query);
List<String> list = new ArrayList<String>();
for(SearchWord word : indexResults.getResults()){
list.add(word.getWord());
}
return list;
}
}
SearchWord:
#IndexType(name = "search_word")
public class SearchWord extends Index {
// Find method static for request
public static Index.Finder<SearchWord> find = new Index.Finder<SearchWord>(SearchWord.class);
public enum WordType {
NAME,
STRONG_SEARCH_WORD,
WEAK_SEARCH_WORD,
BANNED
}
private String word;
private WordType wordType;
public SearchWord() {
}
public SearchWord(IndexWord indexWord) {
super.id = ""+indexWord.getId();
this.word = StringUtils.lowerCase(indexWord.getWord());
this.wordType = WordType.valueOf(indexWord.getType());
}
public String getId() {
return super.id;
}
public void setId(String id) {
super.id = id;
}
public String getWord() {
return word;
}
public void setWord(String word) {
this.word = word;
}
public WordType getWordType() {
return wordType;
}
public void setWordType(WordType wordType) {
this.wordType = wordType;
}
#Override
public Map toIndex() {
HashMap map = new HashMap();
map.put("id", super.id);
map.put("word", word);
map.put("word_type", wordType.toString());
return map;
}
#Override
public Indexable fromIndex(Map map) {
if (map == null) {
return this;
}
this.word = (String) map.get("word");
this.wordType = WordType.valueOf((String)map.get("word_type"));
return this;
}
}
The code works very well but I must say that I'm not that sure that I have implemented this correctly. I'm really struggling to understand the documentation.
So my questions are basically:
Have I implemented the Future and Promise correctly?
Would it be better to create a custom actor, and in that actor perform the index
search, like the example in the docs:
=====
return async(
Akka.asPromise(ask(myActor,"hello", 1000)).map(
new Function<Object,Result>() {
public Result apply(Object response) {
return ok(response.toString());
}
}
)
);
Maybe you have some great example that I have not found yet?
AFAIK, your code is totally ok.
I may be wrong, but I think that the second option is strictly equivalent to the first one, since the Akka.future() method is a wrapper around the Akka.promise() method.
From the Akka class source code of Play 2.0.4:
/**
* Executes a block of code asynchronously in the application Akka Actor system.
*/
public static <T> Promise<T> future(java.util.concurrent.Callable<T> callable) {
return asPromise(akka.dispatch.Futures.future(callable, system().dispatcher()));
}
Although you have correctly implemented the Promise and Future, i wouldn't consider this code to be "non-blocking"...
It seems that the blocking call is
List<String> list = IndexService.find(term);
and although this is now wrapped in a promise/future, it is still a blocking call...
If you want to be truly non-blocking (with all its benefits), you'll have to make your data access (queries) non-blocking...
Oh, and a non-blocking action method should return a Promise of a Result, not a Result...
This is how i should write your code:
#BodyParser.Of(value = BodyParser.Json.class)
public static F.Promise<Result> complete(final String term) {
scala.concurrent.Future<List<String>> listFuture = IndexService.find(term);
F.Promise<List<String>> listPromise = F.Promise.wrap(listFuture);
return listPromise.map(new F.Function<List<String>, Result>() {
#Override
public Result apply(List<String> list) throws Throwable {
return ok(Json.toJson(list));
}
});
}
Hope this helps!