Manually start a turnbasedgame multiplayer, Android - android

Background:
I have a working game where user can start matches through Google's standard interface. 2-4 players works fine.
I have created a custom interface where players can connect as "Friends" and from that interface start matches.
Issue:
When I manually calling Games.TurnBasedMultiplayer.createMatch for 2 players, it works most of the time.
Function is called in the end of onSignInSucceeded.
(I would prefere to call this in onActivityResult (as the default interface does) but then I'm not connected...)
When I call it for 3-4 players, it never works.
The callback returns GamesStatusCodes.STATUS_NETWORK_ERROR_OPERATION_FAILED.
Observation It seems also to differ depending on the persons Goolge IDs, some starts with G follows by numbers and some only have the numbers (not starting with G).
public void onSignInSucceeded() {
....
TurnBasedMatchConfig tbmc = TurnBasedMatchConfig.builder().addInvitedPlayers(myinvitees).setAutoMatchCriteria(autoMatchCriteria).build();
Games.TurnBasedMultiplayer.createMatch(getApiClient(), tbmc).setResultCallback( new ResultCallback<TurnBasedMultiplayer.InitiateMatchResult>() {
#Override
public void onResult(TurnBasedMultiplayer.InitiateMatchResult result) {
processResult(result);
}
});
Where myinvitees is an ArrayList with GoogleIDs of my opponents
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.INTERNET"/>
Edit:
Did some smaller changes but in general I have the same behavior.
Some times the games starting (with up to 4 players) but it seems to prefer the IDs starting with "G"...

So after moving the check if a request for starting a match exist to onSignInSucceeded(), it seems that Google have done something with the GoogleID I'm pulling from the players.
Newer users with ID that startas with G(and a lot of numbers) seems to work but not a mix of old once (that does not start with G) and the new.

Related

How to properly track playback position? [Android Media Broadcast Notifications Spotify API]

After reading the documentation on Spotify's Android Media Notifications API, https://beta.developer.spotify.com/documentation/android-sdk/guides/android-media-notifications/, I successfully managed to receive the notifications metadata and it is displayed properly on my app.
However, the notifications metadata is only updated when the queue changes, when the track changes, and when playback is changed, so unless one of these three actions happens, the "positionInMs" intent extra isn't sent.
As of right now as a workaround I am simply starting a timer using the time the intent was sent, the last known playback position, and the track duration to track current playback position.
This seemed to work at first, but after further testing I've realized that the timer I set can go out of sync, if the track the user is listening to freezes because of a slow internet connection.
Any ideas to properly track the playback position, while accounting for a slow internet connection? Or are there any alternatives I should look into?
I understand that this question is rather old, but I am going to answer anyway if anyone else comes across it.
I recommend constantly querying Spotify to get the playback position. One way you can do this is by using a timer and querying Spotify every given time frame. The below example queries Spotify every 100ms. If you want to reduce/increase the numbers of queries, you can simply use stopwatch.setClockDelay() and provide your required time
For instance, you can use this timer library
implementation 'com.yashovardhan99.timeit:timeit:1.2.0'
Then use the following code:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.spotify);
Stopwatch stopwatch = new Stopwatch();
stopwatch.setOnTickListener(this);
stopwatch.start();
}
#Override
public void onTick(Stopwatch stopwatch) {
Data.getAndroidSpotifyAppRemote().getPlayerApi().getPlayerState().setResultCallback(new CallResult.ResultCallback<PlayerState>() {
#Override
public void onResult(PlayerState playerState) {
Log.d("TAG", playerState.playbackPosition);
}
});
}
Don't forget to add the following code at the top of your class:
implements Stopwatch.OnTickListener

Test In-App-Purchase in Codename One simulator results in Null Pointer Exception

Instead of creating a light and a full version of my app, I decided to go the freemium way and offer a button to upgrade from the light to the full version.
The application is only available on the Google Play Store. So I created an in app purchase in the Play Store as described http://mobilecodetogo.blogspot.fr/2013/03/android-does-it-better-in-app-purchase.html.
Here is the code that I implemented :
if (buyFull) {
if (ParametresGeneraux.getPurchase().isManagedPaymentSupported()) {
String[] skus = {"ParametresGeneraux.getFullVersionSKU()"};
if (ParametresGeneraux.getPurchase().isItemListingSupported()) {
Product[] products = ParametresGeneraux.getPurchase().getProducts(skus);
String items = "";
if (products != null) {
for (Product p : products) {
items += p.getDescription();
}
}
Dialog.show("Produits intégrés", "Les produits intégrés sont " + items,
"OK", "Cancel");
}
// On achète
ParametresGeneraux.getPurchase().purchase("ParametresGeneraux.getFullVersionSKU()");
} else {
Dialog.show("Évolution impossible", "Impossible d'évoluer vers la version complète. Votre compte n'a pas été débité.", "OK", "Compris");
}
Where ParametresGeneraux.getPurchase() is doing Purchase.getInAppPurchase().
When I test it on the simulator with an Android skin (Nexus 5) the listing is not shown and it always results in a null pointer exception after executing the purchase :
java.lang.NullPointerException
at com.codename1.impl.javase.JavaSEPort$82$5$1.run(JavaSEPort.java:7936)
at com.codename1.ui.Display.processSerialCalls(Display.java:1152)
at com.codename1.ui.Display.edtLoopImpl(Display.java:1096)
at com.codename1.ui.Display.mainEDTLoop(Display.java:997)
at com.codename1.ui.RunnableWrapper.run(RunnableWrapper.java:120)
at com.codename1.impl.CodenameOneThread.run(CodenameOneThread.java:176)
On the contrary on the device few hours after submitting the app, the purchase is charged (so item is found and not null). However when I restart the app it is still in light version.
Here is how I test if it is a light version (in the init method from the main class) :
ParametresGeneraux.setPurchase(Purchase.getInAppPurchase());
ParametresGeneraux.setLightVersion(true);
if (ParametresGeneraux.getPurchase().isManagedPaymentSupported()) {
if (ParametresGeneraux.getPurchase().wasPurchased(ParametresGeneraux.getFullVersionSKU())) {
ParametresGeneraux.setLightVersion(false);
}
}
According to this 2014 SO question (and the mentioned RFE that has been closed since then) I assume wasPurchased should also work on Android. So I don't know why it does not work.
Actually my questions are :
Is it possible to test in app purchase with the simulator ?
Is wasPurchased the right method to pick up to check whether the user has bought the feature ?
Thanks a lot for giving me hints!
The simulator doesn't connect to google play and can return null for things you expect to be there. Notice that there are API's that indicate things such as if item listing is supported etc.
You can manipulate some elements of the purchase API via the simulator menu.
So to get rid of the NPE that appears right after the purchase() method returns in the simulator, the main class MUST implement PurchaseCallback interface!!!
The Main CN1 class is the one with the start() and init() methods not the state machine as [indicated by Shai][2]. This is a crucial part and should be stressed in the [Purchase tutorial][3] although this is well written in the API documentation :
public interface PurchaseCallback
Callback interface that the main class must implement in order for in-app-purchasing to work. Once the main class implements this interface the methods within it are invoked to indicate the various purchase states.
Now the itemPurchased() method from the PurchaseCallback implementation gets called when the after purchase() returns. And the simulator keeps track of the purchase in the CN1InAppPurchases file (.cn1 folder on Linux).
Furthermore now that the PurchaseCallback has been implemented, in the simulator (not on the Android device however) the wasPurchased() method returns the expected value depending on whether or not a previous purchase() call succeeded.

How many mayLaunchUrl we can run at a time?

I am trying to utilize ChromeCustomTabs into our project. I ran into several issue when I used mayLaunchUrl. I checked the code Google has on the github. I simply set up an button to test the mayLaunchURL (prerender feature), when I looked up the traffic using chrome dev tool. I did the the traffic and tab got trigger and the url got loaded ( it is simply a GET call with params). However, when I click it multiple times, (after 8-10times, with different params everytime), it STOP working. I stop seeing the requests sent out. (Not seen on chrome dev tool, nor the Proxy I set up).
I wonder if there is a limit times ( restriction) for mayLaunchURL feature, in other words, how many pages we can pre-render in this case? Is there a way to manually cancel the pre-render page and free the resource?
is there a restriction in terms of times to bindCustomTabsService? The way I did to call mayLaunchURL is to have an activity and kill the activity once I finish the tab. Can I bind the service each time even I “kill (finish)” the activtiy every time?
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
customTabActivityHelper = new CustomTabActivityHelper();
customTabActivityHelper.setConnectionCallback(this);
}
#Override
protected void onStart() {
super.onStart();
customTabActivityHelper.bindCustomTabsService(this);
}
#Override
public void onCustomTabsConnected() {
Boolean mayLaunchUrlAccepted = customTabActivityHelper.mayLaunchUrl(Uri.parse(“the URL?f=“+params), null, null);
// the mayLaunchUrlAccepted always return true in my case. Even when there is no request sent.
}
Yes, mayLaunchURL() are very expensive in terms of battery/RAM/network, so it is throttled on app UID level. But limits get dropped after some time.
Best strategy is to use mayLaunchURL() if the confidence that the user will navigate to the URL is very high.
There is the "low confidence" mayLaunchURL() which is not throttled, but performs a more limited set of actions (currently preconnect, not specified which, may change). The low confidence mayLaunchURL is triggered by providing null as the uri and a list of URLs in otherLikelyBundles.

Chartboost Interstitial won't show Ads on Unity

Lately, I have been trying to add static interstitial ads into my Unity game. For some reason, I could not get the system to show anything, or even react to me. After trying to work with the base Chartboost plugin, I tried to match a tutorial that I was following and purchased Prime31's Chartboost plugin and have been using that. However, neither the base plugin, nor Prime31's plugin, seem to be allowing me to show any ads. The code is pretty much done inside a single object, and it seems simple enough.
public class Advertisement : MonoBehaviour {
public string chartboostAppID = "5461129ec909a61e38b1505b";
public string chartboostAppSignature = "672b3b34e3e358e7a003789ddc36bd2bc49ea3b5";
// Use this for initialization
void Start () {
DontDestroyOnLoad(this.gameObject);
ChartboostAndroid.init (chartboostAppID, chartboostAppSignature, true);
ChartboostAndroid.cacheInterstitial(null);
}
void OnLevelWasLoaded(int level) {
ChartboostAndroid.cacheInterstitial(null);
if(Application.loadedLevelName == "Network Lobby") {
showAds();
}
}
public static void showAds() {
Debug.Log("Showing ad");
ChartboostAndroid.showInterstitial(null);
}
}
As you can see, it's pretty straightforward. This object is created at the game's splash screen, which appears only once, and it's never destroyed until the program ends. The goal is, whenever I enter the lobby scene, I want to see an ad before going to the lobby's menus. As it is, I do see the log printing "Showing ad", so I know the function is being called. However, nothing appears. Do I need to disable the GUI system first? Is there a step I'm missing?
I have already performed the following steps:
I have created and registered the app with chartboost, as well as double and triple checked the AppID and App Signature.
I have created a publishing campaign and registered it to the app.
I double-checked the orientation and confirmed that it's correct.
I registered this specific device as a test device.
The tutorial showed a call to ChartBoostAndroid.OnStart(), but there was no function like that for me to call. Perhaps that is from an older version?
I emailed Chartboost support and have not heard from them yet. I do not have that much time on this project, so if anyone can offer help, I'd appreciate it.

Get list of available chromecasts on demand

Ok, so I am trying to figure at how to get an up-to-date list of available chromecast devices, I'm doing this so that my app can check when the chromecast is not in use and then open my receiver app.
I am having some unexpected behaviour from the code below:
public class MainActivity extends Activity {
...
#Override
public void onCreate(Bundle savedInstanceState) {
...
mMediaRouterCallback = new MyMediaRouterCallback();
mMediaRouter = MediaRouter.getInstance(context);
mMediaRouteSelector = new MediaRouteSelector.Builder()
.addControlCategory(CastMediaControlIntent.categoryForCast(context.getString(R.string.app_id)))
.build();
mMediaRouter.addCallback(mMediaRouteSelector, mMediaRouterCallback,
MediaRouter.CALLBACK_FLAG_PERFORM_ACTIVE_SCAN);
}
This adds a MediaRouter callback to the MediaRouter. I have chosen to use the active scan flag.
private class MyMediaRouterCallback extends MediaRouter.Callback {
...
#Override
public void onRouteAdded(MediaRouter router, MediaRouter.RouteInfo info) {
Log.d(TAG, "Description 1 " + info.getDescription());
mSelectedDevice = CastDevice.getFromBundle(info.getExtras());
Log.d(TAG, "Description 2 " + mSelectedDevice.toString());
if(info.getDescription().equals("Chromecast")) {
// code to launch chromecast receiver app here.
}
}
}
My implementation of the MediaRouter.Callback overrides onRouteAdded, it simply prints some information about the devices it has found Description 1 describes the receiver app the device is using, description 2 gives its name.
However when this code is run initially the same device is discovered twice printing:
07-05 21:01:12.270: D/MainActivity(9730): Description 1 Casting HelloText
07-05 21:01:12.280: D/MainActivity(9730): Description 2 "Downstairs"
07-05 21:01:12.280: D/MainActivity(9730): Description 1 Casting HelloText
07-05 21:01:12.280: D/MainActivity(9730): Description 2 "Downstairs"
Then periodically the onRouteAdded callback is called sometimes only listing the device once, other times listing the device twice. My understanding however is that this callback should only be called when a new route is added.
I want to find all the available devices on command, not at random intervals that I can't control, what do I need to be doing? I can't find a callback that seems to be appropriate for this situation (such as whenever devices update/change), nor can I find a way to list them without using callbacks, so I'm a bit stuck.
(I have been basing these tests of the HelloText-Android example found here https://github.com/googlecast/CastHelloText-android, also I started this (my first android project) only a couple of days ago, so I apologise if I am missing something horrendously obvious)
Thanks in advance.
Call getRoutes() to get the list of known routes at the point in time that you desire. Iterate over them. Call matchesSelector() on each to filter out those that match your desired control category.
If you are listening for "onRouteAdded()", you would also need to listen to "onRouteRemoved()" to do a correct bookkeeping; if a device is added, it can be removed and added again so if you just listen to onRouteAdded(), it may seem it is being added multiple times. Getting the list from MedaiaRoute.getRoutes() might be easier if you don't want to be notified immediately and only want to know the list at certain points on demand.

Categories

Resources