OnRealTimeMessageSent callback not being fired reliably? - android

With Google Play Game Services, I'm trying to implement a CallBack such that, if there is an issue with sending a message, then I need to resolve it (as each player "passes" their bid to the next player, and all other players need to see what the player that passed bid)
I thought I would try and use the following to instantiate a RealTimeReliableMessageSentListener for that round of messages, so that I can tell if the message was sent and received by everyone:
(I add the tokenID returned by the call to an ArrayList, and then check off remove each tokenID as it comes back in to track when all messages from this round are received)
#Override
public void sendReadyToPlay() {
dLog("Sending ReadyToPlay");
// Broadcast that I'm ready, and see that they are ready
if (!mMultiplayer){
return; // playing against computer
}
// First byte in message indicates whether it's a final score or not
mMsgBuf[0] = (byte) ('R');
readyToPlayTokens.clear();
// Send to every other participant.
for (Participant p : mParticipants) {
dLog("Participant:" + p.getParticipantId());
if (p.getParticipantId().equals(mMyId)) {
continue;}
if (p.getStatus() != Participant.STATUS_JOINED){
continue;
}
readyToPlayTokens.add(mHelper.getGamesClient().sendReliableRealTimeMessage(new RealTimeReliableMessageSentListener() {
#Override
public void onRealTimeMessageSent(int statusCode, int tokenId, String recipientParticipantId){
dLog("onRealTimeMessageSent number two and size is: " + readyToPlayTokens.size());
if(readyToPlayTokens.contains(tokenId)){
readyToPlayTokens.remove(tokenId);
}
dLog("onRealTimeMessageSent number two and size is: " + readyToPlayTokens.size());
if (statusCode != GamesClient.STATUS_OK) {
mGHInterface.onRealTimeMessageReceived("RTPProblem:" + recipientParticipantId);
} else if (readyToPlayTokens.size() == 0) {
mGHInterface.beginRound();
}
}
}, mMsgBuf, mRoomId, p.getParticipantId()));
dLog("sent to:" + p.getParticipantId());
}
}
I can see the messages coming in almost every time from one device to another, so I can see that the messages are going through, BUT, the RealTimeReliableMessageSent listener is only being fired about 50-60 percent of the time, which isn't very reliable! :)
Can anyone see what I might be doing wrong to keep the listener from firing reliably?

may be it happens because you are using anonymous inner class, try to use in different way like implementing your activity RealTimeReliableMessageSentListener

Related

get last arraylist position before streak gets interrupted

https://www.google.com/search?q=message+image+on+last&sxsrf=ALeKk01qNrLQ61yRXCMSPRxyNaoI0MF_kA:1605295893515&source=lnms&tbm=isch&sa=X&ved=2ahUKEwjj2veboYDtAhWeIbcAHebnB4QQ_AUoAXoECAwQAw&biw=1366&bih=657#imgrc=wzgnznL_g7kUsM
I want to show profile image like shown in above link only at last message of every consecutive messages from same person. Please help me with this.
I have tried many ways but I don't know to hide visibility of top images
if (position > 0) {
if (messageList.get(i).getFrom.equalsIgnoreCase(messagesList.get(position - 1).getFrom()))
{
viewHolder.mProfileImage.setVisibility(View.INVISIBLE);
}
else
{
viewHolder.mProfileImage.setVisibility(View.VISIBLE);
}
}
else
{
viewHolder.mProfileImage.setVisibility(View.VISIBLE);
}
I have used above code and get this result which is shown in this http://i.stack.imgur.com/92SUb.jpg link. With this code I am able to hide all the images other than the first one image. can you please show me the way to hide top message image and not the last one of streak.
I have to assume few things in my answer.
i.e.
messageList is the list of all messages. not the list of only consecutive/streak messages.
you need to show profile images for both sender and receiver.
And you want to only show the profileImage of last consecutive message.
So, here what you should do.
int length = messageList.lenght; //getTotalLenght;
String fromCurrent = messageList[position].getFrom(); //getFrom of current message being painted or shown
String fromNext = fromCurrent; //next message is set to current by default, to avoid error
if(length > postition+1) {
fromNext = messageList[position+1].getFrom(); //if there is next message then get its sender but if it is the last message then nextSender and currentSender are same as I set its default value to the currentSender.
}
console.log("TAG", "FromNext: " + fromNext);
console.log("TAG", "FromCurrent: " + fromCurrent);
if(!fromCurrent.equals(fromNext)) { //checking if last message or not
viewHolder.mProfileImage.setVisibility(View.VISIBLE);
}
else {
viewHolder.mProfileImage.setVisibility(View.INVISIBLE);
}

Android Wear passing data from Activity back to watchface service

I have an Android Wear watch face created, an interactive one. On the face I have a grid area where I listen for an onTapCpmmand:
else if (x >= x6 & x <= x9 & y >= (y5 - (gridYUnit / 2)) & y <= (y8 - (gridYUnit / 2))) {
activityLaunched = new Intent(MyWatchFace.this, ActivityLaunched.class);
activityLaunched .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(activityLaunched );
}
The mew activity then takes over. Within this activity, I have three options, basically ImageButtons, with respective onClickHandlers:
optionOne.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
confirmationIntent = new Intent(ActivityLaunched.this, ConfirmationActivity.class);
confirmationIntent .putExtra(ConfirmationActivity.EXTRA_ANIMATION_TYPE,
ConfirmationActivity.SEARCH_SERVICE);
confirmationIntent .putExtra(ConfirmationActivity.EXTRA_MESSAGE,
getString(R.string.option_one));
currentOption = "1";
broadcastIntent(currentOption);
startActivity(confirmationIntent );
ActivityLaunched.this.finish();
}
});
With broadcastIntent handling the broadcast:
public void broadcastIntent(String currentOption){
Intent optionUpdated = new Intent();
optionUpdated .setAction("com.example.packagename....");
optionUpdated .putExtra("Option", currentOption);
sendBroadcast(optionUpdated );
}
The users selects an options, the activity closes and the flow of control passes to my broadcastReceiver.
Now, I had set up a broadcastReceiver to make a simple toast when an option has been selected. However, I am unable to do any more with this data, other than show a toast.
Within my broadcastReceiver:
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "Option Updated." + intent.getStringExtra("Option"), Toast.LENGTH_LONG).show();
currentOption = intent.getStringExtra("Option");
sendOption .setAction("com.example.packagename....");
sendOption tion.putExtra("Option", currentOption );
context.sendBroadcast(sendOption );
Log.d(TAG, "THIS WORKS : " + currentOption );
}
In my WatchFaceService, I have registered the receiver along with the batteryinforeceivers, and any other system ones, as normal. I am receiving the messages within my broadcastReceiver
Back again to my WatchFaceService, it's where I'm getting issues, I'm not receiving any updates:
optionUpdateReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Bundle results = getResultExtras(true);
String option = results.getString("Option");
Log.d(TAG, " NOTHING SHOWING HERE " + currentOption + option );
}
};
I have tried using setters and getters, which required a second launch of the activity to get the real value.
Any ideas as to what I am doing wrong?
I've tried following some other answers and ideas here, as well as other external sources. But as it's Android Wear I'm working with, as volatile as the OS is, anything I tried, that was suggested that worked for Android, appears to be ineffective for Android Wear.
Thanks, Emmett
Your watch face service is not guaranteed to be running when there another activity on top of it. It might be preserved, but equally likely it might be torn down. You could try to register your receiver in WatchFaceService.onCreate() and WatchFaceService.onDestroy(), but that's not a way that is guaranteed to work.
Instead, inside the Activity save the information into SharedPreferences and then read the information within you watch face. When your watch face is created, read the value from the prefs (you can also have a listener for the preferences, to update on their change when they change while the watch face is already launched).
I've actually managed to solve it.
I created a second broadcastreceiver, passed this back to the watchface, and then overrode the register / unregister methods to handle the transmission.
Initially, when I had registered the second receiver, it was spamming the log files and crashing the watch. The reason I had to override was to handle the passing of a filter, which cannot be done from within a watchfacecanvas.engine for some strange reason.
Anyway, it's working fine now, but thanks for help

Couple questions about how to implement turn by turn based games in google game service

I have a couple questions of how to implement google game services in my app.
First of all, after I checked that the user is signed in and the client is connected, I launch
Intent intent = Games.TurnBasedMultiplayer.getSelectOpponentsIntent(mGoogleApiClient, 1, 1, true);
startActivityForResult(intent, RC_SELECT_PLAYERS);
To show the user a dialog where they can select the opponent.
After I get the result from the activity I execute this code
if (request == RC_SELECT_PLAYERS) {
Log.e(LOG_TAG, "Got RC_SELECT_PLAYERS result intent");
if (response != Activity.RESULT_OK) {
// user canceled
return;
}
// Get the invitee list.
final ArrayList<String> invitees = data.getStringArrayListExtra(Games.EXTRA_PLAYER_IDS);
// Get auto-match criteria.
Bundle autoMatchCriteria;
int minAutoMatchPlayers = data.getIntExtra(Multiplayer.EXTRA_MIN_AUTOMATCH_PLAYERS, 0);
int maxAutoMatchPlayers = data.getIntExtra(Multiplayer.EXTRA_MAX_AUTOMATCH_PLAYERS, 0);
if (minAutoMatchPlayers > 0) {
autoMatchCriteria = RoomConfig.createAutoMatchCriteria(minAutoMatchPlayers, maxAutoMatchPlayers, 0);
} else {
autoMatchCriteria = null;
}
TurnBasedMatchConfig turnBasedMatchConfig = TurnBasedMatchConfig.builder()
.addInvitedPlayers(invitees)
.setAutoMatchCriteria(autoMatchCriteria)
.build();
// Create and start the match.
Games.TurnBasedMultiplayer
.createMatch(mGoogleApiClient, turnBasedMatchConfig)
.setResultCallback(new MatchInitiatedCallback());
}
To initiate the match. The problem is, the opponent I challenged doesn't get any notification where he is asked to join the game. So when the user gets a notification to join a game, how can I catch this notification and show the user the appropriate content? Which intent result should I look for?
In my MatchInitiatedCallback I check which turn it is now:
public class MatchInitiatedCallback implements ResultCallback<TurnBasedMultiplayer.InitiateMatchResult> {
private static final String LOG_TAG = "MatchInitiatedCallback";
#Override
public void onResult(TurnBasedMultiplayer.InitiateMatchResult result) {
// Check if the status code is not success.
Status status = result.getStatus();
if (!status.isSuccess()) {
Log.e(LOG_TAG, "showError() " + status.toString());
//showError(status.getStatusCode());
return;
}
TurnBasedMatch match = result.getMatch();
// If this player is not the first player in this match, continue.
if (match.getData() != null) {
Log.e(LOG_TAG, "Not my turn");
//showTurnUI(match);
return;
}
// Otherwise, this is the first player. Initialize the game state.
//initGame(match);
Log.e(LOG_TAG, "initGame()");
// Let the player take the first turn
//showTurnUI(match);
Log.e(LOG_TAG, "showTurnGui()");
}
}
But this code gets executed even before my opponent selects to join.
Shouldn't he first be able to accept or decline the game?
Can someone please tell me if I'm doing this properly or if this is supposed to be like this? If not, how should it be implemented correctly?
EDIT: I took all this code from the documentation. It does show some code samples of how to implement things, but not of how the code all comes together and the order in which things should be executed, or how to handle notifications and such.
Yes, it is supposed to work like this. You must take a turn before the opponent actually receives the invitation. In fact, if you invite several opponents, each of them will have to accept the invitation and take a turn before the next opponent is invited, meaning it can take quite a while before you know whether you actually got a match going.
To avoid asking the users to take turns during the invitation phase, your program can take a dummy turn for each user to pass the invitation to the next user. When all users have joined you can start to take real turns.

Android Google Play Games Services Turn based Multiplayer not Automatching

I'm trying to develop a simple Turn based multiplayer game in android using Play games services. I followed all the steps in the docs: https://developers.google.com/games/services/android/turnbasedMultiplayer#implementing_auto-matching The only difference is that I don't want my players to be able to invite friends I want it to be purely Automatching. The game is only 2 player and it can only start ONCE 2 players have been matched. My problem is it doesn't seem to be automatching players. I run the app on 2 devices and they never seem to find each other... They both connect to the Play Games Services fine but they both just create a new game. Here is my code after I connect the GoogleApiClient.
#Override
public void onConnected(Bundle bundle) {
pDialog.dismiss();
Toast.makeText(this, "Connected", Toast.LENGTH_LONG).show();
showDialog("Matching players");
Bundle autoMatchCriteria = RoomConfig.createAutoMatchCriteria(1,1,0);
TurnBasedMatchConfig tbmc=TurnBasedMatchConfig.builder().
setAutoMatchCriteria(autoMatchCriteria).build();
Games.TurnBasedMultiplayer.createMatch(mGoogleApiClient,
tbmc).setResultCallback(new MatchInitiatedCallback(this));
}
Here is my MatchInitiatedCallback
public class MatchInitiatedCallback implements
ResultCallback<TurnBasedMultiplayer.InitiateMatchResult> {
private Context context;
public MatchInitiatedCallback(Context c) {
context = c;
}
#Override
public void onResult(TurnBasedMultiplayer.InitiateMatchResult
initiateMatchResult) {
pDialog.dismiss();
if(!initiateMatchResult.getStatus().isSuccess()) {
Toast.makeText(context, "ERROR: " +
initiateMatchResult.getStatus().getStatusCode(), Toast.LENGTH_LONG).show();
return;
}
TurnBasedMatch match = initiateMatchResult.getMatch();
if(match.getData() != null) {
Toast.makeText(context, "Player2 " + match.getData().toString(),
Toast.LENGTH_LONG).show();
} else {
Toast.makeText(context, "Player1", Toast.LENGTH_LONG).show();
initGame(match);
}
}
}
Both devices show the TOAST that says: "Player1" and call the initGame(match) method which is here:
public void initGame(TurnBasedMatch match) {
String initialise = "initialised";
Games.TurnBasedMultiplayer.takeTurn(mGoogleApiClient,
match.getMatchId(),initialise.getBytes(Charset.forName("UTF-16")),
match.getParticipantId(Games.Players.getCurrentPlayerId(mGoogleApiClient))).
setResultCallback(this);
}
#Override
public void onResult(TurnBasedMultiplayer.UpdateMatchResult
updateMatchResult) {
if(updateMatchResult.getMatch().getStatus() ==
TurnBasedMatch.MATCH_STATUS_AUTO_MATCHING) {
Toast.makeText(this, "Still automatching",
Toast.LENGTH_LONG).show();
} else {
Toast.makeText(this, "Not automatching", Toast.LENGTH_LONG).show();
}
}
And once again they both Display the TOAST: "Still automatching"
What am I doing wrong. Why don't the devices automatch. Did I skip a step somewhere. Please help.
Try to change your initGame method so it specifies null for the next participant (to let Play Game services find a player for auto-matching):
public void initGame(TurnBasedMatch match) {
String initialise = "initialised";
Games.TurnBasedMultiplayer.takeTurn(
mGoogleApiClient,
match.getMatchId(),
initialise.getBytes(Charset.forName("UTF-16")),
null
).setResultCallback(this);
}
Also make sure to use two different google+ accounts on the two devices.
I tried your code and both devices said "Player1" and "Not automatching"(!). After changing to null, first device said "Player1" and "Still automatching" and second device said "Player2 [B#41b08830"
I think your problem is due to the way invitations as well as auto matching is handled by Play Game services. When hooking up participants to a TurnBasedMultiplayer match, invitations are sent to participants one by one. When you call takeTurn in the initGame method, you must specify the next participant to receive an invitation. When that participant has accepted the invitation, he must call takeTurn and specify the next participant to receive an invitation and so on. If you specify null, it means the next invitation goes to an automatched player.

Android In-app Billing, how confirm that product was downloaded

I trying use Dungeons example in my app. In Android development guide it's written that I should confirm delivery product to user sending CONFIRM_NOTIFICATIONS to market, but I don't see it in example or am I wrong? Should I confirm download and my app should remember if content was successfully delivered?
Where is the best place to invoke downloading, in activity using AsyncTask, in ResponseHandler class or different?
This is something that I've been wondering about today too. From what I can see, in the Dungeons example, when BillingService#purchaseStateChanged is called, it automatically acknowledges all notifications after verifying the purchases.
See lines 506-509 in the example BillingService.java:
if (!notifyList.isEmpty()) {
String[] notifyIds = notifyList.toArray(new String[notifyList.size()]);
confirmNotifications(startId, notifyIds);
}
The solution would appear to be relocating this logic to a place you can manually call when you have completed delivery of your content.
I'm planning to remove that code and make the BillingService#confirmNotifications public so I can call it from my PurchaseObserver implementation when I've delivered my content.
I'll update with the result, but it seems to be a good starting point.
I hope Following Code helps u.
#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);
Log.v("log_tag", "Item Purchased");
}
mCatalogAdapter.setOwnedItems(mOwnedItems);
mOwnedItemsCursor.requery();
}
In Log if you get "Item Purchased" it indicates that you have successfully download the Item.

Categories

Resources