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