Mike Francis: My Mobile Home

Development with Windows Phone, Windows Azure, and Windows 8

Windows Phone: Don’t write to the InstalledLocation Folder

Crashes that occur not during development, but only after the application is installed by the Windows Phone store are among the most difficult to troubleshoot. This is one of those bugs.

Windows Phone 8 expanded the file storage APIs to include the StorageFile class support for parity with Windows 8. This class gives you access to ‘special folders’ including the folder where the application is installed. You can get to this folder as follows:

Windows.ApplicationModel.Package package = Windows.ApplicationModel.Package.Current;
Windows.Storage.StorageFolder installedLocation = package.InstalledLocation;

During development you can read and write from this folder, however after installing from the Windows Phone store, any write attempts to this folder will result in a file exception being thrown. Again, this bug will not occur if the app is sideloaded, only when the app is installed from the store. Most likely this is a security precaution to prevent any tampering with the installed files. 

This type of scenario, makes a strong argument for using the beta testing feature of Dev Center that allows you to test the store presentation and installation experience of your app to a specific list of users. By looking at the Dev Center generated crash logs (yes these are generated for beta apps as well as production), you can find the cause of the crash. 

Instead if using the InstalledLocation, you can read and write to the Local Folder. See here for more information.

Thanks,

Mike

Windows Phone: Don’t call LaunchForTest in Release

Calling ScheduledActionService.LaunchForTest is great for forcing a background task to run. This is important when you are developing and you need to debug your background agent. You may even want to call this in response to user action. You should not do this. The main reason is in Windows Phone 8 calling LaunchForTest, will throw an InvalidOperation exception. You may say that, ‘this works on my machine’, and you’d be right. This is because this exception is thrown only if the application is installed via the Windows Phone store. This does not occur if you sideload the app. Fortunately most of these scenarios are caught during certification testing. However, the Windows Phone certification team will report to you that that app crashes immediately after installation – without much more explanation. You will have a frustrating experience trying to reproduce this bug.

This type of scenario, makes a strong argument for using the beta testing feature of Dev Center that allows you to test the store presentation and installation experience of your app. In fact, by looking at the Dev Center generated crash logs, we found the cause of this crash. 

Frame

Image

Function

Offset

0

coredll.dll

xxx_RaiseException

19

1

mscoree3_7.dll

WatsonUnhandledManagedException

296

2

mscoree3_7.dll

Dbg_NotifyManagedException

93

3

mscoree3_7.dll

FirstPassException

1044

4

 

TransitionStub

0

5

 

Microsoft.Phone.Scheduler.SystemNotificationInterop.CheckHr

600

6

 

Microsoft.Phone.Scheduler.SystemNotificationInterop.LaunchNotification

128

7

 

Microsoft.Phone.Scheduler.ScheduledActionService.LaunchForTest

368

8

 

BritCo.App.Register_BackGroundAgent_ForLiveTile

240

9

 

BritCo.App..ctor

124

10

mscoree3_7.dll

IL_CallManaged

884

11

mscoree3_7.dll

BCL_System_Reflection_Invoke

1371

12

mscoree3_7.dll

BCL_System_Reflection_RTMI_Invoke

167

13

mscoree3_7.dll

BCL_System_Reflection_RTCI_Invoke

107

14

 

System.Reflection.RuntimeConstructorInfo.InternalInvoke

104

15

 

System.Reflection.RuntimeConstructorInfo.InternalInvoke

1240

16

 

System.Reflection.ConstructorInfo.Invoke

104

17

 

.__c__DisplayClass30._GetCreateObjectDelegate_b__2a

92

18

 

MS.Internal.TypeProxy.CreateInstance

100

19

 

MS.Internal.FrameworkCallbacks.CreateKnownObject

512

It turns our that the Windows Phone team added this exception to prevent the explicit launching of background agents in store deployed apps.  Why? Doing this can cause excessive battery drain and goes against the design of background agents.

Another common reason for wanting to call this API is that you may have code in the background agent you want explicitly triggered by user action. See Shawn Wildermuth’s blog post Confusion Around WP7.1 Periodic Agents for a discussion of this issue and how to code for it.

Thanks,

Mike

Productivity: A Zero Inbox Solution or Inbox = Action

Many of us in the software development business rely on email as our primary means of communication. Email is great – allowing us to prioritize and document our work. 90% of my job as a consultant involves email.

IF IT HURTS, DON’T DO IT

I took a ‘Productivity course’ a couple of years ago around optimizing the use of email. This technique involved categorizing or tagging your email using the Outlook ‘Categories’ feature. Here is a blog post that discusses a similar process. I tried using this method, and found that for me, it added too much overhead – categorizing everything was a chore and I did not see much return on the effort. Also, the whole system falls apart if you don’t explicitly categorize.  I found I was missing some emails and therefore not seeing them in my Outlook Tasks list – per the course guidelines.

As the PM for outlook.com recently said, there are two types of people that use email: pilers and filers. Pilers use one folder for all of their email where filers use folders to organize their email. (I’ve never understood pilers – I have seen people – and you know who you are -  that literally have their lifetime of email in a single Inbox. The time it takes to find a relevant email would drive me crazy.)

I am definitely a filer — I use the ‘Rule’ feature of Outlook to automatically move the email from my Inbox to the proper folder depending on who it is from or the subject. For example, I have a rule that says, if the incoming email is from the campus dining alias (think menu of the week) the mail is moved to the ‘Campus Dining’ folder. However if an email is from the President of the company, it is moved into my Inbox – but I am getting ahead of myself. Please read on.

VARYING DEGREES OF IMPORTANCE

In the above example, I think you would agree that the two sources of email have different levels of importance. That is, if I never-ever read the email from the Campus Dining alias there will minimal consequences. However, the email from the President of the company could have some very relevant information related to my job.

INBOX = ACTION

The principal I use is that for a message to be in my Inbox, is that it must be actionable by me within the next 24 hours. I enforce this by setting up a rule that moves all email not addressed to me to a second inbox, I call it Inbox2. If you’re thinking I must have a lot of rules, you’d be right. I have a rule and corresponding folder for every alias I subscribe to. For some aliases that have very similar information, I’ll have multiple rules send email to that folder. The following is my ‘All’ rule:

Inbox2 rule - ALL email is moved here unless another rule is defined.

Note that this rule is the last in the rules list. This gives other rules up the list to intercept the message and move it to the proper folder.

RECIPIENT, SENDER, ACTION

For an email to be sent directly to my Inbox, I have the following rules:

  • If sent directly to me — move to my Inbox. The thinking is that if someone is sending me (the recipient) email directly most likely it will have some action for me, even if just to acknowledge it.
  • If from the company president or my boss — move to my Inbox. The thinking here is email sent from the President or other important person will most likely be sent to an alias and not directly to me. To catch these emails, I have an explicit rule for that sender.

These rules greatly reduce the ‘noise’ in my Inbox.

Then with each email in my inbox, I review for action. If there is no action for me, I manually move it to my Archive folder or delete it. As I complete the required action, I move the email to the Archive folder. (It’s a good feeling.) If no action is required within the next 24 hours, I’ll set the Follow-Up flag and move it to the Archive folder. I then periodically check my Tasks list where this pending action will be listed.

PERIODIC REVIEW

I get added to aliases all the time in the course of my job – sometimes without knowing ahead of time. Since all of my email will be moved to my Inbox2, unless I have a rule setup, I need to periodically check this folder to make sure I’m not missing anything. If I do miss an email, I’ll create a rule (and folder if necessary) to make sure I don’t miss it in the future. I also will also unsubscribe from aliases and delete email during this review.

IT WORKS FOR ME

I know there are a lot of ‘zero-inbox’ methods out there. This one works for me in my particular work environment where a lot of email is sent to aliases. Please let me know what you are using.

Mike

WP8: Lock Screen Notifications Sample

 

lock1

Having your app update the lock screen is one of the cool features of Windows Phone 8. It’s pretty easy to add this functionality to your app. See the documentation here for the details. I wrote sample code which you can download here.

The following are a couple of interesting things I found when putting together this sample:

To invoke the emulator’s lock screen press F12. Then press any button. The emulator will then be locked.

 

 

 

 

 

You can also invoke the lock screen via the new and cool ‘Simulation Dashboard’. Click on the ‘Locked’ radio button to lock the emulator. (see below)

image

The docs say the following ‘The lock screen’s app icon, count, and text are pulled directly from the app’s primary Tile.’ I found that the lock screen does not use the app icon from your primary tile. Instead it uses the a separate 38×38 image in your app, specifically for the lock screen, specified in the manifest file.

 

 

 

 

 

 

 

 

 

To have the lock screen update, you need to go to the device settings and enable it. The sample includes a button which will take you directly to the settings page for the lock screen. (Using the new WP8 API LaunchUriAsync.)

settings

In the lock screen settings, select your app’s lock screen icon in the ‘Choose apps to show quick status’ control and specify your app in the ‘Chose app to show detailed status’ drop down. Unless you do this you will not see the lock screen update. (see to the left)

 

 

 

 

 

 

 

The lock screen uses the .BackContent and .Count properties of the main tile StandardTileData to display status and count. To update the main tile:

void UpdateTile(DateTime time)
{
    ShellTile tile = ShellTile.ActiveTiles.FirstOrDefault();
    var data = new StandardTileData();
    data.Count = time.Second;
    data.BackContent = string.Format(time.Second.ToString() + " seconds have elapsed.");
    tile.Update(data);
}

Mike

WP8: App Capabilities are now in Your Hands

imageIn Windows Phone 8, you are responsible for specifying the correct capabilities that are used by your application in the WMAppManifest.xml file. This is a departure from Windows Phone 7, where capabilities are detected during ingestion, with the capabilities being written to the WMAppManifest.xml file – overwriting what you specified during development. There are good and bad aspects to the WP7 approach, in WP7 you and your customers got the correct list of capabilities ensuring an accurate shopping and installation experience. The drawback was that in some cases, the capabilities detection would not properly detect an assembly in your app, resulting in a failure during certification testing due to the app not functioning properly or crashing.

For the Windows Phone 8 Store Test Kit, capability detection is no longer part of the automated tests. This is still available for Windows Phone 7 apps.

With the change in capability detection, you may be tempted to just include all of the capabilities. The problem with this is certain capabilities trigger different prompts in the install experience. For example, if you have specified the ID_CAP_LOCATION capability, during installation the user will be prompted with the ‘This application is using the location API, are you sure you want to install this?’ (I’m paraphrasing) prompt. If your app is not using the Location API, the user will get a misleading prompt during installation.

Additionally the capabilities of your app are listed in the Windows Phone Store catalog.  This list is generated from the manifest file. Specifying the capabilities of your app accurately will reflect the true functionality of your app to your potential customers.

image

See the Windows Phone 8 documentation topic ’App capabilities and hardware requirements for Windows Phone’ for information on capabilities and their related assemblies.

Windows Phone 8 SDK Launched Today!

Here is a quick summary of Windows Phone 8 announcements made today at the Build 2012 Conference and elsewhere.

The Windows Phone 8 SDK is now available for download here.

The updated Windows Phone Toolkit is available via NuGet here.

The updated Windows Phone Toolkit source and documentation is available on Codeplex here: http://phone.codeplex.com.

OData Client Tools for Windows Phone Apps has been updated and can be installed from here. See the blog post here. OData V3 now supported in Windows Phone apps!

Windows Phone Dev Center Accounts $8 for 8 Days: Developers can register for a Window Phone Developer Account for $8 (regularly $99) for the next eight days. (Register at http://dev.windowsphone.com) If you have an MSDN subscription, be sure and use the Window Phone Dev Developer Account included with your subscription.

Windows Phone Developer Blog kick-off post here.

Watch Webcast: Windows Phone 8 Launch here.

Watch Build Keynotes and Sessions here.

The Starbucks Wi-Fi Login Scenario: Why does this crash?

University of Arizona Starbucks

Developer Scenario: You have written your app to make sure there is a network connection prior to downloading data and populating the app. You have thoroughly tested you app at work with wired internet, in your car with 2, 3, 4 and no G (no connection) cellular connections. You also diligently tested your app with your home Wi-Fi and it works GREAT! You publish your app to the marketplace and find you are getting a few bad reviews (app is crashing). In reviewing your analytics, you see that these crashes are occurring when connected to Wi-Fi. You take your app to your favorite internet café and notice that the Windows Phone navigates to the web browser after connecting to the Wi-Fi access point. Wondering what will happen if you do NOT agree to the ‘terms-of-service’ you fire up your app and BOOM it crashes! :( You start your debugger and find that your app is in fact downloading data, but instead of being in XML format:

<?xml version="1.0" encoding="utf-8"?>
<breakfast_menu>
  <food>
    <name>Belgian Waffles</name>
    <price>$5.95</price>
  </food>
</breakfast_menu>

its in the form of:

<!DOCTYPE html>
<html class=" " lang="en-US">
  <head>
    <title>Starbucks Coffee Company</title>
. . .
Your app proceeds to deserialize the incoming data and quickly crashes since it is not in the expected format.

Detecting and Mitigating this scenario

The best way to protect against this scenario, is to validate the data. You don’t need to validate the entire response stream, just enough to know that its XML (or JSON, or whatever) and NOT HTML. You can the very quickly check a very small portion of the returned data to determine if the data you are receiving is the expected data. You can also validate against a response header. Here are the two methods (assume you are downloading xml):

        void wc_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)

        {

            string res = e.Result.ToString(); // make sure returned data is not Café’s login page.

            if (res.Contains("<?xml"))

                result = "Connected!";

            else

                result = "Not Connected!";

        }

 

        void wc_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)

        {

            var t = (sender as WebClient).ResponseHeaders[HttpRequestHeader.ContentType];

 

            if (res.Contains("text/xml")) // make sure returned data is xml and not Café’s (html) login page.

                result = "Connected!";

            else

                result = "Not Connected!";

 

            }

        }

Thanks,

Mike

WP7: TimeZone Info and how to Get It

timeUnlike on the desktop, Silverlight for Windows Phone only provides local and UTC time zone information. I had a requirement for a stock trading application to display all of the transaction times in Eastern time. The difficulty was determining if Daylight Savings Time was in effect or not. On the desktop TimeZoneInfo supports all of the time zones supported in Windows 7, so this is very straight forward.

On Windows Phone, we considered using a rule based on dates, but of course this would break ff the daylight savings rules ever change, which they do from time to time. The following is a solution using the GeoNames service. GeoNames has several geo-location related web services including time zone. (GeoNames is free for up to 30K requests per day. They have a variety of pay plans offering various requests and response times.)

The time zone web service returns the current time zone information for a given latitude, longitude pair. In a nutshell to display transaction times in Eastern time, you apply the East Coast time zone offset returned by GeoNames to the stored UTC value. Code below:

private void button1_Click(object sender, RoutedEventArgs e)
{
    // get account at http://www.geonames.org/ 30K requests / username / day limit.
    // get current timezone info for NYC
    var txtURL = new Uri(http://api.geonames.org/timezone?lat=40.71417&lng=-74.00639&username=demo1);
    var request = (HttpWebRequest)WebRequest.Create(txtURL);
    string responseString = "";
    request.Method = "GET";
    request.BeginGetResponse(a =>
    {
        var response = request.EndGetResponse(a);
        var responseStream = response.GetResponseStream();
        using (var sr = new StreamReader(responseStream))
        {
            using (StreamReader reader = new StreamReader(responseStream))
            {
                DateTime t1 = new DateTime();
                try
                {
                    responseString = reader.ReadToEnd();
                    Debug.WriteLine(responseString);

                    // Get dst offset for NYC
                    XDocument doc = XDocument.Parse(responseString);
                    var dstOffset = GetTime(doc, "dstOffset");
                    var offset = Convert.ToDouble(dstOffset);

                    // Convert local current time to UTC - we will display this in NYC time.
                    var t = TimeZoneInfo.ConvertTime(DateTime.Now, TimeZoneInfo.Utc);
                    // apply offset to adjust current utc time to East Coast Time.
                    t1 = t.AddHours(offset);
                }
                catch (Exception ex)
                {
                    Dispatcher.BeginInvoke(() =>
                    {
                        if (ex.Message == "NullReferenceException")
                        {
                            XDocument doc = XDocument.Parse(responseString);
                            var statusMessage = doc.Descendants("status");
                            var q = from c in statusMessage
                                    select c;
                            var en = q.GetEnumerator();
                            en.MoveNext();
                            MessageBox.Show(en.Current.Attribute("message").Value.ToString());
                            return;
                        }
                        else
                        {
                            MessageBox.Show(responseString);
                        }
                        return;
                    });
                }

                Dispatcher.BeginInvoke(() =>
                {
                    localt.Text = DateTime.Now.ToString();
                    ect.Text = t1.ToString();
                });
            }
        }
    }, null);

}

string GetTime(XDocument doc, string element)
{
    var q = from c in doc.Descendants(element)
            select c;
    var en = q.GetEnumerator();
    var t = en.MoveNext();
    return en.Current.Value;
}

You can download a complete sample here.

Thanks,

Mike

WP7: How to Simulate an Application Update

Scenario: You’re developing version 2.0 of your hugely successful Windows Phone application. You want to provide to your users a seamless experience when updating their app to this latest version. That is, you want bring over the current app state into the 2.0 version and not require the user to have to start all over again. You have included the necessary code to do this, but need a way to test it. You ask ‘ Is there any way to simulate an application update with the Windows Phone developer tools?’. You noticed that when using the ‘Application Deployment’ tool that the isolated storage for the app is initialized before the app is installed.

Yes you can simulate an application update. You need to use Visual Studio to do this. When Visual Studio deploys an application, it does not first uninstall the application.

Here is the process to simulate an app update. This will preserve the isolated storage between deployments.

1. Sideload the 1.0 XAP file to the phone or emulator using the ‘Application Deployment’ tool. (We’ll call this MyApplication.XAP)

2. Using Visual Studio create a dummy Windows Phone application (We’ll call this PhoneApp1)

3. Build PhoneApp1 (debug or release)

4. Open the folder where the PhoneApp1.xap is located (e.g. D:\p\PhoneApp1\PhoneApp1\Bin\Debug)

5. Delete PhoneApp1.XAP

6. Copy the updated XAP for your application to this folder (MyApplication.XAP 2.0).

7. Rename MyApplicaiton.XAP to PhoneApp1.XAP

8. Go back to Visual Studio

9. Right Click on Project

10. Select Deploy.

11. The 2.0 version of MyApplication.XAP will now be deployed to the Emulator / Phone. Note that the application binaries are updated, but the isolated storage is the same as before.

12. You can use Windows Phone Power tools to verify.

Thanks,

Mike

WP7: Images in Secondary Tiles do not appear

Problem: Background Images in secondary tiles do not appear if using remote images.

Solution:

<wp:BackgroundImage> and <wp:BackBackgroundImage> can use remote URLs, however, the domains need to be included in the Approved URLS list. For example:

// Lists domains that can send tile updates and so forth as push notifications.
// Only these authorized domains will be allowed by the shell to push new tiles to the phone

var ListOfAllowedDomains = new Collection<Uri> {
new Uri(@"http://i. contoso.com"), new Uri(@"http://i-staging.contoso.com") // e.g. if you published a webservice at http://foo.com/service1.svc — put "http://foo.com" here.
};
pushChannel.BindToShellTile(ListOfAllowedDomains);

By including the domains in the ‘allowed list’ your background images will show up.

Thanks,

Mike

Older Posts »

Switch to our mobile site