Переходы геозоны не попадают, когда я вхожу или покидаю геозону: Xamarin.Android - PullRequest
0 голосов
/ 07 июля 2019

Я использую приложение xamarin.android для создания приложения геозоны.Я использую эмулятор, чтобы проверить это.Всякий раз, когда я создаю геозону, она показывает геозону, но вход или выход из геозоны не уведомляется.Я использую статические значения из эмулятора для входа или выхода из геозоны.Ниже приведен код MainActivity:

using System;

using Android.App;
using Android.Content.PM;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.OS;
using Android.Gms.Maps;
using Android.Support.V7.App;
using Android.Gms.Location;
using Android.Locations;
using Android.Gms.Common.Apis;
using Android.Gms.Common;
using Android.Gms.Maps.Model;
using System.Threading.Tasks;
using Android.Gms.Location.Places;
using Android.Graphics;
using Java.Util;
using System.Collections.Generic;
using Android.Content;
using Android.Util;

namespace LocationTest.Droid
{
    [Activity(Label = "LocationTest", Icon = "@mipmap/icon", Theme = "@style/MainTheme", MainLauncher = true,
        ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
    public class MainActivity : AppCompatActivity,
        IOnMapReadyCallback,
        GoogleApiClient.IConnectionCallbacks,
       Android.Locations.ILocationListener
    {
        private GoogleMap mMap;
        private MapFragment mapFragment;
        private GoogleApiClient apiClient;

        readonly GeofenceTriggerReceiver receiver = new GeofenceTriggerReceiver();

        protected override void OnCreate(Bundle savedInstanceState)
        {
            base.OnCreate(savedInstanceState);

            SetContentView(Resource.Layout.Main);
            SetUpMap();


            mapFragment = FragmentManager.FindFragmentById(Resource.Id.map) as MapFragment;
            mapFragment.GetMapAsync(this);

            if (GoogleApiAvailability.Instance
                    .IsGooglePlayServicesAvailable(this) == 0)
            {
                apiClient = new GoogleApiClient.Builder(this)
                    .AddApi(LocationServices.API)
                    .AddConnectionCallbacks(this)
                    .Build();
            }

            EditText location = FindViewById<EditText>(Resource.Id.location);
            location.Text = "PUT A VALID ADDRESS IN HERE";

            Button addButton = FindViewById<Button>(Resource.Id.addButton);


            addButton.Click += (sender, e) =>
            {
                string text = location.Text;
                if (!string.IsNullOrEmpty(text))
                {
                    //TODO
                    SetupGeofence(text);
                    Log.Debug("SETUP GEOFENCE SHOULD HAVE EXECUTED" , "YEAH BOYYYYYY");
                }
            };



        }



        #region map setup stuff

        private void SetUpMap()
        {
            if (mMap == null)
            {
                FragmentManager.FindFragmentById<MapFragment>(Resource.Id.map).GetMapAsync(this);
            }
        }


        public void OnMapReady(GoogleMap googleMap)
        {
            // the map shows your current location
            mMap = googleMap;

            mMap.MapType = GoogleMap.MapTypeNormal;
            mMap.MyLocationEnabled = true;
            mMap.UiSettings.ZoomControlsEnabled = true;
            mMap.UiSettings.MyLocationButtonEnabled = true;

            if (apiClient != null)
            {
                if (!apiClient.IsConnected)
                    apiClient.Connect();
            }
        }


        #endregion

        Color missColor = Color.Argb(0x30, 0xff, 0, 0);
        Color hitColor = Color.Argb(0x30, 0, 0xff, 0);

        private async void SetupGeofence(string location)
        {
            // sets up the geofence using the coordinates or the location search
            //make sure when testing you put a valid address so be mindful of spelling
            // also try to use an address close to your current location
            LatLng coord = new LatLng(32.2625, 74.6576);
            if (coord != null)
            {
                CircleOptions circleOptions = new CircleOptions()
                    .InvokeCenter(coord)
                    .InvokeFillColor(missColor)
                    .InvokeRadius(2000);
                var circle = mMap.AddCircle(circleOptions);

                //TODO addproximityalert method
                AddProximityAlert(
                    coord.Latitude, coord.Longitude, location,
                    _ => circle.FillColor = hitColor,
                    requestId => 
                    {
                        circle.FillColor = missColor;
                        RemoveProximityAlert(requestId, circle);
                    });
            }
        }

        private async Task<LatLng> GetCoordinate(string place)
        {
            if (Geocoder.IsPresent)
            {
                Geocoder coder = new Geocoder(this);
                var results = await coder.GetFromLocationNameAsync(place, 1);
                if (results.Count >= 1)
                {
                    return new LatLng(
                        results[0].Latitude,
                        results[0].Longitude);
                }

            }

            return null;
        }

        private int requestCode = 1;

        readonly Dictionary<int, PendingIntent> activeGeofences = new Dictionary<int, PendingIntent>();


        private void AddProximityAlert(double latitude, double longitude,
            string poiName, Action<int> enterWork = null,
            Action<int> exitWork = null)
        {
            #region SETUP CODE FOR RECEIVER

            //NOTE: this hash region does not actually build the geofence it is just setup code.
            //register enter and exit actions
            //this is the method that talks to the GeofenceTriggerReceiver

            receiver.RegisterActions(requestCode, enterWork, exitWork);

            //creating the receiver
            Bundle extras = new Bundle();
            extras.PutString("name", poiName);
            extras.PutInt("id", requestCode);
            Intent intent = new Intent(GeofenceTriggerReceiver.IntentName);
            intent.PutExtra(GeofenceTriggerReceiver.IntentName, extras);
            var pendingIntent = PendingIntent.GetBroadcast(this, requestCode, intent, PendingIntentFlags.CancelCurrent);

            #endregion

            #region building the geofence
            if (apiClient != null)
            {
                IGeofence geofence = new GeofenceBuilder()
                    .SetTransitionTypes(Geofence.GeofenceTransitionEnter | Geofence.GeofenceTransitionExit)
                    .SetCircularRegion(latitude, longitude, 50)
                    .SetRequestId(requestCode.ToString())
                    .SetExpirationDuration(Geofence.NeverExpire)
                    .Build();

                GeofencingRequest request = new GeofencingRequest.Builder()
                    .AddGeofence(geofence)
                    .Build();

                LocationServices.GeofencingApi.AddGeofences(apiClient, request, pendingIntent);
            }

            activeGeofences.Add(requestCode, pendingIntent);
            //requestcode increases as geofence locations increase
            requestCode++;


            #endregion


        }

        void OnRemoveButtonClickedAsync(object sender, EventArgs e)
        {
            //TODO
        }

        async void RemoveProximityAlert(int requestId, Circle theCircle)
        {

            PendingIntent pendingIntent;
            if (activeGeofences.TryGetValue(requestId, out pendingIntent))
            {

                if (apiClient != null)
                {
                   await LocationServices.GeofencingApi.RemoveGeofences(apiClient, pendingIntent);
                }
                else
                {
                    LocationManager locManager = LocationManager.FromContext(this);
                    locManager.RemoveProximityAlert(pendingIntent);
                }
            }

            activeGeofences.Remove(requestId);
            receiver.UnregisterAction(requestId);

            // Remove the circle after 1 second of exiting
            await Task.Delay(1000);
            theCircle.Remove();


        }

        Circle currentLocation;



        protected override void OnStart()
        {
            base.OnStart();
            if (apiClient != null && mMap != null)
                apiClient.Connect();
        }

        protected override void OnStop()
        {
            base.OnStop();
            if (apiClient != null)
                apiClient.Disconnect();
        }

        public void OnConnected(Bundle connectionHint)
        {
            //TODO
        }

        public void OnConnectionSuspended(int cause)
        {

        }

        public void OnProviderDisabled(string provider)
        {

        }

        public void OnProviderEnabled(string provider)
        {

        }

        public void OnStatusChanged(string provider, [GeneratedEnum] Availability status, Bundle extras)
        {

        }

        public void OnLocationChanged(Location location)
        {
            var pos = new LatLng(location.Latitude, location.Longitude);

                if (currentLocation == null)
                {
                    var options = new CircleOptions()
                        .InvokeCenter(pos)
                        .InvokeRadius(12)
                        .InvokeFillColor(Color.CornflowerBlue)
                        .InvokeStrokeColor(Color.White)
                        .InvokeStrokeWidth(4);
                    currentLocation = mMap.AddCircle(options);
                }
                else
                {
                    currentLocation.Center = pos;
                }

                mMap.MoveCamera(CameraUpdateFactory.NewLatLng(pos));
        }
    }
}

Ниже мой сервис:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Android.App;
using Android.Content;
using Android.Gms.Location;
using Android.Locations;
using Android.OS;
using Android.Runtime;
using Android.Util;
using Android.Views;
using Android.Widget;

namespace LocationTest.Droid
{
    [BroadcastReceiver(Exported = false)]
    [IntentFilter(new []{GeofenceTriggerReceiver.IntentName})]
    public class GeofenceTriggerReceiver : BroadcastReceiver
    {
        readonly Dictionary<int, Tuple<Action<int>,Action<int>>> actions
        = new Dictionary<int, Tuple<Action<int>, Action<int>>>();

        public const string IntentName = "com.xamarin.locationtest.geofence";

        // this is called when entering geofence and exiting geofence
        // the int key is what you assign it to
        public void RegisterActions(int key, Action<int> enterAction, Action<int> exitAction)
        {
            var work = Tuple.Create(enterAction, exitAction);
            actions.Add(key, work);
        }

        public void UnregisterAction(int key)
        {
            actions.Remove(key);
        }
        public override void OnReceive(Context context, Intent intent)
        {
            bool entering = intent.GetBooleanExtra(LocationManager.KeyProximityEntering, false);

            GeofencingEvent geofencingEvent = GeofencingEvent.FromIntent(intent);
            if(geofencingEvent != null)
            {
                entering = geofencingEvent.GeofenceTransition == Geofence.GeofenceTransitionEnter;
                IList<IGeofence> crossedFences = geofencingEvent.TriggeringGeofences;
                Location location = geofencingEvent.TriggeringLocation;

                Log.Debug(GetType().Name,
                    string.Format("entered at {0}, {1} and crossed {2} fences.",
                        location.Latitude, location.Longitude, crossedFences.Count));
            }

            var extras = intent.GetBundleExtra(IntentName);
            string poiName = extras.GetString("name");
            int id = extras.GetInt("id");

            Tuple<Action<int>, Action<int>> work;
            actions.TryGetValue(id, out work);

            if (entering)
            {
                Log.Debug(GetType().Name, "Entering " + poiName + " - " + id);
                if (work != null && work.Item1 != null)
                {
                    work.Item1(id);
                }
            }

            else
            {
                Log.Debug(GetType().Name, "Exiting " + poiName + " - " + id);
                if (work != null && work.Item2 != null)
                {
                    work.Item2(id);
                }
            }
        }
    }
}

И вот файл манифеста:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="com.companyname.LocationTest" android:installLocation="auto">
    <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="28" />
    <application android:label="LocationTest.Android" android:allowBackup="true">
        <uses-library android:name="org.apache.http.legacy" android:required="false" />
        <meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version" />
        <meta-data android:name="com.google.android.maps.v2.API_KEY" android:value="KEY HERE" />
        <meta-data android:name="com.google.android.gms.maps.API_OPTIONS" android:value="B3H9HE845CFHYG" />
        <service android:name=".GeofenceTriggerReceiver" />
    </application>
    <uses-feature android:glEsVersion="0x00020000" android:required="true" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-library android:name="org.apache.http.legacy" android:required="false" />
    <uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" />
</manifest>
...