Odczytywanie stanu połączenia z siecią GSM (telefonia)
-------------------------------------------------------
Kontynuujemy rozwój projektu 'StanUrzadzenia'
0. Niezbędne uprawnienie READ_PHONE_STATE
W pliku manifestu Properties\AndroidManifest.xml, w obrębie elementu manifest:
W VS/Xamarin można to też ustawić z menu Project/StanUrządzenia Properties/Android Manifest: READ_PHONE_STATE
1. W Android >=6 należy zdobyć te uprawnienia dla procesu:
private const int requestReadPhoneState = 0;
static private bool zdobądźUprawnieniaDoOdczytaniaWłasnościGSM(Activity activity)
{
Permission permissionCheck = ContextCompat.CheckSelfPermission(activity, Manifest.Permission.ReadPhoneState);
if (permissionCheck != Permission.Granted)
{
ActivityCompat.RequestPermissions(activity, new string[] { Manifest.Permission.ReadPhoneState }, requestReadPhoneState);
return false;
}
else
{
//Toast.makeText(activity.getApplicationContext(), "Aplikacja posiada już uprawnienia do odczytania stanu telefonu", Toast.LENGTH_LONG).show();
return true;
}
}
Po przydzieleniu uprawnień (okno dialogowe) wywołana zostanie metoda:
//tylko informacja dla użytkownika
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;
default:
break;
}
}
2. Odczytanie stanu sieci:
static private UrządzenieInfo odczytajSiećTelefoniczną(Activity activity, SignalStrength signalStrength)
{
UrządzenieInfo gsmInfo = new UrządzenieInfo();
gsmInfo.typInformacji = TypInformacji.Inne;
gsmInfo.nazwa = "Sieć GSM";
TelephonyManager tm = (TelephonyManager)activity.GetSystemService(TelephonyService); //menadzer gsm
//Android.Telephony.Gsm.GsmCellLocation loc = (Android.Telephony.Gsm.GsmCellLocation)tm.CellLocation; //lokalizacja telefonu przez gsm, przestarzałe!
if (tm != null)
{
//przy braku uprawnień tu będzie wyjątek Java.Lang.SecurityException -> warto try..catch
gsmInfo.opis = "IMEI: " + tm.Imei;
//gsmInfo.opis = "\nID: "+loc.Cid;
gsmInfo.opis += "\nOperator: " + tm.NetworkOperatorName;
string typSieciTelefonicznej = "";
switch (tm.NetworkType)
{
case NetworkType.OneXrtt: typSieciTelefonicznej = "1xRTT"; break;
case NetworkType.Cdma: typSieciTelefonicznej = "CDMA"; break;
case NetworkType.Edge: typSieciTelefonicznej = "EDGE"; break;
case NetworkType.Ehrpd: typSieciTelefonicznej = "eHRPD"; break;
case NetworkType.Evdo0: typSieciTelefonicznej = "EVDO rev. 0"; break;
case NetworkType.EvdoA: typSieciTelefonicznej = "EVDO rev. A"; break;
case NetworkType.EvdoB: typSieciTelefonicznej = "EVDO rev. B"; break;
case NetworkType.Gprs: typSieciTelefonicznej = "GPRS"; break;
case NetworkType.Hsdpa: typSieciTelefonicznej = "HSDPA"; break;
case NetworkType.Hspa: typSieciTelefonicznej = "HSPA"; break;
case NetworkType.Hspap: typSieciTelefonicznej = "HSPA+"; break;
case NetworkType.Hsupa: typSieciTelefonicznej = "HSUPA"; break;
case NetworkType.Iden: typSieciTelefonicznej = "iDen"; break;
case NetworkType.Lte: typSieciTelefonicznej = "LTE"; break;
case NetworkType.Umts: typSieciTelefonicznej = "UMTS"; break;
case NetworkType.Unknown: typSieciTelefonicznej = "Nieznany"; break;
default: typSieciTelefonicznej = "Inny"; break; //sic!
}
gsmInfo.opis += "\nTyp sieci: " + typSieciTelefonicznej;
gsmInfo.opis += "\nNumer telefonu: " + tm.Line1Number;
string stanPołączenia = "";
switch (tm.CallState)
{
case CallState.Ringing:
stanPołączenia = "Dzwonienie";
break;
case CallState.Offhook:
stanPołączenia = "Trwa rozmowa"; //zajęty
break;
case CallState.Idle:
stanPołączenia = "Nieaktywny"; //wolny
break;
}
gsmInfo.opis += "\nStan połączenia: " + stanPołączenia;
if (signalStrength != null)
gsmInfo.polozeniePaska = signalStrength.Level * 25; //0-4, wymaga API 22 -> trzeba zwiększyć
else gsmInfo.polozeniePaska = -1;
}
else
{
//brak zasięgu
gsmInfo.polozeniePaska = -1;
}
return gsmInfo;
}
3. Uruchomienie w metodzie odświeżListe:
if (zdobądźUprawnieniaDoOdczytaniaWłasnościGSM(this))
{
listaUrządzeń.Add(odczytajSiećTelefoniczną(this, null)); //na razie bez siły sygnału
}
4. Nasłuchiwacz do monitorowania siły sygnału:
_PhoneStateListener phoneStateListener = null;
SignalStrength signalStrength = null;
class _PhoneStateListener : PhoneStateListener
{
private MainActivity activity;
public _PhoneStateListener(MainActivity activity)
{
this.activity = activity;
}
public override void OnSignalStrengthsChanged(SignalStrength signalStrength)
{
activity.signalStrength = signalStrength;
//activity.odswiezListe(); //odświeżanie stąd jest zbyt częste
}
}
Rozwinięcie kodu z metody odswiezListe
if (zdobądźUprawnieniaDoOdczytaniaWłasnościGSM(this))
{
if (phoneStateListener == null) phoneStateListener = new _PhoneStateListener(this);
TelephonyManager tm = (TelephonyManager)this.GetSystemService(TelephonyService);
tm.Listen(phoneStateListener, PhoneStateListenerFlags.SignalStrengths);
listaUrządzeń.Add(odczytajSiećTelefoniczną(this, signalStrength)); //teraz przekazywanie siły sygnału
}
------------------------------------------------------
Odczytywanie stanu sieci radiowej WiFi
Uprawnienia:
Zdobywanie uprawnień przez proces:
private const int requestAccessWifiState = 1;
//!!! w intencjach była ogólniejsza metoda - warto użyć jej tutaj !!!
static private bool zdobądźUprawnieniaDoOdczytaniaWłasnościWiFi(Activity activity)
{
Permission permissionCheck = ContextCompat.CheckSelfPermission(activity, Manifest.Permission.AccessWifiState);
if (permissionCheck != Permission.Granted)
{
ActivityCompat.RequestPermissions(activity, new String[] { Manifest.Permission.AccessWifiState }, requestAccessWifiState);
return false;
}
else
{
//Toast.MakeText(activity.ApplicationContext, "Aplikacja posiada już uprawnienia do odczytania stanu telefonu", ToastLength.Long).Show();
return true;
}
}
Zmiana w istniejącej metodzie:
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;
default:
break;
}
}
Odczytywanie informacji o sieci WiFi:
static private UrządzenieInfo odczytajSiećWiFi(Activity activity)
{
UrządzenieInfo wifiInfo = new UrządzenieInfo();
wifiInfo.typInformacji = TypInformacji.Inne;
wifiInfo.nazwa = "Sieć WiFi";
WifiManager wm = (WifiManager)activity.ApplicationContext.GetSystemService(WifiService);
if (wm != null)
{
WifiInfo wi = wm.ConnectionInfo;
if (wi != null)
{
wifiInfo.opis = "SSID: " + wi.SSID;
wifiInfo.opis += "\nIP: " + wi.IpAddress;
wifiInfo.opis += "\nMAC: " + wi.MacAddress;
int rssi = wi.Rssi;
wifiInfo.polozeniePaska = WifiManager.CalculateSignalLevel(rssi, 100);
}
else wifiInfo.polozeniePaska = -1;
wifiInfo.opis += "\nZapisane sieci: ";
IList _wis = wm.ConfiguredNetworks;
if (_wis != null)
{
foreach(WifiConfiguration _wi in _wis)
{
wifiInfo.opis += "\n\t" + _wi.Ssid;
}
}
else wifiInfo.opis += "brak zapamiętanych sieci";
}
else
{
//brak sieci
wifiInfo.polozeniePaska = -1;
}
return wifiInfo;
}
Wywołanie tej metody należy dodać do odwiezListe.
if(zdobądźUprawnieniaDoOdczytaniaWłasnościWiFi(this))
{
listaUrządzeń.Add(odczytajSiećWiFi(this));
}
Jeżeli chcemy być powiadamiani o zmianach w sieci WiFi (UWAGA! Bardzo częste powiadomienia), należy ustalić BroadcastReceiver:
class WifiReceiver : BroadcastReceiver
{
private readonly TimeSpan czasMiędzyOdświeżeniamiWiFi = TimeSpan.FromMilliseconds(10000);
DateTime? czasOstatniegoOdświeżeniaWiFi = null;
MainActivity activity;
public WifiReceiver(MainActivity activity)
{
this.activity = activity;
}
public override void OnReceive(Context context, Intent intent)
{
//UWAGA! To jest wywoływane bardzo często -> filtrowanie
if (intent.Action == WifiManager.WifiStateChangedAction)
{
DateTime bieżącyCzas = DateTime.Now;
if (czasOstatniegoOdświeżeniaWiFi == null || (bieżącyCzas - czasOstatniegoOdświeżeniaWiFi > czasMiędzyOdświeżeniamiWiFi))
{
czasOstatniegoOdświeżeniaWiFi = bieżącyCzas;
Toast.MakeText(context, "Zmiana stanu WiFi", ToastLength.Long).Show();
//activity.odswiezListe();
}
}
}
}
BroadcastReceiver wifiReceiver = null;
W metodzie odswiezListe:
if (zdobądźUprawnieniaDoOdczytaniaWłasnościWiFi(this))
{
listaUrządzeń.Add(odczytajSiećWiFi(this));
if (wifiReceiver == null) wifiReceiver = new WifiReceiver(this);
IntentFilter _intentFilter = new IntentFilter(WifiManager.WifiStateChangedAction);
Intent _intent = ApplicationContext.RegisterReceiver(wifiReceiver, _intentFilter);
}