Provoke conflict when using Android Snapshots (Game Play Services) - android

I have implemented functions to save and load snapshots using the Game API from Google Play Services. The next step I am working on is to handle conflicts when there is more then one snapshot. And here comes the problem.
In my understanding a conflict should occure when doing the following:
Save a snapshot after making game progress
Sign out (Google Play Services)
Delete all app data
Start game again and make some progress
Sign in (Google Play Services)
Save a new snapshop
Load snapshop
Unfortunately in my case no conflict occures. Instead the current game progress is being saved (step 6) and loading (step 7) just returns this snapshop. There is no indicator that snapshot (step 1) was overwritten - resulting in loosing game progress.
Code for saving:
private void executeSave() {
AsyncTask.execute(new Runnable() {
#Override
public void run() {
GoogleApiClient googleApiClient = App.getGoogleApiHelper().getmGoogleApiClient();
Snapshots.OpenSnapshotResult openResult = Games.Snapshots.open(googleApiClient, getSavegameFilename(), true).await();
Status resultStatus = openResult.getStatus();
Log.d(TAG, "openstatus is: " + resultStatus.getStatusMessage());
if(resultStatus.isSuccess()) {
byte[] localSavegame = getPersistingManager().readBytes();
if(localSavegame != null) {
Log.d(TAG, "Going to save:" + getPersistingManager().read());
createSnapshot(openResult.getSnapshot(), localSavegame).await();
}
}
}
});
}
private PendingResult<Snapshots.CommitSnapshotResult> createSnapshot(Snapshot snapshot, byte[] data) {
GoogleApiClient googleApiClient = App.getGoogleApiHelper().getmGoogleApiClient();
snapshot.getSnapshotContents().writeBytes(data);
SnapshotMetadataChange metadataChange = new SnapshotMetadataChange.Builder().build();
return Games.Snapshots.commitAndClose(googleApiClient, snapshot, metadataChange);
}
Code for loading:
private void executeLoad() {
AsyncTask.execute(new Runnable() {
#Override
public void run() {
GoogleApiClient googleApiClient = App.getGoogleApiHelper().getmGoogleApiClient();
Snapshots.OpenSnapshotResult result = Games.Snapshots.open(googleApiClient, getSavegameFilename(), true).await();
processResult(result, 0);
}
});
}
private void processResult(Snapshots.OpenSnapshotResult result, int retryCount) {
Status resultStatus = result.getStatus();
retryCount++;
if(resultStatus.isSuccess()) {
Log.d(TAG, "No conflict, thats great!");
handleSuccess(result);
} else if (resultStatus.getStatusCode() == GamesStatusCodes.STATUS_SNAPSHOT_CONFLICT) {
Log.d(TAG, "Aww... a conflict!");
handleConflict(result, retryCount);
} else {
Log.e(TAG, "Error while getting savegame, status message: " + resultStatus.getStatusMessage());
}
}
When performing the steps from above this is happening:
1) Save a snapshot after making game progress
absRemotePersistMgmt: openstatus is: STATUS_OK
absRemotePersistMgmt: Going to save:{"solvedQuestions":{"1":[],"2":[1]}}
6) Save a new snapshot
absRemotePersistMgmt: openstatus is: STATUS_OK
absRemotePersistMgmt: Going to save:{"solvedQuestions":{"1":[1,2],"2":[]}}
7) Load snapshop
absRemotePersistMgmt: No conflict, thats great!
What am I missing?
Sources I used:
https://developers.google.com/games/services/android/savedgames
https://www.youtube.com/watch?v=iHc2RBZs5T0
https://www.youtube.com/watch?v=naQhSkzNGAI

Related

QuickMatch onJoinedRoom gets error 2

I'm trying to connect via a quick match. I have everything enabled. APIs are enabled, the debug key and production key are added in the Oauth2 list in Google API Console.
Real-Multiplayer is enabled and game-service is published. I'm trying some sample code in my game, plus i'm signing the user.
I'm getting error 2 in onJoinedRoom
I'm trying to sign-in using this:
public void signInSilently() {
mGoogleSignInClient.silentSignIn().addOnCompleteListener(getActivity(),
new OnCompleteListener<GoogleSignInAccount>() {
#Override
public void onComplete(#NonNull Task<GoogleSignInAccount> task) {
if (task.isSuccessful()) {
//onConnected(task.getResult());
Utils.logDebug("OnlineFragment.startSignInIntent()","onComplete, isSuccessful.");
onConnected(task.getResult());
} else {
startSignInIntent();
Utils.logDebug("OnlineFragment.startSignInIntent()","onComplete, NOT isSuccessful.");
task.getException().printStackTrace();
}
}
});
}
It's always onConnected
private void onConnected(GoogleSignInAccount googleSignInAccount){
mRealTimeMultiplayerClient = Games.getRealTimeMultiplayerClient(getActivity(), googleSignInAccount);
startQuickGame();
}
After connecting, I'm starting the new quick match:
private void startQuickGame() {
if(getActivity() != null){
// auto-match criteria to invite one random automatch opponent.
// You can also specify more opponents (up to 3).
// TODO: Make the first param's value 2
Bundle autoMatchCriteria = RoomConfig.createAutoMatchCriteria(1, 1, ROLE_ANY);
// build the room config:
RoomConfig roomConfig =
RoomConfig.builder(mRoomUpdateCallback)
.setOnMessageReceivedListener(mMessageReceivedHandler)
.setRoomStatusUpdateCallback(mRoomStatusCallbackHandler)
.setAutoMatchCriteria(autoMatchCriteria)
.build();
// prevent screen from sleeping during handshake
getActivity().getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
// Save the roomConfig so we can use it if we call leave().
mJoinedRoomConfig = roomConfig;
// create room:
mRealTimeMultiplayerClient.create(mJoinedRoomConfig);
}
}
Then I'm getting the error in the listener (Only the mentioned function from the listener has been included, other functions are not getting called)
private RoomUpdateCallback mRoomUpdateCallback = new RoomUpdateCallback() {
#Override
public void onRoomCreated(int code, #Nullable Room room) {
// Update UI and internal state based on room updates.
if(room != null)
Log.d("SignInGoogleOnlineFrag", "Room isn't null");
if(code == GamesCallbackStatusCodes.OK)
Log.d("SignInGoogleOnlineFrag", "OK");
if (code == GamesCallbackStatusCodes.OK && room != null) {
Log.d("SignInGoogleOnlineFrag", "Room " + room.getRoomId() + " created.");
} else {
Log.w("SignInGoogleOnlineFrag", "Error creating room: " + code);
// let screen go to sleep
getActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
}

Know when a suscription was cancelled - Play Billing 1.0

I'm using this tuto to integrate Play Billing Library to my app: http://www.androidrey.com/implement-play-billing-library-in-android-application/ and all works good ... well, not at all. I have problems to know when a suscription was cancelled, I tested all the methods to find a resultCode or something to know this state, but have a method that I could not implement. Could be this the problem?
class: BillingManager.java
public void queryPurchases() {
Runnable queryToExecute = new Runnable() {
#Override
public void run() {
long time = System.currentTimeMillis();
Purchase.PurchasesResult purchasesResult = billingClient.queryPurchases(BillingClient.SkuType.INAPP);
if (areSubscriptionsSupported()) {
Purchase.PurchasesResult subscriptionResult
= billingClient.queryPurchases(BillingClient.SkuType.SUBS);
System.out.println("QUERY 0");
if (subscriptionResult.getResponseCode() == BillingClient.BillingResponse.OK) {
purchasesResult.getPurchasesList().addAll(
subscriptionResult.getPurchasesList());
System.out.println("QUERY 1");
} else {
// Handle any error response codes.
}
} else if (purchasesResult.getResponseCode() == BillingClient.BillingResponse.OK) {
// Skip subscription purchases query as they are not supported.
System.out.println("QUERY 2");
} else {
// Handle any other error response codes.
System.out.println("QUERY 3");
}
onQueryPurchasesFinished(purchasesResult);
System.out.println("QUERY RESULT "+ purchasesResult);
}
};
executeServiceRequest(queryToExecute);
}
private void onQueryPurchasesFinished(Purchase.PurchasesResult result) {
// Have we been disposed of in the meantime? If so, or bad result code, then quit
if (billingClient == null || result.getResponseCode() != BillingClient.BillingResponse.OK) {
Log.w(TAG, "Billing client was null or result code (" + result.getResponseCode()
+ ") was bad – quitting");
return;
}
Log.d(TAG, "Query inventory was successful.");
// Update the UI and purchases inventory with new list of purchases
// mPurchases.clear();
onPurchasesUpdated(BillingClient.BillingResponse.OK, result.getPurchasesList());
}
public boolean areSubscriptionsSupported() {
int responseCode = billingClient.isFeatureSupported(BillingClient.FeatureType.SUBSCRIPTIONS);
if (responseCode != BillingClient.BillingResponse.OK) {
Log.w(TAG, "areSubscriptionsSupported() got an error response: " + responseCode);
}
return responseCode == BillingClient.BillingResponse.OK;
}
It is supposed to be called here: MyBillingUpdateListener.java
public class MyBillingUpdateListener implements BillingManager.BillingUpdatesListener {
//final BillingManager billingManager = new BillingManager(,this );
#Override
public void onBillingClientSetupFinished() {
//billingManager.queryPurchases(); THIS IS WHAT I COULD NOT IMPLEMENT
}
Any help is welcome, thanks!.
Play Billing 1.0 does not have the concept of purchase states (anymore), so there currently is no way to get this information using the Play Billing library.
My understanding is that queryPurchases is supposed to return actual valid purchases only. However, it gets the information from a long living cache and you have no way of updating it manually.
onBillingClientSetupFinished is completely unrelated.
Here is an active discussion on the subject: https://github.com/googlesamples/android-play-billing/issues/122

Error You Already Own This Item

I have a new android app in which I am adding in-app billing and I am tearing my hair out with frustration.
I have uploaded a signed APK and published to alpha. I created a set of in-app products and activated them all. I have created a new gmail account and defined them as a tester for the app on the app apk page.
I have factory reset my android phone and initialised it with the new gmail account. I have entered the /apps/testing link in to chrome and signed up as a tester. I then downloaded and installed my app. Inside my app I asked for the in app products that were available and was shown the set i created above. I selected one to buy and went through the following purchase process.
1. Screen shows product to be purchased and price and requests press continue which i do
2. Screen shows payment methods and I select redeem code
3. Screen shows redeem your code and I enter one of the promotion codes I set up in the developer console earlier (not mentioned above - sorry) and press redeem
4. Screen shows product again, this time with price crossed out and offers option to add item which I select (very strange being asked to add again buy hey ho)
5. Screen shows item added
6. After a fews seconds screen shows Error you already own this item.
How can this be, this user did not exist before ten minutes ago and has only used this app once as described above.
I have seen many questions in stack overflow and elsewhere similar to this and tried everything, clearing google play store cache, clearing google play store data etc. This sequence described above is my latest attempt with a completely clean user on a completely clean phone.
I could upload my app code used but that misses the point, which is how can this gmail account already own an item when this gmail account have never purchased anything before from anyone. Surely this is a bug.
All clues very welcome as to how to proceed. Code now added, note this is a hybrid android app, with the user purchase decisions code in javascript/html and the in app actions in the wrapper code below
private void processCommand(JSONObject commandJSON) throws JSONException
{
String command = commandJSON.getString("method");
if ("GetInAppProducts".equals(command))
{
Log.d(TAG, "Querying Inventory");
InAppPurchaseSkuString = null ; // clear the purchased sku. Note this is tested in mConsumeFinishedListener
mHelper.queryInventoryAsync(true, itemSkus, new IabHelper.QueryInventoryFinishedListener()
{
#Override
public void onQueryInventoryFinished(IabResult iabResult, Inventory inventory)
{
InventoryRecord = inventory ;
if (iabResult.isFailure())
{
Log.d(TAG, "Query inventory failed");
SendEndItemsToApp ();
}
else
{
Log.d(TAG, "Query inventory was successful.");
InventoryCheckCount = 0 ; // seems that we cannot just fire off a whole lot of these checks at the same time, so do them in sequence
if (itemSkus.size()>0) { CheckForOwnedItems (); } else { SendEndItemsToApp (); }
}
}
});
}
else if ("BuyInAppProduct".equals(command))
{
JSONArray params = commandJSON.getJSONArray("parameters");
InAppPurchaseSkuString = params.getString(0);
Log.d(TAG, "User decision to purchase " + InAppPurchaseSkuString);
mHelper.launchPurchaseFlow( MainActivity.this, InAppPurchaseSkuString, InAppPurchaseActivityCode, mPurchaseFinishedListener, "mypurchasetoken"); // consider putting the user email address in the last field - need to get from app
};
}//end of ProcessCommand
public void CheckForOwnedItems ()
{
Log.d(TAG, "Pre Purchase Inventory Processing Started");
String sku = itemSkus.get(InventoryCheckCount);
if (InventoryRecord.getSkuDetails(sku) != null)
{
if (InventoryRecord.hasPurchase(sku))
{
consumeItem ();
}
else
{
SendItemToApp ();
InventoryCheckCount++;
if (InventoryCheckCount < itemSkus.size()) { CheckForOwnedItems (); } else { SendEndItemsToApp (); }
};
};
}//end of CheckForOwnedItems
public void SendItemToApp ()
{
String sku = itemSkus.get(InventoryCheckCount);
String priceString = InventoryRecord.getSkuDetails(sku).getPrice().replaceAll("[^\\d.]+", ""); // RegExp removes all characters except digits and periods
String infoString = "InAppProductDetails('" + sku + "','" + "dummy" + "','" + priceString + "');"; // dummy is a placeholder for product description which is not (yet?) used in the app
Log.d(TAG, infoString);
mWebView.evaluateJavascript (infoString, new ValueCallback<String>()
{
#Override
public void onReceiveValue(String s)
{
//Log.d(TAG,"Returned from InAppProductDetails:");
}
}
);
}
public void SendEndItemsToApp ()
{
String endString = "InAppProductsEnd();"; // name is a placeholder for now
Log.d(TAG, endString);
mWebView.evaluateJavascript(endString, new ValueCallback<String>()
{
#Override
public void onReceiveValue(String s)
{
//Log.d(TAG,"Returned from InAppProductsEnd:");
}
}
);
}
public void consumeItem()
{
Log.d(TAG,"Pre Purchase Inventory Query Started");
String sku = itemSkus.get(InventoryCheckCount);
mHelper.consumeAsync(InventoryRecord.getPurchase(sku), mConsumeFinishedListener);
}
IabHelper.OnConsumeFinishedListener mConsumeFinishedListener = new IabHelper.OnConsumeFinishedListener()
{
public void onConsumeFinished (Purchase purchase, IabResult result)
{
if (result.isSuccess())
{
Log.d(TAG, "Pre Purchase Consume Item Completed");
SendItemToApp ();
InventoryCheckCount++;
if (InventoryCheckCount < itemSkus.size()) { CheckForOwnedItems (); } else { SendEndItemsToApp (); }
}
else
{
Log.d(TAG,"Pre Purchase Consume Item Failed");
}
}
};
IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener = new IabHelper.OnIabPurchaseFinishedListener()
{
public void onIabPurchaseFinished (IabResult result, Purchase purchase)
{
if (result.isFailure())
{
Log.d(TAG,"Purchase Scenario Failed");
}
else if (purchase.getSku().equals(InAppPurchaseSkuString))
{
Log.d(TAG,"Purchase Scenario Completed");
String evalString = "InAppProductPurchased('" + InAppPurchaseSkuString + "');";
Log.d(TAG, evalString);
mWebView.evaluateJavascript (evalString, new ValueCallback<String>()
{
#Override
public void onReceiveValue(String s)
{
Log.d(TAG, "Returned from InAppProductPurchased:");
}
}
);
}
}
};
I have found that this error does not occur when using paypal (i.e. real money) to make the purchase, so I believe that this "Error you already own this item" message is in some way connected to using a promotion code for the test. And (so far) my paypal account has not been charged (as I am a resgistered tester for the app).

Android Google Saved Games unexpected conflicts

In my game I have in-game currency and I want to save its value to the cloud. I decided to use Google Saved Games API. Everything works great but when I'm saving data to the Snapshots and then reading it when the game launches again, I'm getting conflicts, even when I'm on the same device. Now I'm saving currency's state after every change, so when player spents or gets some "coins". I'm thinking that this could be very often and services can't handle it because when I'm offline (without connection to the network) everything works nice and fast but when I'm online (connected to Wi-fi) work with Snapshots is slower and as I said I'm getting conflicts with data last saved and previous data I saved (I'm loggging all values...). Sometimes I get even 5 conflicts. I have 3 functions to work with Saved Games. One for reading data, one for saving data and one for checking for conflicts:
Reading data:
private void readSavedGame(final String snapshotName) {
AsyncTask<Void, Void, Boolean> readingTask = new AsyncTask<Void, Void, Boolean>() {
#Override
protected Boolean doInBackground(Void... params) {
Snapshots.OpenSnapshotResult result = Games.Snapshots.open(mGoogleApiClient, snapshotName, false).await();
Snapshot snapshot = processSnapshotOpenResult(result, 0);
if(snapshot != null) {
try {
updateGameData(snapshot.getSnapshotContents().readFully());
Log.d(TAG, "Updating game: "+String.valueOf(coins)+"...");
return true;
} catch (IOException e) {
Log.d(TAG, "Error: " + e.getMessage());
}
}
return false;
}
#Override
protected void onPostExecute(Boolean result) {
super.onPostExecute(result);
if(result) Log.d(TAG, "Game state read successfully...");
else Log.d(TAG, "Error while reading game state...");
updateUi();
}
};
readingTask.execute();
}
Saving data:
private void writeSavedGame(final String snapshotName, final byte[] data) {
AsyncTask<Void, Void, Boolean> updateTask = new AsyncTask<Void, Void, Boolean>() {
#Override
protected Boolean doInBackground(Void... params) {
Snapshots.OpenSnapshotResult result = Games.Snapshots.open(
mGoogleApiClient, snapshotName, false).await();
Snapshot snapshot = processSnapshotOpenResult(result, 0);
if(snapshot != null) {
snapshot.getSnapshotContents().writeBytes(getGameData());
Log.d(TAG, "Saving: "+String.valueOf(coins)+"...");
Snapshots.CommitSnapshotResult commitSnapshotResult = Games.Snapshots.commitAndClose(mGoogleApiClient, snapshot, SnapshotMetadataChange.EMPTY_CHANGE).await();
if(commitSnapshotResult.getStatus().isSuccess()) return true;
}
return false;
}
#Override
protected void onPostExecute(Boolean result) {
if (result) Log.d(TAG, "Game was saved successfully....");
else Log.d(TAG, "Error while saving game state...");
}
};
updateTask.execute();
}
Checking for conflicts or handling OpenSnapshotResult
Snapshot processSnapshotOpenResult(Snapshots.OpenSnapshotResult result, int retryCount) {
Snapshot mResolvedSnapshot = null;
retryCount++;
int status = result.getStatus().getStatusCode();
Log.i(TAG, "Save Result status: " + status);
if (status == GamesStatusCodes.STATUS_OK) {
Log.d(TAG, "No conflict, SNAPSHOT is OK");
return result.getSnapshot();
} else if (status == GamesStatusCodes.STATUS_SNAPSHOT_CONTENTS_UNAVAILABLE) {
return result.getSnapshot();
}
else if (status == GamesStatusCodes.STATUS_SNAPSHOT_CONFLICT) {
Log.d(TAG, "Conflict: "+String.valueOf(retryCount));
Snapshot snapshot = result.getSnapshot();
Snapshot conflictSnapshot = result.getConflictingSnapshot();
// Resolve between conflicts by selecting the newest of the conflicting snapshots.
mResolvedSnapshot = snapshot;
if (snapshot.getMetadata().getLastModifiedTimestamp() <
conflictSnapshot.getMetadata().getLastModifiedTimestamp()) {
mResolvedSnapshot = conflictSnapshot;
}
try {
Log.d(TAG, "Snapshot data: "+new String(snapshot.getSnapshotContents().readFully()));
Log.d(TAG, "Conflicting data: "+new String(conflictSnapshot.getSnapshotContents().readFully()));
} catch (IOException e) {
Log.e(TAG, "ERROR WHILE READING SPAPSHOTS CONTENTS...");
}
Snapshots.OpenSnapshotResult resolveResult = Games.Snapshots.resolveConflict(
mGoogleApiClient, result.getConflictId(), mResolvedSnapshot).await();
if (retryCount < MAX_SNAPSHOT_RESOLVE_RETRIES) {
// Recursively attempt again
return processSnapshotOpenResult(resolveResult, retryCount);
} else {
// Failed, log error and show Toast to the user
String message = "Could not resolve snapshot conflicts";
Log.e(TAG, message);
//Toast.makeText(getBaseContext(), message, Toast.LENGTH_LONG).show();
}
}
// Fail, return null.
return null;
}
Conflict principes are explained nicely here.
My code is based on official docs implementations and samples.
So when offline, everything works excellent but when connected, I'm getting conflicts on the same device... Maybe I'm updating my saved game very often and services can't handle it. Any ideas? Thanks.
As discussed in Saved Games - Conflict resolution
Typically, data conflicts occur when an instance of your application is unable to reach the Saved Games service while attempting to load data or save it. In general, the best way to avoid data conflicts is to always load the latest data from the service when your application starts up or resumes, and save data to the service with reasonable frequency.
In addition to that, it is also recommended to follow Best practices for implementing saved games to deliver the best possible product to your players.
Also, to learn how to implement Saved Games for your platform, see the resources given in Client implementations.

Connecting to existing Google Chromecast Session from Android (for generic remote control)

I am creating a generic Chromecast remote control app. Most of the guts of the app are already created and I've managed to get Chromecast volume control working (by connecting to a Chromecast device along side another app that is casting - YouTube for example).
What I've having difficult with is performing other media commands such as play, pause, seek, etc.
Use case example:
1. User opens YouTube on their android device and starts casting a video.
2. User opens my app and connects to the same Chromecast device.
3. Volume control from my app (works now)
4. Media control (play, pause, etc) (does not yet work)
I found the Cast api reference that explains that you can sendMessage(ApiClient, namespace, message) with media commands; however the "message" (JSON) requires the sessionId of the current application (Youtube in this case). I have tried the following, but the connection to the current application always fails; status.isSuccess() is always false:
Cast.CastApi
.joinApplication(mApiClient)
.setResultCallback(
new ResultCallback<Cast.ApplicationConnectionResult>() {
#Override
public void onResult(
Cast.ApplicationConnectionResult result) {
Status status = result.getStatus();
if (status.isSuccess()) {
ApplicationMetadata applicationMetadata = result
.getApplicationMetadata();
sessionId = result.getSessionId();
String applicationStatus = result
.getApplicationStatus();
boolean wasLaunched = result
.getWasLaunched();
Log.i(TAG,
"Joined Application with sessionId: "
+ sessionId
+ " Application Status: "
+ applicationStatus);
} else {
// teardown();
Log.e(TAG,
"Could not join application: "
+ status.toString());
}
}
});
Is is possible to get the sessionId of an already running cast application from a generic remote control app (like the one I am creating)? If so, am I right in my assumption that I can then perform media commands on the connected Chromecast device using something like this:
JSONObject message = new JSONObject();
message.put("mediaSessionId", sessionId);
message.put("requestId", 9999);
message.put("type", "PAUSE");
Cast.CastApi.sendMessage(mApiClient,
"urn:x-cast:com.google.cast.media", message.toString());
Update:
I have tried the recommendations provided by #Ali Naddaf but unfortunately they are not working. After creating mRemoteMediaPlayer in onCreate, I also do requestStatus(mApiClient) in the onConnected callback (in the ConnectionCallbacks). When I try to .play(mApiClient) I get an IllegalStateException stating that there is no current media session. Also, I tried doing joinApplication and in the callback performed result.getSessionId; which returns null.
A few comments and answers:
You can get the sessionId from the callback of launchApplication or joinApplication; in the "onResult(result)", you can get the sessionId from: result.getSessionId()
YouTube is still not on the official SDK so YMMV, for apps using official SDK, you should be able to use the above approach (most of it)
Why are you trying to set up a message yourself? Why not building a RemoteMediaPlayer and using play/pause that is provided there? Whenever you are working with the media playback through the official channel, always use the RemoteMediaPlayer (don't forget to call requestStatus() on it after creating it).
Yes it is possible , First you have to save sesionId and CastDevice device id
and when remove app from background and again open app please check is there sessionId then call bello line.
Cast.CastApi.joinApplication(apiClient, APP_ID,sid).setResultCallback(connectionResultCallback);
if you get success result then need to implement further process in connectionResultCallback listener.
//Get selected device which you selected before
#Override
public void onRouteAdded(MediaRouter router, MediaRouter.RouteInfo route) {
// Log.d("Route Added", "onRouteAdded");
/* if (router.getRoutes().size() > 1)
Toast.makeText(homeScreenActivity, "'onRouteAdded :: " + router.getRoutes().size() + " -- " + router.getRoutes().get(1).isSelected(), Toast.LENGTH_SHORT).show();
else
Toast.makeText(homeScreenActivity, "'onRouteAdded :: " + router.getRoutes(), Toast.LENGTH_SHORT).show();*/
if (router != null && router.getRoutes() != null && router.getRoutes().size() > 1) {
// Show the button when a device is discovered.
// Toast.makeText(homeScreenActivity, "'onRouteAdded :: " + router.getRoutes().size() + " -- " + router.getRoutes().get(1).isSelected(), Toast.LENGTH_SHORT).show();
mMediaRouteButton.setVisibility(View.VISIBLE);
titleLayout.setVisibility(View.GONE);
castName.setVisibility(View.VISIBLE);
selectedDevice = CastDevice.getFromBundle(route.getExtras());
routeInfoArrayList = router.getRoutes();
titleLayout.setVisibility(View.GONE);
if (!isCastConnected) {
String deid = MyPref.getInstance(homeScreenActivity).readPrefs(MyPref.CAST_DEVICE_ID);
for (int i = 0; i < routeInfoArrayList.size(); i++) {
if (routeInfoArrayList.get(i).getExtras() != null && CastDevice.getFromBundle(routeInfoArrayList.get(i).getExtras()).getDeviceId().equalsIgnoreCase(deid)) {
selectedDevice = CastDevice.getFromBundle(routeInfoArrayList.get(i).getExtras());
routeInfoArrayList.get(i).select();
ReSelectedDevice(selectedDevice, routeInfoArrayList.get(i).getName());
break;
}
}
}
}
}
//Reconnect google Api Client
public void reConnectGoogleApiClient() {
if (apiClient == null) {
Cast.CastOptions apiOptions = new
Cast.CastOptions.Builder(selectedDevice, castClientListener).build();
apiClient = new GoogleApiClient.Builder(this)
.addApi(Cast.API, apiOptions)
.addConnectionCallbacks(reconnectionCallback)
.addOnConnectionFailedListener(connectionFailedListener)
.build();
apiClient.connect();
}
}
// join Application
private final GoogleApiClient.ConnectionCallbacks reconnectionCallback = new GoogleApiClient.ConnectionCallbacks() {
#Override
public void onConnected(Bundle bundle) {
// Toast.makeText(homeScreenActivity, "" + isDeviceSelected(), Toast.LENGTH_SHORT).show();
try {
String sid = MyPref.getInstance(homeScreenActivity).readPrefs(MyPref.CAST_SESSION_ID);
String deid = MyPref.getInstance(homeScreenActivity).readPrefs(MyPref.CAST_DEVICE_ID);
if (sid != null && deid != null && sid.length() > 0 && deid.length() > 0)
Cast.CastApi.joinApplication(apiClient, APP_ID, sid).setResultCallback(connectionResultCallback);
isApiConnected = true;
} catch (Exception e) {
}
}
#Override
public void onConnectionSuspended(int i) {
isCastConnected = false;
isApiConnected = false;
}
};

Categories

Resources