Farklı Android sürümlerinde denetleyicileri destekleme

Oyununuzda oyun kumandalarını destekliyorsanız bu sizin sorumluluğunuzdadır Oyununuzun farklı cihazlarda kumandalara tutarlı şekilde yanıt vermesini sağlamak için Android'in farklı sürümlerinde çalışıyor. Bu sayede oyununuz daha geniş kitlelere ulaşabilir hem de oyuncularınız benzersiz bir oyun deneyimiyle sorunsuz bir oyun Android cihazlarını değiştirdiklerinde veya yeni sürüme geçirdiklerinde bile kumandalarını kullanabilirler.

Bu derste, Android 4.1 ve sonraki sürümlerde bulunan API'lerin nasıl kullanılacağı gösterilmektedir uyumlu bir şekilde destekler. Böylece, oyununuz aşağıdaki Android 3.1 ve sonraki sürümleri çalıştıran cihazlardaki özellikler:

  • Oyun, yeni bir oyun kumandasının eklenip eklenmediğini, değiştirildiğini veya kaldırıldığını algılayabilir.
  • Oyun, oyun kumandasının özelliklerini sorgulayabilir.
  • Oyun, oyun kumandasından gelen hareket etkinliklerini tanıyabilir.

Bu dersteki örnekler, referans uygulama yöntemi doğrultusunda indirilebilen örnek ControllerSample.zip tarafından sağlanmıştır bölümünü ziyaret edin. Bu örnekte, InputManagerCompat öğesinin nasıl uygulanacağı gösterilmektedir Android'in farklı sürümlerini destekleyen arayüze sahip. Örneği derlemek için Android 4.1 (API düzeyi 16) veya sonraki bir sürümü kullanmalıdır. Örnek uygulama, derlendikten sonra Derleme olarak Android 3.1 (API düzeyi 12) veya sonraki sürümleri çalıştıran tüm cihazlarda çalışır hedefi belirleyebilirsiniz.

Oyun kumandası desteği için API'leri soyutlamaya hazırlanın

Bir oyun kumandasının bağlantısının doğru olup olmadığını tespit etmek istediğinizi durumu, Android 3.1 (API düzeyi 12) çalıştıran cihazlarda değişti. Ancak, API'ler yalnızca Android 4.1 (API düzeyi 16) ve sonraki sürümlerde kullanılabilir. hem de Android 4.1 ve sonraki sürümleri destekleyen bir uygulama Android 3.1 ile Android 4.0 arasındaki sürümleri destekleyen yedek mekanizma sağlar.

Hangi özellikler için böyle bir yedek mekanizmasının gerektiğini belirlemenize daha eski sürümler, tablo 1'de oyun kumandası desteğindeki farklılıklar listelenmiştir. Android 3.1 (API düzeyi 12) ile 4.1 (API düzeyi) arasında 16).

Tablo 1. Şu uygulamalarda oyun kumandası desteği için API'ler: Android sürümlerini kullanabilirsiniz.

Kumanda Bilgileri Denetleyici API'sı API düzeyi 12 API düzeyi 16
Cihaz Tanımlama getInputDeviceIds()  
getInputDevice()  
getVibrator()  
SOURCE_JOYSTICK
SOURCE_GAMEPAD
Bağlantı Durumu onInputDeviceAdded()  
onInputDeviceChanged()  
onInputDeviceRemoved()  
Giriş Etkinliği Kimliği D-pad tuşuna basın ( KEYCODE_DPAD_UP, KEYCODE_DPAD_DOWN, KEYCODE_DPAD_LEFT, KEYCODE_DPAD_RIGHT, KEYCODE_DPAD_CENTER)
Oyun kumandası düğmesine basıldığında ( BUTTON_A, BUTTON_B, BUTTON_THUMBL, BUTTON_THUMBR, BUTTON_SELECT, BUTTON_START, BUTTON_R1, BUTTON_L1, BUTTON_R2, BUTTON_L2)
Kontrol çubuğunun ve şapka değiştirme hareketi ( AXIS_X, AXIS_Y, AXIS_Z, AXIS_RZ, AXIS_HAT_X, AXIS_HAT_Y)
Analog tetikleyici basma ( AXIS_LTRIGGER, AXIS_RTRIGGER)

Soyutmayı kullanarak sürüme duyarlı oyun kumandası desteği oluşturabilirsiniz. farklı platformlarda çalışır. Bu yaklaşım aşağıdaki adımları içerir:

  1. API'nin uygulanmasını soyutlayan bir ara Java arayüzü tanımlayın Oyununuzun gerektirdiği oyun kumandası özellikleri.
  2. Arayüzünüzün Android'deki API'leri kullanan bir proxy uygulamasını oluşturun 4.1 ve üzeri sürümler.
  3. Mevcut API'lerden yararlanarak arayüzünüzün özel bir uygulamasını oluşturun Android 3.1 ile Android 4.0 arasındaki sürümler.
  4. Çalışma zamanında bu uygulamalar arasında geçiş yapmak için gereken mantığı ve oyununuzdaki arayüzü kullanmaya başlayabilirsiniz.

Soyutlamanın, uygulamaların doğru ve kolay bir şekilde farklı Android sürümlerinde geriye dönük uyumlu şekilde çalışabileceğinden, Oluşturuluyor Geriye Dönük Kullanıcı Arayüzleri.

Geriye dönük uyumluluk için arayüz ekleyin

Geriye dönük uyumluluk sağlamak için, özel bir arayüz oluşturup daha sonra sürüme özgü uygulamalar ekleyin. Bu yaklaşımın avantajlarından biri Android 4.1'deki (API düzeyi 16) herkese açık arayüzleri yansıtmanıza destekler.

Kotlin

// The InputManagerCompat interface is a reference example.
// The full code is provided in the ControllerSample.zip sample.
interface InputManagerCompat {
    val inputDeviceIds: IntArray
    fun getInputDevice(id: Int): InputDevice

    fun registerInputDeviceListener(
            listener: InputManager.InputDeviceListener,
            handler: Handler?
    )

    fun unregisterInputDeviceListener(listener:InputManager.InputDeviceListener)

    fun onGenericMotionEvent(event: MotionEvent)

    fun onPause()
    fun onResume()

    interface InputDeviceListener {
        fun onInputDeviceAdded(deviceId: Int)
        fun onInputDeviceChanged(deviceId: Int)
        fun onInputDeviceRemoved(deviceId: Int)
    }
}

Java

// The InputManagerCompat interface is a reference example.
// The full code is provided in the ControllerSample.zip sample.
public interface InputManagerCompat {
    ...
    public InputDevice getInputDevice(int id);
    public int[] getInputDeviceIds();

    public void registerInputDeviceListener(
            InputManagerCompat.InputDeviceListener listener,
            Handler handler);
    public void unregisterInputDeviceListener(
            InputManagerCompat.InputDeviceListener listener);

    public void onGenericMotionEvent(MotionEvent event);

    public void onPause();
    public void onResume();

    public interface InputDeviceListener {
        void onInputDeviceAdded(int deviceId);
        void onInputDeviceChanged(int deviceId);
        void onInputDeviceRemoved(int deviceId);
    }
    ...
}

InputManagerCompat arayüzünde aşağıdaki yöntemler sunulur:

getInputDevice()
Ayna getInputDevice(). InputDevice bilgisini alır oyun kumandasının özelliklerini temsil eden bir nesne olarak değerlendirilir.
getInputDeviceIds()
Ayna getInputDeviceIds(). Her biri Bu, farklı bir giriş cihazının kimliğidir. Bu, bir proje başlatma belgesi birden fazla oyuncuyu destekleyen bir oyundur ve kaç oyuncuyu bağlı olduğundan emin olun.
registerInputDeviceListener()
Ayna registerInputDeviceListener(). Yeni bir geliştirici olduğunda bilgi almak için cihaz eklendiğinde, değiştirildiğinde veya kaldırıldığında.
unregisterInputDeviceListener()
Ayna unregisterInputDeviceListener(). Bir giriş cihazı işleyicisinin kaydını siler.
onGenericMotionEvent()
Ayna onGenericMotionEvent(). Oyununuzun müdahale edip idare etmesini sağlar Etkinlikleri temsil eden MotionEvent nesne ve eksen değeri en iyi performans gösteren fonksiyonlar olabilir.
onPause()
Aşağıdaki durumlarda oyun kumandası etkinlikleri için yoklamayı durdurur: ana etkinlik duraklatıldığında veya oyun artık odakta kaldığında.
onResume()
Aşağıdaki durumlarda oyun kumandası etkinlikleri için yoklama başlatır: devam ettirildiğinde veya oyun başlatıldığında ve çalıştırıldığında seçin.
InputDeviceListener
InputManager.InputDeviceListener yansıtıyor kullanır. Bir oyun kumandası eklendiğinde, değiştirildiğinde veya emin olun.

Sonra, InputManagerCompat için çalışan uygulamalar oluşturun farklı platform sürümlerinden geçerlidir. Oyununuz Android 4.1 veya daha yüksek olur ve bir InputManagerCompat yöntemi çağırır. Bu, proxy uygulaması InputManager içindeki eşdeğer yöntemi çağırır. Ancak oyununuz Android 3.1 ile Android 4.0 arasındaki sürümlerde çalışıyorsa özel uygulama InputManagerCompat yöntemlerine yapılan çağrıları şunu kullanarak işler: yalnızca Android 3.1'den sonra kullanıma sunulan API'ler kullanılabilir. Hangisinin sürüme özgü uygulama çalışma zamanında kullanılırsa, şeffaf bir şekilde oyuna geri döner.

Şekil 1. Arayüz için sınıf diyagramı ve sürüme özgü hakkında bilgi edindiniz.

Arayüzü Android 4.1 ve sonraki sürümlerde uygulama

InputManagerCompatV16, InputManagerCompat proxy yönteminin gerçek InputManager ve InputManager.InputDeviceListener. İlgili içeriği oluşturmak için kullanılan InputManager, sistemden elde edildi Context.

Kotlin

// The InputManagerCompatV16 class is a reference implementation.
// The full code is provided in the ControllerSample.zip sample.
public class InputManagerV16(
        context: Context,
        private val inputManager: InputManager =
            context.getSystemService(Context.INPUT_SERVICE) as InputManager,
        private val listeners:
            MutableMap<InputManager.InputDeviceListener, V16InputDeviceListener> = mutableMapOf()
) : InputManagerCompat {
    override val inputDeviceIds: IntArray = inputManager.inputDeviceIds

    override fun getInputDevice(id: Int): InputDevice = inputManager.getInputDevice(id)

    override fun registerInputDeviceListener(
            listener: InputManager.InputDeviceListener,
            handler: Handler?
    ) {
        V16InputDeviceListener(listener).also { v16listener ->
            inputManager.registerInputDeviceListener(v16listener, handler)
            listeners += listener to v16listener
        }
    }

    // Do the same for unregistering an input device listener
    ...

    override fun onGenericMotionEvent(event: MotionEvent) {
        // unused in V16
    }

    override fun onPause() {
        // unused in V16
    }

    override fun onResume() {
        // unused in V16
    }

}

class V16InputDeviceListener(
        private val idl: InputManager.InputDeviceListener
) : InputManager.InputDeviceListener {

    override fun onInputDeviceAdded(deviceId: Int) {
        idl.onInputDeviceAdded(deviceId)
    }
    // Do the same for device change and removal
    ...
}

Java

// The InputManagerCompatV16 class is a reference implementation.
// The full code is provided in the ControllerSample.zip sample.
public class InputManagerV16 implements InputManagerCompat {

    private final InputManager inputManager;
    private final Map<InputManagerCompat.InputDeviceListener,
            V16InputDeviceListener> listeners;

    public InputManagerV16(Context context) {
        inputManager = (InputManager)
                context.getSystemService(Context.INPUT_SERVICE);
        listeners = new HashMap<InputManagerCompat.InputDeviceListener,
                V16InputDeviceListener>();
    }

    @Override
    public InputDevice getInputDevice(int id) {
        return inputManager.getInputDevice(id);
    }

    @Override
    public int[] getInputDeviceIds() {
        return inputManager.getInputDeviceIds();
    }

    static class V16InputDeviceListener implements
            InputManager.InputDeviceListener {
        final InputManagerCompat.InputDeviceListener mIDL;

        public V16InputDeviceListener(InputDeviceListener idl) {
            mIDL = idl;
        }

        @Override
        public void onInputDeviceAdded(int deviceId) {
            mIDL.onInputDeviceAdded(deviceId);
        }

        // Do the same for device change and removal
        ...
    }

    @Override
    public void registerInputDeviceListener(InputDeviceListener listener,
            Handler handler) {
        V16InputDeviceListener v16Listener = new
                V16InputDeviceListener(listener);
        inputManager.registerInputDeviceListener(v16Listener, handler);
        listeners.put(listener, v16Listener);
    }

    // Do the same for unregistering an input device listener
    ...

    @Override
    public void onGenericMotionEvent(MotionEvent event) {
        // unused in V16
    }

    @Override
    public void onPause() {
        // unused in V16
    }

    @Override
    public void onResume() {
        // unused in V16
    }

}

Arayüzü Android 3.1 ile Android 4.0 arasındaki sürümlerde uygulama

Android 3.1'den Android 4.0'a kadar olan sürümleri destekleyen bir InputManagerCompat uygulaması oluşturmak için şunu kullanabilirsiniz: aşağıdaki nesneler:

  • İzlenecek cihaz kimliklerinin SparseArray değeri oyun kumandaları gösterilebilir.
  • Cihaz etkinliklerini işlemek için Handler. Uygulama başlatıldığında veya devam ettirildiğinde, Handler yoklamayı başlatmak için bir mesaj alır. bağlantısı kesilebilir. Handler, kontrol etmek ve cihaz kimliğinin tespit edilip edilmediğini kontrol etmek için geri döndü. null değeri, oyun kumandasının bağlantı kesildi. Handler, uygulama şu durumda yoklamayı durdurur: duraklatıldı.
  • Map/InputManagerCompat.InputDeviceListener nesneler'i tıklayın. İzlenen bağlantının bağlantı durumunu güncellemek için işleyicileri kullanırsınız: oyun kumandaları.

Kotlin

// The InputManagerCompatV9 class is a reference implementation.
// The full code is provided in the ControllerSample.zip sample.
class InputManagerV9(
        val devices: SparseArray<Array<Long>> = SparseArray(),
        private val listeners:
        MutableMap<InputManager.InputDeviceListener, Handler> = mutableMapOf()
) : InputManagerCompat {
    private val defaultHandler: Handler = PollingMessageHandler(this)
    
}

Java

// The InputManagerCompatV9 class is a reference implementation.
// The full code is provided in the ControllerSample.zip sample.
public class InputManagerV9 implements InputManagerCompat {
    private final SparseArray<long[]> devices;
    private final Map<InputDeviceListener, Handler> listeners;
    private final Handler defaultHandler;
    

    public InputManagerV9() {
        devices = new SparseArray<long[]>();
        listeners = new HashMap<InputDeviceListener, Handler>();
        defaultHandler = new PollingMessageHandler(this);
    }
}

Uzanan bir PollingMessageHandler nesnesi uygulayın Handler ve handleMessage() yöntemidir. Bu yöntem, ekli bir oyun kumandasının ve kayıtlı dinleyicileri bilgilendirir.

Kotlin

private class PollingMessageHandler(
        inputManager: InputManagerV9,
        private val mInputManager: WeakReference<InputManagerV9> = WeakReference(inputManager)
) : Handler() {

    override fun handleMessage(msg: Message) {
        super.handleMessage(msg)
        when (msg.what) {
            MESSAGE_TEST_FOR_DISCONNECT -> {
                mInputManager.get()?.also { imv ->
                    val time = SystemClock.elapsedRealtime()
                    val size = imv.devices.size()
                    for (i in 0 until size) {
                        imv.devices.valueAt(i)?.also { lastContact ->
                            if (time - lastContact[0] > CHECK_ELAPSED_TIME) {
                                // check to see if the device has been
                                // disconnected
                                val id = imv.devices.keyAt(i)
                                if (null == InputDevice.getDevice(id)) {
                                    // Notify the registered listeners
                                    // that the game controller is disconnected
                                    imv.devices.remove(id)
                                } else {
                                    lastContact[0] = time
                                }
                            }
                        }
                    }
                    sendEmptyMessageDelayed(MESSAGE_TEST_FOR_DISCONNECT, CHECK_ELAPSED_TIME)
                }
            }
        }
    }
}

Java

private static class PollingMessageHandler extends Handler {
    private final WeakReference<InputManagerV9> inputManager;

    PollingMessageHandler(InputManagerV9 im) {
        inputManager = new WeakReference<InputManagerV9>(im);
    }

    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        switch (msg.what) {
            case MESSAGE_TEST_FOR_DISCONNECT:
                InputManagerV9 imv = inputManager.get();
                if (null != imv) {
                    long time = SystemClock.elapsedRealtime();
                    int size = imv.devices.size();
                    for (int i = 0; i < size; i++) {
                        long[] lastContact = imv.devices.valueAt(i);
                        if (null != lastContact) {
                            if (time - lastContact[0] > CHECK_ELAPSED_TIME) {
                                // check to see if the device has been
                                // disconnected
                                int id = imv.devices.keyAt(i);
                                if (null == InputDevice.getDevice(id)) {
                                    // Notify the registered listeners
                                    // that the game controller is disconnected
                                    imv.devices.remove(id);
                                } else {
                                    lastContact[0] = time;
                                }
                            }
                        }
                    }
                    sendEmptyMessageDelayed(MESSAGE_TEST_FOR_DISCONNECT,
                            CHECK_ELAPSED_TIME);
                }
                break;
        }
    }
}

Oyun kumandasının bağlantısının kesilmesiyle ilgili yoklamayı başlatmak ve durdurmak için geçersiz kılın şu yöntemleri kullanabilirsiniz:

Kotlin

private const val MESSAGE_TEST_FOR_DISCONNECT = 101
private const val CHECK_ELAPSED_TIME = 3000L

class InputManagerV9(
        val devices: SparseArray<Array<Long>> = SparseArray(),
        private val listeners:
        MutableMap<InputManager.InputDeviceListener, Handler> = mutableMapOf()
) : InputManagerCompat {
    ...
    override fun onPause() {
        defaultHandler.removeMessages(MESSAGE_TEST_FOR_DISCONNECT)
    }

    override fun onResume() {
        defaultHandler.sendEmptyMessageDelayed(MESSAGE_TEST_FOR_DISCONNECT, CHECK_ELAPSED_TIME)
    }
    ...
}

Java

private static final int MESSAGE_TEST_FOR_DISCONNECT = 101;
private static final long CHECK_ELAPSED_TIME = 3000L;

@Override
public void onPause() {
    defaultHandler.removeMessages(MESSAGE_TEST_FOR_DISCONNECT);
}

@Override
public void onResume() {
    defaultHandler.sendEmptyMessageDelayed(MESSAGE_TEST_FOR_DISCONNECT,
            CHECK_ELAPSED_TIME);
}

Bir giriş cihazının eklendiğini algılamak için onGenericMotionEvent() yöntemini çağırın. Sistem bir hareket etkinliği bildirdiğinde Bu etkinliğin zaten izlenen bir cihaz kimliğinden mi yoksa bir cihazdan mı geldiğini kontrol edin. yeni cihaz kimliği. Cihaz kimliği yeniyse kayıtlı dinleyicileri bilgilendirin.

Kotlin

override fun onGenericMotionEvent(event: MotionEvent) {
    // detect new devices
    val id = event.deviceId
    val timeArray: Array<Long> = mDevices.get(id) ?: run {
        // Notify the registered listeners that a game controller is added
        ...
        arrayOf<Long>().also {
            mDevices.put(id, it)
        }
    }
    timeArray[0] = SystemClock.elapsedRealtime()
}

Java

@Override
public void onGenericMotionEvent(MotionEvent event) {
    // detect new devices
    int id = event.getDeviceId();
    long[] timeArray = mDevices.get(id);
    if (null == timeArray) {
        // Notify the registered listeners that a game controller is added
        ...
        timeArray = new long[1];
        mDevices.put(id, timeArray);
    }
    long time = SystemClock.elapsedRealtime();
    timeArray[0] = time;
}

Dinleyicilerin bildirilmesi, DeviceEvent gönderilecek Handler nesne İleti sırasına Runnable nesne eklendi. DeviceEvent bir InputManagerCompat.InputDeviceListener referansı içeriyor. Zaman DeviceEvent çalıştırılır, işleyicinin uygun geri çağırma yöntemi oyun kumandasının eklendiğini, değiştirildiğini veya kaldırıldığını bildirmek için kullanılır.

Kotlin

class InputManagerV9(
        val devices: SparseArray<Array<Long>> = SparseArray(),
        private val listeners:
        MutableMap<InputManager.InputDeviceListener, Handler> = mutableMapOf()
) : InputManagerCompat {
    ...
    override fun registerInputDeviceListener(
            listener: InputManager.InputDeviceListener,
            handler: Handler?
    ) {
        listeners[listener] = handler ?: defaultHandler
    }

    override fun unregisterInputDeviceListener(listener: InputManager.InputDeviceListener) {
        listeners.remove(listener)
    }

    private fun notifyListeners(why: Int, deviceId: Int) {
        // the state of some device has changed
        listeners.forEach { listener, handler ->
            DeviceEvent.getDeviceEvent(why, deviceId, listener).also {
                handler?.post(it)
            }
        }
    }
    ...
}

private val sObjectQueue: Queue<DeviceEvent> = ArrayDeque<DeviceEvent>()

private class DeviceEvent(
        private var mMessageType: Int,
        private var mId: Int,
        private var mListener: InputManager.InputDeviceListener
) : Runnable {

    companion object {
        fun getDeviceEvent(messageType: Int, id: Int, listener: InputManager.InputDeviceListener) =
                sObjectQueue.poll()?.apply {
                    mMessageType = messageType
                    mId = id
                    mListener = listener
                } ?: DeviceEvent(messageType, id, listener)

    }

    override fun run() {
        when(mMessageType) {
            ON_DEVICE_ADDED -> mListener.onInputDeviceAdded(mId)
            ON_DEVICE_CHANGED -> mListener.onInputDeviceChanged(mId)
            ON_DEVICE_REMOVED -> mListener.onInputDeviceChanged(mId)
            else -> {
                // Handle unknown message type
            }
        }
    }

}

Java

@Override
public void registerInputDeviceListener(InputDeviceListener listener,
        Handler handler) {
    listeners.remove(listener);
    if (handler == null) {
        handler = defaultHandler;
    }
    listeners.put(listener, handler);
}

@Override
public void unregisterInputDeviceListener(InputDeviceListener listener) {
    listeners.remove(listener);
}

private void notifyListeners(int why, int deviceId) {
    // the state of some device has changed
    if (!listeners.isEmpty()) {
        for (InputDeviceListener listener : listeners.keySet()) {
            Handler handler = listeners.get(listener);
            DeviceEvent odc = DeviceEvent.getDeviceEvent(why, deviceId,
                    listener);
            handler.post(odc);
        }
    }
}

private static class DeviceEvent implements Runnable {
    private int mMessageType;
    private int mId;
    private InputDeviceListener mListener;
    private static Queue<DeviceEvent> sObjectQueue =
            new ArrayDeque<DeviceEvent>();
    ...

    static DeviceEvent getDeviceEvent(int messageType, int id,
            InputDeviceListener listener) {
        DeviceEvent curChanged = sObjectQueue.poll();
        if (null == curChanged) {
            curChanged = new DeviceEvent();
        }
        curChanged.mMessageType = messageType;
        curChanged.mId = id;
        curChanged.mListener = listener;
        return curChanged;
    }

    @Override
    public void run() {
        switch (mMessageType) {
            case ON_DEVICE_ADDED:
                mListener.onInputDeviceAdded(mId);
                break;
            case ON_DEVICE_CHANGED:
                mListener.onInputDeviceChanged(mId);
                break;
            case ON_DEVICE_REMOVED:
                mListener.onInputDeviceRemoved(mId);
                break;
            default:
                // Handle unknown message type
                ...
                break;
        }
        // Put this runnable back in the queue
        sObjectQueue.offer(this);
    }
}

Artık iki InputManagerCompat uygulamanız var: biri , Android 4.1 ve sonraki sürümleri çalıştıran cihazlarda, Android 3.1 ile Android 4.0 arasındaki sürümleri çalıştıran cihazlarda çalışan bir programdır.

Sürüme özgü uygulamayı kullanın

Sürüme özgü geçiş mantığı, fabrikada bulun.

Kotlin

object Factory {
    fun getInputManager(context: Context): InputManagerCompat =
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
                InputManagerV16(context)
            } else {
                InputManagerV9()
            }
}

Java

public static class Factory {
    public static InputManagerCompat getInputManager(Context context) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
            return new InputManagerV16(context);
        } else {
            return new InputManagerV9();
        }
    }
}

Artık bir InputManagerCompat nesnesini örneklendirebilir ve ana makinenizde bir InputManagerCompat.InputDeviceListener kaydedin View. Belirlediğiniz sürüm değiştirme mantığı nedeniyle olduğunda, oyununuz da otomatik olarak Android sürümü yüklü olmalıdır.

Kotlin

class GameView(context: Context) : View(context), InputManager.InputDeviceListener {
    private val inputManager: InputManagerCompat = Factory.getInputManager(context).apply {
        registerInputDeviceListener(this@GameView, null)
        ...
    }
    ...
}

Java

public class GameView extends View implements InputDeviceListener {
    private InputManagerCompat inputManager;
    ...

    public GameView(Context context, AttributeSet attrs) {
        inputManager =
                InputManagerCompat.Factory.getInputManager(this.getContext());
        inputManager.registerInputDeviceListener(this, null);
        ...
    }
}

Ardından, onGenericMotionEvent() yöntemi aşağıda açıklandığı gibi ana görünümünüzde Oyundan MotionEvent İşleme Kumanda: Oyununuz artık oyun kumandası etkinliklerini işleyebilir. .

Kotlin

override fun onGenericMotionEvent(event: MotionEvent): Boolean {
    inputManager.onGenericMotionEvent(event)

    // Handle analog input from the controller as normal
    ...
    return super.onGenericMotionEvent(event)
}

Java

@Override
public boolean onGenericMotionEvent(MotionEvent event) {
    inputManager.onGenericMotionEvent(event);

    // Handle analog input from the controller as normal
    ...
    return super.onGenericMotionEvent(event);
}

Bu uyumluluk kodunun eksiksiz bir uygulamasını ControllerSample.zip örneğinde GameView sınıf sağlandı yukarıdan indirebilirsiniz.