using Android.App;
using Android.OS;
using Android.Support.V7.App;
using Android.Runtime;
using Android.Widget;
using Android.Views;
using System.Collections.Generic;
using System.Threading;
using System;
using static Android.App.ActivityManager;
using Android.Content;
using Android.Content.PM;
using Android.Media;
using Android.Hardware;
using Android.Support.V4.Content;
using Android.Support.V4.App;
using Android;
using Android.Telephony;
using Android.Net.Wifi;
using Android.Locations;

namespace StanUrzadzenia
{
    [Activity(Label = "@string/app_name", Theme = "@style/AppTheme", MainLauncher = true)]
    public class MainActivity : AppCompatActivity, ISensorEventListener, ILocationListener
    {
        ListView listView;

        class _Handler : Handler
        {
            private MainActivity activity;

            public _Handler(MainActivity activity)
            {
                this.activity = activity;
            }

            public override void HandleMessage(Message message)
            {
                activity.odswiezListe();
            }
        };

        _Handler handler;

        protected override void OnCreate(Bundle savedInstanceState)
        {
            base.OnCreate(savedInstanceState);
            // Set our view from the "main" layout resource
            SetContentView(Resource.Layout.activity_main);

            TextView naglowek = FindViewById<TextView>(Resource.Id.naglowek);
            naglowek.Text += "\n" + Build.Manufacturer + " " + Build.Model + " (" + Build.Product + ")";

            listView = FindViewById<ListView>(Resource.Id.listView);
            odswiezListe();

            const int coIleMilisekundOswiezacListe = 2000; //2s
            handler = new _Handler(this);
            ThreadStart ts = new ThreadStart( //wątek .NET, alternatywnie Java.Lang.Thread
                () =>
                {
                    while (true)
                    {
                        //w osobnym watku
                        handler.SendEmptyMessage(0);
                        try
                        {
                            Thread.Sleep(coIleMilisekundOswiezacListe);
                        }
                        catch //(ThreadInterruptedException exc)
                        {
                        }
                    }
                });
            Thread timer = new Thread(ts);
            timer.Start();
        }

        class BatteryReveiver : BroadcastReceiver
        {
            public override void OnReceive(Context context, Intent intent)
            {
                int bateriaPoziom = intent.GetIntExtra(BatteryManager.ExtraLevel, -1);
                if (bateriaPoziom < 10) Toast.MakeText(context, "Niski stan baterii", ToastLength.Long).Show();
                //odswiezListe();
            }
        }

        BroadcastReceiver batteryReceiver;
        _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
            }
        }

        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;

        private void odswiezListe()
        {
            int pozycja = listView.FirstVisiblePosition;
            View v = listView.GetChildAt(0);
            int top = (v == null) ? 0 : v.Top;

            List<UrządzenieInfo> listaUrządzeń = new List<UrządzenieInfo>();

            /*
            listaUrządzeń.Add(odczytajWersjęSystemu(this));
            listaUrządzeń.Add(odczytajStanPamięci(this));
            listaUrządzeń.Add(odczytajStanGłównejKartyPamięci(this));
            listaUrządzeń.Add(odczytajStanDodatkowejKartyPamięci(this));
            listaUrządzeń.Add(odczytajStanProcesora(this));

            batteryReceiver = new BatteryReveiver();
            IntentFilter intentFilter = new IntentFilter(Intent.ActionBatteryChanged);
            Intent intent = this.ApplicationContext.RegisterReceiver(batteryReceiver, intentFilter);
            listaUrządzeń.Add(odczytajStanBaterii(this, intent));

            listaUrządzeń.Add(odczytajObecnoscDodatkowychUrzadzen(this));
            listaUrządzeń.Add(odczytajStanAudio(this));
            listaUrządzeń.Add(odczytajObecnoscCzujnikow(this));

            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
            }

            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);
            }
            */

            listaUrządzeń.Add(odczytajAkcelerometr(this));
            listaUrządzeń.Add(odczytajMagnetometr(this));
            listaUrządzeń.Add(odczytajOrientacje(this));

            if(zdobądźUprawnieniaDoOdczytaniaLokacji(this))
            {
                listaUrządzeń.Add(odczytajPołożenie(this));
            }

            //tu dodawać opisy stanu kolejnych urzadzen

            UrzadzeniaAdapter a = new UrzadzeniaAdapter(this, Resource.Layout.wiersz, listaUrządzeń);
            listView.Adapter = a;

            listView.SetSelectionFromTop(pozycja, top);
        }

        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
            {
                if (dostawca != null)
                {
                    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;
            }
        }

        #region Metody odczytujące stan urządzenia
        private static 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 += "\nWersja: " + Build.VERSION.Release + " (" + Build.VERSION.Incremental + ")";
            systemInfo.opis += "\nTyp CPU: " + Build.CpuAbi; //deprecated
            systemInfo.opis += "\nTyp CPU: ";
            foreach (string abi in Build.SupportedAbis) //API 21
            {
                systemInfo.opis += "\n\t" + abi;
            }
            systemInfo.opis += "\nWyświetlacz: " + Build.Display;
            return systemInfo;
        }

        private static 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ępną = mi.AvailMem / 1024; //kB
                                                      //mi.totalMem
            long pamięćCałkowita = LinuxHelper.ReadRAMTotalSizeKB();
            long pamięćZajęta = pamięćCałkowita - pamięćDostępną;
            pi.opis = "Dostępna pamięć: " + pamięćDostępną + "/" + pamięćCałkowita;
            pi.polozeniePaska = (int)(pamięćZajęta * 100 / pamięćCałkowita);
            return pi;
        }

        private static Tuple<string, int> 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<string, int> tuple = new Tuple<string, int>(opis, procent);
            return tuple;
        }

        private static UrządzenieInfo odczytajStanGłównejKartyPamięci(Activity activity)
        {
            Tuple<string, int> 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;
        }

        private static 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<string, int> 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;
        }

        private static UrządzenieInfo odczytajStanProcesora(Activity activity)
        {
            UrządzenieInfo procesorInfo = new UrządzenieInfo();
            procesorInfo.typInformacji = TypInformacji.StanUrzadzenia;
            procesorInfo.nazwa = "Procesor (CPU)";
            int procesorObciąrzenie = (int)Math.Round(100 * LinuxHelper.ReadCPUUsage());
            String opisProcesora = LinuxHelper.ReadCPUInfo();
            procesorInfo.opis = opisProcesora + "\n";
            procesorInfo.opis += "Obciążenie procesora: " + procesorObciąrzenie + "%";
            procesorInfo.polozeniePaska = procesorObciąrzenie;
            return procesorInfo;
        }

        static private UrządzenieInfo odczytajStanBaterii(Activity activity, Intent intent)
        {
            //Bateria (API 5)            	
            UrządzenieInfo bateriaInfo = new UrządzenieInfo();
            bateriaInfo.typInformacji = TypInformacji.StanUrzadzenia;
            bateriaInfo.nazwa = "Bateria";
            if (intent.GetBooleanExtra(BatteryManager.ExtraPresent, false))
            {
                String bateriaTechnologia = intent.GetStringExtra(BatteryManager.ExtraTechnology);
                BatteryStatus bateriaStan = (BatteryStatus)intent.GetIntExtra(BatteryManager.ExtraStatus, -1);
                String bateriaStanOpis = "";
                switch (bateriaStan)
                {
                    case BatteryStatus.Charging:
                        bateriaStanOpis = "ładowanie";
                        break;
                    case BatteryStatus.Discharging:
                        bateriaStanOpis = "rozładowywanie";
                        break;
                    case BatteryStatus.Full:
                        bateriaStanOpis = "w pełni naładowana";
                        break;
                    case BatteryStatus.NotCharging:
                        bateriaStanOpis = "nie ładowana";
                        break;
                    default:
                    case BatteryStatus.Unknown:
                        bateriaStanOpis = "nieznany";
                        break;
                }
                BatteryPlugged bateriaMetodaLadowania = (BatteryPlugged)intent.GetIntExtra(BatteryManager.ExtraPlugged, -1);
                String bateriaMetodaLadowaniaOpis = "";
                switch (bateriaMetodaLadowania)
                {
                    case BatteryPlugged.Ac:
                        bateriaMetodaLadowaniaOpis = "AC";
                        break;
                    case BatteryPlugged.Usb:
                        bateriaMetodaLadowaniaOpis = "USB";
                        break;
                    case BatteryPlugged.Wireless:
                        bateriaMetodaLadowaniaOpis = "wireless";
                        break;
                    default:
                        bateriaMetodaLadowaniaOpis = "-";
                        break;
                }
                int bateriaSkala = intent.GetIntExtra(BatteryManager.ExtraScale, -1);
                int bateriaPoziom = intent.GetIntExtra(BatteryManager.ExtraLevel, -1);
                int bateriaNapiecie = intent.GetIntExtra(BatteryManager.ExtraVoltage, -1);
                int bateriaTemperatura = intent.GetIntExtra(BatteryManager.ExtraTemperature, -1);
                bateriaInfo.opis = "Technologia: " + bateriaTechnologia + ", stan: " + bateriaStanOpis + " (" + bateriaMetodaLadowaniaOpis + "), poziom naładowania baterii: " + bateriaPoziom + "/" + bateriaSkala + ", napięcie: " + bateriaNapiecie / 1000 + " V, temperatura: " + bateriaTemperatura / 10 + " °C";
                bateriaInfo.polozeniePaska = bateriaPoziom * 100 / bateriaSkala;
            }
            else
            {
                bateriaInfo.opis = "Brak";
                bateriaInfo.polozeniePaska = -1;
            }
            return bateriaInfo;
        }

        static private UrządzenieInfo odczytajObecnoscDodatkowychUrzadzen(Activity activity)
        {
            //Dodatkowe urządzenia
            UrządzenieInfo dodatkoweInfo = new UrządzenieInfo();
            dodatkoweInfo.typInformacji = TypInformacji.Inne;
            dodatkoweInfo.nazwa = "Dodatkowe urządzenia";
            dodatkoweInfo.polozeniePaska = -1;

            PackageManager pm = activity.PackageManager;
            bool czyTelefonObecny = pm.HasSystemFeature(PackageManager.FeatureTelephony);
            dodatkoweInfo.opis = "Telefon: " + (czyTelefonObecny ? "obecny" : "brak");
            if (czyTelefonObecny)
            {
                dodatkoweInfo.opis = pm.HasSystemFeature(PackageManager.FeatureTelephonyGsm) ? " (GSM)" : "";
                dodatkoweInfo.opis = pm.HasSystemFeature(PackageManager.FeatureTelephonyCdma) ? " (CDMA)" : "";
            }
            bool czyKameraObecna = pm.HasSystemFeature(PackageManager.FeatureCamera);
            dodatkoweInfo.opis += "\nAparat fotograficzny/kamera: " + (czyKameraObecna ? "obecna" : "brak");
            if (czyKameraObecna)
            {
                dodatkoweInfo.opis += "\n\tautomatyczna regulacja ostrości: " + (pm.HasSystemFeature(PackageManager.FeatureCameraAutofocus) ? "obecna" : "brak");
                dodatkoweInfo.opis += "\n\tlampa błyskowa: " + (pm.HasSystemFeature(PackageManager.FeatureCameraFlash) ? "obecna" : "brak");
            }
            dodatkoweInfo.opis += "\nCzujnik światła: " + (pm.HasSystemFeature(PackageManager.FeatureSensorLight) ? "obecny" : "brak");
            dodatkoweInfo.opis += "\nCzujnik zbliżeniowy: " + (pm.HasSystemFeature(PackageManager.FeatureSensorProximity) ? "obecny" : "brak");
            dodatkoweInfo.opis += "\nEkran wielodotykowy: " + (pm.HasSystemFeature(PackageManager.FeatureTouchscreenMultitouch) ? "obecny" : "brak");
            dodatkoweInfo.opis += "\nAnimowana tapeta: " + (pm.HasSystemFeature(PackageManager.FeatureLiveWallpaper) ? "obecna" : "brak");

            return dodatkoweInfo;
        }

        static private UrządzenieInfo odczytajStanAudio(Activity activity)
        {
            //Stan audio
            UrządzenieInfo audioInfo = new UrządzenieInfo();
            audioInfo.typInformacji = TypInformacji.Inne;
            audioInfo.nazwa = "Audio";
            audioInfo.polozeniePaska = -1;

            AudioManager am = (AudioManager)activity.GetSystemService(Context.AudioService);
            Mode trybAudio = am.Mode;
            String trybAudioOpis = "Tryb audio: ";
            switch (trybAudio)
            {
                case Mode.Normal:
                    trybAudioOpis += "normalny";
                    break;
                case Mode.Ringtone:
                    trybAudioOpis += "dzwonki";
                    break;
                case Mode.InCall:
                    trybAudioOpis += "w trakcie rozmowy (telefon)";
                    break;
                case Mode.InCommunication:
                    trybAudioOpis += "w trakcie rozmowy (VoIP)";
                    break;
                default:
                case Mode.Invalid:
                    trybAudioOpis += "niezanany lub niepoprawny";
                    break;
            }
            audioInfo.opis = trybAudioOpis;

            RingerMode trybDzwonka = am.RingerMode;
            String trybDzwonkaOpis = "Rodzaj dzwonka: ";
            switch (trybDzwonka)
            {
                case RingerMode.Normal:
                    trybDzwonkaOpis += "normalny";
                    break;
                case RingerMode.Silent:
                    trybDzwonkaOpis += "wyciszony";
                    break;
                case RingerMode.Vibrate:
                    trybDzwonkaOpis += "wibracje";
                    break;
                default:
                    trybDzwonkaOpis += "niezanany";
                    break;
            }
            audioInfo.opis += "\n" + trybDzwonkaOpis;

            audioInfo.opis += "\nWyciszenie mikrofonu: " + (am.MicrophoneMute ? "tak" : "nie");
            audioInfo.opis += "\nOdtwarzanie muzyki: " + (am.IsMusicActive ? "tak" : "nie");

            audioInfo.opis += "\nGłośność systemu: " + am.GetStreamVolume(Stream.System) + "/" + am.GetStreamMaxVolume(Stream.System);
            audioInfo.opis += "\nGłośność dzwonka: " + am.GetStreamVolume(Stream.Ring) + "/" + am.GetStreamMaxVolume(Stream.Ring);
            audioInfo.opis += "\nGłośność alarmu: " + am.GetStreamVolume(Stream.Alarm) + "/" + am.GetStreamMaxVolume(Stream.Alarm);
            audioInfo.opis += "\nGłośność rozmowy: " + am.GetStreamVolume(Stream.VoiceCall) + "/" + am.GetStreamMaxVolume(Stream.VoiceCall);
            audioInfo.opis += "\nGłośność powiadomień: " + am.GetStreamVolume(Stream.Notification) + "/" + am.GetStreamMaxVolume(Stream.Notification);
            audioInfo.polozeniePaska = 100 * am.GetStreamVolume(Stream.System) / am.GetStreamMaxVolume(Stream.System);

            return audioInfo;
        }

        static private String opisCzujnika(IList<Sensor> lista, string nazwa)
        {
            string opis = nazwa + ": ";
            if (lista.Count > 1) opis += "\n";
            if (lista.Count > 0)
                for (int i = 0; i < lista.Count; ++i)
                {
                    if (lista.Count > 1) opis += "\t";
                    Sensor czujnik = lista[i];
                    opis += czujnik.Name + ", wersja: " + czujnik.Version + "\n";
                }
            else opis += "brak\n";
            return opis;
        }

        static private UrządzenieInfo odczytajObecnoscCzujnikow(Activity activity)
        {
            //Dodatkowe urządzenia
            UrządzenieInfo czujnikiInfo = new UrządzenieInfo();
            czujnikiInfo.typInformacji = TypInformacji.Inne;
            czujnikiInfo.nazwa = "Czujniki";
            czujnikiInfo.polozeniePaska = -1;

            SensorManager sm = (SensorManager)activity.GetSystemService(Context.SensorService);
            czujnikiInfo.opis = opisCzujnika(sm.GetSensorList(SensorType.Accelerometer), "Akcelerator");
            czujnikiInfo.opis += opisCzujnika(sm.GetSensorList(SensorType.Gyroscope), "Żyroskop");
            czujnikiInfo.opis += opisCzujnika(sm.GetSensorList(SensorType.Light), "Światło");
            czujnikiInfo.opis += opisCzujnika(sm.GetSensorList(SensorType.MagneticField), "Pole magnetyczne");
            czujnikiInfo.opis += opisCzujnika(sm.GetSensorList(SensorType.Orientation), "Orientacja");
            czujnikiInfo.opis += opisCzujnika(sm.GetSensorList(SensorType.Pressure), "Ciśnienie");
            czujnikiInfo.opis += opisCzujnika(sm.GetSensorList(SensorType.Proximity), "Odległość");
            czujnikiInfo.opis += opisCzujnika(sm.GetSensorList(SensorType.Temperature), "Temperatura");
            czujnikiInfo.opis += opisCzujnika(sm.GetSensorList(SensorType.AmbientTemperature), "Temperatura otoczenia");

            return czujnikiInfo;
        }
        #endregion

        #region GSM
        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;
            }
        }

        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;
            }
        }

        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;
        }
        #endregion

        #region WiFi
        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;
            }
        }

        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<WifiConfiguration> _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;
        }
        #endregion

        #region ISensorEventListener
        //zarzadca czujnikow
        private SensorManager sensorManager = null;
        private Sensor akcelerometr = null;
        private Sensor magnetometr = null;
        private Sensor orientacja = null;

        //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;

        //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;
            }
        }

        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;
        }
        #endregion

        #region LocationListener
        private static LocationManager locationManager = null;
        private static Location lokacja;

        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)
        {
            //
        }

        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;
            }
        }

        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;
        }
        #endregion
    }
}