Czujniki/Sensory ---------------- Kontynuacja projektu "Stan urządzenia" Dla ułatwienia kod do odczytywania stanu urządzenia można zamknąć w komentarze, żeby mieć pustą listę. 1. SensorManager - zarejestrujemy nasluchiwacz (klasa aktywności będzie go implementować), którego metoda onSensorChanged będzie wywoływana gdy zmieni się stan czujnika. Nie będziemy jednak od razu wyświetlać wyniku, a zapiszemy go do pól, które co 2 sekundy będzi odczytywany i zapisywany do struktur wyświetlanych w liście. a. Dodajemy do klasy StanActivity informację o implementowaniu SensorEventListener. Interfejs ten rządza zdefiniowania dwóch metod onAccuracyChanged (będzie pusta) i onSensorChanged (zrobimy to później) public class MainActivity : AppCompatActivity, ISensorEventListener { ... Dodajemy od razu (Ctrl+.) metody OnAccuracyChanged i OnSensorChanged b. Definiujemy prywatne pola: //zarzadca czujnikow private SensorManager sensorManager = null; private Sensor akcelerometr = null; private Sensor magnetometr = null; private Sensor orientacja = null; //w Javie/ADK to jest przestarzałe! //pola, w ktorych zapisywane beda przyspieszenie, pole mg i orientacja private static float ax = 0; //m/s^2 private static float ay = 0; private static float az = 0; private static float a = 0; private static float mx = 0; //mT private static float my = 0; private static float mz = 0; private static float m = 0; private static float oz_azymut = 0; //stopnie private static float ox_pochylenie = 0; private static float oy_nachylenie = 0; c. Pierwsza grupe pól inicjujemy w metodzie StanActivity.OnResume protected override void OnResume() { base.OnResume(); Toast.MakeText(this, "Rozpoczynam odczyty czujników", ToastLength.Long).Show(); //czujniki if (sensorManager == null) { sensorManager = (SensorManager)GetSystemService(SensorService); akcelerometr = sensorManager.GetDefaultSensor(SensorType.Accelerometer); magnetometr = sensorManager.GetDefaultSensor(SensorType.MagneticField); orientacja = sensorManager.GetDefaultSensor(SensorType.Orientation); sensorManager.RegisterListener(this, akcelerometr, SensorDelay.Normal); sensorManager.RegisterListener(this, magnetometr, SensorDelay.Normal); sensorManager.RegisterListener(this,orientacja, SensorDelay.Normal); } } d. Wyrejestrowujemy w OnPause: protected override void OnPause() { base.OnPause(); if (batteryReceiver != null) this.ApplicationContext.UnregisterReceiver(batteryReceiver); if (sensorManager != null) { sensorManager.UnregisterListener(this); //czujniki sensorManager = null; } } e. Definiujemy metody interfejsu SensorEventListener (może to za nas zrobić Eclipse): //metody ISensorEventListener public void OnAccuracyChanged(Sensor sensor, [GeneratedEnum] SensorStatus accuracy) { // } public void OnSensorChanged(SensorEvent e) { switch (e.Sensor.Type) { case SensorType.Accelerometer: ax = e.Values[0]; ay = e.Values[1]; az = e.Values[2]; a = (float)Math.Sqrt(ax * ax + ay * ay + az * az); break; case SensorType.MagneticField: mx = e.Values[0]; my = e.Values[1]; mz = e.Values[2]; m = (float)Math.Sqrt(mx * mx + my * my + mz * mz); break; case SensorType.Orientation: oz_azymut = e.Values[0]; ox_pochylenie = e.Values[1]; oy_nachylenie = e.Values[2]; break; } } f. Zapisane w tych metodach pola odczytujemy w metodach odczyta.. static private UrządzenieInfo odczytajAkcelerometr(Activity activity) { UrządzenieInfo akcelerometrInfo = new UrządzenieInfo(); akcelerometrInfo.typInformacji = TypInformacji.Czujnik; akcelerometrInfo.nazwa = "Akcelerometr"; akcelerometrInfo.opis = "ax=" + ax + "\nay=" + ay + "\naz=" + az + "\na=" + a + " [m/s^2]"; akcelerometrInfo.polozeniePaska = (a > 100) ? 100 : (int)a; return akcelerometrInfo; } static private UrządzenieInfo odczytajMagnetometr(Activity activity) { UrządzenieInfo magnetometrInfo = new UrządzenieInfo(); magnetometrInfo.typInformacji = TypInformacji.Czujnik; magnetometrInfo.nazwa = "Magnetometr"; magnetometrInfo.opis = "Bx=" + mx + "\nBy=" + my + "\nBz=" + mz + "\nB=" + m + " [mT]"; magnetometrInfo.polozeniePaska = (m > 100) ? 100 : (int)m; return magnetometrInfo; } static private UrządzenieInfo odczytajOrientacje(Activity activity) { UrządzenieInfo orientacjaInfo = new UrządzenieInfo(); orientacjaInfo.typInformacji = TypInformacji.Czujnik; orientacjaInfo.nazwa = "Orientacja"; orientacjaInfo.opis = "azymut=" + oz_azymut + "\npochylenie=" + ox_pochylenie + "\nnachylenie=" + oy_nachylenie + " [stopnie]"; orientacjaInfo.polozeniePaska = -1; return orientacjaInfo; } g. Wywolania tych metod dodajemy do metody odswiezListe: listaUrządzeń.Add(odczytajAkcelerometr(this)); listaUrządzeń.Add(odczytajMagnetometr(this)); listaUrządzeń.Add(odczytajOrientacje(this)); 2. LocationManager - lokacja (nie mylić z lokalizacją) - schemat identyczny jak wyżej a. Zaczynamy od uprawnień, jakie musi zadeklarować aplikacja, aby korzystać z lokalizacji (zgrubnej i dokładnej). Dodajemy poniższe znaczniki do pliku manifestu (za uses-sdk): b. Definiujemy pole LocationManager i pole Location, w którym będziemy zapisywać położenie odczytane w metodzie związanej z kolejnym interfejsem - LocationListener (trzeba go dodać!!) public class MainActivity : AppCompatActivity, ISensorEventListener, ILocationListener { ... private static LocationManager locationManager = null; private static Location lokacja; Definiujemy metody wymagane przez nowy interfejs (Ctrl+.) b+. Zdobywamy uprawnienia: private const int requestAccessFineLocation = 2; static private bool zdobądźUprawnieniaDoOdczytaniaLokacji(Activity activity) { Permission permissionCheck = ContextCompat.CheckSelfPermission(activity, Manifest.Permission.AccessFineLocation); if (permissionCheck != Permission.Granted) { ActivityCompat.RequestPermissions(activity, new string[] { Manifest.Permission.AccessFineLocation }, requestAccessFineLocation); return false; } else { //Toast.makeText(activity.getApplicationContext(), "Aplikacja posiada już uprawnienia do odczytania stanu telefonu", Toast.LENGTH_LONG).show(); return true; } } public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Permission[] grantResults) { switch (requestCode) { case requestReadPhoneState: if ((grantResults.Length > 0) && (grantResults[0] == Permission.Granted)) { Toast.MakeText(ApplicationContext, "Udzielono uprawnienia do odczytania stanu telefonu", ToastLength.Long).Show(); odswiezListe(); } break; case requestAccessWifiState: if ((grantResults.Length > 0) && (grantResults[0] == Permission.Granted)) { Toast.MakeText(ApplicationContext, "Udzielono uprawnienia do odczytania stanu sieci WiFi", ToastLength.Long).Show(); odswiezListe(); } break; case requestAccessFineLocation: if ((grantResults.Length > 0) && (grantResults[0] == Permission.Granted)) { Toast.MakeText(ApplicationContext, "Udzielono uprawnienia do odczytania położenia", ToastLength.Long).Show(); odswiezListe(); } break; default: break; } } c. Inicjujemy pole LocationManager w OnResume i zwalniamy w onPause: protected override void OnResume() { base.OnResume(); Toast.MakeText(this, "Rozpoczynam odczyty czujników", ToastLength.Long).Show(); //czujniki if (sensorManager == null) { sensorManager = (SensorManager)GetSystemService(SensorService); akcelerometr = sensorManager.GetDefaultSensor(SensorType.Accelerometer); magnetometr = sensorManager.GetDefaultSensor(SensorType.MagneticField); orientacja = sensorManager.GetDefaultSensor(SensorType.Orientation); sensorManager.RegisterListener(this, akcelerometr, SensorDelay.Normal); sensorManager.RegisterListener(this, magnetometr, SensorDelay.Normal); sensorManager.RegisterListener(this, orientacja, SensorDelay.Normal); } //lokacja if (locationManager == null) locationManager = (LocationManager)GetSystemService(LocationService); string dostawca = locationManager.GetBestProvider(new Criteria(), true); try { lokacja = locationManager.GetLastKnownLocation(dostawca); locationManager.RequestLocationUpdates(dostawca, 1000, 1, this); } catch (Java.Lang.SecurityException exc) //alternatywnie checkPermissions() { Toast.MakeText(ApplicationContext, "Brak uprawnień do odczytania położenia: " + exc.Message, ToastLength.Long).Show(); } } protected override void OnPause() { base.OnPause(); if (batteryReceiver != null) this.ApplicationContext.UnregisterReceiver(batteryReceiver); if (sensorManager != null) { sensorManager.UnregisterListener(this); //czujniki sensorManager = null; } if (locationManager != null) { locationManager.RemoveUpdates(this); //lokacja locationManager = null; } } d. Definiujemy metody interfejsu, ale tylko jednej używamy: //metody ILocationListener public void OnLocationChanged(Location location) { lokacja = location; } public void OnProviderDisabled(string provider) { // } public void OnProviderEnabled(string provider) { // } public void OnStatusChanged(string provider, [GeneratedEnum] Availability status, Bundle extras) { // } e. Definiujemy metodę odczytującą zdobyte w onLocationChanged static private UrządzenieInfo odczytajPołożenie(Activity activity) { UrządzenieInfo położenieInfo = new UrządzenieInfo(); położenieInfo.typInformacji = TypInformacji.Czujnik; położenieInfo.nazwa = "Położenie"; położenieInfo.opis = "brak"; położenieInfo.polozeniePaska = -1; if (locationManager != null) { string dostawca = locationManager.GetBestProvider(new Criteria(), true); if (dostawca != null) { lokacja = locationManager.GetLastKnownLocation(dostawca); if (lokacja != null) { double długośćGeograficzna = lokacja.Longitude; double szerokośćGeograficzna = lokacja.Latitude; double wysokość = lokacja.Altitude; double szybkość = lokacja.Speed; float namiar = lokacja.Bearing; float czas = lokacja.Time; string _dostawca = lokacja.Provider; położenieInfo.opis = "czas: " + czas; położenieInfo.opis += "\nszerokość geograficzna: " + szerokośćGeograficzna; położenieInfo.opis += "\ndługość geograficzna: " + długośćGeograficzna; położenieInfo.opis += "\nwyskość: " + wysokość; położenieInfo.opis += "\nkierunek: " + namiar; położenieInfo.opis += "\nszybkość: " + szybkość; położenieInfo.opis += "\ndostawca: " + _dostawca; położenieInfo.opis += "\nMożliwi dostawcy:"; foreach (string __dostawca in locationManager.AllProviders) { położenieInfo.opis += "\n\t" + __dostawca; } położenieInfo.polozeniePaska = (szybkość > 100) ? 100 : (int)szybkość; } } } return położenieInfo; } f. Wywołujemy ją w metodzie odswiezListe. if(zdobądźUprawnieniaDoOdczytaniaLokacji(this)) { listaUrządzeń.Add(odczytajPołożenie(this)); } ** W emulatorze można zmieniać położenie urządzenia, żeby testować nacisnąć SEND Do testowania należy włączyć lokalizację w urządzeniu !!! Ze względu na źle zorganizowanie zdobywania uprawnień - odczytywanie lokacji zadziała za drugim razem