Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Android Wearable: Creating A Simple Survey Feature Using Xamarin

0.00/5 (No votes)
10 Jun 2016 1  
In this article, you will learn how to create a simple Survey feature using Xamarin for Android Wearable.

Introduction

Having the opportunity to work with Android wearables, particularly smart watches, is very exciting as this is getting more popular nowadays. Building mobile and wearable device apps is not as complex as you may think. I admit that at first, I was kind of afraid when I was assigned to explore and build apps for mobile and wearable, but using the right tools and technologies makes life easier for me to build those apps and prototypes.

Ermm.. Right Tools?

Yes, and I was referring to the awesome Xamarin. Xamarin allows you to build cross-platform apps for Android, iOS and Windows and it uses C# as the backend language. They also introduced Xamarin Forms which allows you to easily create native UI layouts that can be shared across Android, iOS, and Windows Phone. For as long as you know C#, then creating the logic for your app is easy because you are already familiar with the syntax and most of all the .NET libraries. The only learning curve that you will need to take when transitioning from web to mobile is that you will need to know and understand how Android, iOS and Windows platform works and how each framework interpret stuff. To trim down a bit of that learning curve, I have decided to use Xamarin and Visual Studio for the following reasons:

  • Xamarin is now fully integrated with the latest Visual Studio release (VS 2015 as of this writing).
  • Xamarin allows you to build cross-platform apps (iOS, Andriod and Windows app) using C#.
  • I am an experienced C# developer.
  • I am more familiar with Visual Studio development tools.
  • I don't need to learn how to use other frameworks, editors, tools and other programming languages to build native apps.
  • I can take advantage of the cool features provided by Xamarin such as cloud testing and app monitoring.
  • Xamarin and Visual Studio are quite popular and stable platform for building real world apps.
  • Xamarin has its own dedicated support site. So when you encounter any problem during your development, you can easily post your query to their dedicated forums.

I'm writing this article so anyone that might get interested in mobile app development can reference this if they need a simple working app that requires some kind of a questionnaire to collect data from end users. This article will walk you through on building a simple survey questionnaire feature that can be integrated in your Android smart watch app. Generally, a survey is a data gathering method that is utilized to collect, analyze and interpret the views of a group of people.

Before you go any further, make sure that you have the necessary requirements for your system and your development environment is properly configured. For setting up the development environment in Visual Studio, please refer to my previous article here: Getting Started With Android Wearable Using Xamarin and Visual Studio

Let's Get Started!

This time, I'm going to use Visual Studio 2015 with Xamarin version 4.0. Open Visual Studio 2015 and then create a new project by selecting File > New > Project. It should bring up the following dialog below:

Figure 1: Visual Studio Project Templates

Under Templates, select Visual C# > Android > Wear App (Android). Name your app to whatever you like but for the simplicity of this demo, I just named it as "Xamarin.Messaging". Click OK to let Visual Studio generate the necessary files for the application. You should now be able to see the following screen:

Figure 2: The Solution Project

The first thing we need is to add the needed images for our app. In this example, I've added two images under Resources >Drawable folder as shown below:

Figure 3: Resources

The images we’ve added will be used as the background for Buttons and the other is for the question indicator.

Setting Up the Model

Now, add a new class by right-clicking on the solution project and then select Add > Class. Name the class as "Messaging" and add the following properties below:

using System;  
  
namespace Xamarin.Messaging  
{  
    public class Message  
    {  
        public int MessageID { get; set; }  
        public int MemberID { get; set; }  
        public short MessageTypeID { get; set; }  
        public short IconID { get; set; }  
        public string MessageText { get; set; }  
        public bool IsQuestion { get; set; }  
        public string SelectedAnswer { get; set; }  
    }  
}  

The class above represents our view model that mimics the database table schema. But keep in mind that I will not be using any database here for simplicity.

The next step is to add a new class file called "Messaging". This file will contain the logic for our survey feature. Here's the code block below:

using System;  
using System.Collections.Generic;  
using System.Linq;  
using Android.OS;  
using Java.Util;  
  
namespace Xamarin.Messaging  
{  
    #region MESSAGING LOGIC  
    public class Messaging  
    {  
  
        public bool isMessageAvailable { get; set; }  
  
        private Queue<Message> Messages { get; set; }  
        private List<Message> AnsweredMessages { get; set; }  
        private List<Message> RawMessages { get; set; }  
  
        public Messaging()  
        {  
            this.Messages = new Queue<Message>();  
            this.AnsweredMessages = new List<Message>();  
        }  
        public enum MessageIconType { None = 0, Question }  
        public enum MessageType { None = 0, Question, Information }  
        public void Add(Message message) { this.Messages.Enqueue(message); }  
  
        public void Update(Message message)  
        {  
            this.Messages.Dequeue();  
            this.AnsweredMessages.Add(message);  
        }  
  
        public Queue<Message> GetMessages()  
        {  
            var messages = GetMessagesByMemberID(1);  
            messages.ToList().ForEach(x => this.Add(x));  
            return this.Messages;  
        }  
  
        private List<Message> GetMessagesByMemberID(int memberID)  
        {  
            this.RawMessages = new List<Message>();  
            this.RawMessages.Add(new Message() { MessageID = 1, MemberID = 1, 
            MessageTypeID = 2, IconID = 1, MessageText = "Do you drink beer?", 
            IsQuestion = true, SelectedAnswer = "" });  
            this.RawMessages.Add(new Message() { MessageID = 2, MemberID = 1, 
            MessageTypeID = 2, IconID = 2, MessageText = "Do you like to code?", 
            IsQuestion = true, SelectedAnswer = "" });  
            this.RawMessages.Add(new Message() { MessageID = 3, MemberID = 1, 
            MessageTypeID = 3, IconID = 0, MessageText = "Thank you.", 
            IsQuestion = false, SelectedAnswer = "" });  
            return this.RawMessages;  
        }    
    }  
    #endregion  
 
    #region RUNNABLE  
    public class MessageTimerTask : TimerTask  
    {  
        MessagingRunnableTask MRT;  
        public MessageTimerTask(MessagingRunnableTask mrt) { MRT = mrt; }  
        public override void Run()  
        {  
            MRT._handler.Post(new Action(() =>  
            {  
                RedirectToView(MRT);  
            }));  
        }  
  
        void RedirectToView(MessagingRunnableTask mrt)  
        {  
            MainActivity m = new MainActivity();  
            if (mrt._isSurveryDone)  
                m.SetView("Home");  
            else  
                m.SetView("Survey");  
        }  
    } 
 
    public class MessagingRunnableTask  
    {  
        MessageTimerTask _showMessageTask;  
        Timer _showMessageTimer;  
        public Handler _handler;  
        public bool _isSurveryDone = false;  
  
        public MessagingRunnableTask() { _handler = new Handler(); }  
        public void ProcessMessageTask(int waitInMilliseconds, bool isDone)  
        {  
            _isSurveryDone = isDone;  
            _showMessageTask = new MessageTimerTask(this);  
            _showMessageTimer = new Timer();  
            _showMessageTimer.Schedule(_showMessageTask, waitInMilliseconds);  
        }  
    }  
    #endregion  
}  

The Messaging class houses some properties and methods that will be used in the application. The main idea here is to use Queue<T> for storing the list of messages from the data source so we can easily pop-out the message based on the sequence of data from the queue. The Add() method basically adds new message to the queue. The Update() method removes an existing message from the Message queue object, and add a new message to the AnsweredMessages list object. The GetMessages() method gets all messages that are available for a particular user. The GetMessagesByMemberID() is a method where we set some dummy data to test our survey feature. In real scenarios, you may need to get the data from your database, or from a service.

You may also have noticed that the file also contains the implementation for runnable. This is to schedule the survey questionnaire within a given period of time. This means that you can control as to when to prompt the users with the survey questions.

Adding the Layout

Now add a new .AXML file under Resources > Layout. Name the layout as "MessageView" as shown in the figure below:

Figure 4: Adding a new View

After that, switch to "Source" view in the designer and then add the following markup below:

<?xml version="1.0" encoding="utf-8" ?>  
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
                android:orientation="vertical"  
                android:layout_width="fill_parent"  
                android:layout_height="fill_parent"  
                android:layout_centerHorizontal="true"  
                android:maxLines="10"  
                android:scrollbars="vertical">  
    <ImageView android:layout_centerHorizontal="true"  
               android:layout_marginTop="15.0dp"  
               android:layout_width="55px"  
               android:layout_height="50px"  
               android:id="@+id/imgHolder" />  
    <ScrollView android:minWidth="25px"  
                android:minHeight="25px"  
                android:layout_width="match_parent"  
                android:layout_height="wrap_content"  
                android:layout_centerHorizontal="true"  
                android:layout_below="@+id/imgHolder"  
                android:id="@+id/scrollView1">  
        <TableLayout android:layout_width="fill_parent"  
                     android:layout_height="fill_parent"  
                     android:stretchColumns="1">  
            <TextView android:text=""  
                      android:id="@+id/txtQuestion"  
                      android:layout_centerHorizontal="true"  
                      android:layout_width="wrap_content"  
                      android:layout_height="wrap_content"  
                      android:textSize="40dp"  
                      android:layout_marginBottom="10.0dp"  
                      android:gravity="center"  
                      android:layout_below="@+id/imgHolder" />  
            <LinearLayout android:orientation="horizontal"  
                          android:paddingLeft="4.0dip"  
                          android:paddingTop="5.0dip"  
                          android:paddingRight="4.0dip"  
                          android:paddingBottom="1.0dip"  
                          android:layout_width="fill_parent"  
                          android:layout_height="wrap_content"  
                          android:layout_below="@+id/txtQuestion"  
                          android:layout_marginBottom="10.0dp"  
                          android:gravity="center"  
                          android:id="@+id/linearLayoutQuestionButtons">  
                <Button android:id="@+id/btnYes"  
                        android:layout_width="114px"  
                        android:layout_height="46px"  
                        android:text="YES"  
                        android:background="@drawable/imgMessagingButton" />  
                <Button android:id="@+id/btnNo"  
                        android:layout_width="114px"  
                        android:layout_height="46px"  
                        android:text="NO"  
                        android:background="@drawable/imgMessagingButton" />  
                <Button android:id="@+id/btnOk"  
                        android:layout_width="114px"  
                        android:layout_height="46px"  
                        android:text="OK"  
                        android:layout_centerHorizontal="true"  
                        android:background="@drawable/imgMessagingButton"  
                        android:visibility="gone" />  
            </LinearLayout>  
        </TableLayout>  
    </ScrollView>  
</RelativeLayout>  

The markup above simply displays some Buttons, TextBox and an Image for the survey. The next step is to modify the "RectangleMain.axml" file to make it look like below:

<?xml version="1.0" encoding="utf-8" ?>  
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
              xmlns:tools="http://schemas.android.com/tools"  
              android:orientation="vertical"  
              android:layout_width="fill_parent"  
              android:layout_height="fill_parent"  
              tools:context=".MainActivity"  
              tools:deviceIds="wear_round">  
    <TextView android:text="Xamarin.Android Messaging Survey Sample"  
              android:id="@+id/txtWelcome"  
              android:layout_centerHorizontal="true"  
              android:layout_width="wrap_content"  
              android:layout_height="wrap_content"  
              android:textSize="40dp"  
              android:layout_marginBottom="10.0dp"  
              android:gravity="center" />  
    <LinearLayout android:orientation="vertical"  
                  android:id="@+id/layoutMessaging"  
                  android:layout_width="fill_parent"  
                  android:layout_height="fill_parent">  
        <include layout="@layout/messageview" />  
    </LinearLayout>  
</LinearLayout>

The markup above includes the "MessageView" layout that we have just created earlier to the main layout.

Adding the Functionality

Now, create a new class file and name it as "MessageScreen". This file serves as the code behind for the survey logic. Here's the code block below:

using System;  
using System.Collections.Generic;  
using System.Linq;  
using Android.Views;  
using Android.Widget;  
  
namespace Xamarin.Messaging  
{  
    public partial class MainActivity  
    {  
        MessagingRunnableTask _MRT;  
        bool _isQuestionAvailable = true;  
        bool _isMessageAQuestion = true;  
        Messaging _message;  
        Queue<Message> _availableMessages;  
        TextView _txtQuestion;  
        Button _btnYes;  
        Button _btnNo;  
        Button _btnOk;  
        LinearLayout _llQuestionButtons;  
        ImageView _imgMessageIcon;  
        Messaging.MessageIconType _messageIconType;  
        Messaging.MessageType _messageType;  
  
        public void DisplayMessage()  
        {  
            InitializeObjects();  
            _availableMessages = _message.GetMessages();  
            _llQuestionButtons.Visibility = ViewStates.Visible;  
            _isQuestionAvailable = true;  
  
            ShowQuestion();  
  
            RunOnUiThread(WireQuestionButtons);  
  
        }  
  
        void AnswerNo_Click(object sender, EventArgs e) { ShowNextQuestion(); }  
        void AnswerYes_Click(object sender, EventArgs e) { ShowNextQuestion(); }  
        void AnswerOk_Click(object sender, EventArgs e) { ShowNextQuestion(); }  
  
        void WireQuestionButtons()  
        {  
            _btnNo.Click -= AnswerNo_Click;  
            _btnNo.Click += AnswerNo_Click;  
            _btnYes.Click -= AnswerYes_Click;  
            _btnYes.Click += AnswerYes_Click;  
  
            _btnOk.Click -= AnswerOk_Click;  
            _btnOk.Click += AnswerOk_Click;  
        }  

        void InitializeObjects()  
        {  
            _btnNo = FindViewById<Button>(Resource.Id.btnNo);  
            _btnYes = FindViewById<Button>(Resource.Id.btnYes);  
            _btnOk = FindViewById<Button>(Resource.Id.btnOk);  
            _txtQuestion = FindViewById<TextView>(Resource.Id.txtQuestion);  
            _llQuestionButtons = 
            FindViewById<LinearLayout>(Resource.Id.linearLayoutQuestionButtons);  
            _imgMessageIcon = FindViewById<ImageView>(Resource.Id.imgHolder);  
  
            _MRT = new MessagingRunnableTask();  
            _message = new Messaging();  
        }  
  
        void ToogleButtons()  
        {  
            if (_isMessageAQuestion)  
            {  
                _btnNo.Visibility = ViewStates.Visible;  
                _btnYes.Visibility = ViewStates.Visible;  
                _btnOk.Visibility = ViewStates.Gone;  
            }  
            else  
            {  
                _btnNo.Visibility = ViewStates.Gone;  
                _btnYes.Visibility = ViewStates.Gone;  
                _btnOk.Visibility = ViewStates.Visible;  
            }  
        }  

        void ToggleIcon(Messaging.MessageIconType iconType)  
        {  
            switch (iconType)  
            {  
                case Messaging.MessageIconType.None:  
                    {  
                        _imgMessageIcon.SetImageResource(0);  
                        break;  
                    }  
                case Messaging.MessageIconType.Question:  
                    {  
                        _imgMessageIcon.SetImageResource(Resource.Drawable.imgMessagingQuestion);  
                        break;  
                    }  
            }  
        }  

        void ToggleButtonText(Messaging.MessageType messageType)  
        {  
            switch (messageType)  
            {  
                case Messaging.MessageType.Information:  
                    {  
                        _btnOk.Text = "OK";  
                        break;  
                    }  
            }  
        }  
  
        void ShowQuestion()  
        {  
            if (_availableMessages.Any())  
            {  
                var m = _availableMessages.First();  
                _txtQuestion.Text = m.MessageText;  
                _isMessageAQuestion = m.IsQuestion;  
                _messageIconType = (Messaging.MessageIconType)m.IconID;  
                _messageType = (Messaging.MessageType)m.MessageTypeID;  
  
                _message.Update(m);//dequeue  
  
                if (!_availableMessages.Any())  
                    _isQuestionAvailable = false;  
  
                ToggleIcon(_messageIconType);  
                ToogleButtons();  
                ToggleButtonText(_messageType);  
            }  
            else  
                _isQuestionAvailable = false;  
        }  

        void ShowNextQuestion()  
        {  
            if (_isQuestionAvailable)  
                ShowQuestion();  
            else  
            {  
                _btnNo.Visibility = ViewStates.Gone;  
                _btnYes.Visibility = ViewStates.Gone;  
                _llQuestionButtons.Visibility = ViewStates.Gone;  
                _txtQuestion.Text = "Saving...";  
                SaveAndBackToPreviousView(1000);  
            }  
        }  

        void SaveAndBackToPreviousView(int waitInMilliseconds)  
        {  
            _MRT.ProcessMessageTask(waitInMilliseconds, true);  
        }  
    }  
}  

The class above is a partial class that implements the logic and functionality for our survey feature. It is where we initialized the controls and wired some event handlers for Buttons. It also contains some methods to do certain actions based on user interaction. For example, the ToggleButtons() will show or hide a specific Button based on the question presented to the user. The rest of the methods are very much self-explanatory as the method name suggests.

The MainActivity

Next is open up "MainActivity" class and update the code with the following:

using System;  
  
using Android.App;  
using Android.Content;  
using Android.Views;  
using Android.Widget;  
using Android.OS;  
  
namespace Xamarin.Messaging  
{  
    [Activity(Label = "Xamarin.Messaging", 
    MainLauncher = true, Icon = "@drawable/icon")]  
    public partial class MainActivity : Activity  
    {  
        protected override void OnCreate(Bundle bundle)  
        {  
            base.OnCreate(bundle);  
  
            // Set our view from the "main" layout resource  
            SetContentView(Resource.Layout.RectangleMain);  
  
            RegisterSwitchViewtReciever();  
  
            MessagingRunnableTask task = new MessagingRunnableTask();  
            task.ProcessMessageTask(5000, false);  
        }  
  
        public void SetView(string viewName)  
        {  
            Intent intent = new Intent("SwitchView");  
            intent.PutExtra("view", viewName);  
            Application.Context.SendBroadcast(intent);  
        }  
        public void Home()  
        {  
            FindViewById<TextView>
            (Resource.Id.txtWelcome).Visibility = ViewStates.Visible;  
            FindViewById<LinearLayout>
            (Resource.Id.layoutMessaging).Visibility = ViewStates.Gone;  
        }  
  
        SwitchViewReciever switchViewReciever;  
        void RegisterSwitchViewtReciever()  
        {  
            switchViewReciever = new SwitchViewReciever();  
            switchViewReciever.ActionOnRecieve = SwitchView;  
            IntentFilter filter = new IntentFilter("SwitchView");  
            RegisterReceiver(switchViewReciever, filter);  
        }  
  
        public void SwitchView(string view)  
        {  
  
            FindViewById<TextView>(Resource.Id.txtWelcome).Visibility = 
            view == "Home" ? ViewStates.Visible : ViewStates.Gone;  
            FindViewById<LinearLayout>(Resource.Id.layoutMessaging).Visibility = 
            view == "Survey" ? ViewStates.Visible : ViewStates.Gone;  
  
            Action layoutAction;  
            switch (view)  
            {  
                case "Survey":  
                    layoutAction = DisplayMessage;  
                    break;  
                default:  
                    layoutAction = Home;  
                    break;  
            }  
            layoutAction.Invoke();  
        }    
    }  
  
    public class SwitchViewReciever : BroadcastReceiver  
    {  
        public Action<String> ActionOnRecieve;  
        public override void OnReceive(Context context, Intent intent)  
        {  
            ActionOnRecieve.Invoke(intent.GetStringExtra("view") ?? "Home");  
        }  
    }  
}  

The code above is pretty much self-explanatory too. But the important thing to highlight there is the initialization and calling of the ProcessMessageTask() method. This method is responsible for displaying the survey page after 5 seconds. The RegisterSwitchViewtReciever registers the broadcast receiver so we can have access to the data from the broadcast. The SwitchViewReciever class is used to handle the data from a broadcast by implementing a BroadcastReciever. The broadcast will pass the data and tell the app whether to display the "Home" or "Survey" page.

The Output

Running the app will display like this in a real smart watch device.

On Initial Load

Figure 5: Initial load

Displays the Question after 5 Seconds

Figure 6: Survey Pops out

After all questions have been shown, it will then show a “Thank You” message and return to the home view.

Thanks for reading and I hope someone finds this article useful. Smile | :)

Summary

In this article, we've learned how to implement a simple survey feature in our Android app using Xamarin.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here