More on #UWPCommunityToolkit CacheBase #uwpdev

In the first version of UWP Community Toolkit, we only had ImageCache which had its origin in Windows App Studio. A few issues were raised to optimise it and one mentioned extensible cache that can be used to create any case.

FileCache, ImageCache, VideoCache, JsonCache.. you name it.. Yesterday I mentioned CacheBase. FileCache and ImageCache that ship with UWP Community Toolkit are implementations of CacheBase by giving it a specific type.

Today I had to implement ability to pull configuration settings from our server. I tried using current prod version of FileCache but my implementation was somewhat wrong there. It would try to create File from Stream and return null and then fail internally (fixed in current dev branch) however I needed something today. Enter ConfigCache.. well JsonCache really

public class ConfigCache : CacheBase<ConfigurationSetting>
{
    JsonSerializer jsonSerializer = new JsonSerializer();

    /// <summary>
    /// Private singleton field.
    /// </summary>
    private static ConfigCache _instance;

    /// <summary>
    /// Gets public singleton property.
    /// </summary>
    public static ConfigCache Instance => _instance ?? (_instance = new ConfigCache() { MaintainContext = false });

    protected override async Task<ConfigurationSetting> InitializeTypeAsync(StorageFile baseFile)
    {
        using (var stream = await baseFile.OpenStreamForReadAsync())
        {
            return InitializeTypeAsync(stream);
        }
    }

    protected override Task<ConfigurationSetting> InitializeTypeAsync(IRandomAccessStream stream)
    {
        var config = InitializeTypeAsync(stream.AsStream());
        return Task.FromResult<ConfigurationSetting>(config);
    }

    private ConfigurationSetting InitializeTypeAsync(Stream stream)
    {
        var reader = new StreamReader(stream);

        using (var jsonReader = new JsonTextReader(reader))
        {
            return jsonSerializer.Deserialize<ConfigurationSetting>(jsonReader);
        }
    }
}

In this case I am using a specific type to deserialise json to. How do I use it ?

ConfigCache.Instance.CacheDuration = TimeSpan.FromDays(1);

this.ConfigurationSettings = await ConfigCache.Instance.GetFromCacheAsync(new Uri(urlPath));

This would ensure that if configuration is older than a day, it will be downloaded again. Either way the caller will get deserialised data.

Advertisements

Coding4Fun v2.0.9 released #wpdev #windev #winrt

Coding4Fun toolkit v2.0.9 for Windows Platform dev has been released and packages are available for download from Nuget.

This update builds additional support for Windows Runtime on Windows Phone 8.1 and Windows 8.1. Controls added to this release include

  • MetroFlow control (Windows 8.1 and WP 8.1)
  • Prompts (Toast, User, Message, Input, PasswordInput) for WP 8.1
  • BrushToBrushConverter now allows use of parameter to set output Opacity.

AppBarPrompt requires additional work the port wasn’t successful first time around. For issues there’s codeplex.

Happy coding

WinRT and application view wide Pointer event monitoring #wpdev #windev

It seems like every year I go through same technical difficulties. Last year I blogged about WinRT and pointer manipulation #win8dev #winrtdev

One of the underlying classes detects manipulation by user by means of Touch class. This class never made it to WinRT XAML and I have been messing around for a few days now… until something finally sunk in..

CoreWindow exposes following events

PointerEntered Occurs when a pointer moves into the bounding box of the Windows Store app.
PointerExited Occurs when the pointer moves outside the bounding box of the Windows Store app.
PointerMoved Occurs when a pointer moves within the bounding box of the Windows Store app.
PointerPressed Occurs when a mouse button is clicked, or a touch or pen contact is detected, within the bounding rectangle of the Windows Store app.
PointerReleased Occurs when a mouse button is released, or a touch or pen contact is lifted, within the bounding rectangle of the Windows Store app.

These events work exactly like Touch.TouchFrameReported and get bubbled up no matter which UIElement is tapped.

Time to continue porting

WindowsPhone 8.1, NavigationBar and Silverlight apps #wpdev

With Windows Phone 8.1 Microsoft drastically changed on of the basic chassis requirements in Windows Phone since day 0. The hardware buttons at the bottom of the phone. There were many reasons and one of them was the ability to use same chassis for both Android and Windows Phone devices. This many cited was very important smaller OEMs that recently signed up to Windows Phone ecosystem.

WP7 resolutions:

  • 800 x 480

WP8 resolutions (and scaling factors as reported  by Silverlight apps):

  • 800 x 480     (1.0)
  • 1280 x 720   (1.5)
  • 1280 x 768   (1.6)
  • 1920 x 1080 (2.25)

For Silverlight Windows Phone app (most of the apps that is) the resolution defaults to 800 x 480. This fits nicely with Scaling factor 1.6 which was used by many early Nokia devices. The scaling factor 1.5 however gave 853 x 480. This primarily affected HTC 8 S/X devices and Samsung ATIV S devices only. Later when Lumia 1520 came out, it uses 1020 and that used 2.25 and that also had 853 x 480 res.

What this meant was that WP7 and any WP8 apps that fix their resolution would leave 53 px gap. With my 1Shot camera app, I have a complicated control structure and I ended up fixing many heights and widths.. Not only that I also move certain objects on OrientationChanged using specific values of TranslateX and TranslateY. Last week after a user complaint, I added code to detect 720p and 1080p resolutions and to stretch those by additional 53px. However I never tested this on newer 720p devices that no longer have hardware buttons.

What Windows Phone Dev team did was added another system control like ApplicationBar called NavigationBar. Unlike ApplicationBar, NavigationBar isn’t accessible from within application. Playing with emulator set to show NavigationBar did not show any change in size reported by

double width = Application.Current.Host.Content.ActualWidth;
double height = Application.Current.Host.Content.ActualHeight;

After much complaining around twitter I came across windows phone 8.1 hide NavigationBar post on MSDN Forums. One of the suggestions was using PhoneApplicationFrame.FullScreen. Setting it to true or false made no difference.. none at all. After another round of complains, I came across this post Layout and the Windows Phone navigation bar.. it suggest that SizeChanged event should take care of it and ActualWidth and ActualHeight properties will sort it out.

Being not particularly clever, I thought that Page’s SizeChanged would be fired.. sure it was firing but ActualWidth and ActualHeight were 0.0. Width and Height were NaN so that was useless. Thinking that I could do better than that, I tried using SizeChanged exposed by Application.Current.Host.Content.. nope no difference.. it wasn’t a particularly bright idea.. Yesterday I spent time deliberating whether I should use hardcoded lists to indicate NavigationBar availability or not.. I already do so for high resolution sensors.. nah too much hassle

So today I said.. surely there must be something… on SizeChanged event handler of page, I scanned App.RootFrame.. I found something.. a private field called _visibleRegion correctly showed that 53 px at the botton were not available on 720p emulator when NavigationBar was visible. I think I am clever than most…

private Thickness GetMargin()
{
    Thickness t = new Thickness();

    var field = App.RootFrame.GetType().GetField("_visibleRegion", BindingFlags.Instance | BindingFlags.NonPublic);

    if (field != null)
    {
        object visibleRegion = field.GetValue(App.RootFrame);

        if (visibleRegion != null && visibleRegion is Thickness)
        {
            t = (Thickness)visibleRegion;
        }
    }

    return t;
}

This would get me the right margin and I could just just correct a few bits and bingo.. hahah yah right.. FieldAccessExpcetion eat that you clever git.. Apps don’t run under full trust on phone and I couldn’t reflect to this level. Sigh.. This was hard.. why had Windows Phone team gone way out of their way to piss developers off ?? Having almost lost all hope, I thought, let me try subscribe to Page’s LayoutRoot grid’s SizeChanged event… had a look there.. event handler exposed NewValue and they showed the correct values!!! yay

double gridWidth = e.NewSize.Width > e.NewSize.Height ? e.NewSize.Width : e.NewSize.Height;
double gridHeight = e.NewSize.Width > e.NewSize.Height ? e.NewSize.Height : e.NewSize.Width;

double w = Application.Current.Host.Content.ActualWidth;
double h = Application.Current.Host.Content.ActualHeight;
double hostWidth = w > h ? w : h;
double hostHeight = w > h ? h : w;

bool hasSoftButtons = hostWidth > gridWidth;

Just for your sanity.. I always want Landscape mode so width is always greater than height based on supported resolutions.. so there you have it.. subscribe to LayoutRoot’s SizeChanged and get the right size.. OnResize, the dimensions reflect 800 x 480 resolution and not 853 x 480.

Finally!

WinRT License API, Silverlight 8.1 apps and sideload detection #wpdev

Since early 2011, I have been using the method described here.
Recently I have been upgrading all my apps to target Windows Phone 8.1 API. Most of previous API is still accessible in WP 8.1 SL8.1 apps. However a great deal more is available under WinRT API.

With my Alarm Clock app, I have started using WinRT API to pin and update Tiles. I have used WinRT API for background tasks as I can run them more frequently and I can detect Timezone change. I have added IAP to the app.
The app however is available in 2 flavours Free (with ads and restrictions) and Paid. So far I have only been updating the paid app. Of course I use sideload detection for Paid app however while considering update of Free version, I decided to use CurrenApp to execute License check and potentially offer to convert Free users in-place as opposed to getting them to buy another app!!

In good old SL API, I would have used

var license = new Microsoft.Phone.Marketplace.LicenseInformation();
IsTrial = license.IsTrial();

With WinRT that becomes

IsTrial = CurrentApp.LicenseInformation.IsTrial;

While developing and deploying if you observe the behaviour, the IsTrial never returns false. You cannot test Trial scenario without explicit pre-processor directives!
Of course CurrentAppSimulator is only available for WinRT app and not SL8.1 apps. The same behaviour would be exposed by the sideloaded apps. Not downloaded from store equates to full version. Like in good old days, WMAppPRHeader.xml is still attached after certification. So lets modify the code

try
{
   XDocument doc = XDocument.Load("WMAppPRHeader.xml");
 
   IsTrial = CurrentApp.LicenseInformation.IsTrial;
}
catch
{
   IsTrial = true;
}

You treat all apps without WMAppPRHeader.xml as trial. Job done!
Note that IAP are not affected. If you had TestIAP, it is not active by default.

CurrentApp.LicenseInformation.ProductLicenses[&amp;quot;TestIAP&amp;quot;].IsActive;

Happy coding!

Image scaling related crashes on 1080p devices #wpdev

Back in March one of the 1Shot camera app users emailed me stating that the app crashes when using he uses digital zoom on Lumia 1520. I couldn’t reproduce the issue on my 1020. I then borrowed a friend’s 1520 and hmm sure I could reproduce it but I couldn’t catch the exception.

So we left it at that.. fast forward on Friday I get a mail back from chap in question and he states that he’s running latest greatest version of preview and the freaky crash is still happening. Luckily I have the 1520 at my desk and decided to put it to good use over the weekend.

So I put VS configuration in Debug mode and I set VS to catch all thrown exceptions. Run app and swipe left right and top bottom and every so often the app crashes.. no exception being caught.. the app just disappears and we are back to home screen. The only clue was the output of debug mode.. The program ‘[4880] AgHost.exe’ has exited with code -1073741819 (0xc0000005) ‘Access violation’.

The sad reality, the debug output is littered with messages starting ‘AgHost.exe’ (CoreCLR: Silverlight AppDomain): A quick check on the net showed that AgHost.exe is used to manage access through identity verification.. great. The error code wasn’t particularly useful either.

In this particular case, the error only occurred when zooming in. My implementation of digital zoom was scaling the preview image for the live view. The only action associated with crash was zooming in and out. As it happens, I detect manipulation delta and compute scale..

private void LivePreviewTapTarget_ManipulationDelta(object sender, System.Windows.Input.ManipulationDeltaEventArgs e)
{
    if (!this.viewModel.CaptureInitiated && AppSettings.InternalAppSettings.DragZoom)
    {
        SetDragToScale(e.CumulativeManipulation.Translation);
        e.Handled = true;
    }
}

void SetDragToScale(System.Windows.Point pScale)
{
    double x = Math.Abs(pScale.X);
    double y = Math.Abs(pScale.Y);

    double manipulation = x > y ? pScale.X : pScale.Y;

    bool zoomOut = manipulation >= 0 ? false : true;

    double scale = (this.viewModel.HasHighResolutionCamera ? 0.01 : 0.005) * Math.Sqrt(Math.Pow(x, 2) + Math.Pow(y, 2));

    if (zoomOut)
        this.viewModel.ViewScale = initialScale + scale;
    else
        this.viewModel.ViewScale = initialScale - scale;

    System.Diagnostics.Debug.WriteLine("zoomout {0}, scale {1}", zoomOut, scale);
}

My initial thought was that it being a newer SoC, the Xaml Renderer was somehow being proactive somewhere and getting itself in a mess.

Test 1: show less frames and show larger jumps so there is less rendering. For High Res camera I used constant of 0.01.. increase it to 0.05.

The resultant build crashed very very fast. hardly took a swipe or two to head back to home screen.

So I wanted to try the reverse but by laptop decided to shutdown and I was too knackered to continue yesterday.
Earlier today I had a chat with Bill Reiss.. he mentioned that he had some problems with 1520 too and that it had something to do with how large the image becomes on 1080p screen.

So I decided to continue where I left yesterday but with a reduction only for 1080p devices.
Test 2: reduce the multiplication constant to 0.0015 if a 1080p device is detected.
Result: Significant reduction in crashes.. I can still get it to crash but not that often. Here is the changed version

int DeviceScaleFactor = -1;
private void GetScaleFactor()
{
    object physicalScreenResolutionObject;

    if (DeviceExtendedProperties.TryGetValue("PhysicalScreenResolution", out physicalScreenResolutionObject))
    {
        var physicalScreenResolution = (Size)physicalScreenResolutionObject;

        DeviceScaleFactor = (int)(physicalScreenResolution.Width / 4.8);
    }
    else
    {
        DeviceScaleFactor = Application.Current.Host.Content.ScaleFactor;
    }
}

void SetDragToScale(System.Windows.Point pScale)
{
    double x = Math.Abs(pScale.X);
    double y = Math.Abs(pScale.Y);

    double manipulation = x > y ? pScale.X : pScale.Y;

    bool zoomOut = manipulation >= 0 ? false : true;

    if (this.DeviceScaleFactor == -1)
    {
        this.GetScaleFactor();
    }

    double scale = (this.viewModel.HasHighResolutionCamera ? 0.01 : 0.005) * Math.Sqrt(Math.Pow(x, 2) + Math.Pow(y, 2));

    if (DeviceScaleFactor == 225)
    {
        scale = 0.0015 * Math.Sqrt(Math.Pow(x, 2) + Math.Pow(y, 2));
    }

    if (zoomOut)
        this.viewModel.ViewScale = initialScale + scale;
    else
        this.viewModel.ViewScale = initialScale - scale;

    System.Diagnostics.Debug.WriteLine("zoomout {0}, scale {1}", zoomOut, scale);
}

if the Device scale factor is 225, its a 1080p device and one should exercise caution.

Where did the SystemTray vanish with #WinPRT #wpdev?

With Silverlight WP8 API, SystemTray is exposed in PhoneApplicationPage through Microsoft.Phone.Shell.

<phone:PhoneApplicationPage
    shell:SystemTray.IsVisible="True" 
    shell:SystemTray.BackgroundColor="AliceBlue"
    shell:SystemTray.ForegroundColor="Black"
    shell:SystemTray.Opacity="0.75">
    <shell:SystemTray.ProgressIndicator>
        <shell:ProgressIndicator />
    </shell:SystemTray.ProgressIndicator>
</phone:PhoneApplicationPage>
SystemTray.BackgroundColor = Colors.Cyan;
SystemTray.ForegroundColor = Colors.White;
SystemTray.IsVisible = true;
SystemTray.Opacity = 0.8;
SystemTray.ProgressIndicator = new ProgressIndicator() { IsIndeterminate = true, IsVisible = true };

it was very easily done through xaml itself. You could do it from codebehind by accessing static properties of SystemTray class.
However with WinPRT, the Page class does not expose SystemTray and now it lives as Windows.UI.ViewManagement.StatusBar.
No xaml declarative business here.

var statusBar = StatusBar.GetForCurrentView();
statusBar.BackgroundColor = Colors.Black;
statusBar.BackgroundOpacity = 0.8;
statusBar.ForegroundColor = Colors.White;
statusBar.ProgressIndicator.Text = "loading";
await statusBar.ShowAsync();

If I find anything declarative, I will post those at a later date.