package net.fourbytes.slimodk; import android.content.*; import android.database.Cursor; import android.net.Uri; import android.os.Build; import android.os.Bundle; import com.badlogic.gdx.controllers.Controller; import com.badlogic.gdx.controllers.android.AndroidController; import com.badlogic.gdx.utils.JsonValue; import net.fourbytes.shadow.ControllerHelper; import net.fourbytes.shadow.Shadow; import java.lang.reflect.Method; /** * Contains alternative versions to the ODK's controller methods. * <br> * Part of SlimODK and thus needs SlimODK to be initialized for most of * it's parts to be functional. */ public final class SlimODKController { private SlimODKController() { } /** * List of all LibGDX controllers registered by the OUYA. */ public final static Controller[] controllers = new Controller[4]; static BroadcastReceiver receiver; /** * Initializes the controller receiver for 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 || receiver != null) { return; } for (int i = 0; i < controllers.length; i++) { int deviceID = getIDForPlayer(i); if (deviceID != -1) { Controller controller = getControllerForID(deviceID); if (controller == null) { System.err.println("ControllerHelper didn't get PLAYER:"+i+";ID:"+deviceID+" yet! (init)"); } controllers[i] = controller; } } receiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if (intent.getAction().equals("tv.ouya.controller.added")) { int playerNum = intent.getIntExtra("PLAYER_NUM", -1); if (playerNum < 0 || playerNum >= controllers.length) { return; } int deviceID = intent.getIntExtra("DEVICE_ID", -1); System.out.println("Adding controller with ID "+deviceID+" for player "+playerNum); if (controllers[playerNum] != null) { System.out.println("Already mapped OUYA controller to player #"+playerNum+"; remapping"); } Controller controller = getControllerForID(deviceID); if (controller == null) { System.err.println("ControllerHelper didn't get PLAYER:"+playerNum+";ID:"+deviceID+" yet! (onReceive)"); } controllers[playerNum] = controller; } else if (intent.getAction().equals("tv.ouya.controller.removed")) { int deviceID = intent.getIntExtra("DEVICE_ID", -1); System.out.println("Removing controller with ID "+deviceID); for (int i = 0; i < controllers.length; i++) { Controller controller = controllers[i]; if (controller != null && getIDForController(controller) == deviceID) { controllers[i] = null; break; } } } } }; IntentFilter filter = new IntentFilter(); filter.addAction("tv.ouya.controller.added"); filter.addAction("tv.ouya.controller.removed"); SlimODK.context.registerReceiver(receiver, filter); } /** * Unregisters the controller receiver for 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 || receiver == null) { return; } for (int i = 0; i < controllers.length; i++) { controllers[i] = null; } SlimODK.context.unregisterReceiver(receiver); receiver = null; } /** * Gets the controller with the given ID from the list of registered controllers. * @param deviceID the controller's device ID * @return the controller instance; null otherwise */ public static Controller getControllerForID(int deviceID) { ControllerHelper ch = Shadow.controllerHelper; if (ch == null) { return null; } for (Controller controller : ch.controllers) { if (getIDForController(controller) == deviceID) { return controller; } } return null; } /** * Gets the device ID of the given controller. * @param controller controller to get the ID from * @return device ID in case the given controller is an instance of AndroidController; -1 otherwise */ public static int getIDForController(Controller controller) { return controller instanceof AndroidController ? ((AndroidController)controller).getDeviceId() : -1; } /** * Gets the player's controller ID for the given player. * @param playerNum the player to get the ID for * @return the controller device ID; null otherwise */ public static int getIDForPlayer(int playerNum) { Uri controllerURI = Uri.parse("content://tv.ouya.controllerdata/"); Cursor cursor = SlimODK.context.getContentResolver().query(controllerURI, new String[] {"input_device_id"}, "player_num = ?", new String[] {playerNum+""}, null); if (cursor == null) { return -1; } if (!cursor.moveToNext()) { cursor.close(); return -1; } int deviceID = cursor.getInt(0); cursor.close(); return deviceID; } /** * Gets the player number having the controller with the given ID. * @param deviceID the player's controller ID * @return the player's number; null otherwise */ public static int getPlayerForID(int deviceID) { Uri controllerURI = Uri.parse("content://tv.ouya.controllerdata/"); Cursor cursor = SlimODK.context.getContentResolver().query(controllerURI, new String[] {"player_num"}, "input_device_id = ?", new String[] {deviceID+""}, null); if (cursor == null) { return -1; } if (!cursor.moveToNext()) { cursor.close(); return -1; } int playerNum = cursor.getInt(0); cursor.close(); return playerNum; } private static String controllerMappingsStr; /** * Returns the system's internal controller remapping as JsonValue. * @return System's controller remapping as JsonValue; null if it failed (f.e. API < 11) */ public static JsonValue getControllerSystemMappings() { if (controllerMappingsStr != null) { return SlimODK.jsonReader.parse(controllerMappingsStr); } if (Build.VERSION.SDK_INT < 11) { return null; } ContentResolver cr = SlimODK.context.getApplicationContext().getContentResolver(); Bundle bundle = null; try { //REFLECTION Method method = ContentResolver.class.getDeclaredMethod("call", Uri.class, String.class, String.class, Bundle.class); method.setAccessible(true); bundle = (Bundle) method.invoke(cr, Uri.parse("content://tv.ouya.controllerdata/"), "get_button_remap_json", null, null); } catch (Exception e) { e.printStackTrace(); } if (bundle == null) { return null; } controllerMappingsStr = bundle.getString("button_remap"); if (controllerMappingsStr == null) { return null; } return SlimODK.jsonReader.parse(controllerMappingsStr); } }