Another cloud enabled WP7 Wx app ..                  Part Un: The Phone Client

June 2010. I decide that one of the first WP7 apps I should do is surely a weather app. And with the whole “It’s not Sunny & 73” jab against the iPhone weather app, one just had to have cloud support for “glance & go” weather, right? :). Then, after Windows Phone launched, I took one look at the Weather Channel app. Oops! Off course, mine didn’t stand a chance against their rich UI! So, I never quite bothered submitting the weather app; but I still use it to demo Push Notifications from the cloud. So, that is what we shall do in this post; remember though, this was before we had the Push Notification Helpers & the Azure Toolkit. So, this will all be down to rather basic details; sometimes it may be worth knowing how stuff works just out of the box.

So, we shall strive for a really basic Weather app that shows current/forecast weather for a bunch of places that the user is interested in. There are off course several free sources of weather data; but few get as simple as the Yahoo API. So, let us head over (here) for the Yahoo Weather feed. It essentially a semi-RESTful API that we make a HTTP GET call against, passing in a WOEID & unit of measurement. The Where On Earth ID (WOEID) is simply a unique indicator of the Lat-Long of a place on earth. If you look up the weather of any city on Yahoo, the WOEID is in the URL or it can also be derived from geo-coding an address.

Here is a basic look at what we are striving to build:

Add City

Weather

 

 

 

 

 

 

 

 

 

 

 

 

So initially, we ask the user what city or town they want weather for. We fire off the user’s search criteria to Yahoo’s service to come back with a scrollable list of locations with State & Country information. We bind this return data to a Listbox and allow the user to pick the right one; not fail-proof, but you get the idea. Here is what we want to hang on to for each city the user cares about; and this is defined in our global App.xaml.cs file:


        public class LocationStuff
        {
            public string City { get; set; }
            public string State { get; set; }
            public string Country { get; set; }
            public string WOEID { get; set; }
        }

Armed with this, we can go ahead & request possible city matches from Yahoo’s GeoPlanet API & parse the response before binding to our XAML UI:


        // Registering for the API is needed. 
        string yahooGeoServiceURL = "http://where.yahooapis.com/v1/places.q('" + user-typed-city + "');start=0;count=5?appid='Your Developer ID'";

        var client = new WebClient();
        client.DownloadStringCompleted += ClientDownloadStringCompleted;
        client.DownloadStringAsync(new Uri(yahooGeoServiceURL, UriKind.Absolute));

        private void ClientDownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
        {
            string possibleLocationsXML = e.Result;

            if (possibleLocationsXML != string.Empty)
            {
                // LINQ to XML.
                XDocument xmlDoc = XDocument.Parse(possibleLocationsXML);

                var locationInfo = from xElem in xmlDoc.Descendants(XName.Get("place", "http://where.yahooapis.com/v1/schema.rng"))
                                   select new App.LocationStuff
                                   {
                                       City = xElem.Element("{http://where.yahooapis.com/v1/schema.rng}name").Value,
                                       State = xElem.Element("{http://where.yahooapis.com/v1/schema.rng}admin1").Value,
                                       Country = xElem.Element("{http://where.yahooapis.com/v1/schema.rng}country").Value,
                                       WOEID = xElem.Element("{http://where.yahooapis.com/v1/schema.rng}woeid").Value
                                   };

                foreach (var stuff in locationInfo)
                {
                    App.LocationStuff newLocation = new App.LocationStuff();
                    newLocation.City = stuff.City;
                    newLocation.State = stuff.State;
                    newLocation.Country = stuff.Country;
                    newLocation.WOEID = stuff.WOEID;

                    SomeLocationListToBindTo.Add(newLocation);
                }
            }
         }

So, once the user selects the city they want weather for, we have it’s WOEID available right away to fetch latest weather from Yahoo. To pull off parsing for weather, we define two more little classes:


        public class StuffWeCareAbout
        {
            public string City { get; set; }
            public string State { get; set; }
            public string Condition { get; set; }
            public int ConditionCode { get; set; }
            public string Temp { get; set; }
            public string Description { get; set; }
            public string ImageURL { get; set; }
            public IEnumerable Forecasts { get; set; }
        }

        public class Forecast
        {
            public string Day { get; set; }
            public string High { get; set; }
            public string Low { get; set; }
            public int ConditionCode { get; set; }
        }

The actual GET call to fetch weather & it’s subsequent parsing is as follows. Please note that Yahoo returns weather icons as GIFs, which Silverlight cannot render out of the box; so I have a set of weather icons locally (from Weather.com) & simply map the appropriate icons based on weather condition.


        // WebClient request at this URL.
        string yahooWXServiceURL = "http://weather.yahooapis.com/forecastrss?w=" + currentWOEID;

        private void ClientDownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
        {
            string weatherRSS = e.Result.Replace("yweather:", "yweather");
            
            if (weatherRSS != string.Empty)
            {                
                // LINQ to XML parsing.
                XDocument xmlDoc = XDocument.Parse(weatherRSS);

                // Notice the nested LINQ for repeating forecasts.
                var weatherInfo = from xElem in xmlDoc.Descendants("channel")
                                  select new StuffWeCareAbout
                                  {
                                      City = xElem.Element("yweatherlocation").Attribute("city").Value,
                                      State = xElem.Element("yweatherlocation").Attribute("region").Value,
                                      Condition = xElem.Element("item").Element("yweathercondition").Attribute("text").Value,
                                      ConditionCode = Convert.ToInt16(xElem.Element("item").Element("yweathercondition").Attribute("code").Value),
                                      Temp = xElem.Element("item").Element("yweathercondition").Attribute("temp").Value,
                                      Description = xElem.Element("item").Element("description").Value,
                                      Forecasts = from xSubElement in xElem.Element("item").Elements("yweatherforecast")
                                                  select new Forecast
                                                  {
                                                      Day = xSubElement.Attribute("day").Value,
                                                      High = xSubElement.Attribute("high").Value,
                                                      Low = xSubElement.Attribute("low").Value,
                                                      ConditionCode = Convert.ToInt16(xSubElement.Attribute("code").Value)
                                                  }
                                  };


                foreach (var stuff in weatherInfo)
                {
                    // UI binding & Weather Icon selection here.
                }
             }
          }

Also, as the user adds more cities that he/she wants weather for, the Application Bar navigation buttons are supposed to allow them to cycle through them by going left/right. However, a button is inconvenient, right? Why not just swipe to right/left for the next/previous city? Yup, that makes sense and needs our app to support flick gestures. There are a few ways to achieve this; following was just my way of doing things:


        // Reference the XNA library in the project.    
        using Microsoft.Xna.Framework.Input.Touch;

        // Wire up the top-most layout grid to watch out for Manipulation events.
        private void LayoutRoot_ManipulationCompleted(object sender, ManipulationCompletedEventArgs e)
        {
            // Read gestures if available.
            while (TouchPanel.IsGestureAvailable)
            {
                // Read the current gesture.
                GestureSample gesture = TouchPanel.ReadGesture();

                // Only act on flicks. 
                if (gesture.GestureType == GestureType.Flick)
                {
                    float startX = gesture.Position.X;
                    float endX = gesture.Delta.X;

                    if (startX > endX)
                    {
                        // Flick to the left.
                        if (GlobalLocationList.Count > currentLocationNumber + 1)
                        {
                            // Load next city.
                            currentLocationNumber ++;
                        }
                    }
                    else if (startX < endX)
                        {
                            // Flick to the right.
                            // Load previous city.
                            currentLocationNumber --;
                        }
                    }
                }
             }
         }

That’s it with our phone app UI. I skipped showing some XAML since it can be entirely customized with how you want the weather UI to look like; so it is this easy to add some weather data to your WP7 apps. Hope this was interesting. Please stay tuned as we look at Live Tiles & Push Notifications from the cloud in upcoming posts.

Adios!

Push Notification Payloads

Glance & Go! Get back to life 🙂 These have been the kind of concepts Windows Phone has been trying to be good at; only time will tell how successful we have been at this game. However, Push Notifications are undoubtedly one of the coolest features of the Windows Phone ecosystem. The Start screen comes alive with Live Tiles and Push Notifications from the cloud. And this gets way better with the next Mango release.

In addition to pinned Application tiles, we can now programmatically create Secondary Live Tiles for our apps; tiles that are deep-linked to bring the user directly to a certain area of the application, often bypassing the start experience when the app is launched under normal circumstances. These livelier secondary Live Tiles also have a nice flip animation built in to expose a back side of the tile with extra information. And just like application tiles, the secondary tiles can be updated with Push Notifications through the Microsoft Push Notification Services (MPNS). In addition, we can now have Deep Toasts — ones with extra parameters and when clicked, not only launch the app; but also gives the developer the opportunity to use the parameters to take the user to a certain part of the application.

A nice walkthrough of these new Mango Live Tile features, along with code samples can be found (here).

All this however raises the question, what needs to change for Push Notifications? Thankfully, not much! We use the same ways to create or re-use Channel URIs from MPNS and convey that to our cloud service for use in Push Notifications.  The secondary Live Tiles are each created with a unique URI and we need to inform our cloud service of this extra piece of information so that we may control exactly which secondary Live Tile we update with our Push Notification. And we use the same APIs (BindToShellTile & BindToShellToast) to register our Tile & Toast updates to the Shell, so that the OS processes those incoming Push payloads. That brings us to the main story — so what exactly does your cloud service need to send out in the Push Notification HTTP Post to MPNS? Glad you asked! I often fiddle & have to look up these payloads. So, why not try to compile?

In the present Windows Phone OS 7.0, this is how the Payload looks for a pinned Application Tile Push update:


<wp:Notification xmlns:wp="WPNotification">
 <wp:Tile>
   <wp:BackgroundImage>someURI<wp:BackgroundImage>
   <wp:Count>XX</wp:Count>
   <wp:Title>someTitle</wp:Title>   
 </wp:Tile>
</wp:Notification>

And, here is what we need to send for a Toast update:


<wp:Notification xmlns:wp="WPNotification">
 <wp:Toast>
   <wp:Text1>someText</wp:Text1>
   <wp:Text2>someLongerText</wp:Text2>  
 <wp:Toast>
</wp:Notification>

Come Mango or Windows Phone OS 7.1, our cloud service needs to send some extra bits to MPNS to have the fine-grained control of exactly which Secondary Live Tile to update. Here’s the payload to update a Secondary Live Tile; notice the extra ID & back-of-tile bits:


<wp:Notification xmlns:wp="WPNotification">
 <wp:Tile ID="/MainPage.xaml?someParam=someID">
   <wp:BackgroundImage>someURI<wp:BackgroundImage>
   <wp:Count>XX</wp:Count>
   <wp:Title>someTitle</wp:Title>
   <wp:BackBackgroundImage>someURI</wp:BackBackgroundImage>
   <wp:BackContent>someContent</wp:BackContent>
   <wp:BackTitle>someTitle</wp:BackTitle>
 </wp:Tile>
</wp:Notification>

And, this is how we should construct a payload for a Deep Toast, so that the app gets a chance to process the extra parameters & navigate the user to a certain part of the application:


<wp:Notification xmlns:wp="WPNotification">
 <wp:Toast>
   <wp:Text1>someText</wp:Text1>
   <wp:Text2>someLongerText</wp:Text2>
   <wp:Param>/MainPage.xaml?someParam=someID</wp:Param>
 <wp:Toast>
</wp:Notification>

That’s it for now. Go ahead & Push enable your WP7 apps — they should sell better & be rated higher compared to their ordinary counterparts.

Adios!

Thoughts on the HP Envy 17

At the beginning of this year, it was pretty clear that I needed new computing hardware for some much needed oomph.  My company laptop, though not bad, was just falling short of what I was up to. So, a month-long search followed and I finally settled on the HP Envy 17” beast. Make no mistake, it is not the Dad’s computer type machine and I had to forego a bonus, along with a few limbs 🙂

Engadget ran a nice review of the Envy 17 (here).

Here are few of the characteristics that had me drawn:

  • Quad Core I7 @ TB 2.9 GHz – This is not the new Sandy Bridge stuff; but at the beginning of the year, I did not want to wait. Things seem settled now; but initial Sandy Bridge shipments had recalls; so I am at peace with my decision. This processor with the rest of the hardware is a beast. I have thrown everything I had at it; yet does not slow down.
  • 8 GB RAM for heavy development & media.
  • 160 GB SSD + 700 GB regular hard-drive @ 7200 RPM. Here is a number – a well-optimized Windows 7 Ultimate on the SSD does a cold-boot in about 5 seconds, gotta love that!
  • Slot loading CD/DVD drive for sleekness.
  • Massive 17” super crisp display with 1920×1080 full-HD resolution. This was one of core features I was after. Being my development machine, the extra real estate comes in so handy; and just about any media looks stunning.
  • Full metal MacBook style uni-body look. I think the etched metal & the glowing HP logo look cool on the cover. The laptop simply looks exquisite!
  • Array for ports to support all your accessories.
  • Despite few complaints from other owners, I personally like the keyboard. It is well laid out and the backlit keys have just the right sensory feel.
  • The Beats music setup means that the even without any speakers, the computer plays most music with high fidelity & some thump.

Now, despite all this awesomeness, this baby is not for everyone and has a unique audience that loves it despite what others say. Here are few downsides to consider:

  • The laptop itself is rather sleek & not bad for carrying; but the HP power adapter is a brick and your shoulders will not be happy if you have the whole thing around all day. Dell power cords do work; but show intermittent flicker; so not sure if any long-term damage would occur.
  • All the power comes at a little price – what did you think? 🙂 I was very cautious about the heat issues out of the I7; but it is not that bad. The left side of the keyboard does get a little warm compared to the right; but again nothing painful. It is the bottom left of the laptop that gets quite warm with heavy use; and I am not a PC gamer at all. So, while definitely not just a desktop replacement, this baby is not meant for your lap & works best on an even surface.
  • The HP touchpad is better than much of its competition with large glass-like touch surface without the physical left & right buttons. And it does work; but the sensitivity of the multi-touch functions is nowhere close compared to a MacBook. And this is not HP’s fault but that of Synaptics who makes the driver.

That’s about all I had. I personally love how fast & sleek this machine is. I do not have a separate monitor at home & the resolution really helps in making it a wonderful all-round development/main pc.  At the end, you just have to know what you are getting into. Hope this was of interest.

Adios!