Click here to Skip to main content
Click here to Skip to main content
Go to top

An Easy Guide For Developing and Publishing Apps in Intel AppUp Store for New Ultrabook Devices

, 13 Jan 2013
Rate this:
Please Sign up or sign in to vote.
How to build and publish Ultrabook desktop Apps in Intel AppUP store

Download PART-1-Rough-Layout-noexe.zip

Download PART-2-Paint-Without-Color-Change-Working-noexe.zip

Download PART-3-Paint-With-Color-Change-noexe.zip

Download Part-4-No-Style-Solution.zip

All New:

 Download KIDSOO_LAPTOP_VERSION_GAL_SUPPORT_NO_SENSORS-noexe.zip

 Download kidsoo_laptop_version_gal_support_no_sensors.zip

1. Introduction to Intel AppUp and Opportunities  

Intel  AppUp is an App store that is mainly dedicated to offering Apps for devices that supports Intel Architecture. Primarily AppUp offers Apps for PC, Netbooks, Laptops and Ultrabooks. With the introduction of Windows 8, desktop experience is split into Metro style   environment and desktop environment. Desktop environment and desktop flavours Apps are the one AppUp offers at this moment for Ultrabook.

So what is the opportunity there in AppUp? This might just be the first question you may ask if you have never worked with Apps or if you happen to be an existing App developer for Apple or Android market. Let me tell you, AppUp is still in it's early stage and can be considered as a start up. Having said that, there are many good things to start with AppUp

a) It is free for developers. Yes, this is a very big incentive right now. 

b) It offers you many goodies and resources. One of the goodies is a free code signing certificate which otherwise costs you about $200. 

c) AppUp takes the burden of testing your app in several environments and systems with different specifications, they test for your UI homogeneity, application crashes, as well as functionality. So they do a lot of stuff for you.

If this is not motivating enough for you, then take a breath and read some reviews about new Ultrabook devices and see some videos featuring Ultrabook. Let me tell you, Ultrabook is a great innovation in all rights. It gives you the power of laptop and flexibility of tablets. Beside other sensors, the most important aspect of Ultrabook devices is that they have touch screen. And that changes the way you perform your computation and they way you use it for complex programs. 

The good thing is that Ultrabook is not yet very cheap. So these devices are bought by users with wealth and means. Hence Ultrabook gives us all the more reasons to think some serious commercial application unlike Android market which is mainly Ad supported and which sees more free Apps   being downloaded then paid App.

Ultrabooks work on Windows 8 platform which has two major stores for Apps: Windows Store and Intel AppUp store. Windows Store offers Apps of both Metro style as well as of desktop style. However to publish desktop apps in windows App store is costly. You need to give a $100 royalty to Microsoft every year beside spending another couple of hundreds of dollars of buying code signing certificate from Symantec. 

From my personal experience I can also tell you that the App submission and validation process in Windows Store is anything but pleasant.

Having read a little summery of the device that we are speaking about, the application environment and App stores, we may easily   get a push to checkout with Intel AppUp. 

I would recommend you to download the AppUp client for your laptop from  

http://appup.com

Browse through some apps, download few free apps to get a feel about the system first. You will be surprised to see how easy the AppUp has made it to manage your desktop applications, downloading, installing and removing the Apps. 

2. What Kind of App can you make for Ultrabook Desktop flavor?  

There are several articles on the difference between a desktop App and a Metro style App. However if you are lazy like me and do not want to leave this page to check out the difference, here is an easy and simple explanation for you.

See the Image bellow. It depicts the Windows 8 GUI. Observe the bottom left rectangle . That is tab for windows 8 desktop. So in simple  terms, in windows 8, conventional desktop environment that we are accustomed to is a nice little App in itself. 

Figure 1: Windows 8 GUI

 

Having understood or 'seen' the difference between desktop and Metro UI for Windows 8, it is now time to understand the difference between Metro style app and desktop apps. 

If you have a second look at the Win8 UI, you can see several colorful tiles. Each of these are actually different applications or apps. If you spend some time looking and working with few of them, you will realize these apps fall under "Readers".

Metro style UI was develop to give Windows 8 phone and tablets a modern look and feel.  And what you do with tablets? You read news, watch movies, play games, do social networking. That is exactly what Metro style is for. These Apps are mainly there for entertaining you and give you quick information. GPS, News related apps are all great in Metro environment. But what you can clearly see is that there are no serious "tools" in metro styles. Tools that we are so accustomed to work with like editors, shells, calculators,  IDE's are missing from these metro app lists. 

Now if you click ( or touch)on the search button at the top right corner in your "start bar", you will see many small app icons visible which certainly has Notepad, Paint, Wordpad, Command Window, Calculators and others. Select any of them and you will be automatically taken to the desktop environment . When you close these apps or minimize them, you stay in the desktop environment. 

Figure 2: Searching in App List 

To summarize , we can say desktop apps are the producers and metro apps are consumers. Blog reader, place finder, simple touch games, to-do lists, personal information maintenance, social network integration are some of the things that are best suited for metro environment.   

Desktops are conventional power apps. You have a lot of control over the way your app should work and type of work. Many modules and components developed for Windows XP also works with Windows 8. So desktop App may be a good choice if you are already a product designer and developer ( The name 'Product developers' are now obsolete and  people prefer 'App Publisher' as a more sexier and appealing name) you have better chances of quick and powerful App development in desktop environment where you can reuse a lot of components that you are already working with or have worked with.  

Till date, I have not seen a great Enterprise App like SAP, Photoshop or Tally build on any of the modern mobile environment. And that is mainly due to the fact that mobile environments are meant for being mobile or a quick check and serious productivity or enterprise solutions needs you to be on your desk working with keyboard shortcuts and mouse. 

If you are lucky like me to have an Ultrabook already, you must be knowing how wonderful it is to work with Ultrabook on your desk with combination of mouse, touch, sensors, keyboards and how easy it is to use it to read those pdf files while you are resting on your couch.

If you do not have an ultrabook already, dont get dissapointed. You have a good news here. You can actually build apps in Windows 7 environment and all of them (technically most of them) works in ultrabook too. Other than the special sensors like ambient light sensors and accelerometers, all touch interfaces are available in windows 7 development environment and you can develop these logic with mouse and transfer back to touch interfaces. 

This knowledge that you can still develop a killing Ultrabook App even without having an Ultrabook or Windows 8 is something that you must really cherish. 

With this understanding of App segments and knowledge that desktop Apps could be ( rather than 'should be') power apps and also that these can be easily made available across all windows platform since XP (or even 98?) and that there are more than billion Windows users ( I don't have exact numbers though!) we will kick start our journey of becoming "App Publisher". 

3. Starting with AppUp developers account

Once you get a look and feel about the App store, the apps, the environment and the possibilities, it is now your turn to show what you are capable of doing and  head straight to AppUp for creating a developers account. 

Technically you will create an Intel partner's account which automatically translates your credential to AppUp publisher.

If you are not already an App publisher, then do note that App Stores, publishing and getting accustomed to both may be real pain at the beginning. But once you decide to take the blow, learning curve and comfort degree should ease off. 

Before we move forward, here is an important thing that you should do: Download and install Firefox in your laptop (or PC, whatever you are using). There are several transactions in Intel site that is not supported by chrome and some other transactions fails flat with Internet explorer. Firefox at the moment is most stable browser to save you from some nightmare with your initial days with AppUp publishing.

Head straight to http://software.intel.com

Register your account. Once registered, you will receive a notification. However unlike some other sites, Intel account notification may take time. Refresh you mail in two minutes to see the account activation mail.

Once you login to your account, the first screen you see is as follows.

 

Figure 3: AppUp Initial Dashboard 

Please don't get puzzled to not to see anything related to AppUp. Actually AppUp works as follows.

You belong to an organization and represent an organization. Organization publishes software and you have the authority for publishing. So before anything, you need to create an organization. Dont worry, if you are not part of any organization or if you want to create an individual account, create an organization by your name.  Update your profile information that you see while logged in for the first time. 

At the top you see communities, resources and  developers tool menus. Open Resources, select Software Partner ( under Businesses tab) and create an organization. Once you have created an organization, on the right tab you will see register for Intel AppUP. Update your information and return to dashboard.  

Figure 4:  AppUp Dashboard with AppUp tab

Now you will see another tab: AppUP.  Congratulation! You have crossed the first hurdle of registering and finding a way to get into AppUP. Create an application ( even if you do not have one or have not built one, just create an application). Once you have an application listed, you will see the code signing certificate option on the right  tab. 

 

Figure 5: AppUp dashboard with Code Signing Certificate Application option

4. Code Signing Certificate 

I assume most of you already know what is that, but for those who do not know, see the image bellow.

 

Figure 6: Difference of Plain Installer and Installer Signed with Code Signing Certificate

When you Crete an exe or MSI installer for your application, at the time of installation, your system checks the digital signature and if no signature is found, warns you that it is from unknown publisher. Digital signature not only gives the user a trust but also protects publishers interest. As your App will be in internet, it stands a chance of being modified. With digital signature in place, your exe or installer can not be changed.

Having understood a bit of code signing stuff and what a digital signature is and why is it necessary, we will go to acquire a certificate which at this moment is a goodie from Intel.

If you were lazy enough to skip some part of the articles, or if you had already have an account with Intel and have managed to skip the previous part of article, I shall tell you again that code signing is done in corporation with your browser and at this moment Comodo supports only Internet Explorer and Firefox. You are better off  applying for a code signing certificate from Firefox browser if you wish to have it in a hassle free manner.

Prerequisites for code signing:

Note that they require certain documents for assigning you the code. One of them is last few month's electricity bill or land phone bill that should be on your name and the address that you mention.  Passport, driving licenses are used for Identity proof and not address proof. So you should be ready with it.

However there is another way out. When you jump into the exciting world of Apps, there are several aspects other than programming. App publicity and support are two of them.  So it is better to register a domain on the name for which you are applying for code signing. For example if you want to get a code for individual account on your name say 'Harry', then buy a domain with that name say harry.com or harry.net or whatever and purchase a hosting. Host a simple WordPress blog or site and put your information there. You might feel this step as a waste of money but Apps generally needs publishers URL and support URL. So if you are serious about the App business, it always makes sense to have your website. You can use your site to provide technical specification, answer the queries of your user and so on.  

Having a domain on your name or your organization's name eases the burden of verification and you can get one within couple of days.

Leaving you with your fight for getting a code signing certificate, I would move ahead with the actual stuff: Building an App for Ultrabook.

5. Kidsoo: An app for your kids to play around with Ultrabook

I already have three Apps published in AppUp for Ultrabook and six more are under validation. However I thought to build a simple  App for Kids from the scratch. It would give a greater control in understanding the nooks and corners of developing a real App for Ultrabook. At the same time  it will provide a means you to look into your development cycle as well. 

 5.1 Prerequisites  

Before we move ahead, here are few things you need to remember about Ultrabook apps.

1) Ultrabooks are hybrids, so them come in different specifications and screen sizes ( and of course resolution). So make your app as independent of screen size and resolution as possible.

2) One of the primary requirement for Apps is that the GUIs and menus must be homogeneous throughout the application. So you should not have button background as white in a form and green in another.

3) Apps must not crash ( As much as possible).

4) They must do what they claim to do

5) Any App for Ultrabook environment should be specifically thought as touch screen app and therefore you must select your controls accordingly.  Fingers are just too bolted to select normal menus.

6) App should use a special user folder and should not write data in program folder ( which obviously they cant). If user uninstalls the App, all the data written by the App must be deleted.

7) Whenever you update your App, either to incorporate feature release or updating to meet the validation criteria, you need to specify the version. At some point, managing the versions becomes tough. So it always helps if you adapt some standard version control technique from the word go. It can save you from lot of pain.

Well, if you are into serious App business  then one of your other priorities should be to get your apps to as many App stores and channels and environment as possible. Remember Angry Birds? You get it every where, Google play store, Apple App Store, Google chrome store, Intel AppUp and what not. So logically your App should be something that can easily be migrated or ported to other platforms. Therefore it is essential to separate visual from your main logic.  

Touch logic is almost similar in all environments. So you are better off working with touch logic and then add other features as bonus on Ultrabook.

Taking many other factors into consideration, WPF to me is the most suited environment for Ultrabook development. One of the major reasons is that it allows to develop in no style mode and then apply styling. 

Do remember at this moment that Apps also do need to be visually pleasing along with their functionality and I have learnt it in a very hard way.

Let us start by understanding the layouts.

5.2 Layout of your App 

My first App for Intel AppUp, ImageGrassy had a miserable layout issue and was messy in many ways as far as layout was concerned. It was partly because that was my first Wpf application and secondly, I never had this idea that the app had to run on so many different screen specifications. I ultimately had to redesign the GUI and interfaces to fix the issues. My struggle with the layout motivated me to provide some insights about layout issues in App. 

 This is one of the most crucial step of your App. You should design a layout that stands flexible even in lower resolutions or in lesser screen specifications. Many developers gets into a false impression that if you build a WPF application, it automatically becomes resolution independent. Well the statement is half true. You need to still figure out the methods to make the App resolution independent.

Let us see a few quick fix and tips to get a real device independent visual.

First look into the following image. This very much the standard layout adopted by most software and Apps. You may use the entire layout or some part of it as par your application. We will first build a simple pattern that satisfies our primary objective. For that we will use some standard rules and techniques.

 

Figure 7: Standard layout used by Apps

1. We will start from one 'L'. It could be Top-Right, Top-Left, Left-Bottom or Right-Bottom, Left-Bottom and make all the other properties as auto.

2. We will develop the project for least resolution(800x600) and try to see if it scales to the higher resolution. This is a technique that is been existing since early days of GUI design and still holds good.

Our WPF solution is simple at the beginning. If you change the resolution to 600x800, you can still see your Window running fine.  

<Window x:Class="Kidsoo.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="600" Width="800" 
        WindowState="Maximized">
    <Grid Background="Azure">
    </Grid>
</Window>

We will design a simple layout and validate that against all possible resolutions.

Here is our WPF MainWindow code for our initial layout.

<Window x:Class="Kidsoo.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="600" 
        Width="800" WindowState="Maximized">
    <Grid Background="Azure">
        <DockPanel VerticalAlignment="Top" HorizontalAlignment="Stretch" 
          Height="100"  Background="Beige"></DockPanel>
        <DockPanel VerticalAlignment="Stretch" HorizontalAlignment="Left" 
           Width="100" Margin="0,100" Background="BlueViolet">
            
        </DockPanel>
        <DockPanel VerticalAlignment="Bottom" HorizontalAlignment="Stretch" 
           Height="100" Background="Brown">
            
        </DockPanel>
        <DockPanel HorizontalAlignment="Right" VerticalAlignment="Stretch" 
          Width="100" Margin="0,100" Background="Aquamarine">
            
        </DockPanel>
        <DockPanel VerticalAlignment="Stretch" HorizontalAlignment="Stretch" 
          Margin="100" Width="Auto" Height="Auto" 
          Background="Chartreuse"></DockPanel>
    </Grid>
</Window> 

This is how it looks like:

 

Figure 8: Screen showing the output of Layout-Only Solution

Please don't waste your energy in laughing out by seeing the color combination. Every segment of layout is given a different color for easy distinguishing and we will modify every bit of them as we progress along.

Also note that there are several other ways of designing the layout of your choice. For example defining grid rows and columns etc. It is your choice and you may suitably choose a preliminary layout that suits your comfort and App.

Once we are done fixing our layout, we can move ahead with the app itself.

5.3  Preliminary Investigation about the functionality

I will now comeback to the App concept. We are building an App for the kids here. The objective is that kids can paint with their little finger or can learn Alphabets or Numeric or about fruits, animals. Intel AppUp content rating starts from 3+ years, but this App here is very much targeted towards toddlers keeping my twenty month old son in mind.

What my son does when sees the Ultrabook? He either moves his fingers across the screen as he sees me to do so, or hits keys or the space beside mouse pad, he some times moves his hand over mouse pad and some times tries to lift it( He actually manages to lift it a little due to weight factor). So primary focus here is to give him some fun in whatever he does with Ultrabook and keep in mind of the randomness of his activities.

So Kidsoo should be:

1) Draw with finger with random colors automatically getting selected.

2) Alphabets with Pictures when the kid press any keyboard key

3) Some music when the touches different screen area randomly ( or for fun)

4) Some pictures or music when the kid tries to move Ultrabook.

Remember one thing, you are building the App for a user group and segment. Hence first put yourself in that  user category  and think how best would they be using the App. What layout or UI would help them the best. If you do some preliminary investigation about the App, you can build one with great flexibility and the App stands a chance of winning hearts and a commercial success too.

As we have discussed here, Kidsoo is targeted to toddlers and you don't hit them or bore them with check boxes, radio buttons, and data grids. Similarly if you are building an App with images, don't display the final result or main image in a 64x64 thumbnail size image viewer.

Understanding the concept of the Application and the target audience and thereby selecting your layout of Controls accordingly at the primary stage will help you in great deal to build good Apps.

5.4  Moving ahead with Kidsoo 

To start with, we want to get the paint part working first. I will not be using any other layout parts other than the center and the left pane. For drawing we need a canvas or Image control. I will prefer an Image control and move ahead with implementing that part with mouse.

As the mouse is pressed and moved, it should draw pixels on the screen. Periodically, the color should get changed. Once a while the screen must also be cleared for kids to keep painting.

Here is our new layout.

<Grid >
    <DockPanel VerticalAlignment="Top" HorizontalAlignment="Stretch" 
            Height="0"  Background="Beige"></DockPanel>
    <DockPanel VerticalAlignment="Stretch" HorizontalAlignment="Left" 
            Width="100" Margin="0,0" Background="AliceBlue">
        
    </DockPanel>
    <DockPanel VerticalAlignment="Bottom" 
       HorizontalAlignment="Stretch" Height="00" Background="Brown">
        
    </DockPanel>
    <DockPanel HorizontalAlignment="Right" VerticalAlignment="Stretch" 
      Width="0" Margin="0,0" Background="Aquamarine">
        
    </DockPanel>
    <DockPanel VerticalAlignment="Stretch" HorizontalAlignment="Stretch" 
                Margin="100,0,0,0" Width="Auto" 
                Height="Auto" Background="WhiteSmoke">
        <Image x:Name="Image1" Height="Auto" Width="Auto"></Image>
    </DockPanel>
</Grid> 

Observe that we still have the same layout but the DockPanel width and heights are modified to suite our need.  

Having fixed the layouts, we now want to get on with our coding. But as we have already learnt at the beginning of this article to keep the logic part separate from GUI, we will add another C# class to our project called Logic and add the functionality there.

 using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
namespace Kidsoo
{
    public class Logic
    {
        public static BitmapImage DrawPoint(BitmapImage originalImage, 
                      Point center, Brush b, Pen p, double rad)
        {
            double Scale = 1;
            double newWidth = originalImage.Width * Scale;
            double newHeight = originalImage.Height * Scale;
            RenderTargetBitmap targetImage = new RenderTargetBitmap((int)Math.Ceiling(newWidth),
                                                                    (int)Math.Ceiling(newHeight),
                                                                    96, 96,
                                                                    PixelFormats.Default);
            DrawingVisual dv = new DrawingVisual();
            using (DrawingContext dc = dv.RenderOpen())
            {
 
                ImageBrush db = new ImageBrush(originalImage);
                double Degrees = 0;
 
 
 
                //dc.DrawText(formattedText, p);
                dc.DrawEllipse(b, p, center, rad, rad);
            }
            targetImage.Render(dv);
            BitmapEncoder be = new BmpBitmapEncoder();
            be.Frames.Add(BitmapFrame.Create(targetImage));
            MemoryStream memoryStream = new MemoryStream();
            BitmapImage bImg = new BitmapImage();
            be.Save(memoryStream);
            bImg.BeginInit();
            bImg.StreamSource = new MemoryStream(memoryStream.ToArray());
            bImg.EndInit();
            memoryStream.Close();
 
            return bImg;
        }
    }
}

We now have a DrawPoint method that draws an ellipse of specified radius over a specific point with a specific brush style. It uses the drawing context of WPF to render a desired shape in an image.  You can also use DrawingContext for drawing a text, rectangle, line or other stuff.

Having our main functionality in place, all we need to do is attach an event handler and see if it is working or not.

We will go with MouseMove event. In the event handler we shall check if the left button is pressed, if pressed we will find the location relative to the image. Already present content of the image will be passed to this function along with the position data and we will use a simple Red brush to test this part.

Let us see what MainWindow.cs looks like.

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
       img= new BitmapImage();
       Image1.Source = img;
    }
    BitmapImage img;
    private void Image1_MouseMove_1(object sender, MouseEventArgs e)
    {
        if (e.LeftButton.Equals(MouseButtonState.Pressed))
        {
            
            Point current = e.GetPosition(Image1);
            img = Logic.DrawPoint(img, current, new SolidColorBrush(Colors.Red), new Pen(Brushes.Red, 1), 1);
            Image1.Source = img;
        }
    }
}

You can now build the application and see the result. What you see? Nothing right? This is because you don't really have an image to write or paint. So we will create an empty image in paint and store it in App execution folder. We will read this in the constructor after InitializeComponent .

public MainWindow()
{
    InitializeComponent();
    img = new BitmapImage(new Uri(System.IO.Path.GetFullPath("main.png")));
    Image1.Source = img;
 
}
BitmapImage img;
private void Image1_MouseMove_1(object sender, MouseEventArgs e)
{
    if (e.LeftButton.Equals(MouseButtonState.Pressed))
    {
        Point current = e.GetPosition(Image1);
        img = Logic.DrawPoint(img, current, 
          new SolidColorBrush(Colors.Red), new Pen(Brushes.Red, 2), 3);
        Image1.Source = img;
    }
}

OK, as you are using an external image, dont forget to set the image stretch property as Fill.

<Image x:Name="Image1" Height="Auto" Width="Auto" 
         MouseMove="Image1_MouseMove_1" Stretch="Fill"></Image> 

Now build the App and see what is happening.

It will draw with red paint but way away from your mouse position as you can see. This is because you had not specified any width and size for your Image1 and main.png is of different size than your image. As Image1 height and width are not set explicitly, Image1.Height and Image1.Width will return NaN. So you dont have any means of getting the actual specification for drawing context.  

We will use System.Windows.SystemParameters.PrimaryScreenWidth and System.Windows.SystemParameters.PrimaryScreenHeight to obtain the size of the drawing context. We will calculate the fraction by which Image and main.png (or .bmp whatever) differs and scale our points to that fraction. 

if (e.LeftButton.Equals(MouseButtonState.Pressed))
{
 
    Point current = new Point(e.GetPosition(Image1).X * img.Width / 
      (System.Windows.SystemParameters.PrimaryScreenWidth - 100), 
      e.GetPosition(Image1).Y * img.Height / System.Windows.SystemParameters.PrimaryScreenHeight);
    img = Logic.DrawPoint(img, current, new SolidColorBrush(Colors.Red), new Pen(Brushes.Red, 2), 3);
    Image1.Source = img;
}

If you compile your application now, you will see that points are much closer to mouse but they starts getting blotted as you keep painting. This is because you still have no physical height and width and your image is still of Infinite height and width.

Another fix is in DrawPoint method. Remember we used dpi=96. The image you created may not have this dpi, so we replace the default dpi with actual dpi of the image. 

If you create an Image of size 256x256 (main.png) you will get the optimum result as desired for kids. They want to see big and thick lines and points. If you make an image of size say 3000x3000, drawn points will be much smaller, taking out the fun part.

Right then. Our solution is working for one color and for mouse movement perfectly.

However: a) We want periodic color change

and          b) To clear the drawing window occasionally so that fun continues.

We will achieve this with the help of two background threads. We are using workerClear to clear the window after 50 seconds and workerNewColor to change the color after every 5 seconds.

Observe the use of Dispatcher here. As your parent thread and background threads are two different heaps, you need to update any control or DependencyObject ( like currentColor here) from Dispatcher.Invoke delegate. 

You can similarly add effect for other animations. Note that infinitely running background threads are some times difficult to remove by your Garbage collector. Dont be surprised if you dont see your application closing even after clicking close button.

In order to force closing down of any running background thread and clearing the memory used by them, we will add Closed event handler for the window and use InvokeShutdown() for dispathcher.

Here is the code for paint part of Kidsoo.

 using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;
namespace Kidsoo
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        #region variables
        BitmapImage img;
        BackgroundWorker workerClear;
        BackgroundWorker workerNewColor;
        Brush currentBrush;
        Random rnd = new Random();
        #endregion
        public MainWindow()
        {
           InitializeComponent();
           img = new BitmapImage(new Uri(System.IO.Path.GetFullPath("main.bmp")));
           Image1.Source = img;
           Image1.Width = System.Windows.SystemParameters.PrimaryScreenWidth - 100;
           Image1.Height = System.Windows.SystemParameters.PrimaryScreenHeight;
           currentBrush = new SolidColorBrush(Color.FromRgb(255,0,0));
           ////////////////////Worker Clear will be used to clear the screen////////////////////////////////////
           workerClear = new BackgroundWorker();
           workerClear.DoWork += workerClear_DoWork;
           workerClear.WorkerReportsProgress = true;
           workerClear.ProgressChanged += workerClear_ProgressChanged;
           workerClear.RunWorkerAsync();
////////////////////////////////// This will be used for changing the Color///////////////////////
          workerNewColor = new BackgroundWorker();
          workerNewColor.DoWork += workerNewColor_DoWork;
          workerNewColor.WorkerReportsProgress = true;
          workerNewColor.ProgressChanged += workerNewColor_ProgressChanged;
          workerNewColor.RunWorkerAsync();
            //// Why do we have ProgressChanged? There is no progress bar here.
            // ProgressChange pumps a message to parent thread when invoked. This is a good way to 
            // let your parent thread know about any background thread to avoid application hang
        }
        void workerNewColor_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            
        }
        void workerNewColor_DoWork(object sender, DoWorkEventArgs e)
        {
            while (true)
            {
                System.Threading.Thread.Sleep(5000);
                byte r = (byte)rnd.Next(0, 255);
                byte g = (byte)rnd.Next(0, 255);
                byte b = (byte)rnd.Next(0, 255);
           
                this.Dispatcher.Invoke(
                     DispatcherPriority.Normal,
                     (System.Windows.Forms.MethodInvoker)delegate()
                     {
                         currentBrush = new SolidColorBrush(Color.FromRgb(r, g, b));
                     }
         );
                workerNewColor.ReportProgress(10);
                System.Threading.Thread.Sleep(1000);
                //throw new NotImplementedException();
            }
            //throw new NotImplementedException();
        }
        void workerClear_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            //throw new NotImplementedException();
        }
        void workerClear_DoWork(object sender, DoWorkEventArgs e)
        {
            while (true)
            {
                System.Threading.Thread.Sleep(40000);
                
                this.Dispatcher.Invoke(
                        DispatcherPriority.Normal,
                        (System.Windows.Forms.MethodInvoker)delegate()
                        {
                            img = new BitmapImage(new Uri(System.IO.Path.GetFullPath("main.bmp")));
                            Image1.Source = img;
              
                        }
            );
                workerClear.ReportProgress(2);
                System.Threading.Thread.Sleep(1000);
            }
            //throw new NotImplementedException();
        }
       
        private void Image1_MouseMove_1(object sender, MouseEventArgs e)
        {
            if (e.LeftButton.Equals(MouseButtonState.Pressed))
            {
                Point current = new Point(Math.Floor(e.GetPosition(Image1).X * img.Width / 
                  (System.Windows.SystemParameters.PrimaryScreenWidth - 100)), 
                  Math.Floor(e.GetPosition(Image1).Y * img.Height / 
                  System.Windows.SystemParameters.PrimaryScreenHeight));
                img = Logic.DrawPoint(img, current, currentBrush, new Pen(currentBrush, 2), 3);
                Image1.Source = img;
            }
        }
        private void Window_Closed_1(object sender, EventArgs e)
        {
            this.Dispatcher.InvokeShutdown();
        }
    }
}

Here is how it screen looks after few seconds of  

Figure 9: Here is how it screen looks after few seconds of drawing

However, all that we did here was general functionality. So what we do for Ultrabook and touch screen? Simple. Replicate the mouse move method in TouchMove event handler. So our code should have been something similar to this: 

private void Image1_TouchMove_1(object sender, TouchEventArgs e)
{
    Point current = new Point(Math.Floor(e.GetPosition(Image1).X * img.Width / 
      (System.Windows.SystemParameters.PrimaryScreenWidth - 100)), 
      Math.Floor(e.GetPosition(Image1).Y * img.Height / 
      System.Windows.SystemParameters.PrimaryScreenHeight));
    img = Logic.DrawPoint(img, current, currentBrush, new Pen(currentBrush, 2), 3);
    Image1.Source = img;
}

But unfortunately TouchEvents are little different from Mouse events and you don't have GetPosition() method for TouchEventArgs. 

You need to use GetTouchPosition() of TouchDevice from TouchEventArgs.

private void Image1_TouchMove_1(object sender, TouchEventArgs e)
{
    Point current = new Point(Math.Floor(e.TouchDevice.GetTouchPoint(Image1).Position.X * img.Width / 
      (System.Windows.SystemParameters.PrimaryScreenWidth - 100)), 
      Math.Floor(e.TouchDevice.GetTouchPoint(Image1).Position.Y * img.Height / 
      System.Windows.SystemParameters.PrimaryScreenHeight));
    img = Logic.DrawPoint(img, current, currentBrush, new Pen(currentBrush, 2), 3);
    Image1.Source = img;
}

This is simple isn't it?

But what about touch  gestures and swipe left or down or pinch or zoom gesture? Even though we do not need them here for Kidsoo, I will extend the touch gesture part a little. Touch gestures can be analized through 'Manipulation' event groups. Firstly you need to enable Manipulation and then  trap ManipulationDelta to track the amount of manipulation across X and Y coordinates. 

Following is the XAML part for Image1 

<Image x:Name="Image1" Height="Auto" Width="Auto" 
  MouseMove="Image1_MouseMove_1" Stretch="Fill" TouchMove="Image1_TouchMove_1" 
  IsManipulationEnabled="True" ManipulationStarting="Image1_ManipulationStarting" 
  ManipulationDelta="Image1_ManipulationDelta" ManipulationCompleted="Image1_ManipulationCompleted" 
  ManipulationInertiaStarting="Image1_ManipulationInertiaStarting"   ></Image> 

Remember, manipulation events traps the total movement along with speed and do not give you control over independent pixels. So you should use these events for gestures and not for pixel specific actions.

double cumulativeDeltaX, cumulativeDeltaY, linearVelocity;

private void Image1_ManipulationStarting(object sender, ManipulationStartingEventArgs e)
{
    e.ManipulationContainer = Image1; 
    e.Handled = true;
    cumulativeDeltaX = 0;
    cumulativeDeltaY = 0;
    linearVelocity = 0;
}

Following part of code will give you standard pinch and zoom for images. However our Kidsoo will not have this code as we do not see any ways kids using multi touch. But you can incorporate this code to analyse and understand the manipulation behavior and can reuse it wisely for your work. 

private void Image1_ManipulationDelta(object sender, ManipulationDeltaEventArgs e)
{
    cumulativeDeltaX = cumulativeDeltaX+e.CumulativeManipulation.Translation.X; 
    cumulativeDeltaY = cumulativeDeltaY+e.CumulativeManipulation.Translation.Y; 
    //store value of linear velocity into horizontal direction   
    linearVelocity = linearVelocity+e.Velocities.LinearVelocity.X;
        ////////////////////////////
         Matrix borderMatrix = ((MatrixTransform)Image1.RenderTransform).Matrix;
    //determine if action is zoom or pinch
        int AppConstantsMinimumZoom=-40;
        int AppConstantsMaximumZoom=40;
    var maxScale = Math.Max(e.DeltaManipulation.Scale.X, e.DeltaManipulation.Scale.Y);
    //check if not crossing minimum and maximum zoom limit
    if((maxScale <  1 && borderMatrix.M11 *maxScale >  AppConstantsMinimumZoom) ||
    (maxScale >  1 && borderMatrix.M11 *maxScale <  AppConstantsMaximumZoom))
    {
        Image1.Height = Image1.Height * maxScale;
        Image1.Width = Image1.Width * maxScale;
        
        //scale to most recent change (delta) in X & Y 
        borderMatrix.ScaleAt(e.DeltaManipulation.Scale.X, 
           e.DeltaManipulation.Scale.Y, Image1.ActualWidth/2,Image1.ActualHeight/2);
        //render new matrix
        Image1.RenderTransform = new MatrixTransform(borderMatrix);
}

Point to be noted here is that even this code is developed in Windows 7 and works perfectly for Ultrabook. So not having an Ultrabook is no more a good excuse to not develop an App for Ultrabook.

It's now time to give the kid something more to cherish about: Add some functionality when he hits the keyboard keys. We are adding an Alphabet learning here. So when the kid hits A key, a large image containing Apple with Letter A appears. For doing this, we will create a resource folder by name Alphabet and keep our media resources there. 

Now add a KeyDown event with your main window. And add the logic to display different images for different key  press.

private void Window_KeyDown_1(object sender, KeyEventArgs e)
{
    switch (e.Key)
    {
        case Key.A:
            img = new BitmapImage(new Uri(System.IO.Path.GetFullPath("Alphabets/A.png")));
                    Image1.Source = img;
            break;
        case Key.B:
            img = new BitmapImage(new Uri(System.IO.Path.GetFullPath("Alphabets/B.png")));
            Image1.Source = img;
            break;
    }
}

You can complete the rest of the alphabets. Important thing here is that while we created Alphabet directory, it was inside your Project directory. But while you make the installer your application will be running from the installation directory. So Alphabets directory must be relative to the  installation directory. To get it straight, once you complete all the images in Alphabet directory, you can copy that to bin/debug if you are in debug mode or bin/release if you are in release mode.

Another little fun that I want to add in this App. I want the App to actually teach the kid about the images. How? Simple using Microsoft TextToSpeech Engine. And trust me working with TextToSpeech is just as easy as it goes.

So firstly we will add Reference to System.Speech

Now just declare an object of SpeechSynthesizer and adjust the rate of the Synthesizer. Make it slow for easy understanding of the Kid. 

speaker = new System.Speech.Synthesis.SpeechSynthesizer();
speaker.Rate = -8; 

And our KeyDown event handler is modified as follows.

private void Window_KeyDown_1(object sender, KeyEventArgs e)
{
    switch (e.Key)
    {
        case Key.A:
            img = new BitmapImage(new Uri(System.IO.Path.GetFullPath("Alphabets/A.png")));
                    Image1.Source = img;
                    System.Threading.Thread.Sleep(400);                    
                    speaker.SpeakAsync("A for Apple");
            break;
        case Key.B:
            img = new BitmapImage(new Uri(System.IO.Path.GetFullPath("Alphabets/B.png")));
            Image1.Source = img;
            speaker.SpeakAsync("B for Banana");
            break;
    }
}

Note the use of Async method instead of simple Speak method. If you use Speak, first the synthesizer will be activated speaking the sentence, followed by loading the image. That would be too useless right?

The last part of media that we had discussed was to play some music with pictures for toddlers learning. Here we have added couple of buttons to play two different songs with respective image.

See  the Screen bellow

Figure 10: Screen after adding media option

And the code? They are pretty simple and straight forward. We added two MediaElements to hold the respective audio files and play the media element upon button click.

Our left dock panel is now modified as

<DockPanel VerticalAlignment="Stretch" HorizontalAlignment="Left" 
           Width="100" Margin="0,0" Background="AliceBlue">
    <StackPanel>
    <Button x:Name="btnTwinkle" Content="Twinkle" 
            Margin="2,2,2,2" Click="btnTwinkle_Click"></Button>
    <Button x:Name="btnAlphabet" Content="Alphabet Song" 
            Margin="2,2,2,2" Click="btnOther_Click"></Button>
        <MediaElement x:Name="mediaTwinkle" Source="Songs/Music2.mp3" 
            LoadedBehavior="Manual"  />
        <MediaElement x:Name="mediaAlphabet" 
            Source="Songs/AlphabetSong.wav" LoadedBehavior="Manual"  />
    </StackPanel>
</DockPanel>

And the code behind goes as bellow.

void StopAllSongs()
{
    mediaTwinkle.Stop();
    mediaAlphabet.Stop();
}
private void btnOther_Click(object sender, RoutedEventArgs e)
{
    img = new BitmapImage(new Uri(System.IO.Path.GetFullPath("Songs/alphabet.jpg")));
    
    Image1.Source = img;
    StopAllSongs();
    mediaAlphabet.Play();
}
private void btnTwinkle_Click(object sender, RoutedEventArgs e)
{
    img = new BitmapImage(new Uri(System.IO.Path.GetFullPath(
                   "Songs/Twinkle_Twinkle_Little_Star.gif")));
    Image1.Source = img;
    StopAllSongs();
    mediaTwinkle.Play();
} 

5.5 Applying Style

If you see the workflow properly, you will laugh at the design. Well that is how it works in WPF. You set layout, you add functionality and then you apply style. As the solution is for kids, you expect them not to know the alphabets and they will only understand the photos. So we will apply little button style and replace Text content with Images.

Here is a little ButtonStyle.

<Style x:Key="AnimButton" TargetType="Button">
    <Setter Property="OverridesDefaultStyle" Value="True"/>
    <Setter Property="Margin" Value="5"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="Button">
                <Border Name="border" 
                BorderThickness="0" 
                Background="{TemplateBinding Background}">
                    <ContentPresenter HorizontalAlignment="Left" 
                               VerticalAlignment="Top" />
                </Border>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsMouseOver" Value="True">
                        <Setter Property="Opacity" Value=".6">
                            
                        </Setter>
                        
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

Add this in <Windows.Resources> section. You can observe that the style comes with a ContentPresenter which allows us to replace the text content with Image and Text Content.

It uses a simple trigger of changing the opacity. You can add some sound with MediaElement in trigger to add more effects.

<Button x:Name="btnTwinkle"   Margin="2,2,2,2" 
            Style="{StaticResource AnimButton}" Click="btnTwinkle_Click"  Width="88" >
    <StackPanel Orientation="Horizontal">
        <Image Source="/Songs/twinkle.jpg" Width="85" ></Image>
    </StackPanel>
</Button>

Here is the simple screen after adding some style and effect to the App.

Figure 11: Screen after adding styling

5.6 Working with directory

If your App contains a database or if you are writing some files in disk or for games if you want to store and update the stores then you can not do it in App's installation directory. Invariably your App will be installed in Program Files or Program Files(x86) which will not give write permission to your App. In this cases, anything you want to write or any file you want to update should be in Special user folder.

This is another tricky part of the App as Intel has a strict prerequisite that the App data must be cleaned once the App is uninstalled. 

We will follow a rule here: 

c:\Users\USER_NAME\AppData\Roaming\YOUR_COMPANY_NAME\APP_NAME

Where capitalized letters are variables. Remember, installer does not create any directory in the User Special folder. So either you need to create the folder with an installer class or you need to do it through your program. To keep it simple, we will cover creating Application folder through your Apps only.

When the App is loading, we will check if the Application folder exists or not. If not exist we will create it. If you have a xml or database file, you can first store it in App program directory and copy it to App data directory after creating the App data folder.

Let us declare a class called WorkingPath and store the data path in a static variable for the path to be accessed from every class of the project.

namespace Kidsoo
{
    class WorkingPath
    {
        public static string Path = Environment.GetFolderPath(
          Environment.SpecialFolder.ApplicationData) + "\\Integrated Ideas\\Kidsoo";
    }
}

In WindowLoaded event handler we will check for ApplicationData\COMPANY_NAME folder. If it does not exist, we will create it. Then we will check for ApplicationData\COMPANY_NAME\APP_NAME and do the same.

private void Window_Loaded_1(object sender, RoutedEventArgs e)
{
    try
    {
        if(!Directory.Exists(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)+"\\Integrated Ideas"))
        {
            Directory.CreateDirectory(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\Integrated Ideas");
          
        }
        if (!Directory.Exists(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\Integrated Ideas\\Kidsoo"))
        {
            Directory.CreateDirectory(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\Integrated Ideas\\Kidsoo");
        }
    }
    catch (Exception ex) 
    {
        MessageBox.Show(ex.Message);
    }
}

Now to show the usage, we will add a simple method to save the drawing in Image1 and will call the method before clearing the Image.

public void Save(string filePath,BitmapSource Image)
{
    try
    {
        BitmapEncoder encoder = null;
        var image = Image;
        using (var fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write))
        {
            if (filePath.EndsWith(".jpg"))
                encoder = new JpegBitmapEncoder();

            if (filePath.EndsWith(".jpeg"))
                encoder = new JpegBitmapEncoder();

            if (filePath.EndsWith(".jpg"))
                encoder = new JpegBitmapEncoder();

            if (filePath.EndsWith(".png"))
                encoder = new PngBitmapEncoder();

            if (filePath.EndsWith(".tif"))
                encoder = new TiffBitmapEncoder();

            if (filePath.EndsWith(".tiff"))
                encoder = new TiffBitmapEncoder();

            if (filePath.EndsWith(".bmp"))
                encoder = new BmpBitmapEncoder();
            encoder.Frames.Add(BitmapFrame.Create(image));
            encoder.Save(fileStream);
        }
    }
    catch (Exception ex)
    {
  //      MessageBox.Show("Can not save! Make sure you have permission " + 
             //   "to access the folder and that image is not opened elsewhere");
    }
}

This method can save a BitmapSource type object to any specific Image type. I added all the encoders so that you can resuse the code appropriately in your App.

The workerClaer's  DoWork method is now changed as bellow.

void workerClear_DoWork(object sender, DoWorkEventArgs e)
{
    
    while (true)
    {
        System.Threading.Thread.Sleep(40000);
        if (!SongsMode)
        {
            this.Dispatcher.Invoke(
                    DispatcherPriority.Normal,
                    (System.Windows.Forms.MethodInvoker)delegate()
                    {/////////////
                        try
                        {
                            string fileName = WorkingPath.Path+"\\"+DateTime.Now.Date.ToShortDateString() + 
                              "_" + DateTime.Now.TimeOfDay.TotalMilliseconds + ".jpg";
                            Save(fileName, Image1.Source as BitmapSource);
                        }
                        catch (Exception ) {//MessageBox.Show(ex.ToString()) ;
                        }
                        //////////////
                        img = new BitmapImage(new Uri(System.IO.Path.GetFullPath("main.bmp")));
                        Image1.Source = img;
                    }
        );
        }
        workerClear.ReportProgress(2);
        System.Threading.Thread.Sleep(1000);
    }
    //throw new NotImplementedException();
} 

And you can see the working folder with captured image in the figure bellow. 

Figure 12: Saved Image in the directory

5.7 Finetuning the App for Ultrabook Use 

There are several sensors in Ultrabook that you can wisely use to add that little effect to your application. I will show a wonderful use of Ambient light sensor here. 

See while Kids play with the system, they will move their hand and fingers randomly over the screen which may lead to minimizing or closing down the application affecting their fun factor. So we will remove the control box and allow closing of the application by blocking the light entirely.

Light sensors are found just beside your camera. So when you block the camera panel with you hand, the App should be closed. 

Isn't that a fun? 

You can refer Working With Ambient Light Sensor  To kick start with WinRT ( Windows Runtime) environment that gives you the ability to trap sensors event and play with the sensors.

You can add LightSensor event handler in MainWindow() constructor as bellow

try
{ 
    ls = Windows.Devices.Sensors.LightSensor.GetDefault();
    ls.ReadingChanged += ls_ReadingChanged;
}
catch (Exception ex)
{
}  

And in ReadingChanged method  add this simple snippet of code.  

this.Dispatcher.Invoke(
                           DispatcherPriority.Normal,
                           (System.Windows.Forms.MethodInvoker)delegate()
{
    if (ls.GetCurrentReading().IlluminanceInLux < 2)
   {
       this.Close();
   }
}
);

Last thing you got to do here is  removing the control box from Window and disallow any resizing.

WindowStyle="None" ResizeMode="NoResize"  

Just adding the above two properties with your Window declaration in XAML part gives us the desired window state. 

You can work with other sensors, be creative and come up with effects that kids would love.

 

Remember it is one thing to have the sensors and knowing what they do and what they can do and it is entirely a different ball game  to use them seamlessly in your application to make it more attractive. Remember at the end of the day, sensors should add fun factor to your app and should not just be there just because they can be there! 

Ok. The good thing here is that the App really touched the customers it was intended to! I installed it in my Ultrabook and handed over the ultrabook to my 20 months old son ( courageous!). Now he simply loves playing it and he spends a lot of time hitting the keys and buttons and nudging in the screen. 

However as we always say, get your application being tested by real users. Observing my son to play with Kidsoo and the Ultrabook  presents few more cases here. 

 

a) Kids tend to hit the Ultrabook in any empty space they could find. 

b) They keep pulling the screen forth and back  

c)   They push the Ultrabook and try to move it. 

d) They love music and sound of any nature  

 

As a pure fun application for the kids, I though why not go little more innovative and do something silly but funny for them? The objective here is to enlighten the heart of your kid and allow him to be himself.  So I cameup with few more funny things.  

a) To have a framework that plays random piano tunes as they touch the screen.

b)  Have a color array with 360 colors and change the app color depending upon the compass position.

c) Load a library of information, say wild animals, or vegetables and  let the media be loaded when they pull the scrren nearer to them or push it.  

d) play funny sounds whenever they hit Ultrabook. ( Dont worry! Those tender hands cant damage your Ultrabook. Mine is still intact)    

 

 So lets kick start  another exciting round of fun.  We will start with point c) in above paragraph and try to implement the concept. Look, the advantage of an Ultrabook over tablet is that Ultrabook comes with the power of Laptop. So you have little worry about keeping resources in the memory ( if they do not consume a lot of it of course). So we will group the resources in more reusable way then say what we did with out buttons. We want to have several images and information regarding those images. 

 One of the things that WPF provides is a very strong data accessing and binding mechanism. You can bind any sort of media with any sort of controls with proper styling. As we already have the design of what our resources are, let us start ahead and do the coding.

 

Our resources will be set of images and some information associated with it. Hardcoding the images are not solution as it will take a recompilation, every time we want to update resource. So we will keep a dictionary of resources through XML file and will use List(Not ListBox ) to access it.  

 public class ImageEntity
    {
        #region Property

        public String ImagePath
        {
            get;
            set;
        }
        public String Info
        {
            get;
            set;
        }

        #endregion
    } 

 The main resource as you can see has image path and some information associated with it. You can choose to render the text along with speech synthesis. 

ImageEntity is data definition class and we will again keep our design strategy intact and would write data access in a different class. 

Let us have a class by name ImageView and dump the method for reading from XML file, casting the information to ImageEntity object and returning the list of information.

 public static List<ImageEntity> GetAllImagesData(string path)
        {
            
            try
            {
                // Load Xml Document
                XDocument XDoc = XDocument.Load(path);
                
                // Query for retriving all Images data from XML
                var Query = from Q in XDoc.Descendants("Image")
                            select new ImageEntity
                            {
                                ImagePath = System.IO.Directory.GetCurrentDirectory() + "\\" + Q.Element("ImagePath").Value,
                                Info= Q.Element("Info").Value
                            };
                // return images data
                
                return Query.ToList<ImageEntity>();
            }
            catch (Exception ex)
            {
                System.Windows.MessageBox.Show("Problem Loading this gallery"+ex);
                return null;
            }
        }   

 So the above code should take the path of the xml file where you manage the resources, search for ImagePath and Info sections, use a simple LinQ to select them as an object of ImageEntity and add the object to List.

At this point of time I want to draw your attention to one of the major issues with AppUp and Apps.

Observe the use of  System.IO.Directory.GetCurrentDirectory()  to get the curent directory. This code assumes that you are executing the application directly through it's exe or through the shortcut of the exe placed in either user start option or program directory.   In either cases, GetCurrentDirectory()  will return the actual installation directory of exe. 

However one of the preferred prerequisite of AppUp(though not mandatory) is that the app should be executed from AppUp client also. AppUp resides in an entirely different directory and therefore I would prefer you to use Environment.CurrentDirectory instead of GetCurrentDirectory() method. 

 Now let us see the structure of SML file. As you can see the query  looks for Image  element and extracts ImagePath and Info  elements from the block from top descendants. Therefore there should be a root element which should enclose the Image elements.   Let us call the root element as Images. The code here assumes that your images are present in the same directory that of the xml file. You can suitably modify that to keep Animal resources in an Animal directory and so on. 

 Here is the sample structure of the xml file. 

 <?xml version="1.0" encoding="utf-8" standalone="yes"?>
<Images>
<Image>
<ImagePath>rose.png</ImagePath>
<Info>
Rose Flower
</Info>
</Image>
<Image>
<ImagePath>monkey.png</ImagePath>
<Info>
Monkey Animal 
</Info>
</Image>
</Images>   

 So you can create many different xml files with different resources, like one that contains domestic animals, one that contains edibles and so on. 

 Another great thing with this approach is  we are not loading all the resources in the memory. Rather we are keeping only the path of the resources. We can  load  the images as par our logic from the path element. 

 Let us now have a MainWindow class member of type List<ImageEntity> say childImages and load the resources from xml at the constructor after InitializeComponent() call. 

childImages=ImageView.<ImageEntity>GetAllImagesData("myRes.xml");  

With image management in place, let us again go back to the sensor part and see how to make it work.  

 As par our discussion, we want to load random resources when the kid taps or hits the Ultrabook. In such a scenario  the Accelerometer Shaken event is shoot.   In order to lay a sensor framework which can be utilized in almost all the Ultrabook related Apps, we declare the    sensor objects in the class context and initialize all the sensors from a method called InitializeSensors(). It automatically checks the presence of the sensor and registers appropriate event handlers. You can download Kidsoo for Ultrabook with only ambient light sensor in action and other sensors being initialized.

 

Now it is only a matter of writing appropriate code in each sensor event handlers for the Apps to do interesting things par sensor event. Here is the sensor part with ambient light sensor in action for reader's reference.

  #region declare all sensors
        System.Collections.Generic.IList<string> sensors = new List<string>();
        Windows.Devices.Sensors.Compass cmp;
        Windows.Devices.Sensors.Gyrometer gyro;
        Windows.Devices.Sensors.Inclinometer inc;
        Windows.Devices.Sensors.LightSensor ls;
        Windows.Devices.Sensors.SimpleOrientationSensor sos; 
        #region Initialize sensors
                 
        void InitializeSensors()
        {
            
            
             
        Windows.Devices.Sensors.Accelerometer acc;
        #endregion
            try
            {
                acc = Windows.Devices.Sensors.Accelerometer.GetDefault();
                //acc.GetCurrentReading();
                acc.Shaken += acc_Shaken;
<pre>                sensors.Add("ACCELEROMETER");
            }
            catch (Exception ex)
            {
            }
            try
            {
                cmp = Windows.Devices.Sensors.Compass.GetDefault();
                cmp.GetCurrentReading();
                sensors.Add("COMPASS");
                cmp.ReadingChanged += cmp_ReadingChanged;
            }
            catch (Exception ex)
            {
            }
            try
            {
                gyro = Windows.Devices.Sensors.Gyrometer.GetDefault();
                gyro.GetCurrentReading();
                gyro.ReportInterval = 100;
                gyro.ReadingChanged += gyro_ReadingChanged;
                sensors.Add("GYROMETER");
            }
            catch (Exception ex)
            {
            }
            try
            {
                inc = Windows.Devices.Sensors.Inclinometer.GetDefault();
                //       inc.GetCurrentReading();
                inc.ReadingChanged += inc_ReadingChanged;
                sensors.Add("INCLINOMETER");
            }
            catch (Exception ex)
            {
            }
            try
            {
                ls = Windows.Devices.Sensors.LightSensor.GetDefault();
                ls.ReadingChanged += ls_ReadingChanged;
                sensors.Add("LIGHT SENSOR");
            }
            catch (Exception ex)
            {
            }
            try
            {
                Windows.Devices.Sensors.OrientationSensor os = Windows.Devices.Sensors.OrientationSensor.GetDefault();
                sensors.Add("ORIENTATION SENSOR");
            }
            catch (Exception ex)
            {
            }
            try
            {
                sos = Windows.Devices.Sensors.SimpleOrientationSensor.GetDefault();
                sensors.Add("SORIENTATION SENSOR");
                sos.OrientationChanged += sos_OrientationChanged;
            }
            catch (Exception ex)
            {
            }
            
        }
        #endregion
 #region Event HandlingMethods
        void sos_OrientationChanged(Windows.Devices.Sensors.SimpleOrientationSensor sender, Windows.Devices.Sensors.SimpleOrientationSensorOrientationChangedEventArgs args)
        {
            
        }
        void cmp_ReadingChanged(Windows.Devices.Sensors.Compass sender, Windows.Devices.Sensors.CompassReadingChangedEventArgs args)
        {
            
        }
        
        void acc_Shaken(Windows.Devices.Sensors.Accelerometer sender, Windows.Devices.Sensors.AccelerometerShakenEventArgs args)
        {
            
            
        }
        void inc_ReadingChanged(Windows.Devices.Sensors.Inclinometer sender, Windows.Devices.Sensors.InclinometerReadingChangedEventArgs args)
        {
            this.Dispatcher.Invoke(
                           DispatcherPriority.Normal,
                           (System.Windows.Forms.MethodInvoker)delegate()
                           {
                               double pitch = args.Reading.PitchDegrees;
                               double roll = args.Reading.RollDegrees;
                               if (pitch > 60)
                               {
                                   if (Math.Abs(roll) > 30)
                                   {
                                       if (roll < 0)
                                       {
                                           try
                                           { 
                                           }
                                           catch (Exception ex) { }
                                       }
                                   }
                               }
                           });
            //throw new NotImplementedException();
        }
        void ls_ReadingChanged(Windows.Devices.Sensors.LightSensor sender, Windows.Devices.Sensors.LightSensorReadingChangedEventArgs args)
        {
            this.Dispatcher.Invoke(
                           DispatcherPriority.Normal,
                           (System.Windows.Forms.MethodInvoker)delegate()
                           {
                               if (ls.GetCurrentReading().IlluminanceInLux < 2)
                               {
                                   this.Close(); ;
                               }
                           }
            );
            //throw new NotImplementedException();
        }
        void gyro_ReadingChanged(Windows.Devices.Sensors.Gyrometer sender, Windows.Devices.Sensors.GyrometerReadingChangedEventArgs args)
        {
            this.Dispatcher.Invoke(
                           DispatcherPriority.Normal,
                           (System.Windows.Forms.MethodInvoker)delegate()
                           {
                               try
                               {
                                   //labStatus.Content = string.Format("X=>{0},Y=>{1},Z=>{2}",args.Reading.AngularVelocityX,args.Reading.AngularVelocityY,args.Reading.AngularVelocityZ);
                                   if ((Math.Abs(args.Reading.AngularVelocityX) > 15) && (Math.Abs(args.Reading.AngularVelocityY) > 5) && (Math.Abs(args.Reading.AngularVelocityZ) > 5))
                                   {
                                   }
                               } 
                               catch (Exception ex) { } 
                           }
                                                   );
            //throw new NotImplementedException();
        } 
        #endregion  
    

One of the important things you can see here is the usage of    

  this.Dispatcher.Invoke(
                           DispatcherPriority.Normal,
                           (System.Windows.Forms.MethodInvoker)delegate()
                           {
});  

within all the sensor event handler. I want to add some quick note about this technique here. See sensors run in a separate thread than the UI thread. So if you want to update any UI element from sensor events, you should get access of the UI threads dispatcher and update the element. There is obviously an alternative route of using DependencyObjects and binding the objects with current MainWindow class through INotifyPropertyChange interface methods. However it depends upon your preference and style of coding as to what technique you should adopt. Pundits will suggest to go with DependencyProperty, however if you are a beginner ( As the article  assumes you are) then using event handling technique is an easy and preferred way. Once you are good enough understanding the sensor behavior, you can use DependencyPropery.

But for me, writing a separate class for every sensor, declaring it's properties and registering the property change becomes a boring task.   

     

 Now it is time to write a small method called DisplayResource()  That should randomly or serially display a resource from childImages list.

List<ImageEntity> childImages = new List<ImageEntity>();
        Random rndImg = new Random();
        void DisplayResource()
        {
            int n = rndImg.Next(childImages.Count);
            ImageEntity selectedIE = childImages[n];
            img = new BitmapImage(new Uri(selectedIE.ImagePath));
            Image1.Source = img;
            speaker.SpeakAsync(selectedIE.Info);
        } 

 Well from which event handler you want to call this method and in what cases is purely your choice. Give wings to your imagination and add spice to this method or sensor event handlers.

One interesting point that I see while I observe my kid playing with Kidsoo is that he loves sound and loves the music of "Twinkle-Twinkle". It should be a common case with all the kids. Why not modify the ImageEntity class to also hold a wav file and play that along with rendering the images? Like when you load the image of dog, it may also play the wave file that has the barking of dog.

Do let me know what are the things you have done to entertain the kids! 

 

 6.  Creating the Installer for your App 

Well, you have done the hard work, build your App, added effects, tested and now the App is ready to be installed. Now we need to look into installer issues. Before we proceed here are few quick things that Intel wants your Installer to do: 

a) There should be a shortcut in either Program Menu or Desktop or preferably both.

b) Installer must be signed with your Code Signing Certificate.

c) At the time of Uninstall, your application data must be wiped off.

I want to add an interesting thing here. Remember we discussed how your Apps are managed by windows 8?  You need to actually search the Apps to locate yours.  Search is populated from Program Menu and not from Desktop. So if you put the shortcut of your app in program menu, it will be searchable. 

The icon of the App appears in main windows 8 tiles if you create a desktop shortcut. So I will prefer both the options here.  

You have used Visual Studio 2012 for developing your App. However this version of VS does not come ported with any standard installer. So we will take the help of visual studio 2010. 

6.1 Creating a Custom Action for deleting application data 

Custom actions are basically either installer class or external executable that can be executed by the installer at Installation or Uninstalling process you  specify.

We assume that our Application folder i.e. \Integrated Ideas\Kidsoo may contain several files and in some of your Apps may contain several sub folder and each sub folder may contain several files. So we need to write a program that can wipe off these sub directories and files and the main App directory recursively and call the exe of that program from Uninstall option.

You can create a command line program in either VS 2010 or VS 2012 to achieve this.

//Here is the program for our Kidsoo App.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace DeleteAppPath
{
    class Program
    {
        static void Main(string[] args)
        {
            string settingsDirectory = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
            string s = settingsDirectory + "\\Integrated Ideas\\Kidsoo";
            if (Directory.Exists(s))
            {
                clearFolder(s);   
            }
            Directory.Delete(s);
        }
        static private void clearFolder(string FolderName)
        {
            DirectoryInfo dir = new DirectoryInfo(FolderName);
            foreach (FileInfo fi in dir.GetFiles())
            {
                fi.Delete();
            }
            foreach (DirectoryInfo di in dir.GetDirectories())
            {
                clearFolder(di.FullName);
                di.Delete();
            }
        }
    }
}

Once you run this, your application folder along with all it's sub folders and files will be wiped off.

6.2  Preparing Setup 

Start a setup project in visual studio 2010, let us say KidsooSetup.

Add files to your application folder. All the files in your Debug or Release directory should be here.

You also have Some extra folders in your App like Songs and Alphabet. Right click on Application folder and Add Folder. Once folder with appropriate name is created, copy the files from Apps debug/Alphabet folder to Installers Application Folder/Alphabet folder and so on.

Now your Application Folder looks as follows

 Figure 13: Setup application folder after adding the other folders

It is now time to create shortcut to desktop and program files:

Right click on the Apps executable and select "Create Shortcut" option. Once shorcut is created, copy that to User's Desktop. Create another Shortcut and Copy that to User's program Menu.

You can also create a custom App icon and use these icons for shortcut. Your icons must be in Application directory. Once you have created the shortcuts, go to User's Desktop , click on the Shortcut file, on the property editor you will see an Icon property. Just browse and select the specific Icon.

 6.3 Adding Custom Action for Uninstall Process

You already have the custom installer Exe for your App by name DelAppPath. First Load that in Application folder by adding file. Click on Custom Action as seen in image bellow.

 

 Figure 14: Custom Action in VS 2010 Setup project

You can see an Uninstall option. Right click on Uninstall and select Add Custom Action. Browse and select DeleteAppPath.exe for custom action.

Now select the exe and change 'Installer Class' to false as bellow.

 

 Figure 15: Setting Custom Action for Uninstall

That is all that you needed to do to create an installer. Now build this setup project. You will see KidsooSetup.msi inside debug folder of your setup project.

However I strongly recommend to update the Setup settings and add product name, manufacturer url, support url and Product version in Setup setings.

7. Signing Installer with Code Signing Certificate

Once your certificate is sent by Comodo, open your email in Firefox, and click on the link. However you will not find any physical certificate. Remember we discussed that the certificate is bind with browser. So you need to now open Tools->Options, in the advanced tab select View Certificates.

You will see the certificate as bellow.

 

 Figure 16: Code Signing Certificate in Comodo

You need to backup this certificate. Remember while backing up, it will ask you a password, let us say YOUR_PASSWORD. Do not ever by any means forget this password. Otherwise your certificate is of no use. After backup, the file looks something like this.

Figure 17: Certificate after backup.

Great. Now it's time to sign the installer. Visual studio comes ported with digital signing tool and it needs to be done through Visual Studio command prompt. I have written a small batch script to ease up the process.

Create a batch file say 'Sign.bat' and add following Line

signtool sign /f Comodo-IICS.p12 /p YOUR_PASSWORD KidsooSetup.msi.

copy the certificate,  and the bat file in your Setup project's debug directory.

Open visual studio command prompt , change the directory to your setup project's debug directory and enter command 'sign' without quotes. That is it! 

Now head straight to AppUp and submit your App for validation. Ok and if you are using 'Ultrabook' in App's name or description don't forget to add (TM) with it. 

8. Conclusion

This article is an effort to guide the beginners to get started with AppUp in general and Ultrabook  App publishing in specific. This uses a simple App for Kids to demonstrate the important factors and concepts that comes into play for App development and making for Ultrabook environment.

I could have written about my submission ImageGrassy, but I felt doing an App from scratch gives me more flexibility in terms of a tutorial. I have also uploaded the zip files of every step for you to distinguish between the stages and work on each stage in your own way. Also there are many snippets presented in this article that are not embedded in the main code for you to figure that out and use.

I have tried to cover most of the areas where I struggled at the initial stage and have tried to explain in detail. However if I have missed anything, you are free to suggest the sections and changes.

Kidsoo is a big project for me which is scheduled to be released in AppUp by March with huge features and entertaining and amusing stuff.  But even in it's current form Kids would just love the application. Hope I am able to properly show you the path for App development and publishing for Ultrabook. 

 

9. Disclaimer 

All media files used in the sample application may be subjected to copyright. I do not have copyright use to use these media files for commercial usage. I request you to figure out copyright of the files before using them.  

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Grasshopper.iics
CEO Integrated Ideas
India India
gasshopper.iics is a group of like minded programmers and learners in codeproject. The basic objective is to keep in touch and be notified while a member contributes an article, to check out with technology and share what we know. We are the "students" of codeproject.
 
This group is managed by Rupam Das, an active author here. Other Notable members include Ranjan who extends his helping hands to invaluable number of authors in their articles and writes some great articles himself.
 
Rupam Das is mentor of Grasshopper Network,founder and CEO of Integrated Ideas Consultancy Services, a research consultancy firm in India. He has been part of projects in several technologies including Matlab, C#, Android, OpenCV, Drupal, Omnet++, legacy C, vb, gcc, NS-2, Arduino, Raspberry-PI. Off late he has made peace with the fact that he loves C# more than anything else but is still struck in legacy style of coding.
Rupam loves algorithm and prefers Image processing, Artificial Intelligence and Bio-medical Engineering over other technologies.
 
He is frustrated with his poor writing and "grammer" skills but happy that coding polishes these frustrations.
Group type: Organisation

83 members

Follow on   Twitter   Google+

Comments and Discussions

 
QuestionSanford.dll - missing? Pinmemberdyma14-Jan-13 22:17 
AnswerRe: Sanford.dll - missing? PingroupGrasshopper.iics14-Jan-13 22:51 
GeneralRe: Sanford.dll - missing? Pinmemberdyma15-Jan-13 0:27 
QuestionHmmmm - app certificate PinprotectorPete O'Hanlon28-Dec-12 10:14 
AnswerRe: Hmmmm - app certificate PinmemberRanjan.D28-Dec-12 12:09 
AnswerRe: Hmmmm - app certificate PingroupGrasshopper.iics28-Dec-12 12:24 
QuestionMetro PinmemberDewey27-Dec-12 23:35 
AnswerRe: Metro PingroupGrasshopper.iics27-Dec-12 23:42 
SuggestionSmall suggestion while creating installers PinmemberRanjan.D27-Dec-12 15:50 
GeneralRe: Small suggestion while creating installers PingroupGrasshopper.iics27-Dec-12 16:33 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web01 | 2.8.140916.1 | Last Updated 14 Jan 2013
Article Copyright 2012 by Grasshopper.iics
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid