Namespaces

Variants
Actions

Please note that as of October 24, 2014, the Nokia Developer Wiki will no longer be accepting user contributions, including new entries, edits and comments, as we begin transitioning to our new home, in the Windows Phone Development Wiki. We plan to move over the majority of the existing entries over the next few weeks. Thanks for all your past and future contributions.

Creating an RSVP Reader for Asha devices

From Wiki
Jump to: navigation, search
Featured Article
12 Jan
2014

This article explains how to create an accelerometer controlled RSVP Reader for Asha Devices.

Note.pngNote: This is an entry in the Nokia Asha Wiki Competition 2013H2.

Article Metadata
Code ExampleTested with
SDK: Nokia Asha SDK 1.0
Devices(s): Nokia Asha 501
CompatibilityArticle
Created: arunkam (14/12/2013)
Last edited: kiran10182 (12 Jan 2014)

Contents

Introduction

Rapid Serial Visual Presentation (RSVP) presents small chunks (often single words) of text, images, or other visual information to the user one after another. RSVP can increase the reading speed because there is no need to move the eyes to scan along lines of text. It is particularly useful for visually impaired users because each individual word can be displayed to fill the whole screen the mobile device.

This article shows how to create a simple RSVP reader application where the speed that words are displayed is controlled by an accelerometer (or by pressing a button to scan forwards). It covers the both the technical challenges involved, as well as discussing about some of the ways in which it can be optimized.

RSVP example


RSVP animation controlled using Accelerometer.

Implementation

The core of the RSVP implementation is the Tokenizer class, which splits the string into individual units for display. These units are referred to as "tokens". The Tokenizer class is robust enough that it can easily handle the various special cases we will talk about later.

The following three methods are the most important.

// Used to split the string into multiple tokens
private void populateTokens(boolean isMultipleDelim)
{
int startPos = 0;
int delPos = 0;
int count = 0;
if (!isMultipleDelim)
{
//Split for a single delimiter usually a single space.
 
while ((delPos = text.indexOf(delimeter, startPos)) > 0)
{
if (delPos > startPos)
{
String temp = text.substring(startPos, delPos);
tokens.addElement(temp);
}
startPos = delPos + 1;
}
if (startPos < text.length() - 1)
{
tokens.addElement(text.substring(startPos));
}
} else
{
//Split based on multiple delimiters
int del_length = delims_array.length;
 
for (int i = 0; i < del_length; i++)
{
delPos = text.indexOf(delims_array[i], startPos);
if (delPos > -1)
{
 
if (delPos > startPos)
{
String temp = text.substring(startPos, delPos);
tokens.addElement(temp);
}
startPos = delPos + 1;
if (startPos < text.length() - 1)
{
tokens.addElement(text.substring(startPos));
}
i = -1;
}
}
}
length = tokens.size();
 
}

The code above splits the text according to the delimiter that is specified. It is also capable of splitting the text based on multiple delimiters (discussed shortly).

The following code is used to get the next token and check for the availability of more tokens. Since there can be more than just one word in each token we append multiple strings to generate the token of desired word length.

//Used to get the next token
public String nextToken()
{
StringBuffer token_to_return = new StringBuffer();
// Adding the required number of words to the present token.
for (int y = 0; y < wordcount; y++)
{
try
{
if (current_position + y < length)
{
token_to_return.append(tokens.elementAt(current_position + y).toString());
}
} catch (ArrayIndexOutOfBoundsException aob)
{
System.out.println("Error");
}
//Adding a space
token_to_return.append(" ");
}
// If the playback is paused
 
if (!pause)
{
current_position += wordcount;
}
if (s != null)
{
if (current_position <= length)
{
try
{
// For LWUIT implementation alone, we are setting the value of a slider to the current position.
s.setProgress(current_position);
} catch (Exception e)
{
}
}
} else
{
System.out.println("Slider is null");
}
return token_to_return.toString();
}
 
public boolean hasMoreTokens()
{
return (current_position < length);
}


User Interface

This article elaborates on how an RSVP Reader can be implemented in 3 most commonly used user interface modes in Asha.

  1. LWUIT
  2. LCDUI
  3. Canvas/Game Canvas

LWUIT

RSVP can be implemented in LWUIT by extending a TextArea class. While it is possible to reset the text with each token and call repaint, a more efficient approach is to animate the component. The animation simply changes the text area's value to the next (or previous) token after a specified time delay. The time delay determines the frames-per-second (FPS) at which the text will be displayed.

The code below shows the animation portion of the RSVP text area.

  public boolean animate()
{
long current = System.currentTimeMillis();
 
if ((current - lastInvoke > tokenizer.getTimeDelay()) | tokenizer.isPause())
{
lastInvoke = current;
if (tokenizer.hasMoreTokens())
{
presentWord = tokenizer.nextToken();
this.setText(presentWord);
this.setAlignment(TextArea.CENTER);
repaint();
} else
{
breakanimation = true;
}
if (breakanimation)
{
presentWord = "";
breakanimation = false;
this.getComponentForm().deregisterAnimated(this);
return false;
}
return true;
}
 
return false;
}

LCDUI

An RSVP LCDUI Custom Item can be embedded in any LCDUI form, in a manner similar to what is done using LWUIT. We will extend the CustomItem class and modify the paint() method. The paint() method will keep painting the text in a parallel thread. We modify the text value after a time delay.

 new Thread()
{
public void run()
{
while (true)
{
try
{
setPresentWord();
Thread.sleep(timeDelay);
} catch (InterruptedException ex)
{
ex.printStackTrace();
}
if (animation_done)
{
break;
}
}
}
}.start();

Canvas/Game Canvas

This implementation is same as the one done for LCDUI custom item. The important thing to notice in both these custom implementations is that we need to wrap the text so that the texts do not exceed the boundaries of the screen.

Use a slightly modified version of the code provided in this article for this purpose: TextWrapUtil to draw Multiple line text in Java ME

User Interaction

It is important to allow user interaction so that the user can play/pause the scrolling text, navigate backward or forward for any text he/she missed. This can be incorporated in various ways

  1. Next/Previous Button - This is demonstrated in the LWUIT Example. By clicking on this button, the present token is incremented or decremented and rendered.
  2. Pause/Play Button - This button will pause or play the tokens based on the time delay.
  3. Using accelerometer - We can either increase or decrease the current token to be displayed based on the accelerometer sensor. The main part of that code for that is given below:
      private static int[] data2actionEvents(Data[] data)
    {
     
    ChannelInfo cInfo = data[0].getChannelInfo();
    boolean isInts = cInfo.getDataType() == ChannelInfo.TYPE_INT ? true : false;
    int[] events = new int[BUFFER_SIZE];
     
    if (isInts)
    {
    int[][] ints = new int[2][BUFFER_SIZE];
    for (int i = 0; i < 2; i++)
    {
    ints[i] = data[i].getIntValues();
    }
    for (int i = 0; i < BUFFER_SIZE; i++)
    {
    events[i] = getActionKey(ints[0][i], ints[1][i]);
    }
    return events;
    }
    double[][] doubles = new double[2][BUFFER_SIZE];
    for (int i = 0; i < 2; i++)
    {
    doubles[i] = data[i].getDoubleValues();
    }
    for (int i = 0; i < BUFFER_SIZE; i++)
    {
    events[i] = getActionKey(doubles[0][i], doubles[1][i]);
    }
    return events;
    }
     
    public void dataReceived(SensorConnection sensor, Data[] d, boolean isDataLost)
    {
    int[] events = data2actionEvents(d);
    for (int i = 0; i < BUFFER_SIZE; i++)
    {
    if (events[i] == exEvent && !IS_TRIGGERING_EVENT_ALWAYS)
    {
    continue;
    }
     
    exEvent = events[i];
    long current = System.currentTimeMillis();
    if (current - lastRendertime > rs.getTimeDelay())
    {
    lastRendertime = current;
    switch (events[i])
    {
    case Canvas.LEFT:
    // Going to previous entry
    gotoPrev();
    break;
    case Canvas.RIGHT:
    //Going to the next entry
    gotoNext();
     
    break;
    default:
    }
    }
    }
    }
     
    private static int getActionKey(double axis_x, double axis_y)
    {
    // axis_x: LEFT or RIGHT
    if (Math.abs(axis_x) > Math.abs(axis_y))
    {
    return axis_x < 0 ? Canvas.RIGHT : Canvas.LEFT;
    }
    // axis_y: UP or DOWN
    return axis_y < 0 ? Canvas.UP : Canvas.DOWN;
    }
    The logic behind this is simple.The accelerometer sensor returns data about X,Y,Z c ordinates. We are tracking the X-Coordinate alone and if the value is less than zero, then the phone has turned left. If it is greater than zero, then the phone has turned right.
  4. Using Gestures - The gesture API is available in Nokia UI for Canvas and LCDUI components. For more information see Building a communication system for visually impaired users on the Asha software platform


Development issues

It is important to keep the following things in mind while including RSVP functionality into your app

  1. Text must not be displayed too quickly. The ideal display rate depends to some extent on the chunk size and the user. A range of 200 - 300ms is a reasonable rate for displaying 1-2 words.
  2. It is important to provide a way to navigate back and forth between words in case the user loses their position.
  3. Larger tokens can be used, but the time taken to understand the text increases with the number of words to display.
  4. Word length is also a factor. Longer words take longer to read.

Optimizations

The following methods can be used to optimise RSVP reading in particular circumstances.

Sentence based splitting

Sentences can be used as tokens instead of individual words. More words makes it easier for the user to track context, but increases the time required to read each token, and how easy each token is to see.

To implement sentence based splitting, you can set the delimiter in a Tokenizer object to a "."

Progress indicator

Users often feel more comfortable/engaged knowing their current position within the entire RSVP text.

This has been implemented using a Slider in LWUIT in the Tokenizer class.

Reduced duration of high frequency words

It is not necessary for all words to have the same duration. High frequency words like "a", "the", "an" etc. can be shown more quickly. This can be implemented by modifying the getTimeDelay() function in Tokenizer class. The function can be changed to return a value based on the value of the present token.

Punctuation pauses

Conversely, pausing longer for punctuation can make the text more readable. Often it is useful to include the punctuation in the preceding token.

This can be incorporated by setting the time delay for the various punctuations differently.

Proposition integration

Another way of splitting could be based on propositions like "and","although","because" etc. This naturally breaks the sentence into various phrases that have distinct meaning of their own. The only thing is that the time delay has to be adjusted accordingly.

Summary

This article describes how to create an RSVP Reader. It implements the same using LWUIT, LCDUI and Canvas. It also discusses strategies for enhancing the user experience while reading.


Version Hint

Windows Phone: [[Category:Windows Phone]]
[[Category:Windows Phone 7.5]]
[[Category:Windows Phone 8]]

Nokia Asha: [[Category:Nokia Asha]]
[[Category:Nokia Asha Platform 1.0]]

Series 40: [[Category:Series 40]]
[[Category:Series 40 1st Edition]] [[Category:Series 40 2nd Edition]]
[[Category:Series 40 3rd Edition (initial release)]] [[Category:Series 40 3rd Edition FP1]] [[Category:Series 40 3rd Edition FP2]]
[[Category:Series 40 5th Edition (initial release)]] [[Category:Series 40 5th Edition FP1]]
[[Category:Series 40 6th Edition (initial release)]] [[Category:Series 40 6th Edition FP1]] [[Category:Series 40 Developer Platform 1.0]] [[Category:Series 40 Developer Platform 1.1]] [[Category:Series 40 Developer Platform 2.0]]

Symbian: [[Category:Symbian]]
[[Category:S60 1st Edition]] [[Category:S60 2nd Edition (initial release)]] [[Category:S60 2nd Edition FP1]] [[Category:S60 2nd Edition FP2]] [[Category:S60 2nd Edition FP3]]
[[Category:S60 3rd Edition (initial release)]] [[Category:S60 3rd Edition FP1]] [[Category:S60 3rd Edition FP2]]
[[Category:S60 5th Edition]]
[[Category:Symbian^3]] [[Category:Symbian Anna]] [[Category:Nokia Belle]]

This page was last modified on 12 January 2014, at 20:02.
272 page views in the last 30 days.

Was this page helpful?

Your feedback about this content is important. Let us know what you think.

 

Thank you!

We appreciate your feedback.

×