name: inverse layout: true class: center, middle, inverse --- class: center, middle, inverse # Interaction Technique Design Lauren Bricker CSE 340 Spring 2022 --- layout: false [//]: # (Outline Slide) # Agenda - Introducing key concepts for menus assignment --- # What is a Menu in theory? ??? - Supports selection of an item from a fixed set of options - Options are set and determined in advance - Typically used for “commands” (verbs, things to do) - Occasionally for selecting a value (e.g., picking a font) -- count: false .left-column-half[ - Supports selection of an item from a fixed set of options - Options are set and determined in advance - Typically used for “commands” (verbs, things to do) - Occasionally for selecting a value (e.g., picking a font) ] -- count: false .right-column-half[ In Counter we saw a pre-defined "hamburger" menu and responded to user selections through an `onOptionsItemSelected` callback ] --- # What is a Menu in theory? .left-column-half[ - Supports selection of an item from a fixed set of options - Options are set and determined in advance - Typically used for “commands” (verbs, things to do) - Occasionally for selecting a value (e.g., picking a font) Now we will create our own menu interactors!!! ] -- .right-column-half[
stateDiagram-v2 [*] --> Selecting : Press/
startSelection() Selecting --> [*]: Release/
endSelection() Selecting --> Selecting: Drag/
updateModel()
] --- count: false # What is a Menu in theory? .left-column-half[ - Supports selection of an item from a fixed set of options - Options are set and determined in advance - Typically used for “commands” (verbs, things to do) - Occasionally for selecting a value (e.g., picking a font) Now we will create our own menu interactors!!! ] .right-column-half[
stateDiagram-v2 [*] --> Selecting : Press/
startSelection() Selecting --> [*]: Release/
endSelection() Selecting --> Selecting: Drag/
updateModel()
Works in all Menus! ] --- # Example Menus Types .left-column50[ ## Pull down Menu ![:img Traditional Menu inside a web browser, 70%,width](img/menus/menu.png) ] -- .right-column50[ ## Pie Menu ![:img Pie Menu, 70%,width](img/menus/pie.jpg) ] -- count: false Which is better, and why? -- count: false This is question we're going to try to answer... --- # Menus! .left-column60[ HCI Goals: - Explore Propositional Production Systems - Define event handlers and bubbling - Understand pie menus - Create rectangular and non-rectangular interactors - Design your own original interactor - Record user study data - Produce plausible experiment results (within expected ranges) - Collect, parse, and interpret results collected from a study. ] .right-column40[ Android Goals: - Experience the Android event handling APIs - Handle touch input - Produce output with `onDraw()` - Implement developer defined callbacks to maintain separation of concerns. - Practice implementing state machines and event handling ] --- # Menus Assignment Goal: to compare pie menus, linear menus, and a custom menu you make! We provide support for - Testing your menus (`TestActivity`) - Running the experiment (`ExperimentActivity`) You implement - Three different types of menus - Some testing code --- name: inverse layout: true class: center, middle, inverse --- # Menus implementation --- layout: false # Menus Assignment .left-column-half[ ## Class Hierarchy
classDiagram AbstractMainActivity <|-- ExperimentActivity AbstractMainActivity <|-- TestActivity AbstractMenuExperimentView <|-- MenuExperimentView MenuExperimentView <|-- PieMenuView MenuExperimentView <|-- NormalMenuView MenuExperimentView <|-- CustomMenuView class MenuExperimentView { essentialGeometry() onTouchEvent() startSelection() endSelection() updateModel() } class TrialListener
] .right-column-half[ ## Enums Used for PPS in Menu assignment *and* for experimental conditions. [Documentation](https://docs.oracle.com/javase/tutorial/java/javaOO/enum.html)
classDiagram class State { START SELECTING } class MenuType { NORMAL PIE CUSTOM } class TaskType { LINEAR RELATIVE UNCLASS }
] ??? Enums - Used for PPS (PPS States; Essential Geometry) in Menu assignment *and* for experimental conditions - Easy to inspect if you want to (can use to determine possible states, number items, etc) --- # Handling onTouchEvent .left-column-half[ You will write the PPS code to handle one generic type of Menu (in `MenuExperimentView`) You will define the essential geometry for each specific type of menu (in `NormalMenuView`, `PieMenuView`, and `CustomMenuView`) Through the magic of Java inheritance, it will all work! ] .right-column-half[
stateDiagram-v2 [*] --> Selecting : Press/
startSelection() Selecting --> [*]: Release/
endSelection() Selecting --> Selecting: Drag/
updateModel()
] --- # Drawing Menus - Each menu pops up on the screen in it's own View with a bounding box. - This will feel very familar... i.e think back to Doodle. - You will have to draw your menus in the View! .left-column50[ ### Pull down Menu ![:img Traditional Menu that students will implement, 40%,width](img/menus/normal-bounding.png) ] .right-column50[ ### Pie Menu ![:img Pie Menu that students will implement, 40%,width](img/menus/pie-bounding.png) ] --- name: inverse layout: true class: center, middle, inverse --- # Custom Listeners ## What are they? Why should we use them? --- layout:false # Custom Listeners - Used in Menus - Why create custom listeners? -- - Maintains "Separation of Concerns" - The objects that need information can get a message to update when the model has changed Good example: a model that sends multiple views information on state changes. --- # How to implement custom listeners The object that needs to inform other objects about changes - define a custom interface for the listener - keep track of of everything that "listens" for changes, i.e. everything that implements that listener interface. -- Anything *using* the the changes needs to - implement the custom listener interface (specifically, the method in that interface that will be called) - register itself as a listener with the view Remember the `EnclosureListener`? [slides](../wk04/events.html#50) --- # Creating a new type of listener (1/4) Step 1: Define the new type of listener ```java // Defines a new named inner interface for listening to an interesting event public interface MyListener { void onInterestingEvent(); // can include a parameter } ``` --- # Creating a new type of listener (2/4) Step 2: Create an instance variable to store the registered listeners. Also create a method for setting (if there is one) or adding (if there are many) listeners. ```java // variable to store the listener(s) in once registered. public class MyObject extends SomeObject { protected MyListener mListener; // could also be a list of listeners ... public void setMyListener(MyListener mListener) { this.mListener = mListener; // could also be stored in a list. } } ``` --- # Creating a new type of listener (3/4) Step 3: Somewhere else in that object, when needed, call the listener! ```java // Method in MyObject that needs the listeners to do something! public void someMethod() { mListener.onInterestingEvent(); } ``` --- # Creating a new type of listener (4/4) Step 4: Implement the listener elsewhere in your code! ```java public class TheListeningObject implements MyListener { // MyObject mObject = new MyObject(); // on construction, or onCreate if a view public TheListeningObject() { mObject.setMyListener(this); // one mechanism for setting up callbacks! } // implementing the MyListener interface! public void onInterestingEvent() { // Do what we need to when we get notified of the event! } ``` --- # Think... Pair... Share... Think about how a `View.OnClickListener` and `View#onClick()` work! - What are we as the app developer seeing and utilizing? - what steps are hidden for us by the toolkit? --- # Custom Listener in Menus In Menus, we use a custom listener to record experiment data This keeps us from coupling (too tightly) the Menu Views from the code to handle the experiement. --- # Custom Listener in Menus (1/4) Step 1: We setup the listener interface for you ```java public interface TrialListener { /** Callback function called when a trial is finished. */ void onTrialCompleted(ExperimentTrial trial); } ``` --- # Custom Listener in Menus (2/4) Step 2: Create an instance variable to store the registered listeners. Also create a method for setting (if there is one) or adding (if there are many) listeners. We register the listeners in `AbstractMenuExperimentView` ```java // Currently registered TrialLister instance or null. private TrialListener mTrialListener = null; // Register the trial listener with the menu. This will be notified when the trial is complete. public void setTrialListener(TrialListener listener) { mTrialListener = listener; } ``` --- # Custom Listener in Menus (3/4) Step 3: Somewhere else in that object, when needed, call the listener! You get to implement this part when you need to record a trial! Look for the TODOs! --- # Creating a new type of listener (4/4) Step 4: Implement the listener elsewhere in your code! This is another piece you will do! --- # Custom listeners in Menus
classDiagram ExperimentActivity ..> AbstractMenuExperimentView : setTrialListener() ExperimentActivity --> TrialListener : Implements class TrialListener { onTrialCompleted() } class AbstractMenuExperimentView { setTrialListener() }
--- # Custom listeners in Menus You implemented this ```java // TODO: Register callback to record a trial ``` .left-column60[ What method do we call to register the callback? `setTrialListener()` What do we do in the a callback?
Record the results ] .right-column40[
classDiagram AbstractMenuExperimentView ..> TrialListener : onTrialCompleted() TrialListener ..> ExperimentActivity : record result class TrialListener { onTrialCompleted() } class ExperimentActivity { AbstractMenuExperimentView mMenuView }
] --- # Registering a TrialListener in Menus In `ExperimentActivity` to record the results of a trial ```java // TODO: register a TrialListener with the menu: // TODO: When the user completes a trial, the menu listener should take care of the following: // TODO: 1. Write the result to your CSV file. This should be accomplished with // ExperimentSession.recordResult(). // TODO: 2. show the menu for the next trial, if there is another trial available. // TODO: 3. If another trial is not available, announce with a Toast and change the text in the // instruction view to say the session is completed by using R.string.session_completed // from strings.xml. For completeness, don’t forget to reset the session (to null) // if you are done with all of the sessions. ``` --- # End of Deck