Odczytywanie stanu urządzenia ----------------------------- W tym pliku opisany jest projekt startowy do ćwiczeń z odczytywania stanu urządzenia W API niższym niż API 5 brakuje niektórych klas odpowiedzialnych za detekcję stanu baterii i detekcji dodatkowych urządzeń (będzie zaznaczone w tekście) W tym projekcie zdefiniowany jest osobny wątek, który co dwie sekundy uruchamia metodę odswiezListe, która zbiera i wyświetla informacje o urządzeniach. 1. Zacznijmy od pobrania wersji systemu. a. Zdefiniujmy funkcję: static private UrządzenieInfo odczytajWersjęSystemu(Activity activity) { UrządzenieInfo systemInfo = new UrządzenieInfo(); systemInfo.nazwa = "Wersja systemu"; systemInfo.typInformacji = TypInformacji.Inne; systemInfo.polozeniePaska = -1; systemInfo.opis = "\nBieżąca data i czas: " + DateTime.Now.ToString(); systemInfo.opis += "\nBieżąca data: " + DateTime.Now.ToLongTimeString(); systemInfo.opis += "\nBieżący czas: " + DateTime.Now.ToLongDateString(); systemInfo.opis += "\nProducent: " + Build.Manufacturer; systemInfo.opis += "\nUrządzenia: " + Build.Device; systemInfo.opis += "\nS/N: " + Build.Serial; systemInfo.opis += "\nWersja: " + Build.VERSION.Release + " (" + Build.VERSION.Incremental + ")"; //systemInfo.opis += "\nTyp CPU: " + Build.CpuAbi; //deprecated systemInfo.opis += "\nTypy CPU: "; foreach(string abi in Build.SupportedAbis) //API 21 { systemInfo.opis += "\n\t" + abi; } systemInfo.opis += "\nWyświetlacz: " + Build.Display; return systemInfo; } b. Wywołanie tej funkcji dodajmy do metody odswiezListe: private void odswiezListe() { int pozycja = listView.FirstVisiblePosition; //zapobieganie przewijaniu przy odświeżaniu View v = listView.GetChildAt(0); int top = (v == null) ? 0 : v.Top; List listaUrzadzeń = new List(); listaUrzadzeń.Add(odczytajWersjęSystemu(this)); UrzadzeniaAdapter a = new UrzadzeniaAdapter(this, Resource.Layout.wiersz, listaUrzadzeń); listView.Adapter = a; listView.SetSelectionFromTop(pozycja, top); } 2. Pamięć - nie ma jednoznacznego źródła co należy w Androidzie (Linuxie) traktować jako pamięć wolną. System dąży do maksymalnego wykorzystania pamięci (pamięć wolna to pamięć stracona) na wszelkiego typu bufory (przyspieszenie działania). Aplikacje usuwane są z pamięci dopiero, gdy jest to konieczne (przyspieszenie ponownego uruchamiania/przywracania). Ilość dostępnej pamięci można pobrać z ActivityManager.GetMemoryInfo(mi) - niejednoznaczna jej interpretacja Całkowita - z pliku /proc/meminfo - pierwsza linia zawiera "MemTotal: 739300 kB" public static class LinuxHelper { [MethodImpl(MethodImplOptions.Synchronized)] public static int ReadRAMTotalSizeKB() { try { RandomAccessFile reader = new RandomAccessFile("/proc/meminfo", "r"); //klasa Java string s = reader.ReadLine(); reader.Close(); string _sr = "memtotal:"; s = s.ToLower(); s = s.Remove(s.LastIndexOf(_sr), _sr.Length); s = s.Remove(s.LastIndexOf("kb")); s = s.Trim(); int m = int.Parse(s); return m; } catch (IOException exc) { exc.PrintStackTrace(); return -1; } } } Przykładowa zawartość pliku /proc/meminfo na Samsung Galaxcy Tab 10.1 MemTotal: 739300 kB MemFree: 9200 kB Buffers: 5144 kB Cached: 136256 kB SwapCached: 0 kB Active: 541176 kB Inactive: 88560 kB itd. Zasadnicza metoda odczytująca stan pamięci: static private UrządzenieInfo odczytajStanPamięci(Activity activity) { //Pamięć wewnętrzna UrządzenieInfo pi = new UrządzenieInfo(); pi.typInformacji = TypInformacji.StanUrzadzenia; pi.nazwa = "Pamięć (RAM)"; ActivityManager am = (ActivityManager)activity.GetSystemService(ActivityService); MemoryInfo mi = new MemoryInfo(); am.GetMemoryInfo(mi); long pamięćDostępna = mi.AvailMem / 1024; //kB //mi.totalMem long pamięćCałkowita = LinuxHelper.ReadRAMTotalSizeKB(); long pamięćZajęta = pamięćCałkowita - pamięćDostępna; pi.opis = "Dostępna pamięć: " + pamięćDostępna + "/" + pamięćCałkowita; pi.polozeniePaska = (int)(pamięćZajęta * 100 / pamięćCałkowita); return pi; } Jej wywołanie należy dodać do oswiezListe. 3. Karty pamięci (główna i dodatkowa) - inaczej niż pamięć RAM, bo jest na nich system plików, z którego możemy skorzystać. Klasa StatFS. Obie funkcje niemal takie same, korzystają z funkcji pomocniczej pobierzStanPamięci static private Tuple pobierzStanPamięci(Java.IO.File memoryDirectory) { StatFs systemPlików = new StatFs(memoryDirectory.Path); long wolneMiejsce = systemPlików.AvailableBlocksLong * systemPlików.BlockSizeLong / 1024 / 1024; //MB long rozmiar = systemPlików.BlockCountLong * systemPlików.BlockSizeLong / 1024 / 1024; //MB long zajęteMiejsce = rozmiar - wolneMiejsce; String opis = "Ścieżka: " + memoryDirectory.Path + "\n"; opis += "Wolne miejsce: " + wolneMiejsce + " / " + rozmiar; int procent = (int)(zajęteMiejsce * 100 / rozmiar); Tuple tuple = new Tuple(opis, procent); return tuple; } static private UrządzenieInfo odczytajStanGłównejKartyPamięci(Activity activity) { Tuple tuple = pobierzStanPamięci(Android.OS.Environment.RootDirectory); UrządzenieInfo kartaPamięciInfo = new UrządzenieInfo(); kartaPamięciInfo.typInformacji = TypInformacji.StanUrzadzenia; kartaPamięciInfo.nazwa = "Głowna karta pamięci"; kartaPamięciInfo.opis = tuple.Item1; kartaPamięciInfo.polozeniePaska = tuple.Item2; return kartaPamięciInfo; } static private UrządzenieInfo odczytajStanDodatkowejKartyPamięci(Activity activity) { UrządzenieInfo kartaPamięciInfo = new UrządzenieInfo(); kartaPamięciInfo.typInformacji = TypInformacji.StanUrzadzenia; kartaPamięciInfo.nazwa = "Dodatkowa karta pamięci"; if (Android.OS.Environment.ExternalStorageState.Equals(Android.OS.Environment.MediaMounted)) { Tuple tuple = pobierzStanPamięci(Android.OS.Environment.ExternalStorageDirectory); kartaPamięciInfo.opis = tuple.Item1; kartaPamięciInfo.polozeniePaska = tuple.Item2; } else { kartaPamięciInfo.opis = "Brak"; kartaPamięciInfo.polozeniePaska = -1; } return kartaPamięciInfo; } 4. Procesor (obciazenie) - pobieranie z plików /proc/cpuinfo - parametry /proc/stat - bieżący stan static private UrządzenieInfo odczytajStanProcesora(Activity activity) { UrządzenieInfo procesorInfo = new UrządzenieInfo(); procesorInfo.typInformacji = TypInformacji.StanUrzadzenia; procesorInfo.nazwa = "Procesor (CPU)"; int procesorObciążenie = (int)Math.Round(100 * LinuxHelper.ReadCPUUsage()); String opisProcesora = LinuxHelper.ReadCPUInfo(); procesorInfo.opis = opisProcesora + "\n"; procesorInfo.opis += "Obciążenie procesora: " + procesorObciążenie + "%"; procesorInfo.polozeniePaska = procesorObciążenie; return procesorInfo; } Do klasy LinuxHelper dodajemy funkcje pomocnicze: public static class LinuxHelper { ... //http://stackoverflow.com/questions/3118234/how-to-get-memory-usage-and-cpu-usage-in-android public static float ReadCPUUsage() { try { RandomAccessFile reader = new RandomAccessFile("/proc/stat", "r"); string load = reader.ReadLine(); string[] toks = load.Split(" "); long idle1 = long.Parse(toks[5]); long cpu1 = long.Parse(toks[2]) + long.Parse(toks[3]) + long.Parse(toks[4]) + long.Parse(toks[6]) + long.Parse(toks[7]) + long.Parse(toks[8]); try { Java.Lang.Thread.Sleep(360); } catch //(Java.Lang.Exception e) { } reader.Seek(0); load = reader.ReadLine(); reader.Close(); toks = load.Split(" "); long idle2 = long.Parse(toks[5]); long cpu2 = long.Parse(toks[2]) + long.Parse(toks[3]) + long.Parse(toks[4]) + long.Parse(toks[6]) + long.Parse(toks[7]) + long.Parse(toks[8]); return (float)(cpu2 - cpu1) / ((cpu2 + idle2) - (cpu1 + idle1)); } catch (IOException exc) { exc.PrintStackTrace(); } return 0; } //http://www.roman10.net/how-to-get-cpu-information-on-android/ public static string ReadCPUInfo() { StringBuffer sb = new StringBuffer(); //sb.append("abi: ").append(Build.CPU_ABI).append("\n"); if (new File("/proc/cpuinfo").Exists()) { try { BufferedReader br = new BufferedReader(new FileReader(new File("/proc/cpuinfo"))); string line; while ((line = br.ReadLine()) != null) { sb.Append(line + "\n"); } if (br != null) { br.Close(); } } catch (IOException exc) { exc.PrintStackTrace(); } } return sb.ToString(); } }