Multi-Display Communications API का इस्तेमाल, सिस्टम का इस्तेमाल करने वाले ऐप्लिकेशन के लिए इसमें किया जा सकता है: AAOS का इस्तेमाल, उसी ऐप्लिकेशन (पैकेज के समान नाम वाले) से करने के लिए किया जा रहा है जो किसी दूसरे ऐप्लिकेशन में चल रहा है कार में ऑक्यूपंट ज़ोन. इस पेज पर, एपीआई को इंटिग्रेट करने का तरीका बताया गया है. सीखने में आपको यह भी दिख सकता है कि CarOccupantZoneManager.OccupantZoneInfo.
ऑक्यूपंट ज़ोन
ऑक्यूपंट ज़ोन का कॉन्सेप्ट, उपयोगकर्ता को डिसप्ले के सेट पर मैप करता है. हर ऑक्यूपंट ज़ोन में एक डिसप्ले है, जिसका टाइप DISPLAY_TYPE_MAIN. ऑक्यूपंट ज़ोन में अतिरिक्त डिसप्ले भी हो सकते हैं, जैसे कि क्लस्टर डिसप्ले. हर ऑक्यूपंट ज़ोन के लिए एक Android उपयोगकर्ता असाइन किया जाता है. हर उपयोगकर्ता के अपने खाते होते हैं और ऐप्लिकेशन चुनें.
हार्डवेयर कॉन्फ़िगरेशन
Comms API, सिर्फ़ एक SoC के साथ काम करता है. एक SoC मॉडल में, सभी ऑक्यूपंट ज़ोन और उपयोगकर्ता एक ही SoC पर चलते हैं. Comms API में तीन कॉम्पोनेंट होते हैं:
Power Management API का इस्तेमाल करके, क्लाइंट ऑक्यूपंट ज़ोन में दिखाया जाता है.
डिस्कवरी एपीआई का इस्तेमाल करके, क्लाइंट अन्य व्यस्त की स्थितियों पर नज़र रख सकता है साथ ही, उन ऑक्यूपंट ज़ोन में मिलते-जुलते क्लाइंट पर नज़र रखने के लिए किया जा सकता है. इस्तेमाल की जाने वाली चीज़ें कनेक्शन एपीआई का इस्तेमाल करने से पहले, Discovery API का इस्तेमाल करना चाहिए.
Connection API की मदद से, क्लाइंट अपने साथी क्लाइंट से, एक और ऑक्यूपंट ज़ोन और पीयर क्लाइंट को पेलोड भेजने के लिए.
कनेक्शन के लिए, Discovery API और Connection API की ज़रूरत होती है. द पावर management API ज़रूरी नहीं है.
Comms API अलग-अलग ऐप्लिकेशन के बीच कम्यूनिकेशन की सुविधा नहीं देता है. इसके बजाय, इसे सिर्फ़ एक जैसे पैकेज नाम वाले ऐप्लिकेशन के बीच कम्यूनिकेशन के लिए डिज़ाइन किया गया है और इसका इस्तेमाल सिर्फ़ अलग-अलग दिखने वाले उपयोगकर्ताओं के बीच बातचीत के लिए किया जाता है.
इंटिग्रेशन गाइड
AbstrackReceiverService को लागू करें
Payload
पाने के लिए, पैसे पाने वाले ऐप्लिकेशन को ऐब्स्ट्रैक्ट तरीके लागू करना ज़रूरी है
AbstractReceiverService
में परिभाषित किया गया है. उदाहरण के लिए:
public class MyReceiverService extends AbstractReceiverService {
@Override
public void onConnectionInitiated(@NonNull OccupantZoneInfo senderZone) {
}
@Override
public void onPayloadReceived(@NonNull OccupantZoneInfo senderZone,
@NonNull Payload payload) {
}
}
onConnectionInitiated()
तब शुरू होता है, जब भेजने वाला क्लाइंट किसी
इस रिसीवर क्लाइंट से कनेक्ट कर रहा है. अगर यह पता लगाने के लिए उपयोगकर्ता की पुष्टि करना ज़रूरी हो
तो कनेक्शन, MyReceiverService
को को
अनुमति से जुड़ी गतिविधि को सेव करने की कोशिश करेंगे. साथ ही, इसके हिसाब से acceptConnection()
या rejectConnection()
को कॉल करेंगे
ट्रैक करें. वरना, MyReceiverService
सिर्फ़ कॉल कर सकते हैं
acceptConnection()
.`
onPayloadReceived()is invoked when
MyReceiverServicehas received a
Payloadfrom the sender client.
MyReceiverService` को इसे बदल सकता है
करने का तरीका:
- अगर उपलब्ध हो, तो
Payload
को उससे जुड़े पाने वाले एंडपॉइंट पर फ़ॉरवर्ड करें. यहां की यात्रा पर हूं रजिस्टर किए गए रिसीवर के एंडपॉइंट पाने के लिए,getAllReceiverEndpoints()
पर कॉल करें. यहां की यात्रा पर हूंPayload
को दिए गए रिसीवर एंडपॉइंट पर फ़ॉरवर्ड करें,forwardPayload()
पर कॉल करें
या,
Payload
को कैश मेमोरी में सेव करें. साथ ही, इसे तब भेजें, जब पाने वाले का एंडपॉइंट अनुमानित हो रजिस्टर की गई है, जिसके लिएMyReceiverService
को इसके ज़रिए सूचना दी जाती हैonReceiverRegistered()
AbsडेटReceiverService का एलान करें
पाने वाले ऐप्लिकेशन को, लागू किए गए AbstractReceiverService
का एलान करना होगा
मेनिफ़ेस्ट फ़ाइल, कार्रवाई के साथ इंटेंट फ़िल्टर जोड़ें
आपको इस सेवा के लिए android.car.intent.action.RECEIVER_SERVICE
का इस्तेमाल करना है और इन शर्तों को पूरा करना ज़रूरी है
android.car.occupantconnection.permission.BIND_RECEIVER_SERVICE
अनुमति:
<service android:name=".MyReceiverService"
android:permission="android.car.occupantconnection.permission.BIND_RECEIVER_SERVICE"
android:exported="true">
<intent-filter>
<action android:name="android.car.intent.action.RECEIVER_SERVICE" />
</intent-filter>
</service>
android.car.occupantconnection.permission.BIND_RECEIVER_SERVICE
अनुमति
यह पक्का करता है कि सिर्फ़ फ़्रेमवर्क इस सेवा के साथ जुड़ सकता है. अगर यह सेवा
इस्तेमाल करने के लिए अनुमति की ज़रूरत नहीं होती. हालांकि, हो सकता है कि कोई दूसरा ऐप्लिकेशन इसे चालू कर पाए
और उसे सीधे Payload
भेजें.
अनुमति का एलान करें
क्लाइंट ऐप्लिकेशन को अपनी मेनिफ़ेस्ट फ़ाइल में अनुमतियों का एलान करना ज़रूरी है.
<!-- This permission is needed for connection API -->
<uses-permission android:name="android.car.permission.MANAGE_OCCUPANT_CONNECTION"/>
<!-- This permission is needed for discovery API -->
<uses-permission android:name="android.car.permission.MANAGE_REMOTE_DEVICE"/>
<!-- This permission is needed if the client app calls CarRemoteDeviceManager#setOccupantZonePower() -->
<uses-permission android:name="android.car.permission.CAR_POWER"/>
ऊपर दी गई तीनों अनुमतियों में से हर एक खास अधिकार वाली अनुमतियां हैं. ये अनुमतियां ज़रूरी हैं
अनुमति वाली सूची में मौजूद फ़ाइलों की मदद से, पहले से अनुमति दी जाती है. उदाहरण के लिए, यहां अनुमति वाली सूची में
MultiDisplayTest
ऐप्लिकेशन:
// packages/services/Car/data/etc/com.google.android.car.multidisplaytest.xml
<permissions>
<privapp-permissions package="com.google.android.car.multidisplaytest">
… …
<permission name="android.car.permission.MANAGE_OCCUPANT_CONNECTION"/>
<permission name="android.car.permission.MANAGE_REMOTE_DEVICE"/>
<permission name="android.car.permission.CAR_POWER"/>
</privapp-permissions>
</permissions>
कार मैनेजर चुनें
एपीआई का इस्तेमाल करने के लिए, क्लाइंट ऐप्लिकेशन को CarServiceLifecycleListener
रजिस्टर करना होगा, ताकि
उनसे जुड़े कार मैनेजर देखें:
private CarRemoteDeviceManager mRemoteDeviceManager;
private CarOccupantConnectionManager mOccupantConnectionManager;
private final Car.CarServiceLifecycleListener mCarServiceLifecycleListener = (car, ready) -> {
if (!ready) {
Log.w(TAG, "Car service crashed");
mRemoteDeviceManager = null;
mOccupantConnectionManager = null;
return;
}
mRemoteDeviceManager = car.getCarManager(CarRemoteDeviceManager.class);
mOccupantConnectionManager = car.getCarManager(CarOccupantConnectionManager.class);
};
Car.createCar(getContext(), /* handler= */ null, Car.CAR_WAIT_TIMEOUT_WAIT_FOREVER,
mCarServiceLifecycleListener);
(भेजने वाले) 'डिस्कवर'
रिसीवर क्लाइंट से कनेक्ट करने से पहले, भेजने वाले क्लाइंट को
CarRemoteDeviceManager.StateCallback
को रजिस्टर करके, पैसे पाने वाला क्लाइंट:
// The maps are accessed by the main thread only, so there is no multi-thread issue.
private final ArrayMap<OccupantZoneInfo, Integer> mOccupantZoneStateMap = new ArrayMap<>();
private final ArrayMap<OccupantZoneInfo, Integer> mAppStateMap = new ArrayMap<>();
private final StateCallback mStateCallback = new StateCallback() {
@Override
public void onOccupantZoneStateChanged(
@androidx.annotation.NonNull OccupantZoneInfo occupantZone,
int occupantZoneStates) {
mOccupantZoneStateMap.put(occupantZone, occupantZoneStates);
}
@Override
public void onAppStateChanged(
@androidx.annotation.NonNull OccupantZoneInfo occupantZone,
int appStates) {
mAppStateMap.put(occupantZone, appStates);
}
};
if (mRemoteDeviceManager != null) {
mRemoteDeviceManager.registerStateCallback(getActivity().getMainExecutor(),
mStateCallback);
}
रिसीवर से कनेक्शन का अनुरोध करने से पहले, भेजने वाले को यह पक्का करना होगा कि पाने वाले ऑक्यूपंट ज़ोन और रिसीवर ऐप्लिकेशन के फ़्लैग सेट किए गए हैं. या फिर, गड़बड़ियां हो सकती हैं. उदाहरण के लिए:
private boolean canRequestConnectionToReceiver(OccupantZoneInfo receiverZone) {
Integer zoneState = mOccupantZoneStateMap.get(receiverZone);
if ((zoneState == null) || (zoneState.intValue() & (FLAG_OCCUPANT_ZONE_POWER_ON
// FLAG_OCCUPANT_ZONE_SCREEN_UNLOCKED is not implemented yet. Right now
// just ignore this flag.
// | FLAG_OCCUPANT_ZONE_SCREEN_UNLOCKED
| FLAG_OCCUPANT_ZONE_CONNECTION_READY)) == 0) {
return false;
}
Integer appState = mAppStateMap.get(receiverZone);
if ((appState == null) ||
(appState.intValue() & (FLAG_CLIENT_INSTALLED
| FLAG_CLIENT_SAME_LONG_VERSION | FLAG_CLIENT_SAME_SIGNATURE
| FLAG_CLIENT_RUNNING | FLAG_CLIENT_IN_FOREGROUND)) == 0) {
return false;
}
return true;
}
हमारा सुझाव है कि भेजने वाले, पाने वाले से कनेक्शन का अनुरोध सिर्फ़ तब करें, जब पाने वाले के फ़्लैग सेट कर दिए गए हैं. हालांकि, इसके कुछ अपवाद हैं:
FLAG_OCCUPANT_ZONE_CONNECTION_READY
औरFLAG_CLIENT_INSTALLED
यह कनेक्शन बनाने के लिए कम से कम ज़रूरतों को पूरा करता है.अगर रिसीवर ऐप्लिकेशन को उपयोगकर्ता की अनुमति के लिए यूज़र इंटरफ़ेस (यूआई) दिखाना ज़रूरी है कनेक्शन,
FLAG_OCCUPANT_ZONE_POWER_ON
औरFLAG_OCCUPANT_ZONE_SCREEN_UNLOCKED
अन्य ज़रूरी शर्तें भी पूरी करना होगा. बेहतर उपयोगकर्ता अनुभव,FLAG_CLIENT_RUNNING
, औरFLAG_CLIENT_IN_FOREGROUND
का इस्तेमाल करने का सुझाव भी दिया जाता है. ऐसा न करने पर उपयोगकर्ता आश्चर्यचकित हो जाएं.फ़िलहाल (Android 15) में
FLAG_OCCUPANT_ZONE_SCREEN_UNLOCKED
लागू नहीं हुआ है. क्लाइंट ऐप्लिकेशन इसे अनदेखा कर सकता है.फ़िलहाल (Android 15) में, Comms API को एक से ज़्यादा उपयोगकर्ताओं के लिए एक साथ इस्तेमाल करने की सुविधा मिलती है Android इंस्टेंस, ताकि मिलते-जुलते ऐप्लिकेशन के लिए एक ही लंबा वर्शन कोड इस्तेमाल किया जा सके (
FLAG_CLIENT_SAME_LONG_VERSION
) और हस्ताक्षर (FLAG_CLIENT_SAME_SIGNATURE
). इस वजह से, ऐप्लिकेशन को यह पुष्टि नहीं करनी होगी कि दो मान सहमत हैं.
बेहतर उपयोगकर्ता अनुभव के लिए, अगर फ़्लैग नहीं है, तो भेजने वाला क्लाइंट यूज़र इंटरफ़ेस (यूआई) दिखा सकता है
सेट. उदाहरण के लिए, अगर FLAG_OCCUPANT_ZONE_SCREEN_UNLOCKED
सेट नहीं है, तो भेजने वाले
एक टोस्ट या एक डायलॉग दिखा सकता है, ताकि उपयोगकर्ता को उसकी स्क्रीन को अनलॉक करने का प्रॉम्प्ट भेजा जा सके
रिसीवर का ऑक्यूपंट ज़ोन.
जब भेजने वाले को रिसीवर ढूंढने की ज़रूरत न हो (उदाहरण के लिए, जब यह सभी रिसीवर और स्थापित कनेक्शन ढूंढ लेता है या निष्क्रिय हो जाता है), तो यह को रोका जाए.
if (mRemoteDeviceManager != null) {
mRemoteDeviceManager.unregisterStateCallback();
}
डिवाइस को खोजने की सुविधा बंद होने पर, मौजूदा कनेक्शन पर कोई असर नहीं पड़ता. भेजने वाले व्यक्ति ये काम कर सकते हैं
कनेक्ट किए गए रिसीवर को Payload
भेजना जारी रखें.
(भेजने वाला) कनेक्शन का अनुरोध करें
जब रिसीवर के सभी फ़्लैग सेट हो जाते हैं, तब भेजने वाला व्यक्ति कनेक्शन का अनुरोध कर सकता है पाने वाले को:
private final ConnectionRequestCallback mRequestCallback = new ConnectionRequestCallback() {
@Override
public void onConnected(OccupantZoneInfo receiverZone) {
}
@Override
public void onFailed(OccupantZoneInfo receiverZone, int connectionError) {
}
@Override
public void onDisconnected(OccupantZoneInfo receiverZone) {
}
};
if (mOccupantConnectionManager != null && canRequestConnectionToReceiver(receiverZone)) {
mOccupantConnectionManager.requestConnection(receiverZone,
getActivity().getMainExecutor(), mRequestCallback);
}
(पाने वाला सेवा) कनेक्शन स्वीकार करें
एक बार जब भेजने वाला, रिसीवर से कनेक्ट करने का अनुरोध करता है,
रिसीवर ऐप्लिकेशन में मौजूद AbstractReceiverService
को कार सेवा के लिए इस्तेमाल करना होगा,
और AbstractReceiverService.onConnectionInitiated()
शुरू हो जाएगा. जैसे
इसकी जानकारी (भेजने वाले) अनुरोध कनेक्शन में दी गई है,
onConnectionInitiated()
एक ऐब्स्ट्रैक्ट तरीका है और इसे
क्लाइंट ऐप्लिकेशन में मिलेगा.
जब पाने वाला व्यक्ति कनेक्शन का अनुरोध स्वीकार कर लेता है, तो भेजने वाले का
ConnectionRequestCallback.onConnected()
शुरू किया जाएगा और इसके बाद कनेक्शन
स्थापित हो जाता है.
(भेजने वाला) पेलोड भेजें
कनेक्शन बन जाने के बाद, भेजने वाला व्यक्ति Payload
को
पाने वाला:
if (mOccupantConnectionManager != null) {
Payload payload = ...;
try {
mOccupantConnectionManager.sendPayload(receiverZone, payload);
} catch (CarOccupantConnectionManager.PayloadTransferException e) {
Log.e(TAG, "Failed to send Payload to " + receiverZone);
}
}
भेजने वाला व्यक्ति, Payload
में Binder
ऑब्जेक्ट या बाइट अरे रख सकता है. अगर
भेजने वाले को अन्य डेटा टाइप भेजना होगा, तो डेटा को बाइट में क्रम से लगाना होगा
अरे का इस्तेमाल करें, तो Payload
ऑब्जेक्ट बनाने के लिए बाइट कलेक्शन का इस्तेमाल करें और
Payload
. इसके बाद, रिसीवर क्लाइंट को रिसीव किए गए डेटा से बाइट कलेक्शन मिलता है
Payload
, और बाइट अरे को उम्मीद के मुताबिक डेटा ऑब्जेक्ट में डीसीरियलाइज़ करता है.
उदाहरण के लिए, अगर ईमेल भेजने वाला व्यक्ति, पाने वाले को स्ट्रिंग hello
भेजना चाहता है
FragmentB
आईडी वाला एंडपॉइंट, डेटा टाइप तय करने के लिए प्रोटो बफ़र का इस्तेमाल कर सकता है
इस तरह:
message MyData {
required string receiver_endpoint_id = 1;
required string data = 2;
}
पहली इमेज में Payload
फ़्लो दिखाया गया है:
(पाने वाला सेवा) पेलोड पाएं और भेजें
पैसे पाने वाले व्यक्ति के ऐप्लिकेशन को Payload
मिलने के बाद,
AbstractReceiverService.onPayloadReceived()
शुरू हो जाएगा. जैसा कि यहां बताया गया है
पेलोड भेजें, तो onPayloadReceived()
ऐब्सट्रैक्ट तरीके का इस्तेमाल करें और इसे क्लाइंट ऐप्लिकेशन पर लागू करना ज़रूरी है. इस तरीके में,
क्लाइंट, Payload
को उससे जुड़े रिसीवर एंडपॉइंट पर फ़ॉरवर्ड कर सकता है या
Payload
को कैश मेमोरी में सेव करें. इसके बाद, मैसेज पाने वाले का अनुमानित एंडपॉइंट होने पर इसे भेजें
रजिस्टर किया गया.
(पाने वाले का एंडपॉइंट) रजिस्टर और अपंजीकृत करें
रिसीवर को रजिस्टर करने के लिए, उसे पाने वाले ऐप्लिकेशन को registerReceiver()
पर कॉल करना होगा
एंडपॉइंट के बारे में भी बताएंगे. आम तौर पर, इस्तेमाल का उदाहरण यह होता है कि फ़्रैगमेंट को Payload
पाने वाले की ज़रूरत होती है, इसलिए
यह रिसीवर एंडपॉइंट को रजिस्टर करता है:
private final PayloadCallback mPayloadCallback = (senderZone, payload) -> {
…
};
if (mOccupantConnectionManager != null) {
mOccupantConnectionManager.registerReceiver("FragmentB",
getActivity().getMainExecutor(), mPayloadCallback);
}
पैसे पाने वाले क्लाइंट में AbstractReceiverService
के भेजे जाने के बाद
रिसीवर के एंडपॉइंट से Payload
, उससे जुड़ा PayloadCallback
होगा
शुरू किया गया.
क्लाइंट ऐप्लिकेशन तब तक एक से ज़्यादा रिसीवर एंडपॉइंट को रजिस्टर कर सकता है, जब तक
क्लाइंट ऐप्लिकेशन के लिए receiverEndpointId
सबसे अलग होते हैं. receiverEndpointId
AbstractReceiverService
इसका इस्तेमाल करके यह तय करेगा कि कौनसा रिसीवर
पेलोड को भेजने के लिए एंडपॉइंट. उदाहरण के लिए:
- भेजने वाले ने
Payload
मेंreceiver_endpoint_id:FragmentB
के बारे में बताया है. टास्क कब शुरू होगाPayload
, रिसीवर कॉल मेंAbstractReceiverService
पेलोड इस पते पर भेजने के लिएforwardPayload("FragmentB", payload)
FragmentB
- भेजने वाले ने
Payload
मेंdata_type:VOLUME_CONTROL
के बारे में बताया है. टास्क कब शुरू होगाPayload
मिलने के बाद, पाने वालेAbstractReceiverService
को पता चल जाता है कि इस तरह केPayload
कोFragmentB
को भेजा जाना चाहिए, ताकि यहforwardPayload("FragmentB", payload)
if (mOccupantConnectionManager != null) {
mOccupantConnectionManager.unregisterReceiver("FragmentB");
}
(भेजने वाला) कनेक्शन खत्म करें
भेजने वाले व्यक्ति को एक बार Payload
भेजने की ज़रूरत नहीं है. उदाहरण के लिए,
तो यह कनेक्शन बंद हो जाना चाहिए.
if (mOccupantConnectionManager != null) {
mOccupantConnectionManager.disconnect(receiverZone);
}
एक बार डिसकनेक्ट होने के बाद, भेजने वाले व्यक्ति को Payload
नहीं भेजे जा सकते हैं.
कनेक्शन फ़्लो
कनेक्शन फ़्लो को दूसरी इमेज में दिखाया गया है.
समस्या का हल
लॉग देखें
इससे जुड़े लॉग देखने के लिए:
लॉग करने के लिए इस निर्देश को चलाएं:
adb shell setprop log.tag.CarRemoteDeviceService VERBOSE && adb shell setprop log.tag.CarOccupantConnectionService VERBOSE && adb logcat -s "AbstractReceiverService","CarOccupantConnectionManager","CarRemoteDeviceManager","CarRemoteDeviceService","CarOccupantConnectionService"
CarRemoteDeviceService
की अंदरूनी स्थिति को हटाने के लिए औरCarOccupantConnectionService
:adb shell dumpsys car_service --services CarRemoteDeviceService && adb shell dumpsys car_service --services CarOccupantConnectionService
Null Car RemoteDeviceManager और CarOccupantConnectionManager
इन संभावित असल वजहों की जांच करें:
कार सेवा क्रैश हो गई. जैसा कि पहले दिखाया गया है, दोनों मैनेजर कार सेवा क्रैश होने पर जान-बूझकर
null
पर रीसेट करके सेट की गई हो. कार सर्विस करते समय रीस्टार्ट होता है, तो दोनों मैनेजर शून्य वैल्यू पर सेट हो जाते हैं.CarRemoteDeviceService
याCarOccupantConnectionService
नहीं है चालू किया गया. यह तय करने के लिए कि इनमें से कोई चालू है या नहीं, इसे चलाकर देखें:adb shell dumpsys car_service --services CarFeatureController
mDefaultEnabledFeaturesFromConfig
देखें, जिसमें यह होना चाहिएcar_remote_device_service
औरcar_occupant_connection_service
. इसके लिए उदाहरण:mDefaultEnabledFeaturesFromConfig:[car_evs_service, car_navigation_service, car_occupant_connection_service, car_remote_device_service, car_telemetry_service, cluster_home_service, com.android.car.user.CarUserNoticeService, diagnostic, storage_monitoring, vehicle_map_service]
डिफ़ॉल्ट रूप से, ये दोनों सेवाएं बंद रहती हैं. जब किसी डिवाइस पर यह सुविधा काम करती है तो आपको इस कॉन्फ़िगरेशन फ़ाइल को ओवरले करना होगा. इस सुविधा को चालू किया जा सकता है कॉन्फ़िगरेशन फ़ाइल में दो सेवाएं:
// packages/services/Car/service/res/values/config.xml <string-array translatable="false" name="config_allowed_optional_car_features"> <item>car_occupant_connection_service</item> <item>car_remote_device_service</item> … … </string-array>
एपीआई को कॉल करते समय अपवाद
अगर क्लाइंट ऐप्लिकेशन, एपीआई का इस्तेमाल सही तरीके से नहीं कर रहा है, तो एक अपवाद हो सकता है. इस मामले में, क्लाइंट ऐप्लिकेशन अपवाद वाले मैसेज की जांच कर सकता है और क्रैश स्टैक की सुविधा का इस्तेमाल करें. एपीआई के गलत इस्तेमाल के कुछ उदाहरण यहां दिए गए हैं:
registerStateCallback()
इस क्लाइंट ने पहले ही एकStateCallback
रजिस्टर किया है.unregisterStateCallback()
इस ईमेल पते से, किसी भीStateCallback
को रजिस्टर नहीं किया गया हैCarRemoteDeviceManager
इंस्टेंस.registerReceiver()
receiverEndpointId
पहले से रजिस्टर है.unregisterReceiver()
receiverEndpointId
रजिस्टर नहीं किया गया है.requestConnection()
ऐसा कनेक्शन पहले से मौजूद है जिसे मंज़ूरी मिलना बाकी है या पहले से मौजूद है.cancelConnection()
रद्द करने के लिए कोई कनेक्शन बाकी नहीं है.sendPayload()
कोई स्थापित कनेक्शन नहीं है.disconnect()
कोई स्थापित कनेक्शन नहीं है.
Client1, Client2 को पेलोड भेज सकता है, लेकिन उसका उलटा नहीं
कनेक्शन को डिज़ाइन को ध्यान में रखकर बनाया गया है. दो-तरफ़ा कनेक्शन स्थापित करने के लिए, दोनों
client1
और client2
को एक-दूसरे से कनेक्ट करने का अनुरोध करना होगा. इसके बाद,
मंज़ूरी लें.