as5: Menus
Last revised: 9:00pm, Sunday, February 16th, 2020- February 19th, 2020
- Part 0-3 (programming part)
- Due February 26th, 2020
- Lock February 28th, 2020 - Part 4-5 (analysis part)
- Due March 2nd, 2020
- Lock March 4th, 2020
Android Goals:
- Further practice using callbacks; `onDraw()`
- Further practice with translate
- Gain more experience working with callbacks.
- Further practice with state machines and event handling
HCI Goals:
- Record user study data
- Produce plausible experiment results (within expected ranges)
- Understand pie menus
- Design your own interactor
- Collect, parse, and interpret results collected from a study.
- Overview of assignment
- Part 0: Overview
- Part 1: Implement MenuExperimentView and MainActivity
- Part 2: Implement Pie and Normal Menus
- Part 3: Implement a Custom Menu
- Part 4: Conduct and Write Up User Study
- Reflection
- Submission Instructions
Accept the Assignment / Turn-in the Assignment / Review your Submissions
Overview of assignment
This is a two part assignment.
You will create three menus – a linear menu, a pie menu, and a custom menu that you design. You will also test them in an experiment.
The coding re-uses many concepts from ColorPicker. Please start early, and reach out if you find you are spending more than 10 hours.
The user study will include the following: Write your consent form using our template and print out recruit, consent and run 5 participants; Download your data and import it into the spreadsheet we provide; Analyze the data and write the report.
NOTE: If you are unable to finish parts 1-3, you can borrow a phone with working code installed to finish parts 4-5.
Key Files to look at
- MainActivity.java
- Activity that displays the option to navigate between sessions. Also adds the corresponding menu view to the view hierarchy.
- MenuExperimentView
- View that can displays and handle input for a menu. This is where you implement the state machine that will work for all of your menus. This is the parent class of NormalMenuView and PieMenuView
- PieMenuView
- View that implements pie menus. This knows how to draw a pie menu, and figure out where input is in it. It inherits from MenuExperimentView
- NormalMenuView
- View that implements normal linear menus. Similar to PieMenuView
- CustomMenuView
- View that implements normal linear menus. Similar to PieMenuView
Classes that have functions and fields you may need (your classes inherit from them)
- AbstractMainActivity
- AbstractMenuExperimentView
- TrialListener
Other files you may want to look at
- ExperimentSession.java
- Class that sets up all the conditions for the experiment and creates an iterator with all the trials.
- ExperimentTrial.java
- Class that stores all the data for a single trial.
- TestActivity.java
- Activity that app starts out in. Lets you test your menus before running the experiment
Part 0: Overview
Read this spec and take a look at the classes listed above.
You will be implementing a class that can display a pie menu, a class that can display a linear menu, and a custom menu of your design, for use in an experiment comparing which is faster for the user to select menu items from. By menu items we mean the individual items in a menu, such as the number 1 in the sample video.
In this experiment we will have 9 conditions, each of which will include
the number of trials (where totalTrials = NUM_REPEATS*ITEM_MAX
trials). You can think of this as a three dimensional array
Menus | |||
---|---|---|---|
Tasks | PIE |
NORMAL |
CUSTOM |
LINEAR |
totalTrials | totalTrials | totalTrials |
RELATIVE |
totalTrials | totalTrials | totalTrials |
UNCLASS |
totalTrials | totalTrials | totalTrials |
The three menu types (specified in an Enum
in the code) are PIE
(round), NORMAL
(linear) and CUSTOM
(your custom menu).
The three task types (also an Enum
) are LINEAR
(menu items such as
1,2,4,8,16,32,64,128) ; RELATIVE
(menu items such as
Up/UpRight/Right/Down/etc…); and UNCLASS
(menu items such as
Print/Cast/Bookmark/etc);
The trials are specific combinations of menu item, task type, and menu type. So for example, one trial might involve showing the user a pie menu, with the numbers 1..128 in it, and asking them to select number 3. The participant can select any option, no matter what as soon as they complete a selection, the result is recorded and the next trial begins.
For any given session (one user’s worth of trials), each combination
of menu type, task type, and menu item, will be repeated NUM_REPEATS
times (NUM_REPEATS
is specified in ExperimentSession.java
). In
addition, for any specific combination of menu type and task type, at
most ITEM_MAX
items (a total of ITEM_MAX*NUM_REPEATS
trials) will
be shown to the user. If you set both of these to 1 for testing, you
can test all your conditions very quickly. Make sure to set them to
the required values for user testing:
ITEM_MAX
must be at least 4 and NUM_REPEATS
must be 3.
In the second half (week 2) of this project, you will recruit 5
friends or students and have them complete one session each. Thus, you
will have a total of 5 (participant sessions) * 9 (conditions) *
ITEM_MAX*NUM_REPEATS
, or 540, data points when you have completed
this assignment. You will analyze the data from this experiment in
part 2 of this project.
We have implemented in ExperimentSession
the code for you to generate
all of the trials from a setup file called menuContents.csv
found in
the assets directory. Make sure that you understand the createTrials()
method
provided in ExperimentSession.java which sets up conditions for the
whole experiment. ExperimentSession
is an iterator, so to run the
trials for a given session you just use session.next()
as long as
session.getNext()
is true.
Note: that we give the user feedback two ways.
- For updates that the user can ignore, throughout the code, we use something called a Toast - a widget that appears at the bottom of the screen and shows some announcement text. Toasts are temporarily displayed and then disappear.
See Toast and for an example of how it is used look in
AbstractMainActivity.java
- For critical experimental information (i.e. what to select in a trial), we give the user instructions by changing the contents of the
TextView
at the bottom of the screen (by changing the contents ofR.id.instructionTextView
). This is a permanent change that will be visible until they finish the trial, so a Toast is not an appropriate choice.
Part 1: Implement MenuExperimentView and MainActivity
Tasks
- Implement
onTouchEvent()
inMenuExperimentView
includingstartSelection()
endSelection()
updateModel()
reset()
- Implement
onDraw()
inMenuExperimentView
- Implement
showMenuForTrial()
inMainActivity
(and set up and implement aTrialListener
)
For this part, you will be working in MenuExperimentView.java
and MainActivity
.
This section will entail defining the functions which power your menu experiment.
The MenuExperimentView
class includes several methods that you will need to implement. You
will implement the state machine logic in onTouchEvent
(similar to
what you’ve done in ColorPicker).
One tricky thing about context menus – they can appear anywhere in
your user interface. To support this, we set things up so that the
menu view is going to MATCH_PARENT
width and height (i.e. its bounding box is the whole screen). However, the
menu itself should show up right where the user presses down. To make this easier for your menus, you will translate the canvas so that they can draw themselves in a logical location given where the finger pressed in onDraw()
. Then you will call drawMenu()
with this translated canvas, which is what each specific menu implements to draw itself properly.
Handling Touch Events
You will handle touch input by implementing the onTouchEvent
method.
This is the event handler that is invoked when a touch occurs in this
view. The state machine defined in onTouchEvent
should work, without
changes, for every menu you implement. The only menu-specific code is
in essentialGeometry()
(it finds the current index). Thus
onTouchEvent()
is implemented in the parent class,
MenuExperimentView
and is not changed in the child classes.
MenuExperimentView
’s implementation of onTouchEvent makes
use of your menu’s essentialGeometry()
function to determine the
relative position of the user’s finger. Essential geometry will be passed the finger’s position relative to the menu’s (0,0), i.e. where the user pressed. You should implement your linear menu
so this is its top left corner, and your pie menu so that the user’s finger is in
the center of the pie.
You MUST NOT perform any assignments within essentialGeometry()
, as it violates the utility
of that function. Instead, essentialGeometry()
will return the index associated with the desired
view, allowing the function calling it to act on that value.
You need to keep track of two main states: START
and
SELECTING
. When in the SELECTING
state you need to distinguish
between the event type to determine if the user has selected an option
or if they are still in the middle of making a choice.
Relevant touch events include ACTION_DOWN
, ACTION_MOVE
, and
ACTION_UP
; think about how these touch events relate to the change
and how the UI should respond to these events.
More details about essentialGeometry()
, specific to each menu, are below.
Details for startSelection()
, endSelection()
and updateModel()
can be found in MenuExperimentView
. Note that there are no guards on these transitions – any click inside the menu causes it to appear, and once it appears, dragging causes updateModel() to be called no matter where the finger is. Similarly, the menu must be removed when selection ends, and the trial recorded, no matter where the finger is. You do not need to check whether the user clicked on the
correct menu item when you call endTrial()
. This data will be recorded automatically
by ExperimentSession
.
Drawing your Menu
Your menu should ONLY BE VISIBLE when you are in the SELECTING
state. You can check this in onDraw()
. In addition, it needs to redraw whenever something important changes (like the selected item). Be sure to call invalidate()
in the appropriate methods of the state machine to make this happen.
For onDraw()
, your will do some setup that will allow your
subclasses to draw properly. First, you will need to check if you are
in the proper state to draw (you should only draw when in the SELECTING
state).
Next, you really want to draw from the (0,0) location of the menu,
rather than the (0,0) of the parent. But remember that your width and
height are set using MATCH_PARENT
. To fix this, we need to change
the coordinate system of the canvas so that (0,0) is at the
startPoint
for this interaction.
Finally, since this is an abstract class, we need to call the real
drawing method, which our children will implement. This is called
drawMenu()
and should be overridden by PieMenuView
,
NormalMenuView
, and CustomMenuView
. Therefore, your onDraw()
implementation in
MenuExperimentView.java
will be pretty short.
Implementing MainActivity
In MainActivity you will implement part of the method
showMenuForTrial(ExperimentTrial trial)
. Your main job is to
register a callback with it that knows what to do when a trial is
completed.
MainActivity also needs to implement the code to respond to
onTrialCompleted()
, a method of the TrialListener interface. In
particular, this code should always remove the current menu being
shown. Then it should check if the session is over (remember the
session is an iterator), and if not call showMenuForTrial()
with the
next trial. If the session is over, it should update text of
InstructionTextView
to say that the session is completed, and also display a Toast to the same effect.
Note: This means that until the next session is started, the system should not display any menus if the user clicks.
Part 2: Implement Pie and Normal Menus
Tasks
-
NormalMenuView
: ImplementessentialGeometry()
anddrawMenu()
-
PieMenuView
: ImplementessentialGeometry()
anddrawMenu()
Both PieMenuView
and NormalMenuView
extend MenuExperimentView
. You
will implement essentialGeometry()
for each and determine what menu item the
touch event maps to. You’ll have to come up with the math logic to map
from touch event to an item index.
You will also implement drawMenu()
which at a minimum draws the menus as shown in
the screenshots. If you want to do something different, you may, as
long as the size and position of each menu item does not change. For
example, you can override the paint properties defined in
MenuExperimentView
, position the text differently, or draw more
decorations on the menus.
Be sure to check the AbstractMenuExperimentView
starter code for any additional values that you should use when creating your menus.
NormalMenuView
For the NormalMenuView
, essentialGeometry()
will return -1 if the
pointer is outside the bounds of the menu in any direction or has
moved less than MIN_DIST
(inherited from
AbstractMenuExperimentView
) since interaction started. Otherwise
it should return the item number of the menu item that the pointer
is currently inside of.
The width of each item in the normal menu is CELL_WIDTH
and the height is
CELL_HEIGHT
.
PieMenuView
For the PieMenuView
, essentialGeometry()
will return -1 if the pointer
has moved less than MIN_DIST
since selection started, and
otherwise it will return the item number currently being selected. Item
number is the menu item that a ray from
the center of the menu to the pointer intersects, with the first item being at the top of the pie. The pie menu has no maximum diameter, so anything outside of the radius MIN_DIST
around the finger will return a selection.
For PieMenuView, the given RADIUS
corresponds to the outer radius. The inner radius is defined by RADIUS - TEXT_SIZE * 2
.
The radius of the circle in the pie menu is RADIUS - TEXT_SIZE * 2
.
Some additional hints for the pie menu
-
drawArc()
will draw a pizza-pie shaped arc, so you can do things like highlight a menu item with a single method call. - You will need a rotational offset to ensure the top menu item is at the top of the pie (both when drawing and in essential geometry) because angle is traditionally measured from cardinal east. You can add this in radians before converting from angle to index.
- Just as in color picker, you should look to the atan function for
your pie menu’s
essentialGeometry()
function. - Your pie menu text does not need to be centered – as long as it is contained within the outer ring of the pie menu, you are fine.
Related APIs
Part 3: Implement a Custom Menu
Create a new menu! Working off of the provided MenuExperimentView
interface, build your own third menu. This menu should be different from the Pie/Normal menus. You are encouraged to explore user interactions here, and you will receive credit as long as your code shows significant effort. Your menu does not have to be great here – if you choose, you can aim to create the “worst menu ever” for this submission. Alternatively, you can aim to outcompete our provided menu views!
Be sure to make use of the same abstractions (essentialGeometry()
and a state machine) in this implementation.
Part 4: Conduct and Write Up User Study
(not due at the same time as the code portion)
Tasks
- Conduct user study
- Run a trial on yourself
- Create a final consent form from this sample
- Recruit 5 participants
- Have them sign your consent form
- Have them complete a session with
ITEM_MAX
set to at least 4 andNUM_REPEATS
set to 3. - Download the recorded data
- Analyze recorded data
- Write a report
Conduct User Study
To finalize the consent form, you will need to copy over the text from our sample consent form and modify it in all of the places marked as such. You should print out two copies of the consent form for each participant – one for them and one for you.
You will need to try out your own program as a participant to fill in the consent form (since you’ll need to know how long it takes). This is also a good time to double check that your data is not lost by downloading it.
Downloading your data
You can use the Android Studio Device File Explorer to access the file. This allows you to directly access the files on your Android device (emulated or physical) through a GUI window.
It will likely be in /storage/emulated/0/CSE340_Menus/TestResult.csv or
/sdcard/CSE340_Menus/TestResult.csv`.
Create a clean CSV
You should use the hamburger menu in the app you just implemented to Clear Result CSV
before starting your study so that your data does not contaminate your results. Make sure that you do not clear the results between submissions! This will erase your trial data.
Our implementation uses the ExperimentSession object to create, manage, and record experiment data to the CSV. If you are interested, check out the recordResult function on line 213 of ExperimentSession.java (as always, modify at your own risk!)
Recruit participants and have them sign your consent form
You can ask friends or classmates for help. Do not coerce anyone into participating in your study. Make sure they know they have a choice, and have read and signed the consent form. You will be required to turn in signed consent forms with your report. The language used in your consent form is key, so ensure that it does not come off as forceful or coercive.
Collect data
Have each participant complete a session. Once all participants are
done, you and download your final data file. It should have at least
ITEM_MAX*NUM_REPARTS*NUM_PARTICIPANTS
(540) data points in it. You
can use the emulator or your phone for this, and any mouse you want.
You will need to turn in your final data file with your report.
When collecting data, you should inform users that all interactions will begin with tapping on the center of the screen. This should help avoid cases where your menu is unusable due to the screen format.
Write a Report
You will need to write up a brief report about your study. We have provided a template for you to use here. Please reference this template as necessary when writing this report.
Reflection
Lastly, you should also write a reflection. Please answer the questions separately. Tell us:
Re-read our Properties of People Design Tips for Vision and Motor. Which of these design tips did you employ when creating your Custom menu? List at least one Visual design tip and one Motor design tip.
Given the structure of our Pie/Normal menus, how would you create an accessible menu when working with the MenuExperimentView class? What might be hard about this?
How could you better account for the case where a menu appears off of the phone screen? For instance, if a user attempts to access the Normal menu from the bottom of the screen.
Submission Instructions
You will change the following files:
Part 0-3:
- MainActivity.java
- MenuExperimentView.java
- NormalMenuView.java
- CustomMenuView.java
- PieMenuView.java
Part 4-5:
- TestResult.csv
- Signed consent forms (images/scans)
- Report.pdf
- Reflection
Your reflection and report will be uploaded to Gradescope. The code will be submitted to GitGrade.
We will provide a method for submitting the csv file. It should NOT be put in your report.
Grading Rubric
First Half (30 points)
- State machine implementation works: (12 pts)
- Normal menu draws correctly (3 pts)
- Pie menu draws correctly (3 pts)
- Normal & Pie menus correctly implement essential geometry (5 pts)
- Custom menu works (2 pts)
- Trials & callbacks handled correctly (4 pts)
- onDraw translates correctly (1 pt)
Second Half (30 points)
- Reasonable CSV output: 1pt
- Consent forms: 1pt
- Report:
- Description of study process: 5pt
- Demonstrate understanding of results: 5pt
- Makse appropriate/good use of charts: 4pt
- Draw appropriate conclusions about linear vs. pie menu vs custom menu: 5pt
- Reflection (9pts)