2012-04-23 16 views
5

Szukam sposobu na wykrycie i dostęp do wymiennych kart SD na różnych urządzeniach z systemem Android (Samsung, Motorola, LG, Sony, HTC).Jak uzyskać dostęp do wymiennych nośników pamięci na urządzeniach z systemem Android?

Muszę również być zgodny z 2.2, więc Environment.isExternalStorageRemovable() jest niedostępny dla mnie.

Motorola posiada własną bibliotekę, a dla Samsung mogę wykryć istnienie /external_sd/

nie mam pojęcia, dla reszty z nich. Na przykład, widziałem /_ExternalSD/ na niektórych LG, ale katalog pozostaje nawet po usunięciu SD.

Bonus pytanie: czy ACTION_MEDIA_MOUNTED zamiar być transmitowane do każdego z nich

Każda wskazówka na to byłoby bardzo pomocne.

+0

Cokolwiek poza metodami w "Środowisku" wykracza poza zakres SDK i nie będzie wiarygodne. – CommonsWare

Odpowiedz

0

Te funkcje są dostępne we wszystkich wersjach Androida:

  • Aby uzyskać folderu aplikacji na zewnętrznej pamięci masowej, zadzwoń Context.getExternalFilesDir.

  • Należy pamiętać, że aplikacja wymaga wyraźnej zgody na dostęp do pamięci zewnętrznej, i że należy sprawdzić, czy jest ona dostępna poprzez Environment.getExternalStorageState

  • I tak, ACTION_MEDIA_MOUNTED będzie transmitowany gdy nośnik wymienny będzie dostępny (Powinieneś również słuchać ACTION_MEDIA_EJECT i ACTION_MEDIA_REMOVED)

+0

Dzięki Tony, ale to tylko zwróci/mnt/sdcard, które nie jest wymiennym urządzeniem pamięci masowej. Zmieniłem moje pytanie, więc jest ono dokładnie sformułowane. – znat

+0

Tak, pamięć zewnętrzna jest * zwykle *, ale nie * zawsze * wymienna. Jaki jest twój dokładny przypadek użycia? –

+0

Aplikacja musi umożliwiać wybór urządzeń do przechowywania plików do pobrania. Zazwyczaj wewnętrzna lub zewnętrzna wymienna pamięć masowa. Z tego, co widzę, oddzielenie nie jest takie jasne. Na przykład. Samsung montuje wymienne sd na/mnt/sdcard/external_sd. LG on/mnt/sdcard/_ExternalSD/ale katalog i niektóre pliki pozostają, nawet jeśli dysk wymienny jest odłączony. Co sugeruje, że nie ma logicznej separacji – znat

3

Oto klasa używam znaleźć wszystkie sdcards na urządzeniu; wbudowany i wymienny. Używam go na Ice Cream Sandwich, ale powinno działać na dwóch poziomach.

public class GetRemovableDevice { 

private final static String TAG = "GetRemoveableDevice"; 

public GetRemovableDevice() { 
} 

public static String[] getDirectories() { 
    MyLog.d(TAG, "getStorageDirectories"); 
    File tempFile; 
    String[] directories = null; 
    String[] splits; 
    ArrayList<String> arrayList = new ArrayList<String>(); 
    BufferedReader bufferedReader = null; 
    String lineRead; 

    try { 
     arrayList.clear(); // redundant, but what the hey 
     bufferedReader = new BufferedReader(new FileReader("/proc/mounts")); 

     while ((lineRead = bufferedReader.readLine()) != null) { 
      MyLog.d(TAG, "lineRead: " + lineRead); 
      splits = lineRead.split(" "); 

      // System external storage 
      if (splits[1].equals(Environment.getExternalStorageDirectory() 
        .getPath())) { 
       arrayList.add(splits[1]); 
       MyLog.d(TAG, "gesd split 1: " + splits[1]); 
       continue; 
      } 

      // skip if not external storage device 
      if (!splits[0].contains("/dev/block/")) { 
       continue; 
      } 

      // skip if mtdblock device 

      if (splits[0].contains("/dev/block/mtdblock")) { 
       continue; 
      } 

      // skip if not in /mnt node 

      if (!splits[1].contains("/mnt")) { 
       continue; 
      } 

      // skip these names 

      if (splits[1].contains("/secure")) { 
       continue; 
      } 

      if (splits[1].contains("/mnt/asec")) { 
       continue; 
      } 

      // Eliminate if not a directory or fully accessible 
      tempFile = new File(splits[1]); 
      if (!tempFile.exists()) { 
       continue; 
      } 
      if (!tempFile.isDirectory()) { 
       continue; 
      } 
      if (!tempFile.canRead()) { 
       continue; 
      } 
      if (!tempFile.canWrite()) { 
       continue; 
      } 

      // Met all the criteria, assume sdcard 
      arrayList.add(splits[1]); 
     } 

    } catch (FileNotFoundException e) { 
    } catch (IOException e) { 
    } finally { 
     if (bufferedReader != null) { 
      try { 
       bufferedReader.close(); 
      } catch (IOException e) { 
      } 
     } 
    } 

    // Send list back to caller 

    if (arrayList.size() == 0) { 
     arrayList.add("sdcard not found"); 
    } 
    directories = new String[arrayList.size()]; 
    for (int i = 0; i < arrayList.size(); i++) { 
     directories[i] = arrayList.get(i); 
    } 
    return directories; 
} 

}

MyLog.d jest klasą śladowy, który rozszerza Log.d - może być pominięte.

Klasa czyta/proc/mounts/a:

  1. sprawdza, czy nazwa ścieżki jest Wewnętrzna książka sdcard
  2. sprawdza, czy jest to urządzenie blokowe
  3. przeskakuje mtdblock urządzeń
  4. pomija niczego, co nie jest zamontowany
  5. przeskakuje bezpiecznych i ASEC katalogów
  6. pilnuje istnieje, jest katalogiem i czytaj/write available

Jeśli wszystko się zgadza, zakłada, że ​​masz sdcard i dodaje ścieżkę do listy tablic. Zwraca tablicę ciągów nazw ścieżek.

Aby wywołać funkcję GetDirectories, kod coś podobnego do:

String[] sdcardDirectories = GetRemoveableDevice.getDirectories(); 

Ścieżki zwrócony może być używany do tworzenia listy wyboru użytkownika, skanowanie do pliku, czy cokolwiek innego.

Ponadto, tutaj dwie linie MyLog.d z testem emulator (druga linia sdcard emulatora)

19/09 15: 57: 12,511: D/GetRemoveableDevice (651) lineRead/dev/block/mtdblock2/cache yaffs2 rw, nosuid, nodev 0 0

09-19 15: 57: 12.511: D/GetRemoveableDevice (651): lineRead:/dev/block/vold/179: 0/mnt/sdcard vfat rw, dirsync, nosuid, nodev, noexec, uid = 1000, gid = 1015, fmask = 0702, dmask = 0702, allow_utime = 0020, strona kodowa = cp437, iocharset = iso8859-1, shortname = mixed, utf8, errors = reount -ro 0 0

+0

Ooops. Zapomniałem wspomnieć, że sprawdzenie statusu odczytu/zapisu eliminuje niezmontowane sdkardy, które wciąż mają wpis w katalogu/mnt /. –

+0

Wiem, że ten wątek jest stary, ale zamieniam kod wykrywania pamięci masowej w bibliotekę ogólnego przeznaczenia i chcę odróżnić pamięć zewnętrzną, która jest stała, i to, co jest faktycznie usuwalne. Nie wiem, czy twoje rozwiązanie spełnia ten wymóg?Wydaje się, że pierwsza instrukcja "if" w twojej pętli zapisze jakiekolwiek wystąpienie ścieżki zwróconej przez "getExternalStorageDirectory()", która często NIE jest fizycznie usuwalna, prawda? –

+0

Przepraszam, że trwało to tak długo. Głowa w dół przy klawiaturze pracującej nad projektem. Aby odpowiedzieć, tak, ścieżka od getExtenalStorageDirectory jest zwykle niezamkniętą sdcard. Pierwszą pozycją na zwróconej liście jest sDcard getExternal. Jeśli lista zawiera wiele wpisów, użyj drugiej lub następnej pozycji. Możesz również sprawdzić, czy można go zdemontować. Możesz także wykonać prosty projekt, aby wyświetlić listę (i cokolwiek chcesz), a następnie sprawdzić, co się stanie, gdy usuniesz i zamienisz usuwalne karty SD. –

1

Na podstawie klasy Howards wykonałem pewne modyfikacje ons, aby działało na Galaxy S3.

  1. Środowisko.getExternalStorageDirectory() zwraca pamięć wewnętrzną na S3.
  2. Wymienny przechowywania niekoniecznie jest zamontowany w/mnt
  3. Wymienne nośniki muszą mieć VFAT

_

public static String getDirectory() { 
     Log.d(TAG, "getStorageDirectories"); 
     File tempFile; 
     String[] splits; 
     ArrayList<String> arrayList = new ArrayList<String>(); 
     BufferedReader bufferedReader = null; 
     String lineRead; 

     try { 
      arrayList.clear(); // redundant, but what the hey 
      bufferedReader = new BufferedReader(new FileReader("/proc/mounts")); 

      while ((lineRead = bufferedReader.readLine()) != null) { 
       Log.d(TAG, "lineRead: " + lineRead); 
       splits = lineRead.split(" "); 

       // skip if not external storage device 
       if (!splits[0].contains("/dev/block/")) { 
        continue; 
       } 

       // skip if mtdblock device 
       if (splits[0].contains("/dev/block/mtdblock")) { 
        continue; 
       } 

       // skip if not in vfat node 
       if (!splits[2].contains("vfat")) { 
        continue; 
       } 

       // skip these names 
       if (splits[1].contains("/secure")) { 
        continue; 
       } 

       if (splits[1].contains("/mnt/asec")) { 
        continue; 
       } 

       // Eliminate if not a directory or fully accessible 
       tempFile = new File(splits[1]); 
       if (!tempFile.exists()) { 
        continue; 
       } 
       if (!tempFile.isDirectory()) { 
        continue; 
       } 
       if (!tempFile.canRead()) { 
        continue; 
       } 
       if (!tempFile.canWrite()) { 
        continue; 
       } 

       // Met all the criteria, assume sdcard 
       return splits[1]; 
      } 

     } catch (FileNotFoundException e) { 
     } catch (IOException e) { 
     } finally { 
      if (bufferedReader != null) { 
       try { 
        bufferedReader.close(); 
       } catch (IOException e) { 
       } 
      } 
     } 

     return null; 
    } 
+0

Wierzę, że nie jest to również sposób zalecany przez google. – Raghunandan

+2

Zgadzam się, że to hack. Ale to najczystszy hack, jaki widziałem. Jeśli znajdziesz właściwy sposób, daj nam znać. – tmanthey

+0

Jaka jest inna forma od tej, którą opublikowałem – Raghunandan

1

podstawie 2 klas przedstawionych powyżej I zmodyfikowana klasa dalej zauważyć, że cała zewnętrzna pamięć wymienna na kilku telefonach i tabletach, które mogłem znaleźć, została zamontowana za pomocą vold, demona woluminu.

  // skip if not external storage device 
      if (!splits[0].contains("vold")) { 
       continue; 
      } 

      if (splits[1].contains("/mnt/asec")) { 
       continue; 
      } 

      // Eliminate if not a directory or fully accessible 
      tempFile = new File(splits[1]); 
      if (!tempFile.exists()) { 
       continue; 
      } 
      if (!tempFile.isDirectory()) { 
       continue; 
      } 
      if (!tempFile.canRead()) { 
       continue; 
      } 
      if (!tempFile.canWrite()) { 
       continue; 
      } 

      // Met all the criteria, assume sdcard 
      arrayList.add(splits[1]); 
+0

Dzięki za podzielenie się tym, czego się nauczyłeś. +1. Pamiętaj, że "powyżej" nie jest stabilną własnością odpowiedzi ... na tej stronie są obecnie 3 inne klasy, a 2 klasy, o których mówisz, mogą pojawić się pod Twoimi, gdy ktoś obejrzy tę stronę. – LarsH

0

Jest to metoda, którą stworzyłem i używam. To działało na Samsung Galaxy S4, Samsung Galaxy Note 3 i Sony Xperia Z2.

private static String[] getRemovableStoragePaths() { 
    String[] directories; 
    String[] splits; 
    ArrayList<String> pathList = new ArrayList<String>(); 
    BufferedReader bufferedReader = null; 
    String lineRead; 

    try { 
     bufferedReader = new BufferedReader(new FileReader("/proc/mounts")); 

     while ((lineRead = bufferedReader.readLine()) != null) { 
      Log.d(TAG, "lineRead: " + lineRead); 
      splits = lineRead.split(" "); 
      Log.d(TAG, "Testing path: " + splits[1]); 

      if (!splits[1].contains("/storage")) { 
       continue; 
      } 

      if (splits[1].contains("/emulated")) { 
       // emulated indicates an internal storage location, so skip it. 
       continue; 
      } 

      // Eliminate if not a directory or fully accessible 
      Log.d(TAG, "Path found: " + splits[1]); 

      // Met all the criteria, assume sdcard 
      pathList.add(splits[1]); 
     } 

    } catch (FileNotFoundException e) { 
    } catch (IOException e) { 
    } finally { 
     if (bufferedReader != null) { 
      try { 
       bufferedReader.close(); 
      } catch (IOException e) { 
      } 
     } 
    } 

    // Send list back to caller 

    if (pathList.size() == 0) { 
     pathList.add("sdcard not found"); 
    } else { 
     Log.d(TAG, "Found potential removable storage locations: " + pathList); 
    } 
    directories = new String[pathList.size()]; 
    for (int i = 0; i < pathList.size(); i++) { 
     directories[i] = pathList.get(i); 
    } 
    return directories; 
} 
Powiązane problemy