Porting Android* Touch to Windows* 8 UI (C#)

By David Medawar

Porting Android* Touch to Windows* 8 UI (C#)

Objective

This article describes how developers can port pre-existing Android touch code to Windows 8 UI. This document assumes that developers are familiar with writing touch code for Android. In the porting exercises, C# is the target programming language. APIs listed are current as of both Ice Cream Sandwich (ICS) and Windows 8 Release Preview. These code samples were written using the Visual Studio* 2012 RC IDE.

1. Introduction

More and more, touch is becoming a popular usage model for computing. Touch feels natural, is simplistic, can be used on any device, and doesn’t require bringing along a mouse when on the go. While touch is intuitive, the consumer needs are ever changing just like technology as a whole. Change often brings a migration from one OS to another. This paper targets developers porting preexisting Android touch code to the Windows 8 UI solution.

The paper is suitable for developers new to touch and those who are experienced. Simple single-touch porting is discussed as well as the more challenging multi-touch. There are two perspectives dealing with touch: designing the code, and then writing the supporting back-end (or “code-behind”) code. Both perspectives are covered in this paper; XAML design view is discussed along with the supporting C# code.

The APIs listed are current as of Ice Cream Sandwich (ICS), Windows 8 Release Preview, and the Visual Studio 2012 RC IDE. Please note that in the future, these APIsmay change.

2. Prerequisite: Migrating the Design from XML to XAML

Before delving into the code-behind differences regarding touch, this paper begins with migrating Android XML to Windows 8 UI XAML. Note that this section doesn’t exhaustively list all scenarios but does provide a few useful examples along with additional resources.

1. Extend the View class with a custom view class and create the corresponding custom XML file (refer to OnTouchEvent API)

2. Use the project main.XML file (refer to OnTouch API)

In the case of Windows 8 UI, when working with C#, XAML file keywords are used, regardless if developers want to use simple keywords for easy touch detection or to create a custom manipulation (discussed later). The similarity to Android is that developers can also add and use custom XAML files, such as defining a special app layout, etc.

Note that XAML is a derivative of XML. It is based on XML markup, and Microsoft has used it for one method of content presentation in Windows 8. It is at the heart of UI Elements in Windows 8. The full differences and porting scenarios between XML and XAML are outside this document’s scope, but developers can start with this great source for an XAML overview: http://msdn.microsoft.com/en-us/library/ms752059.aspx

When creating a new C# Windows 8 UI project in Visual Studio, multiple XAML files are generated. Here they are:

  • App.xaml: the application entry point, used to invoke other XAML pages
  • GroupDetailPage.xaml
  • GroupedItemsPage.xaml
  • ItemDetailPage.xaml

Refer to this link for more information on page navigation:
http://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh771188.aspx

2a. Header Differences

This section shows small code snippets for both XAML and XML headers. Sample main.XML Android code may look like the following:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
<Button android:text="Button" android:id="@+id/button1" android:layout_width="wrap_content" android:layout_height="wrap_content"></Button>
<TextView android:text="TextView" android:layout_height="wrap_content" android:id="@+id/textView1" android:layout_width="fill_parent"></TextView>
</FrameLayout>

The XML version is specified along with the namespace, and the parent layout parameters are defined. Note that within the parent, FrameLayout, Button and TextView child objects are described. In the case of Windows 8 UI App.xaml, this is what the developer may see:

<Application
    x:Class="MetroMathMania.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:MetroMathMania"
    xmlns:localData="using:MetroMathMania.Data">

    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>

                <!--
                    Styles that define common aspects of the platform look and feel
                    Required by Visual Studio project and item templates
                 -->
                <ResourceDictionary Source="Common/StandardStyles.xaml"/>
            </ResourceDictionary.MergedDictionaries>

            <!-- Application-specific resources -->
            
            <x:String x:Key="AppName">MetroMathMania</x:String>
        </ResourceDictionary>
    </Application.Resources>
</Application>

Since this XAML code is the application entry point, note that by default, it doesn’t specify the use of UI Elements. Other navigation pages mentioned above handle that job, such as the following:

<common:LayoutAwarePage
    x:Name="pageRoot"
    x:Class="MetroMathMania.GroupDetailPage"
    DataContext="{Binding DefaultViewModel, RelativeSource={RelativeSource Self}}"
    IsTabStop="false"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:MetroMathMania"
    xmlns:data="using:MetroMathMania.Data"
    xmlns:common="using:MetroMathMania.Common"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <Page.Resources>

        <!-- Collection of items displayed by this page -->
        <CollectionViewSource
            x:Name="itemsViewSource"

        <!-- Back button and page title -->
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition Width="*"/>
            </Grid.ColumnDefinitions>
            <Button x:Name="backButton" Click="GoBack" IsEnabled="{Binding Frame.CanGoBack, ElementName=pageRoot}" Style="{StaticResource BackButtonStyle}"/>
            <TextBlock x:Name="pageTitle" Text="{Binding Title}" Style="{StaticResource PageHeaderTextStyle}" Grid.Column="1"/>
        </Grid>

While parent layouts and UI elements such as buttons appear in both XML and XAML, note the organizational differences of namespace entities. Specifically, it’s important to note that when creating a new Windows 8 UI project, the “Common” directory contains many auto-generated definitions (similar to the “res” folder in Android):

In Windows 8 UI, the default layout and resource types come from files in Common. It is strongly advised that developers do not modify these files but instead add additional custom files if needed for application-specific defines. Recall that above, in App.xaml, there was a section for specifying the use of a Resource Dictionary. The default parameter selects what is already defined in the Common directory, and if needed, developers can create and use a custom dictionary instead.

2b. Specifying Touch in XAML

Typically, in Android, touch is specified programmatically only with Java*; XML files don’t specify touch event handlers. In Windows 8 UI however, the practice is for XAML keywords to be used. Then, the backend C# code defines the event handler function bodies. Take a look at some of these keywords and an overview of handling touch in Windows 8 UI XAML files:

http://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh465387.aspx#intro_to_touch_input

In Windows 8 UI, touch can be thought of as defined at three levels: simple touch keyword usage, pointer event definition, and custom manipulation events. XAML keywords are available for all levels, and the link above lists these.

2c. Additional XAML Resources

The following links provide additional XAML tutorials:

Simple Canvas use in XAML (useful for coordinate positioning of UI Elements): http://www.dailyfreecode.com/code/canvas-layout-xaml-209.aspx

Simple XAML tap example (see Section 2): http://software.intel.com/en-us/articles/enabling-touch-in-windows-8-metro-style-apps-with-c/

3. Porting Touch Code: Java to C#

The previous sections focused on application design differences between XML and XAML markup files. Here, this paper digs deeper: looking at porting Java–based event handler code to C#.

3a. Porting Simple Touch Handler: Image Example

This section starts with the simple event handler basics: how to port an Android Java-based touch event handler to C# in Windows 8 UI.

In Android, UI Elements, such as Button, derive from the parent View class. Likewise, in Windows 8 UI, viewable objects derive from UIElement. Refer to the following link as reference: http://msdn.microsoft.com/en-us/library/windows/apps/windows.ui.xaml.uielement

Now, suppose that an Android application, ASPV, utilizes two touch scenarios:

      Handles touch when main View is touched
        Handles touch when custom View class element is touched

    ASPV doesn't specify touch handlers in its XML; this is all done programmatically. For 1) above, the OnTouch API is used and requires the definition of an event listener. See the following snippet:

    /** A Simple Photo Viewer class **/
    /** This app is a simple photo viewer for Android **/
    /** using simple touch gestures to navigate through album **/

    public class ASPV extends Activity implements OnTouchListener{
        View this_view;


    /** get the view associated with this Activity's handle **/
            this_view = getWindow().getDecorView().findViewById(android.R.id.content);


    this_view.setOnTouchListener(new OnTouchListener()
           {
               public boolean onTouch(View v, MotionEvent event)
               {
                  
                   /** get the touch coordinates **/
                   int x = (int) event.getX();
                   int y = (int) event.getY();
                  
                   /** get exit button coordinates (truncated to int) **/
                   int exit_button_x = (int) exit_button.getX();
                   int exit_button_y = (int) exit_button.getY();
                  
                   /** check if use touch is within bounds of exit button **/

    When porting to Windows 8 UI, developers use two files: the desired XAML file and its corresponding .cs C# source file. Developers begin by first specifying the touch event handler name in XAML and then writing the backend C# code in the .cs file. Unlike the Android code sample, there is no need to explicitly register a listener as the XAML already specifies the designated handler. Thus, developers may incorporate touch for an Image such as follows:

    In file.xaml:

    <!-- Row 1 cells for the game table-->
            <Image x:Name="c11"  Height="100"  Width="100" Tapped="Image_Tapped" Canvas.Top="0" Canvas.Left="100" ManipulationMode="All" />
            <Image x:Name="c12"  Height="100"  Width="100" Tapped="Image_Tapped" Canvas.Top="0" Canvas.Left="200" ManipulationMode="All" />
            <Image x:Name="c13"  Height="100"  Width="100" Tapped="Image_Tapped" Canvas.Top="0" Canvas.Left="300" ManipulationMode="All" />

    Note the specification of the touch event handler name, Image_Tapped. Here is the corresponding C# support code:

    In file.xaml.cs:

    //called when one of the game images is clicked
    private void Image_Tapped(object sender, TappedRoutedEventArgs e)
    {
          //find out which game object was clicked
          FrameworkElement source_image = e.OriginalSource as FrameworkElement;

          for (int row = 0; row < ROWS; row++)
          {
               for (int col = 0; col < COLS; col++)
               {
                   //we found a match!
                   if (source_image.Name.Equals(images[row, col].Name))
                   {

    Like the View parameter passed into the Android handler, the generic sender object can be used to identify which UIElement was tapped. In this case, the UIElement is specifically an Image type.

    For 2) above, the semantics in the Windows 8 UI case can be met by creating a custom XAML file. Then, other XAML files would need to be updated so that the user can actually navigate to the custom XAML page.

    3b. Porting for Pointer Identification

    The next porting exercise is more involved. When dealing with multi-touch, it's important to track the ID of the pointer used for gesture recognition, etc. This document assumes that "pointer" means "finger".

    In Android, developers may want to handle pinch/zoom as an example. Tracking pointer positions on the screen can start with some defines:

        /** tracks starting and ending positions of the pointer devices **/
        int primary_x_start, primary_y_start, primary_x_end, primary_y_end;
        int secondary_x_start, secondary_y_start, secondary_x_end, secondary_y_end;

        /** track pointer IDs **/
        int primary_ID = -1, secondary_ID = -1;

    Here is one important note; in Android, pointer IDs may change. When pressing a finger down, the ID issued to the finger may not equate to the ID received when that finger was last pressed down. However, the ID is guaranteed not to change until the finger is released. Thus, developers must continually track pointer IDs.

    In this Android example, View class is extended to override OnTouchEvent:

    // it's now time to override touch events for when user 
    // touches the slider **/
    @Override
    public boolean onTouchEvent(MotionEvent event)
    {		
      int event_type = event.getAction();
    	switch (event_type & MotionEvent.ACTION_MASK)
    	{
    		case MotionEvent.ACTION_DOWN:
    		case MotionEvent.ACTION_POINTER_DOWN:
    		{				
    			start_x = (int) event.getX();
    			start_y = (int) event.getY();
    			
    			/** need to determine the index of the pointer and see if it is 
                                                         the primary or secondary finger **/
    			int index = (event.getAction() & MotionEvent.ACTION_POINTER_ID_MASK) >> 
                                                        MotionEvent.ACTION_POINTER_ID_SHIFT;
    			int id = event.getPointerId(index);
    				
    			if(event_type == MotionEvent.ACTION_DOWN)
    			{
    				primary_ID = id;
    					
    				primary_x_start = start_x;
    				primary_y_start = start_y;
    			}
    				
    			else //ACTION_POINTER_DOWN
    			{
    				secondary_ID = (event_type >> MotionEvent.ACTION_POINTER_ID_SHIFT);					
    			
    				secondary_x_start = start_x;
    				secondary_y_start = start_y;
    			}
    						
    			legal_sliding = false; /** assume an illegal move of the slider 
                                                                 unless proven otherwise **/
    				
    			if(Math.abs(slider_left - start_x) < 80) /** if horizontal position is 
                                                                  "close enough" to slider **/
    			{
    				if(Math.abs(slider_bottom - start_y) < 80) /** if vertical position is 
                                                           "close enough" to slider **/
    					legal_sliding = true; /** the user has begun a legal touch event for 
                                                                        moving slider knob **/
    			}
    				
    			return true;
    		}
    

    This snippet uses MotionEvent to capture pertinent information when fingers are pressed down on the screen. Positional coordinates are captured, and a mask is used to determine if the primary or secondary pointer is pressed down. When a multi-touch event begins, the first pointer to press down is considered to be primary.

    Similarly, Windows 8 UI allows developers to handle pointer events. Take a look at this tutorial. It gives a great rundown on pointer events in Windows 8 UI along with deciphering pointer IDs.

    http://msdn.microsoft.com/en-us/library/windows/apps/xaml/jj150606.aspx

    The subtle difference is that unlike Android's use of MotionEvent, Windows 8 UI uses PointerRoutedEventArgs to determine which pointer was invoked. Further, the Windows 8 UI solution doesn't use a bit mask for identifying the pointer; a simple API call fetches the appropriate ID.

    Notice how in this example, the event argument passed into the Windows 8 UI handler is specifically PointerRoutedEventArgs. This object type is specific to how touch will be handled in the event handler.

    3c. Custom Manipulation Events: the Windows 8 UI Way

    Now, this paper unveils the trickiest example thus far: migrating from Android gesture recognition to manipulation events in Windows 8 UI. Typically, a gesture listener is used in Android, and this usage builds on the already mentioned MotionEvent object type. Feel free to look at the following link as reference if needed:

    http://developer.android.com/reference/android/view/GestureDetector.html

    The following is another useful link that provides an excellent code example for the Android side:

    http://www.androidsnippets.com/gesturedetector-and-gesturedetectorongesturelistener

    Notice an important point: like overriding OnTouchEvent as mentioned above, recognizing gestures requires the use of defining a listener. Furthermore, the various overridden handlers based on gesture type all use the basic MotionEvent object for recognition.

    This is where Windows 8 UI requires the most porting changes when compared to the previous document sections. Windows 8 UI doesn't simply use just one object type for its various manipulation events; it depends on the phase of the manipulation. This involves when a manipulation starts, when an object is dragged (delta event), when the manipulation is completed, and so on. Refer to the following link for a description of the various manipulation stages and corresponding object types:

    http://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh465387#using_manipulation_events

    A code example for Windows 8 UI is now introduced. It will only use a subset of the manipulation event classes for simplicity. A game scenario may involve the user first pressing a finger on a game image on the screen, dragging it, and then releasing a finger in such a way that the image should be flung across the screen. For some time, the image will undergo a kinetic state where its speed magnitude is greater than its initial state due to the fling gesture. The object speed slows down over time, and eventually, the object returns to inertia.

    In Windows 8 UI, the scenario can be implemented as follows. First, it is mandatory that the manipulation mode is explicitly enabled in the XAML:

    <Image x:Name="c13"  Height="100"  Width="100" Tapped="Image_Tapped" Canvas.Top="0" Canvas.Left="300" ManipulationMode="All" />

    This is important because by default, the ManipulationMode property is "None" which means that manipulations will not occur.

    Next, as previously mentioned, a subset of the manipulation events will be used. The following supporting C# code indicates what is called based on specific manipulation events:

    images[x, y].ManipulationStarted += manip_start;
    images[x, y].ManipulationDelta += manip_delta;
    images[x, y].ManipulationInertiaStarting += manip_complete;

    As one may guess, to the right of the equations, the code specifies the actual routine names that handle the events.

    Now, when manipulation begins, the code may look as follows:

    //invoked when user begins a gesture on game tile
            void manip_start(object sender, ManipulationStartedRoutedEventArgs e)
            {
                //clear fling velocity components
                vel_x = 0;
                vel_y = 0;
                
                //grab the image (game tile) where manipulation began!!!
                img = sender as Image;
    
                //retain image location in canvas at start of gesture
                initial_x = Canvas.GetLeft(img);
                initial_y = Canvas.GetTop(img);
    
                //find array position of the image
    
                for (x = 0; x < images.GetLength(0); x++)
                {
                    for (y = 0; y < images.GetLength(1); y++)
                    {
                        if (img.Equals(images[x,y]))
                        {
                            //we found the match...update the array positions
                            img_x = x;
                            img_y = y;
                            break;
                        }
                    }
                }
    

    In this snippet, the image that was pressed is retrieved and then searched in the array of images. This is useful as the image that was pressed should be distinguished from others. Again, notice how the second parameter passed into the routine is once again different than previously shown; it's pertinent to this specific event type.

    This paper won't exhaustively show all manipulation scenarios, but a point should be made as to object kinetics. Often times, developers may want to retrieve velocity information that relates to the specific gesture that the user performed when pressing, dragging, and finally releasing an image. This allows for a real-life experience where the user expects that the object will follow the trajectory based on how the image was released.

    To do this, consider the delta manipulation, which occurs while the game object is dragged. Note that this routine is frequently called so long as the image is not released. Here is sample code demonstrating how to update image position along with maintaining velocity information.

    //invoked when user continues a gesture on game tile (eg: dragging a game tile)
    
         void manip_delta(object sender, ManipulationDeltaRoutedEventArgs e)
         {
             //allow user to drag the image before letting finger go 
    
             if (!e.IsInertial) //only update position if user hasn't yet flung tile
             {
                 pos_x = initial_x;
    
                 if (e.Cumulative.Translation.X >= 0)
                     pos_x += Math.Min(e.Cumulative.Translation.X, PERIMETER_MAX); 
    
                 else //moved in negative axis direction
                     pos_x -= Math.Max(e.Cumulative.Translation.X, PERIMETER_MAX); 
    
                    …
    
                 Canvas.SetLeft(images[img_x, img_y], pos_x);
                 Canvas.SetTop(images[img_x, img_y], pos_y);
    
    
                 //update sliding velocity
                 vel_x = e.Velocities.Linear.X;
                 vel_y = e.Velocities.Linear.Y;
    

    In Windows 8 UI, rotational velocity can be retrieved as well as various other parameters. Manipulation events also support multi-touch. Refer to the link previously mentioned for more information as further examples are outside this document’s scope.

    4. Summary

    This paper showed the basic framework for porting Android touch code to Windows 8 UI using C#. Importantly, this paper discussed how both design and code-behind changes should be considered. The examples started with migrating XML to XAML, and then finally writing the event handlers in C#. The difficulty for the porting exercises ranged from a simple touch handler to writing custom manipulation events for more advanced gesture detection, making this document suitable for both beginners and experienced touch designers alike. At the end of the day, Windows 8 UI is yet another great framework that covers all aspects of what users expect with the touch experience. Feel free to now play with the code and experience what Windows 8 UI has to offer!

    About the Author
    David Medawar is a Software Engineer with Intel Corporation. He has been with the company for the last seven years, and his former development experience includes System BIOS and boot-loader enabling. David currently works on app enabling for Windows 8 and Android.

    Notices
    INFORMATION IN THIS DOCUMENT IS PROVIDED IN CONNECTION WITH INTEL PRODUCTS. NO LICENSE, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, TO ANY INTELLECTUAL PROPERTY RIGHTS IS GRANTED BY THIS DOCUMENT. EXCEPT AS PROVIDED IN INTEL'S TERMS AND CONDITIONS OF SALE FOR SUCH PRODUCTS, INTEL ASSUMES NO LIABILITY WHATSOEVER AND INTEL DISCLAIMS ANY EXPRESS OR IMPLIED WARRANTY, RELATING TO SALE AND/OR USE OF INTEL PRODUCTS INCLUDING LIABILITY OR WARRANTIES RELATING TO FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABILITY, OR INFRINGEMENT OF ANY PATENT, COPYRIGHT OR OTHER INTELLECTUAL PROPERTY RIGHT.

    UNLESS OTHERWISE AGREED IN WRITING BY INTEL, THE INTEL PRODUCTS ARE NOT DESIGNED NOR INTENDED FOR ANY APPLICATION IN WHICH THE FAILURE OF THE INTEL PRODUCT COULD CREATE A SITUATION WHERE PERSONAL INJURY OR DEATH MAY OCCUR.

    Intel may make changes to specifications and product descriptions at any time, without notice. Designers must not rely on the absence or characteristics of any features or instructions marked "reserved" or "undefined." Intel reserves these for future definition and shall have no responsibility whatsoever for conflicts or incompatibilities arising from future changes to them. The information here is subject to change without notice. Do not finalize a design with this information.

    The products described in this document may contain design defects or errors known as errata which may cause the product to deviate from published specifications. Current characterized errata are available on request.

    Contact your local Intel sales office or your distributor to obtain the latest specifications and before placing your product order.

    Copies of documents which have an order number and are referenced in this document, or other Intel literature, may be obtained by calling 1-800-548-4725, or go to: http://www.intel.com/design/literature.htm

    Intel and the Intel logo are trademarks of Intel Corporation in the U.S. and other countries.

    This sample source code is released under the Intel Sample Source Code License Agreement

    *Other names and brands may be claimed as the property of others

    Copyright© 2012 Intel Corporation. All rights reserved.

    Para obtener información más completa sobre las optimizaciones del compilador, consulte nuestro Aviso de optimización.