Survey
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
Understanding Android UI and Intents by Implementing Sudoku Uichin Lee KAIST KSE March 14, 2013 Hello, Android Chapter 3 Objective: • Review Android Sudoku Example to understand Android User Interfaces and Intents Filling a 9×9 grid with digits so that each column, each row, and each of the nine 3×3 sub-grids that compose the grid contains all of the digits from 1 to 9 Getting Started • UI Design methods: – Procedural design: written in Java code (like Swing, e.g., JButton, JFrame) – Declarative design: XML description of UI objects • Preferred method • Creating the Opening Screen Project name: Sudoku Build target: Android 2.2 Application name: Sudoku Package name: org.example.sudoku Create Activity: Sudoku Min SDK Version: 8 Part 4 Android – User Interfaces Using XML Layouts Victor Matos Cleveland State University Notes are based on: The Busy Coder's Guide to Android Development by Mark L. Murphy Copyright © 2008-2009 CommonsWare, LLC. ISBN: 978-0-9816780-0-9 & Android Developers http://developer.android.com/index.html 4. Android – UI - User Interfaces The View Class • The View class represents the basic building block for user interface components. • A View occupies a rectangular area on the screen and is responsible for drawing and event-handling. • View is the base class for widgets that are used to create interactive UI components (buttons, text fields, etc.). • The ViewGroup subclass (of View) is the base class for layouts, which are invisible containers that can hold other Views (or other ViewGroups) and define their layout properties. 5 4. Android – UI - User Interfaces Using Views All of the views in a window are arranged in a single tree. You can add views either from code or by specifying a tree of views in one or more XML layout files. Once you have created a tree of views, there are typically a few types of common operations you may wish to perform: 1. 2. 3. 4. Set properties: for example setting the text of a TextView. Properties that are known at build time can be set in the XML layout files. Set focus: The framework will handled moving focus in response to user input. To force focus to a specific view, call requestFocus(). Set up listeners: Views allow clients to set listeners that will be notified when something interesting happens to the view. For example, a Button exposes a listener to notify clients when the button is clicked. Set visibility: You can hide or show views using setVisibility(int). 6 4. Android – UI - User Interfaces A brief sample of UI components Layouts Linear Layout Relative Layout Table Layout A LinearLayout is a GroupView that will lay child View elements vertically or horizontally. A RelativeLayout is a ViewGroup that allows you to layout child elements in positions relative to the parent or siblings elements. A TableLayout is a ViewGroup that will lay child View elements into rows and columns. 7 4. Android – UI - User Interfaces A brief sample of UI components Widgets GalleryView TabWidget Spinner DatePicker Form Controls A DatePicker is a widget that allows the user to select a month, day and year. Includes a variety of typical form widgets, like: image buttons, text fields, checkboxes and radio buttons. 8 4. Android – UI - User Interfaces A brief sample of UI components WebView MapView AutoCompleteTextView ListView It is a version of the EditText widget that will provide auto-complete suggestions as the user types. The suggestions are extracted from a collection of strings. A ListView is a View that shows items in a vertically scrolling list. The items are acquired from a ListAdapter. 9 4. Android – UI - User Interfaces What is an XML Layout? An XML-based layout is a specification of the various UI components and the relationships to each other – and to their containers – all written in XML format. Android considers XMLbased layouts to be resources, and as such layout files are stored in the res/layout directory inside your Android project. 10 4. Android – UI - User Interfaces What is an XML Layout? Each XML file contains a tree of elements specifying a layout of widgets and containers that make up one View (shown later). The attributes of the XML elements are properties, describing how a widget should look or how a container should behave. Example: If a Button element has an attribute value of android:textStyle = "bold" that means that the text appearing on the face of the button should be rendered in a boldface font style. 11 4. Android – UI - User Interfaces An example The application places a button to occupy the screen. When clicked the button’s text shows current time. import import import import import import java.util.Date; android.app.Activity; android.os.Bundle; android.view.View; android.view.View.OnClickListener; android.widget.Button; public class AndDemo extends Activity { Button btn; @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); setContentView(R.layout.main); btn = (Button) findViewById(R.id.myButton); btn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { updateTime(); } }); }// onCreate // private void updateTime() { btn.setText(new Date().toString()); } } 12 4. Android – UI - User Interfaces An example This is the XML-Layout definition <?xml version="1.0" encoding="utf-8"?> <Button xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/myButton" android:text="" android:layout_width="fill_parent" android:layout_height="fill_parent" /> The root element needs to declare the Android XML namespace: xmlns:android="http://schemas.android.com/apk/res/android" All other elements will be children of the root and will inherit that namespace declaration. Because we want to reference this button from our Java code, we need to give it an identifier via the android:id attribute. 13 4. Android – UI - User Interfaces An example cont. <?xml version="1.0" encoding="utf-8"?> <Button xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/myButton" android:text="" android:layout_width="fill_parent" android:layout_height="fill_parent" /> The remaining attributes are properties of this Button instance: • android:text indicates the initial text to be displayed on the button face (in this case, an empty string) • android:layout_width and android:layout_height tell Android to have the button's width and height fill the "parent“ container, in this case the entire screen. 14 4. Android – UI - User Interfaces UI Hierarchy UI Tree The utility HierarchyViewer displays the UI structure of the current screen shown on the emulator or device (eclipse: Windows > Open Perspectives) (Execute app on emulator, execute HierarchyViewer, click on Emulator > Refresh Screenshot ) 15 4. Android – UI - User Interfaces UI Hierarchy Example: Display UI Hierarchy UI Tree <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/hello" /> </LinearLayout> 4. Android – UI - User Interfaces Attaching Layouts to Java Code PLUMBING. You must ‘connect’ the XML elements with equivalent objects in your Java activity. This allows you to manipulate the UI with code. XLM Layout <xml…. ... ... </xml> JAVA code public class …. { ... ... } 17 4. Android – UI - User Interfaces Attaching Layouts to Java Code Assume the UI in res/layout/main.xml has been created. This layout could be called by an application using the statement setContentView(R.layout.main); Individual widgets, such as myButton could be accessed by the application using the statement findViewByID(...) as in Button btn = (Button) findViewById(R.id.myButton); Where R is a class automatically generated to keep track of resources available to the application. In particular R.id... is the collection of widgets defined in the XML layout. 18 4. Android – UI - User Interfaces Attaching Layouts to Java Code /* AUTO-GENERATED FILE. DO NOT MODIFY. * * This class was automatically generated by the * aapt tool from the resource data it found. It * should not be modified by hand. */ package uichin.kaist; public final class R { public static final class attr { } public static final class drawable { public static final int icon=0x7f020000; } public static final class layout { public static final int main=0x7f030000; } public static final class string { public static final int app_name=0x7f040001; public static final int hello=0x7f040000; } } Where R is a class automatically generated to keep track of resources available to the application. In particular R.id... is the collection of widgets defined in the XML layout. 19 4. Android – UI - User Interfaces Attaching Layouts to Java Code Attaching Listeners to the Widgets The button of our example could now be used, for instance a listener for the click event could be written as: btn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { updateTime(); } }); private void updateTime() { btn.setText(new Date().toString()); } 20 Sudoku Overview (5) Draw Game About.java Game.java PuzzleView.java (1) Main Layout XML Sudoku.java Touch (4) New Game (2) About Keypad.java Pref.java Sudoku.java (3) Menu Key Preference: Menu (6) Key Pad Step 1: Main Layout <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.../android" android:background="@color/background" android:layout_height="fill_parent" android:layout_width="fill_parent" android:padding="30dip" android:orientation="horizontal" > <LinearLayout android:orientation="vertical" android:layout_height="wrap_content" android:layout_width="fill_parent" android:layout_gravity="center" > <TextView android:text="@string/main_title" android:layout_height="wrap_content" android:layout_width="wrap_content" android:layout_gravity="center" android:layout_marginBottom="25dip" android:textSize="24.5sp" /> <Button android:id="@+id/continue_button" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/continue_label" /> <Button android:id="@+id/exit_button" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/exit_label" /> ...more buttons..’ </LinearLayout> </LinearLayout> <resources> <string name="app_name">Sudoku</string> <string name="main_title">Android Sudoku</string> <string name="continue_label">Continue</string> <string name="new_game_label">New Game</string> <string name="about_label">About</string> <string name="exit_label">Exit</string> Step 1: Main Layout Use “GraphicalLayout” Step 1: Main Layout • Emulator: Ctrl + F11 (rotate screen) • Add a new layout for the landscape mode (use “-land” suffix) – Select res, Ctrl+N, select Android/Android XML Layout File/ Step 1: Main Layout • Set up click listeners for all the buttons import import import import import android.app.Activity; android.os.Bundle; android.content.Intent; android.view.View; android.view.View.OnClickListener; public class Soduku extends Activity implements OnClickListener { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.about); // Set up click listeners for all the buttons View continueButton = findViewById(R.id.continue_button); continueButton.setOnClickListener(this); View newButton = findViewById(R.id.new_button); newButton.setOnClickListener(this); View aboutButton = findViewById(R.id.about_button); aboutButton.setOnClickListener(this); View exitButton = findViewById(R.id.exit_button); exitButton.setOnClickListener(this); } } Step 1: Main Layout • onClick handler public void onClick(View v) { Continue switch (v.getId()) { case R.id.continue_button: Intent intent = new Intent(Sudoku.this, Game.class); intent.putExtra(Game.KEY_DIFFICULTY, Game.DIFFICULTY_CONTINUE); startActivity(intent); break; case R.id.about_button: Intent i = new Intent(this, About.class); startActivity(i); break; // More buttons go here (if any) ... case R.id.new_button: openNewGameDialog(); break; case R.id.exit_button: finish(); break; } } Shut down activity and return control (4) New Game (2) About 12-2 Android Intents Part 2 Inter-Process Communication Using Bundles Victor Matos Cleveland State University Notes are based on: Android Developers http://developer.android.com/index.html 12. Android – Intents – Part 2 Intents Android Intents An activity usually presents a single visual user interface from which a number of actions could be performed. Moving from one activity to another is accomplished by having the current activity start the next one through so called intents. Activity-1 startActivityForResult … onActivityResult() … Intent {action + data} Activity-2 requestCode requestResult [ optional data ] onResult() … … 28 12. Android – Intents – Part 2 Intents Android Bundles Most programming languages support the notion of IPC (Inter-Process Communication) method-calling with arguments flowing birectionally from the caller to the invoked method. In android the calling activity issues an invocation to another activity using an Intent object. Notably in Android, the caller does not wait for the called activity to return results. Instead a listening-method [onActivityResult(...) ] should be used. 29 IPC Inter-Process Communication 12. Android – Intents – Part 2 Intents Android Bundles Normally the IPC expressions actual parameter list, and formal parameter list are used to designate the signature of particpating arguments, and the currently supplied data. Instead of using the traditional formal/actual parameter lists, Android relies on the concept of Intents to establish Inter-processcommunication. Intents optionally carry a named actual list or bundle for data exchange. 30 12. Android – Intents – Part 2 Intents Android Bundles The Android Bundle container is a simple mechanism used to pass data between activities. A Bundle is a type-safe collection of <name, value> pairs. There is a set of putXXX and getXXX methods to store and retrieve (single and array) values of primitive data types from/to the bundles. For example Bundle myBundle = new Bundle(); myBundle.putDouble (“var1”, 3.1415); ... Double v1 = myBundle.getDouble(“var1”); 31 12. Android – Intents – Part 2 Intents Android Intents & Bundles Activity1: Sender Activity2: Receiver Intent myIntentA1A2 = new Intent (Activity1.this, Activity2.class); Bundle myBundle1 = new Bundle(); myBundle1.putInt (“val1”, 123); myIntentA1A2.putExtras(myBundle1); startActivityForResult(myIntentA1A2, 1122); INTENT Sender class / Receiver class requestCode (1122) resultCode Extras: { val1 = 123 } Bundles 32 12. Android – Intents – Part 2 Intents Android Intents & Bundles Activity1: Sender Activity2: Receiver Intent myLocalIntent2 = getIntent(); Bundle myBundle = myLocalIntent.getExtras(); INTENT int val1 = myBundle.getInt(“val1"); Sender class / Receiver class requestCode (1122) resultCode Extras: { val1 = 123 } 33 12. Android – Intents – Part 2 Intents Android Intents & Bundles Activity1: Sender Activity2: Receiver myBundle.putString("val1", 456 ); myLocalIntent.putExtras(myBundle); INTENT setResult(Activity.RESULT_OK, myLocalIntent); Sender class / Receiver class requestCode (1122) resultCode (OK) Extras: { val1 = 456 } 34 Sudoku (5) Draw Game About.java Game.java PuzzleView.java (1) Main Layout XML Touch (4) New Game Sudoku.java (2) About Keypad.java Pref.java Sudoku.java (3) Menu Key Preference: Menu (6) Key Pad Step 2: About Window • Draw a window with some info about Sudoku – Define a new Activity, and start it – Use the AlertDialog class, and show it – Subclass Android’s Dialog class, and show that • How to add a new Activity class in Eclipse? 1. (create a new class) File > New > Class: • Superclass: android.app.Activity 2. (activity registration) AndroidManitest.xml > Application > Application Nodes • Or manually type in <activity…> </activity> in the XML file 3. Auto-filling Override functions: Right click “About.java” > Source > Override/Implement methods > Select “onCreate” Register a new activity here <activity android:name=".About“> </activity> Step 2: About Window • Adding a new layout? (about.xml) – New > Other > Android > Android XML Layout File • This will automatically add R.layout.about (in R.java) about.xml “Layout” ScrollView <?xml version="1.0" encoding="utf-8"?> <ScrollView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:padding="10dip"> <TextView android:id="@+id/about_content" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/about_text" /> </ScrollView> Step 2: About Window package org.example.sudoku; import android.app.Activity; import android.os.Bundle; public class About extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Set “about.xml” layout as a default view setContentView(R.layout.about); } } Step 2: About Window • Applying a theme – Very similar to Cascading Style Sheets (CSS) used for web pages – Default styles, and user-defined styles • Using a default theme: AndroidMenifest.xml – “@android:” prefix means that it’s a reference to a resource defined by Android <activity android:name=".About“ android:label="@string/about_title“ android:theme="@android:style/Theme.Dialog"> </activity> Sudoku (5) Draw Game About.java Game.java PuzzleView.java (1) Main Layout XML Touch (4) New Game Sudoku.java (2) About Keypad.java Pref.java Sudoku.java (3) Menu Key Preference: Menu (6) Key Pad Step 3: Adding a Menu/Setting • Menus in Android: – When you press the physical Menu button • Recent Androids (API 11 and higher) has a soft menu button instead (called an overflow menu button) – Context menu popping up when you press and hold your finger on the screen • Implementing “physical (or soft) menu” 1. Define string labels that will be used in menu (res/values/strings.xml) 2. Define a menu using XML (res/menu/menu.xml) • New > Other > Android > Android XML File (select “menu”) Step 3: Adding a Menu/Setting • Bring up a menu: Sudoku.java import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; @Override public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.menu, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.settings: startActivity(new Intent(this, Prefs.class)); return true; // More items go here (if any) ... } return false; } Read menu definition from xml file Called when a user selects any menu item Step 3: Adding a Menu/Setting • Bring up a setting: Pref.java 1. Create a new layout (choose “Preference”): stored in “res/xml” by default 2. Create a class “Pref.java” (extends “PreferenceActivity”) • Register Activity in the AndroidMenifest.xml <PreferenceScreen xmlns:android="http://schemas.android.com/apk /res/android"> <CheckBoxPreference android:key="music" android:title="@string/music_title" android:summary="@string/music_summary" android:defaultValue="true" /> <CheckBoxPreference android:key="hints" android:title="@string/hints_title" android:summary="@string/hints_summary" android:defaultValue="true" /> </PreferenceScreen> setting.xml (layout) import import import import android.content.Context; android.os.Bundle; android.preference.PreferenceActivity; android.preference.PreferenceManager; public class Prefs extends PreferenceActivity { @Override protected void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.settings); } } Pref.java Sudoku (5) Draw Game About.java (1) Main Layout XML (4) New Game Game.java PuzzleView.java Touch Sudoku.java (2) About Keypad.java Pref.java Sudoku.java (3) Menu Key Preference: Menu (6) Key Pad Step 4: New Game Menu • Pop up a dialog box, asking users to select among three difficulty levels (AlertDialog) import android.app.AlertDialog; import android.content.DialogInterface; import android.util.Log; Sudoku.java <resources> <array name="difficulty"> <item>@string/easy_label</item> public class Sudoku extends Activity implements OnClickListener { <item>@string/medium_label</item> private void openNewGameDialog() { <item>@string/hard_label</item> new AlertDialog.Builder(this) </array> .setTitle(R.string.new_game_title) </resources> .setItems(R.array.difficulty, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialoginterface, int i) { startGame(i); } }) .show(); } private void startGame(int i) { Log.d(TAG, "clicked on " + i); Intent intent = new Intent(Sudoku.this, Game.class); intent.putExtra(Game.KEY_DIFFICULTY, i); startActivity(intent); } } Debugging • Debugging with Log Messages – Log class provides several static methods to print messages of various levels • • • • • • Log.e(): errors Log.w(): warnings Log.i(): information Log.d(): debugging Log.v(): verbose Log.wtf(): what a terrible failure – Eclipse: Window > Show View > Other > Android > LogCat • Debugging with Eclipse debugger – Must enable debugging: AndroidManifest.xml <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="org.example.sudoku" android:versionCode="1" android:versionName="1.0"> <application android:icon="@drawable/icon" android:label="@string/app_name“ android:debuggable=“true”> Sudoku (5) Draw Game About.java Game.java PuzzleView.java (1) Main Layout XML Touch (4) New Game Sudoku.java (2) About Keypad.java Pref.java Sudoku.java (3) Menu Key Preference: Menu (6) Key Pad Step 5: Starting a Game • Procedure: 1. Start a new activity (Game) • Game.java 2. Game initializes its view using PuzzleView • PuzzleView.java protected void onCreate(savedInstanceState) { int diff = getIntent().getIntExtra(KEY_DIFFICULTY, DIFFICULTY_EASY); puzzleView = new PuzzleView(this); setContentView(puzzleView); Activity-1 (Sudoku) Intent {action + data} startActivity() Intent intent = new Intent(Sudoku.this, Game.class); intent.putExtra(Game.KEY_DIFFICULTY, i); startActivity(intent); Activity-2 (Game) PuzzleView Step 5: Starting a Game – PuzzleView • Android 2D graphic package: – Color • E.g., color = Color.argb(127, 255, 0, 255) or color = getResources().getColor(R.color.mycolor) – Paint • Style, color, and other info needed to draw any graphics such as bitmaps, text, and geometric shapes – Canvas: a surface on which you draw! • Display is taken up by an Activity, which hosts a View, which in turn hosts Canvas • Drawing on the canvas by overriding the View.onDraw() method – Path – Drawable: bitmap, Shape, etc. Step 5: Starting a Game – PuzzleView import import import import import import android.content.Context; android.graphics.Canvas; android.graphics.Paint; android.graphics.Rect; android.graphics.Paint.FontMetrics; android.graphics.Paint.Style; import android.os.Bundle; import android.os.Parcelable; import import import import import android.util.Log; android.view.KeyEvent; android.view.MotionEvent; android.view.View; android.view.animation.AnimationUtils; public class PuzzleView extends View { private final Game game; public PuzzleView(Context context) { super(context); this.game = (Game) context; setFocusable(true); setFocusableInTouchMode(true); } private private private private private float width; // width of one tile float height; // height of one tile static final String SELX = "selX"; static final String SELY = "selY"; final Rect selRect = new Rect(); @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { width = w / 9f; height = h / 9f; getRect(selX, selY, selRect); super.onSizeChanged(w, h, oldw, oldh); } private void getRect(int x, int y, Rect rect) { rect.set((int) (x * width), (int) (y * height), (int) (x * width + width), (int) (y * height + height)); } onSizeChanged() is called after the view is created Step 5: Starting a Game - PuzzleView • Drawing the board – onDraw() method is called anytime the view needs to be updated @Override protected void onDraw(Canvas canvas) { // Draw the background... Paint background = new Paint(); background.setColor(getResources().getColor( R.color.puzzle_background)); canvas.drawRect(0, 0, getWidth(), getHeight(), background); Step 5: Starting a Game - PuzzleView • Drawing the grid lines for the board // Define colors for the grid lines Paint dark = new Paint(); dark.setColor(getResources().getColor(R.color.puzzle_dark)); Paint hilite = new Paint(); hilite.setColor(getResources().getColor(R.color.puzzle_hilite)); Paint light = new Paint(); light.setColor(getResources().getColor(R.color.puzzle_light)); // Draw the minor grid lines for (int i = 0; i < 9; i++) { canvas.drawLine(0, i * height, getWidth(), i * height, light); canvas.drawLine(0, i * height + 1, getWidth(), i * height + 1, hilite); canvas.drawLine(i * width, 0, i * width, getHeight(), light); canvas.drawLine(i * width + 1, 0, i * width + 1, getHeight(), hilite); } // Draw the major grid lines for (int i = 0; i < 9; i++) { if (i % 3 != 0) continue; canvas.drawLine(0, i * height, getWidth(), i * height, dark); canvas.drawLine(0, i * height + 1, getWidth(), i * height + 1, hilite); canvas.drawLine(i * width, 0, i * width, getHeight(), dark); canvas.drawLine(i * width + 1, 0, i * width + 1, getHeight(), hilite); } Step 5: Starting a Game - PuzzleView • Drawing the numbers // Define color and style for numbers Paint foreground = new Paint(Paint.ANTI_ALIAS_FLAG); foreground.setColor(getResources().getColor(R.color.puzzle_foreground)); foreground.setStyle(Style.FILL); foreground.setTextSize(height * 0.75f); foreground.setTextScaleX(width / height); foreground.setTextAlign(Paint.Align.CENTER); // Draw the number in the center of the tile FontMetrics fm = foreground.getFontMetrics(); // Centering in X: use alignment (and X at midpoint) float x = width / 2; // Centering in Y: measure ascent/descent first float y = height / 2 - (fm.ascent + fm.descent) / 2; for (int i = 0; i < 9; i++) { for (int j = 0; j < 9; j++) { canvas.drawText(this.game.getTileString(i, j), i * width + x, j * height + y, foreground); } } Sudoku (5) Draw Game About.java Game.java PuzzleView.java (1) Main Layout XML Touch (4) New Game Sudoku.java (2) About Keypad.java Pref.java Sudoku.java (3) Menu Key Preference: Menu (6) Key Pad Step 6: Handling Input • Procedure 1. 2. Create a new layout for keypad (buttons!) Create a new class, Keypad that extends Dialog public class Keypad extends Dialog { private final View keys[] = new View[9]; private View keypad; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setTitle(R.string.keypad_title); setContentView(R.layout.keypad); findViews(); // keys, keypad Views private final int useds[]; private final PuzzleView puzzleView; for (int element : useds) { if (element != 0) public Keypad(Context context, int useds[], PuzzleView puzzleView) { super(context); this.useds = useds; this.puzzleView = puzzleView; } keys[element-1].setVisibility(View.INVISIBLE); } // for each key, keypad view, // set up OnClickListener() setListeners(); } Cf. As of J2SE 5.0, Java allows you to iterate through a collection (array): http://www.java-tips.org/java-se-tips/java.lang/the-enhanced-for-loop.html Step 6: Handling Input • PuzzleView: – Keyboard: if a key is down, onKeyDown()is invoked – Touch: if a user touches the screen, onTouchEvent()is invoked – Then, display keypad: game.showKeypadOrError(selX, selY) @Override public boolean onKeyDown(int keyCode, KeyEvent event) { switch (keyCode) { case KeyEvent.KEYCODE_DPAD_LEFT: select(selX - 1, selY); break; case KeyEvent.KEYCODE_DPAD_RIGHT: select(selX + 1, selY); break; case KeyEvent.KEYCODE_0: case KeyEvent.KEYCODE_SPACE: setSelectedTile(0); break; case KeyEvent.KEYCODE_1: setSelectedTile(1); break; case KeyEvent.KEYCODE_ENTER: case KeyEvent.KEYCODE_DPAD_CENTER: game.showKeypadOrError(selX, selY); break; default: return super.onKeyDown(keyCode, event); } return true; } @Override public boolean onTouchEvent(MotionEvent event) { if (event.getAction() != MotionEvent.ACTION_DOWN) return super.onTouchEvent(event); select((int) (event.getX() / width), (int) (event.getY() / height)); game.showKeypadOrError(selX, selY); return true; } Step 6: Handling Input • Showing keypad and returning the result /** Open the keypad if there are any valid moves */ Game.java protected void showKeypadOrError(int x, int y) { int tiles[] = getUsedTiles(x, y); if (tiles.length == 9) { Toast toast = Toast.makeText(this, R.string.no_moves_label, Toast.LENGTH_SHORT); strings.xml toast.setGravity(Gravity.CENTER, 0, 0); <string toast.show(); name="no_moves_label"> No moves</string> } else { Log.d(TAG, "showKeypad: used=" + toPuzzleString(tiles)); Dialog v = new Keypad(this, tiles, puzzleView); v.show(); } } private void returnResult(int tile) { puzzleView.setSelectedTile(tile); dismiss(); // dismissing a dialog from screen } Keypad.java