यूएसबी होस्ट की खास जानकारी

जब आपका Android से चलने वाला डिवाइस, यूएसबी होस्ट मोड में होता है, तो वह यूएसबी होस्ट के तौर पर काम करता है, बस को चलाता है, और कनेक्ट किए गए यूएसबी डिवाइसों की गिनती करता है. USB होस्ट मोड Android 3.1 और उसके बाद वाले वर्शन में समर्थित है.

एपीआई की खास जानकारी

शुरू करने से पहले, यह समझना ज़रूरी है कि आपको किन क्लास पर काम करना है. कॉन्टेंट बनाने नीचे दी गई टेबल में, android.hardware.usb पैकेज में मौजूद यूएसबी होस्ट एपीआई के बारे में बताया गया है.

टेबल 1. यूएसबी होस्ट एपीआई

कक्षा ब्यौरा
UsbManager इसकी मदद से, कनेक्ट किए गए यूएसबी डिवाइसों की गिनती की जा सकती है और उनसे संपर्क किया जा सकता है.
UsbDevice यह कनेक्ट किए गए यूएसबी डिवाइस को दिखाता है. साथ ही, इसमें इसकी पहचान करने के तरीके शामिल होते हैं जानकारी, इंटरफ़ेस, और एंडपॉइंट मिलते हैं.
UsbInterface यह यूएसबी डिवाइस का इंटरफ़ेस दिखाता है, जो यूएसबी डिवाइस के लिए फ़ंक्शन का सेट तय करता है डिवाइस. किसी डिवाइस में एक या उससे ज़्यादा ऐसे इंटरफ़ेस हो सकते हैं जिन पर बातचीत करनी है.
UsbEndpoint इंटरफ़ेस एंडपॉइंट को दिखाता है, जो इस इंटरफ़ेस के लिए कम्यूनिकेशन चैनल होता है. अगर आप इंटरफ़ेस में एक या उससे ज़्यादा एंडपॉइंट हो सकते हैं. साथ ही, आम तौर पर इसके लिए इनपुट और आउटपुट एंडपॉइंट होते हैं से बातचीत करने की सुविधा देती हैं.
UsbDeviceConnection डिवाइस से कनेक्शन दिखाता है, जो एंडपॉइंट पर डेटा ट्रांसफ़र करता है. यह क्लास आपको सिंक्रोनस या एसिंक्रोनस रूप से डेटा को आगे और पीछे भेजने की सुविधा देता है.
UsbRequest यह UsbDeviceConnection के ज़रिए किसी डिवाइस से संपर्क करने के एसिंक्रोनस अनुरोध को दिखाता है.
UsbConstants Linux के linux/usb/ch9.h में दी गई परिभाषाओं से जुड़े यूएसबी कॉन्सटेंट के बारे में बताता है कर्नेल.

ज़्यादातर मामलों में, आपको इन सभी क्लास का इस्तेमाल करना होगा (UsbRequest सिर्फ़ तब ज़रूरी होता है, जब आपने एसिंक्रोनस कम्यूनिकेशन किया हो) यूएसबी डिवाइस से कम्युनिकेट करते समय. आम तौर पर, आपको जो UsbDevice मिलता है उसे वापस पाने के लिए, UsbManager मिलता है. जब आपके पास डिवाइस हो, तब आपको सही UsbInterface और उस UsbEndpoint को ढूंढना होगा कम्युनिकेट करने के लिए डिज़ाइन किया गया है. सही एंडपॉइंट मिलने के बाद, यूएसबी डिवाइस से संपर्क करने के लिए UsbDeviceConnection खोलें.

Android मेनिफ़ेस्ट की ज़रूरी शर्तें

नीचे दी गई सूची में यह बताया गया है कि आपको अपने ऐप्लिकेशन की मेनिफ़ेस्ट फ़ाइल में, पहले क्या जोड़ना होगा यूएसबी होस्ट एपीआई के साथ काम करता है:

  • हालांकि, Android पर चलने वाले सभी डिवाइस, यूएसबी होस्ट एपीआई के साथ काम करने की गारंटी नहीं देते, इसलिए कोई <uses-feature> एलिमेंट शामिल करें, जो बताता है कि आपका ऐप्लिकेशन android.hardware.usb.host सुविधा.
  • ऐप्लिकेशन के SDK टूल को एपीआई लेवल 12 या उसके बाद के लेवल पर सेट करें. यूएसबी होस्ट एपीआई ये नहीं हैं जो पुराने एपीआई लेवल पर मौजूद हैं.
  • अगर आप चाहते हैं कि आपके ऐप्लिकेशन को अटैच किए गए यूएसबी डिवाइस के बारे में सूचना दी जाए, तो इसके लिए <intent-filter> और <meta-data> एलिमेंट का जोड़ा आपकी मुख्य गतिविधि में android.hardware.usb.action.USB_DEVICE_ATTACHED इंटेंट. कॉन्टेंट बनाने <meta-data> एलिमेंट, बाहरी एक्सएमएल रिसॉर्स फ़ाइल पर ले जाता है, जो इसके बारे में जानकारी देता है डिवाइस की पहचान करने से जुड़ी जानकारी.

    एक्सएमएल रिसॉर्स फ़ाइल में, यूएसबी के लिए <usb-device> एलिमेंट के बारे में बताएं फ़िल्टर करें. नीचे दी गई सूची में, एट्रिब्यूट के बारे में बताया गया है <usb-device>. आम तौर पर, अगर आपको फ़िल्टर करना है, तो वेंडर और प्रॉडक्ट आईडी का इस्तेमाल करें और अगर आपको किसी ग्रुप के हिसाब से फ़िल्टर करना है, तो क्लास, सब-क्लास, और प्रोटोकॉल का इस्तेमाल करें जैसे, बड़ी संख्या में स्टोरेज डिवाइस या डिजिटल कैमरे. आप कोई नहीं या ये सभी एट्रिब्यूट इस्तेमाल किए जा सकते हैं. कोई भी विशेषता तय नहीं करना हर यूएसबी डिवाइस से मेल खाता है, इसलिए सिर्फ़ यही करें अगर आपके ऐप्लिकेशन को इसकी ज़रूरत है, तो:

    • vendor-id
    • product-id
    • class
    • subclass
    • protocol (डिवाइस या इंटरफ़ेस)

    संसाधन फ़ाइल को res/xml/ डायरेक्ट्री में सेव करें. संसाधन फ़ाइल का नाम (.xml एक्सटेंशन के बिना) वही होना चाहिए जो आपने <meta-data> एलिमेंट. एक्सएमएल संसाधन फ़ाइल का फ़ॉर्मैट इसमें है उदाहरण देखें.

मेनिफ़ेस्ट और रिसॉर्स फ़ाइल के उदाहरण

नीचे दिए गए उदाहरण में, मेनिफ़ेस्ट का एक सैंपल और उससे जुड़ी रिसॉर्स फ़ाइल दिखाई गई है:

<manifest ...>
    <uses-feature android:name="android.hardware.usb.host" />
    <uses-sdk android:minSdkVersion="12" />
    ...
    <application>
        <activity ...>
            ...
            <intent-filter>
                <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
            </intent-filter>

            <meta-data android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
                android:resource="@xml/device_filter" />
        </activity>
    </application>
</manifest>

इस स्थिति में, निम्न संसाधन फ़ाइल को res/xml/device_filter.xml और तय करता है कि कोई भी यूएसबी डिवाइस, विशेषताओं को फ़िल्टर किया जाना चाहिए:

<?xml version="1.0" encoding="utf-8"?>

<resources>
    <usb-device vendor-id="1234" product-id="5678" class="255" subclass="66" protocol="1" />
</resources>

डिवाइसों के साथ काम करें

जब उपयोगकर्ता यूएसबी डिवाइसों को Android पर चलने वाले डिवाइस से कनेक्ट करते हैं, तब Android सिस्टम यह पता लगा सकता है कि कि क्या आपकी ऐप्लिकेशन कनेक्ट किए गए डिवाइस में रुचि रखती है. अगर ऐसा है, तो डिवाइस से संपर्क करने की सुविधा मिलती है. ऐसा करने के लिए, आपके ऐप्लिकेशन को:

  1. इंटेंट फ़िल्टर का इस्तेमाल करके, कनेक्ट किए गए यूएसबी डिवाइसों के बारे में जानें. इससे आपको तब सूचना मिलेगी, जब उपयोगकर्ता किसी यूएसबी डिवाइस को कनेक्ट करता है या पहले से कनेक्ट किए गए यूएसबी डिवाइसों की गिनती करके.
  2. अगर उपयोगकर्ता ने अब तक यूएसबी डिवाइस से कनेक्ट करने की अनुमति नहीं ली है, तो उससे पूछें.
  3. यूएसबी डिवाइस से संपर्क करने के लिए, सही इंटरफ़ेस पर मौजूद डेटा को पढ़ें और उसमें बदलाव करें एंडपॉइंट के बारे में भी बताएंगे.

किसी डिवाइस के बारे में जानें

आपका ऐप्लिकेशन या तो किसी इंटेंट फ़िल्टर का इस्तेमाल करके, यूएसबी डिवाइसों को खोज सकता है. इसकी सूचना तब दी जाएगी, जब जब उपयोगकर्ता किसी डिवाइस को कनेक्ट करता है या पहले से कनेक्ट किए गए यूएसबी डिवाइसों की सूची बनाता है. किसी इंटेंट फ़िल्टर तब उपयोगी होता है, जब आपको यह सुविधा चाहिए कि आपका ऐप्लिकेशन पसंदीदा डिवाइस. अगर आपको सभी कनेक्ट किए गए यूएसबी डिवाइसों की सूची देखनी है, तो उनके बारे में जानकारी देना फ़ायदेमंद होता है कनेक्ट किए गए डिवाइस या आपके ऐप्लिकेशन ने किसी इंटेंट के लिए फ़िल्टर नहीं किया है.

इंटेंट फ़िल्टर का इस्तेमाल करें

आपका ऐप्लिकेशन किसी विशिष्ट USB डिवाइस को खोज सके, इसके लिए आप इंटेंट फ़िल्टर android.hardware.usb.action.USB_DEVICE_ATTACHED इंटेंट के लिए फ़िल्टर. इसके साथ इस इंटेंट फ़िल्टर के लिए, आपको एक ऐसी संसाधन फ़ाइल को तय करना होगा जो यूएसबी की प्रॉपर्टी जैसे कि प्रॉडक्ट और वेंडर आईडी. जब उपयोगकर्ता आपके डिवाइस से मेल खाने वाले डिवाइस को कनेक्ट करते हैं फ़िल्टर लागू कर देते हैं, तो सिस्टम उन्हें एक डायलॉग दिखाता है. इसमें पूछा जाता है कि क्या वे आपका ऐप्लिकेशन शुरू करना चाहते हैं. अगर उपयोगकर्ता इसे स्वीकार करते हैं, तो आपके ऐप्लिकेशन को डिवाइस का ऐक्सेस अपने-आप मिल जाता है. ऐसा तब तक होता है, जब तक डिवाइस डिसकनेक्ट हो गया.

यहां दिए गए उदाहरण में, इंटेंट फ़िल्टर का एलान करने का तरीका बताया गया है:

<activity ...>
...
    <intent-filter>
        <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
    </intent-filter>

    <meta-data android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
        android:resource="@xml/device_filter" />
</activity>

नीचे दिए गए उदाहरण में, उस संसाधन फ़ाइल का एलान करने का तरीका बताया गया है जो इन यूएसबी डिवाइसों में आपकी दिलचस्पी है:

<?xml version="1.0" encoding="utf-8"?>

<resources>
    <usb-device vendor-id="1234" product-id="5678" />
</resources>

अपनी गतिविधि में, आपके पास उस UsbDevice को पाने का विकल्प होता है जिससे पता चलता है कि इस तरह के इंटेंट से अटैच किया गया डिवाइस:

Kotlin

val device: UsbDevice? = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE)

Java

UsbDevice device = (UsbDevice) intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);

डिवाइसों की गिनती करें

अगर आपके ऐप्लिकेशन को इस समय कनेक्ट किए गए सभी यूएसबी डिवाइसों की जांच करनी है जब आपका ऐप्लिकेशन चल रहा होता है, तब यह बस में डिवाइसों की गिनती कर सकता है. सभी का हैश मैप पाने के लिए getDeviceList() तरीके का इस्तेमाल करें कनेक्ट किए गए यूएसबी डिवाइस. अगर आपको हैश मैप को यूएसबी डिवाइस के नाम से सेट करना है मैप से डिवाइस हासिल कर सकते हैं.

Kotlin

val manager = getSystemService(Context.USB_SERVICE) as UsbManager
...
val deviceList = manager.getDeviceList()
val device = deviceList.get("deviceName")

Java

UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);
...
HashMap<String, UsbDevice> deviceList = manager.getDeviceList();
UsbDevice device = deviceList.get("deviceName");

अगर आप चाहें, तो हैश मैप से इटरेटर भी ले सकते हैं और हर डिवाइस को प्रोसेस कर सकते हैं एक-एक करके:

Kotlin

val manager = getSystemService(Context.USB_SERVICE) as UsbManager
..
val deviceList: HashMap<String, UsbDevice> = manager.deviceList
deviceList.values.forEach { device ->
    // your code
}

Java

UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);
...
HashMap<String, UsbDevice> deviceList = manager.getDeviceList();
Iterator<UsbDevice> deviceIterator = deviceList.values().iterator();
while(deviceIterator.hasNext()){
    UsbDevice device = deviceIterator.next();
    // your code
}

डिवाइस से संपर्क करने की अनुमति लेना

USB डिवाइस से संचार करने से पहले, आपके ऐप्लिकेशन को आपकी उपयोगकर्ता.

ध्यान दें: यदि आपका ऐप्लिकेशन किसी इंटेंट फ़िल्टर का इस्तेमाल करें, ताकि यूएसबी डिवाइसों के कनेक्ट होने पर उन्हें खोजा जा सके. यह फ़िल्टर अपने-आप अनुमति दें, अगर उपयोगकर्ता आपके ऐप्लिकेशन को इंटेंट मैनेज करने की अनुमति देता है. अगर ऐसा नहीं है, तो आपको अनुमति देनी होगी.

कुछ मामलों में, साफ़ तौर पर अनुमति लेना ज़रूरी हो सकता है. उदाहरण के लिए, जब आपका ऐप्लिकेशन उन USB डिवाइस की सूची बनाता है जो पहले से कनेक्ट हैं और फिर जिनसे संपर्क करना चाहता है एक. किसी डिवाइस से संपर्क करने से पहले, आपको उसे ऐक्सेस करने की अनुमति लेनी होगी. अगर आपने नहीं, तो अगर उपयोगकर्ता ने डिवाइस ऐक्सेस करने की अनुमति नहीं दी है, तो आपको रनटाइम की गड़बड़ी मिलेगी.

साफ़ तौर पर अनुमति पाने के लिए, सबसे पहले एक ब्रॉडकास्ट रिसीवर बनाएं. यह व्यक्ति इसे सुनता है यह इंटेंट, requestPermission() को कॉल करने पर ब्रॉडकास्ट होता है. requestPermission() को किए जाने वाले कॉल डिवाइस से कनेक्ट करने की अनुमति मांगने वाला उपयोगकर्ता. नीचे दिया गया सैंपल कोड, ब्रॉडकास्ट रिसीवर बनाएं:

Kotlin

private const val ACTION_USB_PERMISSION = "com.android.example.USB_PERMISSION"

private val usbReceiver = object : BroadcastReceiver() {

    override fun onReceive(context: Context, intent: Intent) {
        if (ACTION_USB_PERMISSION == intent.action) {
            synchronized(this) {
                val device: UsbDevice? = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE)

                if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
                    device?.apply {
                        // call method to set up device communication
                    }
                } else {
                    Log.d(TAG, "permission denied for device $device")
                }
            }
        }
    }
}

Java

private static final String ACTION_USB_PERMISSION =
    "com.android.example.USB_PERMISSION";
private final BroadcastReceiver usbReceiver = new BroadcastReceiver() {

    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if (ACTION_USB_PERMISSION.equals(action)) {
            synchronized (this) {
                UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);

                if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
                    if(device != null){
                      // call method to set up device communication
                   }
                }
                else {
                    Log.d(TAG, "permission denied for device " + device);
                }
            }
        }
    }
};

ब्रॉडकास्ट रिसीवर को रजिस्टर करने के लिए, इसे अपने onCreate() तरीके में गतिविधि:

Kotlin

private const val ACTION_USB_PERMISSION = "com.android.example.USB_PERMISSION"
...
val manager = getSystemService(Context.USB_SERVICE) as UsbManager
...
permissionIntent = PendingIntent.getBroadcast(this, 0,
                  Intent(ACTION_USB_PERMISSION), PendingIntent.FLAG_IMMUTABLE)
val filter = IntentFilter(ACTION_USB_PERMISSION)
registerReceiver(usbReceiver, filter)

Java

UsbManager usbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
private static final String ACTION_USB_PERMISSION =
    "com.android.example.USB_PERMISSION";
...
permissionIntent = PendingIntent.getBroadcast(this, 0,
              new Intent(ACTION_USB_PERMISSION), PendingIntent.FLAG_IMMUTABLE);
IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
registerReceiver(usbReceiver, filter);

उपयोगकर्ताओं को डिवाइस से कनेक्ट करने की अनुमति मांगने वाला डायलॉग बॉक्स दिखाने के लिए, requestPermission() तरीके को कॉल करें:

Kotlin

lateinit var device: UsbDevice
...
usbManager.requestPermission(device, permissionIntent)

Java

UsbDevice device;
...
usbManager.requestPermission(device, permissionIntent);

जब उपयोगकर्ता डायलॉग का जवाब देते हैं, तो आपके ब्रॉडकास्ट रिसीवर को वह इंटेंट मिलता है जिसमें EXTRA_PERMISSION_GRANTED अतिरिक्त, जो एक बूलियन है इसका इस्तेमाल करें. डिफ़ॉल्ट वैल्यू से कनेक्ट करने से पहले, सही वैल्यू पाने के लिए इस अतिरिक्त वैल्यू की जांच करें डिवाइस.

डिवाइस से बातचीत करें

किसी USB डिवाइस के साथ संचार सिंक्रोनस या एसिंक्रोनस हो सकता है. दोनों ही मामलों में, आपको को एक नया थ्रेड बनाना चाहिए जिस पर सभी डेटा ट्रांसमिशन को पूरा करना है, ताकि आप यूज़र इंटरफ़ेस (यूआई) थ्रेड. किसी डिवाइस के साथ सही तरीके से कम्यूनिकेशन सेट अप करने के लिए, आपको UsbInterface और UsbEndpoint वह डिवाइस जिस पर आपको कम्यूनिकेट करना है और UsbDeviceConnection के साथ इस एंडपॉइंट पर अनुरोध भेजना है. आम तौर पर, आपका कोड:

  • UsbDevice ऑब्जेक्ट के एट्रिब्यूट की जांच करें. जैसे, प्रॉडक्ट आईडी वेंडर आईडी या डिवाइस की क्लास का इस्तेमाल करता है. इससे यह पता चलता है कि आपको डिवाइस.
  • अगर आपने तय कर लिया है कि आपको इस डिवाइस से ही संपर्क करना है, तो UsbInterface, जिनका इस्तेमाल करके आपको बातचीत करनी है उस इंटरफ़ेस का सही UsbEndpoint. इंटरफ़ेस में एक या ज़्यादा एंडपॉइंट हैं और आम तौर पर इसमें दो-तरफ़ा के लिए एक इनपुट और आउटपुट एंडपॉइंट होगा बातचीत करते हैं.
  • सही एंडपॉइंट मिलने पर, UsbDeviceConnection खोलें उस एंडपॉइंट पर.
  • bulkTransfer() या controlTransfer() तरीके का इस्तेमाल करके, वह डेटा दें जिसे आपको एंडपॉइंट पर ट्रांसमिट करना है. आपको ऐसा करना चाहिए मुख्य यूज़र इंटरफ़ेस (यूआई) थ्रेड को ब्लॉक होने से रोकने के लिए, इस चरण को किसी दूसरे थ्रेड में पूरा करें. ज़्यादा के लिए Android में थ्रेड का इस्तेमाल करने के बारे में जानकारी. प्रोसेस और Threads.

नीचे दिया गया कोड स्निपेट, सिंक्रोनस डेटा ट्रांसफ़र करने का एक आसान तरीका है. आपका कोड के पास कम्यूनिकेशन के लिए, सही इंटरफ़ेस और एंडपॉइंट को सही तरीके से खोजने के लिए ज़्यादा लॉजिक होना चाहिए साथ ही, डेटा को मुख्य यूज़र इंटरफ़ेस (यूआई) थ्रेड से अलग थ्रेड में भी ट्रांसफ़र किया जाना चाहिए:

Kotlin

private lateinit var bytes: ByteArray
private val TIMEOUT = 0
private val forceClaim = true

...

device?.getInterface(0)?.also { intf ->
    intf.getEndpoint(0)?.also { endpoint ->
        usbManager.openDevice(device)?.apply {
            claimInterface(intf, forceClaim)
            bulkTransfer(endpoint, bytes, bytes.size, TIMEOUT) //do in another thread
        }
    }
}

Java

private Byte[] bytes;
private static int TIMEOUT = 0;
private boolean forceClaim = true;

...

UsbInterface intf = device.getInterface(0);
UsbEndpoint endpoint = intf.getEndpoint(0);
UsbDeviceConnection connection = usbManager.openDevice(device);
connection.claimInterface(intf, forceClaim);
connection.bulkTransfer(endpoint, bytes, bytes.length, TIMEOUT); //do in another thread

डेटा को एसिंक्रोनस तरीके से भेजने के लिए, initialize को UsbRequest क्लास और एसिंक्रोनस अनुरोध queue का इस्तेमाल करें. इसके बाद, नतीजे का इंतज़ार करें requestWait() के साथ.

डिवाइस से कम्यूनिकेशन बंद किया जा रहा है

डिवाइस से संपर्क करने के बाद या डिवाइस डिटैच करने पर, UsbInterface और UsbDeviceConnection को बंद करें releaseInterface() को कॉल किया और close(). डिटैच किए गए इवेंट सुनने के लिए, ब्रॉडकास्ट रिसीवर बनाने के लिए नीचे दिया गया तरीका अपनाएं:

Kotlin

var usbReceiver: BroadcastReceiver = object : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {

        if (UsbManager.ACTION_USB_DEVICE_DETACHED == intent.action) {
            val device: UsbDevice? = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE)
            device?.apply {
                // call your method that cleans up and closes communication with the device
            }
        }
    }
}

Java

BroadcastReceiver usbReceiver = new BroadcastReceiver() {
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();

      if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) {
            UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
            if (device != null) {
                // call your method that cleans up and closes communication with the device
            }
        }
    }
};

मेनिफ़ेस्ट के बजाय ऐप्लिकेशन के अंदर ब्रॉडकास्ट रिसीवर बनाने से आपको ऐप्लिकेशन, उसके चलने के दौरान केवल अलग किए गए इवेंट को हैंडल करता है. इस तरह, डिटैच किए गए इवेंट केवल उस ऐप्लिकेशन पर भेजा जाता है जो वर्तमान में चल रहा है और सभी ऐप्लिकेशन पर प्रसारित नहीं होता है.