2011-08-08 15 views
33

Pracowałem przez the description and samples for USB host at developer.android.com, aby wykryć podłączone i odłączone urządzenia USB.Android 3.1 Host USB - BroadcastReceiver nie otrzymuje USB_DEVICE_ATTACHED

Jeśli używam filtru intencyjnego w pliku manifestu, aby uruchomić aplikację po podłączeniu urządzenia, działa to doskonale: podłącz, urządzenie zostaje wykryte, Android prosi o pozwolenie na uruchomienie aplikacji, wyświetlane są informacje o urządzeniu w tabeli.

Aplikacja, którą rozwijam, nie powinna być uruchamiana/kończona tylko wtedy, gdy urządzenie jest podłączone/odłączone (np. W celach zarządzania danymi). Nie chcę również, aby okno dialogowe było otwarte, jeśli aplikacja jest już uruchomiona. Dlatego postanowiłem nie uruchamiać działania bezpośrednio, jeśli urządzenie jest podłączone, ale zarejestrować BroadcastReceiver, który (później) powinien powiadomić o aktywności, jeśli urządzenie jest włączone/odłączone. Ten odbiornik rozpoznaje działanie odrywania w porządku, ale nie przywiązanie.

Czy brakuje mi uprawnienia lub atrybutu danych lub czegoś w tym stylu? Samouczek i próbki nie mówią nic o dodatkowych niezbędnych atrybutach.

Oto manifest file:

<?xml version="1.0" encoding="utf-8"?> 
<manifest 
    xmlns:android="http://schemas.android.com/apk/res/android" 
    package="de.visira.smartfdr" 
    android:versionCode="1" 
    android:versionName="1.0"> 

<uses-sdk android:minSdkVersion="12" /> 
<uses-feature android:name="android.hardware.usb.host" /> 

<application android:icon="@drawable/icon" android:label="@string/app_name"> 


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

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

i odbiornik:

public class FDRDetector extends BroadcastReceiver{ 

@Override 
public void onReceive(Context context, Intent intent) { 
    String action = intent.getAction(); 

    Toast.makeText(context, "Action: " + action, 3).show(); 
      // pops up only if action == DETACHED 
} 

Nie rozumiem, dlaczego te same prace intent-filter, jeśli mogę użyć je na działanie, ale nie, jeśli są one stosowane do odbiornika? Nawet jeśli ustawię odbiornik i filtruję w kodzie, załączniki nie zostaną rozpoznane.

Moje środowisko pracy: IDE: Eclipse 3.7 z Android Plugin

Device: Acer Iconia Tab A500

Androida: 3.1

góry dzięki

Odpowiedz

4

Tworzenie odbiornik rozgłaszania w ramach Aplikacja, a nie manifest, pozwala aplikacji obsługiwać tylko odłączone zdarzenia podczas działania. W ten sposób odłączone zdarzenia są wysyłane tylko do aplikacji, która jest aktualnie uruchomiona i nie jest nadawana do wszystkich aplikacji.

34

Aha! Rozgryzłem to. Miałem dokładnie ten sam problem.

Istotą jest - jeśli masz uruchomienie aplikacji automatycznie, gdy urządzenie jest podłączone do zasilania (za pomocą pliku manifestu), to wydaje się, że system Android dostaje ACTION_USB_DEVICE_ATTACHED intencji, a następnie, ponieważ zna swoją aplikację chce działać w takiej sytuacji, faktycznie wysyła twoją aplikację jako cel android.intent.action.MAIN. Nigdy nie wysyła działania ACTION_USB_DEVICE_ATTACHED do aplikacji, ponieważ uważa, że ​​już wie, co aplikacja chce zrobić w tej sytuacji.

Właśnie teraz zidentyfikować problem i myślę, że mam rozwiązanie, ale mogę powiedzieć, co znalazłem:

Nawet jeśli aplikacja jest uruchomiona, a na pierwszym planie, po podłączeniu na urządzeniu USB i systemie Android uzyska intencję ACTION_USB_DEVICE_ATTACHED, wywoła on onResume() w twojej aktywności.

Niestety, nie można po prostu to zrobić:

@Override 
public void onResume() { 
    super.onResume(); 

    Intent intent = getIntent(); 
    Log.d(TAG, "intent: " + intent); 
    String action = intent.getAction(); 

    if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action)) { 
     //do something 
    } 
} 

Ponieważ intencją wróci jako android.intent.action.MAIN NIE ACTION_USB_DEVICE_ATTACHED.

Irytujące, ty również dostać android.intent.action.MAIN, jeśli po prostu opuścić aplikację, ale nie odłącz USB. Wyobrażam sobie, że uśpienie urządzenia i budzenie go z powrotem zrobi to samo.

Z tego, co odkryłem, nie można uzyskać intencji bezpośrednio, ale wygląda na to, że można polegać na onResume() podczas wywoływania, gdy urządzenie USB jest podłączone, więc rozwiązaniem jest po prostu sprawdzić, zobacz, czy port USB jest podłączony za każdym razem, gdy otrzymasz usługę onResume. Możesz także ustawić flagę, gdy USB jest odłączone, ponieważ oczywiście rozłączenie USB jest w porządku.

Więc w sumie odbiornik transmisji może wyglądać następująco:

// BroadcastReceiver when remove the device USB plug from a USB port 
BroadcastReceiver mUsbReceiver = new BroadcastReceiver() { 
    public void onReceive(Context context, Intent intent) { 
     String action = intent.getAction(); 
     if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) {     
     usbConnected=false;    
     } 
    } 
}; 

Trzeba to wnętrze onCreate:

// listen for new devices 
IntentFilter filter = new IntentFilter(); 
filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED); 
registerReceiver(mUsbReceiver, filter); 

to idzie wewnątrz znacznika aktywności w swoim manifeście:

 <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" /> 

Będziesz mieć plik device_filter.xml w katalogu/res/xml /, który wygląda tak :

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

<resources> 
    <usb-device vendor-id="1027" product-id="24577" /> 
    <usb-device vendor-id="1118" product-id="688" /> 
</resources> 

(oczywiście z dowolnych identyfikatorów dostawców i identyfikatory produktów potrzebnych)

I wówczas onCreate wyglądać tak:

@Override 
public void onResume() { 
    super.onResume(); 

    Intent intent = getIntent(); 
    Log.d(TAG, "intent: " + intent); 
    String action = intent.getAction(); 


    if (usbConnected==false) { 
     //check to see if USB is now connected 
    } 
} 

nie mam specjalny kod do sprawdzania aby sprawdzić, czy USB jest podłączony, ponieważ jeszcze nie zagłębiłem się w to. Używam biblioteki, która połączy się, jeśli to możliwe, więc dla mojej aplikacji mogę uruchomić tę pętlę i jestem dobra.

Prawdopodobnie jest również ważne, aby ustawić tryb uruchamiania swojej aktywności w manifeście na "singleTask", aby zapobiec ponownemu uruchomieniu, gdy już działa, lub gdy podłączenie urządzenia USB uruchomi drugie wystąpienie aplikacji!

Więc cała moja działalność tag w moim manifestu wygląda następująco:

<activity 
     android:label="@string/app_name" 
     android:name="com.awitness.common.TorqueTablet" 
     android:theme="@android:style/Theme.Holo.NoActionBar.Fullscreen" 
     android:screenOrientation="landscape" 
     android:configChanges="orientation|keyboardHidden" 
     android:launchMode="singleTask" 
     > 
     <intent-filter > 
      <action android:name="android.intent.action.MAIN" /> 
      <category android:name="android.intent.category.HOME"/> 
     <category android:name="android.intent.category.DEFAULT" /> 
     <category android:name="android.intent.category.LAUNCHER" /> 
     </intent-filter> 

     <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> 

W każdym razie, mam nadzieję, że ktoś pomoże! Byłem zaskoczony, że nie mogłem już znaleźć rozwiązania!

+4

Spróbuj przesłonić OnNewIntent() - jest wywoływana, gdy używasz Androida: launchMode = "singleTop" i prawdopodobnie rozwiązuje twoją sytuację całkiem ładnie. onResume() jest zawsze wywoływana później. – Gusdor

+0

Czy możesz wyjaśnić swój pierwszy akapit "Istota tego jest"? Wydaje mi się to bardzo zdezorientowane. –

+0

Dzięki, zastanawiałem się nad tym samym. Dobrze wiedzieć, że to coś, co po prostu nie działa. Pachnie mnie jak błąd Androida. – Brian

6

Wystarczy podążać dalej od @ Gusdor za wnikliwe komentarza (+1): I wdrożone czek w onNewIntent() że jak @Gusdor zaznacza, nazywa gdy aktywność launchMode jest ustawiony jako singleTask lub singleTop. Następnie, zamiast sprawdzać flagi binarne, jak sugeruje zaakceptowana odpowiedź, wystarczy przekazać zamiar do odbiornika transmisji USB przy użyciu LocalBroadcastManager.Na przykład,

@Override 
protected void onNewIntent(Intent intent) { 
    super.onNewIntent(intent); 
    if (UsbManager.ACTION_USB_ACCESSORY_ATTACHED.equals(intent.getAction())) { 
     LocalBroadcastManager.getInstance(this).sendBroadcast(intent); 
    } 
} 

Następnie, gdziekolwiek jesteś rejestracji istniejącego systemu (broadcast) odbiornik USB, wystarczy zarejestrować ten sam odbiornik z lokalnej transmisji instancji menedżera, czyli

@Override 
protected void onResume() { 
    super.onResume(); 
    myContext.registerReceiver(myUsbBroadcastReceiver, myIntent); // system receiver 
    LocalBroadcastManager.getInstance(myContext).registerReceiver(myUsbBroadcastReceiver, intent); // local receiver 
} 

@Override 
protected void onPause() { 
    super.onResume(); 
    myContext.unregisterReceiver(myUsbBroadcastReceiver); // system receiver 
    LocalBroadcastManager.getInstance(myContext).unregisterReceiver(myUsbBroadcastReceiver); // local receiver 
} 

Można wysłać inny system, a nie transmisja lokalna, ale nie sądzę, że będziesz w stanie użyć akcji UsbManager.ACTION_USB_ACCESSORY_ATTACHED (system uzna to za potencjalne zagrożenie bezpieczeństwa), więc musisz zdefiniować własne działanie. Nic wielkiego, ale po co zawracać sobie głowę, tym bardziej, że nie ma żadnych kosztów związanych z IPC z transmisjami lokalnymi.

Powiązane problemy