Google Play Services on Marshmallow

When it comes to working on Android apps, I really feel like I am starting completely from scratch … or maybe even a bit less than that. And I end up running across weird problems that end up causing me all kinds of issues. This post will talk about one of those problems and how I combined the posts of two others (who I am sure know much more than I about Android) to address my issue.

I am working on an app that uses maps. I am planning on targeting Marshmallow at a minimum. I am also using the Visual Studio Android Emulator. If you don’t already know, the Visual Studio emulator doesn’t come with the Google Play Services, which are required if you want to use maps in your app.

In a previous app, I was able to spin up an emulator, go to http://teamandroid.com/gapps, download the appropriate zip file and drag and drop to the emulator to install. This worked great for me on both KitKat and Lollipop emulators. On Marshmallow … not so much.

I started surfing … I mean researching. And in my research I came across an article from Cheesebaron which you can see here. In a nutshell, he recommends (with references) two different gapps packages to download. The only problem was that when I tried his method of downloading and drag and drop installing, my emulator just started an endless loop of optimizing packages and rebooting.

I then found another article from Rob Prouse about how to do a low level install of gapps packages from the SD card. When I tried his method, which used the gapps package from teamandroid.com, that failed as well. But at least it seemed to install without any obvious errors.

I finally deleted my emulator, started up a new one and combined the two articles. I downloaded the two packages recommended by Cheesebaron. I installed the first one in the manner recommended by Rob Prouse and after installation, was able to setup my Google account on the emulator. I then installed the second package from Cheesebaron using the same SD card installation method. After rebooting the emulator, I was able to deploy my app and run it. I am not sure if this is normal behavior, but I had to go into the app settings on the emulator and enable location for it. In the past, I seem to remember it asking me on first install, but I could be mistaken.

My new Marshmallow emulator setup is as follows:

  • Download gapps packages from Cheesebaron’s article:
  • Install the first package via the emulator SD card as per Rob Prouse
  • Create your google account in the settings/accounts
  • Install the second package via the emulator SD card as per Rob Prouse.

Hopefully this helps someone else and if not, writing it down will help me.

 

Xamarin Dev Days Lab – Prism Step 4

Well, hello from Las Vegas! I am down in LV for the Autodesk Developer Network Dev Days and the Autodesk University. It’s a pretty fun time, especially if you are involved in engineering or CAD of any kind. If you are like me, also a dev person, there is lots of cloud stuff to add in there. And now even virtual reality and augmented reality to geek out!

In any event, travel makes for weird schedules and time awake. So here I am working on navigation in Xamarin Forms projects. But first a little recap: in our last post we really dug into dependency injection and showed the power of it. We saw some concrete examples of how it can make our app better architected, and how that makes it more maintainable. Next we will take that architecture to the next level and add in navigation. You probably remember from the start of the app how we had to register pages for navigation: let’s review that.

In a normal Xamarin app, the navigation system is accessed via a singleton object. To navigate to another page , you have to provide the actual page type of the destination page to the navigation service. Right away, you can see that this could be a headache in the future: if you change the page type, you need to change it everywhere in your app that the page is referenced. Yuck. And what if you have needs that are a bit more dynamic? For example, you could have a free version of an app and a paid version. In that case your dependencies just increased by a factor of …? Well, it depends on the app, but every time you have to make that decision in your app is another level of complexity. Instead, wouldn’t it be cool if you could just determine if the app was paid or not and navigate to the appropriate page based on that status?

Prism provides a better model for navigation. Not only does Prism remove the dependency on types, it also moves the navigation brains up to the view model (where the business logic is) and away from the presentation level (where the Xamarin navigation system resides). And this all begins in the RegisterTypes method of the App object. So let’s start with what we have there.


/// first we have the register types
protected override void RegisterTypes()
{
    // non nav registration here
    Container.RegisterTypeForNavigation
        <View.SpeakersPage, ViewModel.SpeakersViewModel>();
}

/// and our initial navigation
protected override void OnInitialize()
{
    NavigationService.NavigateAsync("SpeakersPage");
}

The above registers the SpeakersPagae for navigation and associates it with the SpeakersViewModel. There is also an optional parameter in the call to associate the registration with a key. Since we didn’t provide a key, Prism made one for us based on the name of the page. When you call NavigateAsync, you provide the key and the Prism navigation system looks up what is associated with the key and instantiates the appropriate page and view model.
We can improve this by specifying our own key. If we do that, in every place we navigate to the page, simply changing the initial registration will allow us to put in a different page. We won’t have to go to every place and change the call. I like to create a static class with the page keys so that I can reduce my use of magic strings.

public static class PageKeys
{
    public const string Speakers = "speakers";
    public const string Details = "details";
}

And now we can update the two functions above:


protected override void RegisterTypes()
{
    // non nav stuff here

    Container.RegisterTypeForNavigation
        <View.SpeakersPage, ViewModel.SpeakersViewModel>
        (PageKeys.Speakers);
}

protected override void OnInitialize()
{
    NavigationService.NavigateAsync(PageKeys.Speakers);
}

 
So that is looking pretty cool. Let’s pretend there is a paid and free version of the app and adjust our registration:

protected override void RegisterTypes()
{
   if (IsPaidApp)
   {
        Container.RegisterTypeForNavigation
          <View.SpeakersExPage, ViewModel.SpeakersExViewModel>
          (PageKeys.Speakers);
   }
   else
   {
       Container.RegisterTypeForNavigation
         <View.SpeakersPage, ViewModel.SpeakersViewModel>
         (PageKeys.Speakers);
   }
}

Awesome! Just by using the key instead of the page type name, we made our app even more flexible and easier to maintain. None of our in app navigation will change, we always just call:


NavigationService.NavigateAsync(PageKeys.Speakers);

What else is important in this? Well I mentioned this before, but the navigation system is rooted into the presentation layer of the code. But navigation is really about business logic. The Prism navigation service abstracts out the presentation and the service is passed around as an interface. For unit testing of your view model, you can mock the interface and your view model won’t know or care.

You probably already know how the view model gets the navigation service (dependency injection, constructor parameter), but just in case it is late or you don’t remember every single detail of the previous posts, we just put the dependency into the constructor and the dependency injection container injects it for us. You can see this in the code. If you are looking at the code and saying: wait, INavigationService is not registered anywhere in your code, you are right. The App base class does it for us because they assumed that you were going to want that service. Dig into the Prism code if you want to find out more.

The last thing I want to bring up with respect to Prism navigation is how to pass data during navigation. When you use the NavigationService.NavigateAsync method, the second parameter is a NavigationParameters object, and you can pass pretty much anything in in. Let’s dive in.

In this example, I want to know when the SpeakersPage is navigated to the first time. So in the app object, I am going to add that parameter to the initial navigation in the OnInitialize method.


protected override void OnInitialize()
{
    var nps = new NavigationParameters();
    nps.Add("first", true);
    NavigationService.NavigateAsync(PageKeys.Speakers, nps);
}

How do we consume this data? And where do we consume it? This data is really business logic data so we want to consume it in the view model. To get the data up to the view model we have to have our view model implement the INavigationAware interface. This interface has two methods: OnNavigatedFrom and OnNavigatedTo. I normally like to implement this in the BaseViewModel class so that all the view models have it already and I can also setup some generic functionality if I want.

public class BaseViewModel : BindableBase, INavigationAware
{
    /// ... other base stuff goes here

    public virtual void OnNavigatedFrom(
        NavigationParameters nps)
    {
    }

    public virtual void OnNavigatedTo(
        NavigationParameters nps)
    {
    }
}

So now in my SpeakersViewModel, I will override the OnNavigatedTo method to implement looking for first run:

public class SpeakersViewModel : BaseViewModel
{
    /// ... existing stuff here

    public override void OnNavigatedTo(
        NavigationParameters nps)
    {
        base.OnNavigatedTo(nps);

        if (nps == null || !nps.ContainsKey("first"))
            return;

        bool firstLoad = (bool) nps["first"];
        if (firstLoad)
        {
            /// do first functionality here
        }
        else
        {
            /// do something else
        }
    }
}

But how does that actually work? What happens is that the navigation service is aware of the page creation. And as part of the page creation, we know that the view model will be automatically injected. The navigation service will look at the view model object that was injected and see if it implements the INavigationAware interface. If it does, it will call the OnNavigatedTo method. More awesomeness!

Well, that is it for navigation. You can see full-on code at the usual place in my GitHub repo under Step 04.
Enjoy!

Xamarin Forms Maps Bits

I ran across a couple of small issues tonight with my work with the Xamarin Forms Map, and it had to do with the precision of the values that I was using for the Center property that I setup in my previous post.

Normally in the Android emulator with Visual Studio, it has a preset starting location. For my app, I wanted something a little closer to home. To get the values for the MapSpan object, I was just outputting the values for the fields from the Center property that I had setup to figure out where I wanted to start from.

When I used those values as my initial start point for the map, I was putting in the full precision that the Visual Studio debugger was showing, approximately 15 digits after the decimal place. When I started forcing these values in, the map wouldn’t update its position.

I then started to play around with the location services in the emulator and the map would update in response to those values. Looking at the values displayed by the emulator, they only used 4 digits. I made the change and everything started working again. Assuming I am in the view model and am using the attached property to bind to set the center point of the map, this didn’t work for me:


// underlying Map.MoveToRegion call doesn't do anything
Center = new MapSpan
(
	new Position(48.0111563131213188, -122.0096835170062306),
	0.0096835170062306,
	0.0111563131213188
);

Instead, try using it like this:


// underlying Map.MoveToRegion call now works
Center = new MapSpan
(
	new Position(48.0111, -122.0096),
	0.0096,
	0.0111
);

I have yet to go looking at why this is the case but it seems likely that the map control can only handle that level of accuracy. If you are finding that you can’t seem to control what the map is displaying, check out the precision of the values in the MapSpan object. And if anyone reading this knows for sure what is happening here, feel free to chime in.

I will be attending a Xamarin dev workshop at Microsoft Vancouver, perhaps there will be someone there that can answer this definitely.

Hope that helps.

Xamarin Forms Map Center

Problem:

I have been working on an app in Xamarin, with the goal of being able to deploy to UWP, Android and IOS. This is my first real effort with Xamarin, and the first time publishing IOS and Android to their respective stores. Actually, this is my first IOS app ever! I still need to get on to Craigslist and find a reasonably priced Mac Mini so that I can build the IOS app.

Some app background: it makes use of the map control. My needs aren’t too difficult, but I need to know what the map control is displaying at any given moment. Specifically, I need the latitude and longitude of the map center. At least at this point, my app doesn’t need to worry about location tracking.

I am going to use Xamarin forms and take advantage of the cross platform UI. I also want to make use of the MVVM pattern and the data binding associated with XAML.I will of course use my favorite MVVM framework: Prism (I am going to do a series on Prism and UWP and a series on Prism and Xamarin Forms as well at some point). All of this sounds great: but unfortunately the map center data structure isn’t exposed as a bindable property, so we can’t use it directly in our view model.

Well, since every C#/XAML blog person needs an attached property post, that is what I decided to do. I am not sure that it is the best solution, but I can say that it seems to be working for me right now. Look for an update on this post if it doesn’t!

Solution:

I decided I wanted two properties. One that turned the tracking on and off and one that stored the information about what the map was viewing.

Attached properties are all kind of the same, so first we will just setup the basics (if you need a bit of a refresher on attached properties, check out the Xamarin docs):

  • Creation
  • Getter/Setter
  • Change event
public static class MapCenterProperty
{
	public static readonly BindableProperty CenterProperty =
		BindableProperty.CreateAttached(
			"Center",
			typeof(MapSpan),
			typeof(MapCenterProperty),
			null,
			propertyChanged: OnCenterChanged);

	public static MapSpan GetCenter(BindableObject view)
	{
		return (MapSpan) view.GetValue(CenterProperty);
	}

	public static void SetCenter(
		BindableObject view, MapSpan mapSpan)
	{
		view.SetValue(CenterProperty, mapSpan);
	}

	private static void OnCenterChanged(
		BindableObject view, object oldValue, object newValue)
	{
	}

	public static readonly BindableProperty TrackCenterProperty =
		BindableProperty.CreateAttached(
			"TrackCenter",
			typeof(bool),
			typeof(MapCenterProperty),
			false,
			propertyChanged: OnTrackCenterChanged);

	public static bool GetTrackCenter(BindableObject view)
	{
		return (bool) view.GetValue(TrackCenterProperty);
	}

	public static void SetTrackCenter(
		BindableObject view, bool value)
	{
		view.SetValue(TrackCenterProperty, value);
	}

	private static void OnTrackCenterChanged(
		BindableObject view, object oldValue, object newValue)
	{
	}
}

So let’s take a look at the TrackCenterProperty first. This is the one that is used to toggle the tracking off and on. The important stuff happens in the OnTrackCenterChanged event: it sets up the tracking. If the old value is false and the new value is true, start tracking. Stop tracking if the reverse is true.

Now it would be great if the Map control had an event that fired when the view of the map changed, but it doesn’t. So that is a bit of an issue. Luckily there is a bit of a hack we can use. We are interested in when the “VisibleRegion” property changes. So we are going to subscribe to the “PropertyChanged” event instead. If the name of the property being changed is “VisibleRegion”, we want to know about it.

Let’s update the OnTrackCenterChanged method from up above to subscribe and unsubscribe depending on the value of TrackCenter. It could look like the following:


private static void OnTrackCenterChanged(
	BindableObject view, object oldValue, object newValue)
{
    Map map = view as Map;
    if (map == null)
        return;

    bool ov = (bool) oldValue;
    bool nv = (bool) newValue;

    if (ov && !nv)
    {
        /// was true, now false, unsubscribe
        map.PropertyChanged -= OnMapPropertyChanged;
    }
    else if (!ov && nv)
    {
        /// was false, now true, subscribe
        map.PropertyChanged += OnMapPropertyChanged;
    }
}

All we are doing is subscribing or unsubscribing to the PropertyChanged event depending on the value of TrackCenter. Below is the event handler for that event. The only thing it really does is check to see if it is the VisibleRegion property being changed and if so, update the value of the CenterProperty.


private static void OnMapPropertyChanged(
	object sender, PropertyChangedEventArgs a)
{
    Map map = sender as Map;
    if (map == null)
        return;

    if (a.PropertyName == "VisibleRegion"
        && map.VisibleRegion != null)
    {
        Debug.WriteLine(&quot;SetCenter&quot;);
        map.SetValue(CenterProperty, map.VisibleRegion);
    }
}

Now all we have to do is setup the OnCenterChanged event. The only thing we have to be concerned about is giving ourselves a bit of fuzziness on whether the center point is changed enough to update the map, otherwise I found that the center point property was being updated too often.

private static void OnCenterChanged(
    BindableObject view, object oldValue, object newValue)
{
    var map = view as Map;
    if (map == null)
        return;

    MapSpan newview = newValue as MapSpan;
    MapSpan oldView = oldValue as MapSpan;

    if (newview != null &&
        !Util.MapSpanHelper.IsEqual(oldView, newview))
    {
        map.MoveToRegion(newview);
        SetCenter(view, newview);
    }
}

And the helper function for checking if the MapSpan has changed enough:

public static class MapSpanHelper
{
    public static bool IsEqual(double d1, double d2)
    {
        double dif = Math.Abs(d1 * 0.00001);
        return (Math.Abs((d1 - d2)) <= dif);
    }

    public static bool IsEqual(MapSpan ms1, MapSpan ms2)
    {
        if (ms1 == null && ms2 == null)
            return true;
        else if (ms1 == null || ms2 == null)
            return false;
        else if (
            IsEqual(ms1.Center.Latitude, ms2.Center.Latitude)
            && IsEqual(ms1.Center.Longitude, ms2.Center.Longitude)
            && IsEqual(ms1.LatitudeDegrees, ms2.LatitudeDegrees)
            && IsEqual(ms1.LongitudeDegrees, ms2.LongitudeDegrees))
            return true;
        else
            return false;
    }
}

You can adjust the fuzziness as appropriate.

Finally, we can setup our XAML and view model. Remember to add the namespaces. The MapCenterProperty class exists in the “Demo.Views” assembly.


xmlns:maps="clr-namespace:Xamarin.Forms.Maps;assembly=Xamarin.Forms.Maps"

xmlns:loc="clr-namespace:Demo.Views;assembly=Demo"

<maps:Map MapType="Street" loc:MapCenterProperty.TrackCenter="True" loc:MapCenterProperty.Center="{Binding Center,Mode=TwoWay}">

</maps:Map>

And the view model:


/// BindableBase provided by Prism, implements the
/// INotifyPropertyChanged interface for the view model
/// and some helper functions
public class DemoViewModel : BindableBase
{
    // ...

    private MapSpan _center = null;
    public MapSpan Center
    {
        get { return _center; }
        set { SetProperty<MapSpan>(ref _center, value); }
    }
}

And there we have it. We now have the viewable region of the map control bound to our view model. From within the view model we can change what is being shown on the map simply by setting the Center property. In the case of my app, I am also going to make use of the GeoLocator plugin from James Montemagno to provide some pretty nice location services to go with the maps in my app.

Hopefully you found this useful.