package net.fourbytes.slimodk;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Binder;
import android.os.IBinder;
import android.os.Parcel;
import android.os.RemoteException;
import com.badlogic.gdx.utils.JsonValue;
/**
* Contains alternative versions to the ODK's IAP methods.
* <br>
* Part of SlimODK and thus needs SlimODK to be initialized for most of
* it's parts to be functional.
*/
public final class SlimODKIAP {
private SlimODKIAP() {
}
static ServiceConnection connection;
static IBinder service;
/**
* Initializes the IAP service binding to the current context if not already initialized.
* Requires the SlimODK itself to be initialized to access the current context.
*/
public static void init() {
if (SlimODK.context == null || connection != null) {
return;
}
connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
SlimODKIAP.service = service;
}
@Override
public void onServiceDisconnected(ComponentName name) {
SlimODKIAP.service = null;
}
};
Intent intent = new Intent();
intent.setClassName("tv.ouya", "tv.ouya.console.service.iap.IapService");
boolean success = SlimODK.context.bindService(intent, connection, Context.BIND_AUTO_CREATE);
if (!success) {
System.out.println("iapService binding failed!");
connection = null;
}
}
/**
* Ends the IAP service binding to the current context if not already ended.
* Requires the SlimODK itself to be initialized to access the current context.
*/
public static void end() {
if (SlimODK.context == null || connection == null) {
return;
}
SlimODK.context.unbindService(connection);
connection = null;
}
private static String gamerDataStr;
/**
* Returns the data of the current user ("gamer") as JsonValue via the IAP API.
* It's a relatively long blocking call, caching only a string representing the JsonValue, so use wisely!
* @return JsonValue representing current gamer; null if an error happened or if IAP not initialized
*/
public static JsonValue getGamerData() {
if (gamerDataStr != null) {
SlimODK.jsonReader.parse(gamerDataStr);
}
if (SlimODK.context == null || connection == null) {
return null;
}
//IBinder that gets the response data
IBinder binder = new Binder() {
@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
//We only need to handle when transaction was a success.
if (code == 1) {
//The OUYA enforces an IStringListener as binder
data.enforceInterface("tv.ouya.console.internal.IStringListener");
//Read the data, check for being null, exception and return true
gamerDataStr = data.readString();
if (gamerDataStr == null) {
gamerDataStr = "";
}
reply.writeNoException();
return true;
}
//Otherwise, it just simply failed
gamerDataStr = "";
return super.onTransact(code, data, reply, flags);
}
};
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
try {
//The OUYA enforces an IIapServiceDefinition to send the transaction
data.writeInterfaceToken("tv.ouya.console.internal.IIapServiceDefinition");
//Developer-specific devID
data.writeString(SlimODK.devID);
//Set the binder that listens to the response
data.writeStrongBinder(binder);
//Transact the data with the iapService. The reply will be empty.
service.transact(7, data, reply, 0);
//Check for exceptions
reply.readException();
} catch (RemoteException e) {
e.printStackTrace();
gamerDataStr = null;
return null;
} finally {
reply.recycle();
data.recycle();
}
//Wait for the gamerDataStr to be non-null as the transaction happens asynchronously.
while (gamerDataStr == null) {
Thread.yield();
try {
Thread.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (gamerDataStr.isEmpty()) {
gamerDataStr = null;
return null;
}
JsonValue json = SlimODK.jsonReader.parse(gamerDataStr);
return json;
}
}