How to create SL4A (scrpting layer for android) native dialogs in python ?

Image

Android has a range of built-in dialogs that allow apps to interact with users. They can be used to display things like spinners and progress bars, and can be used to prompt the user for some kind of input, like a date or string.

All of the methods for creating dialogs live in SL4A’s UI Facade, along with most of the methods you’ll ever need for managing them. The UI Facade also hosts methods for creating webviews and for working with the experimental FullScreenUI stuff.

SL4A and Native Dialogs

The normal flow when using dialogs is to first create the appropriate dialog object, then set any additional features you want it to have, then render it to the user. It takes a few calls, but it’s easy to do. Once it’s displayed, there are methods for getting results from a dialog and for dismissing it. You can also update progress dialogs while they’re being rendered.

Creating Android Dialogs

You create a new dialog using one of the dialogCreate* calls. The standard dialogs are Alert, Input, Password, DatePicker, SeekBar, SpinnerProgress and HorizontalProgress.

For example, to create and render a date picker dialog, you’d do something like…

1
2
3
4
from android import Android
droid = Android()
droid.dialogCreateDatePicker()
droid.dialogShow()

Note that all interaction with the dialog is done by calling methods of droid. This is just a consequence of the way SL4A interfaces with the Android API; the droid object is a ‘god object’, so everything is a method of droid. For simplicity’s sake, there is only ever one instance of a dialog, so any dialogCreate* call will cause any existing dialog to be destroyed.

Customising Dialogs

You set any additional features of a dialog with the dialogSet* calls. What you can customise will depend on what kind of dialog you’ve created.

For example, you could set the positive button text on an alert dialog using dialogSetPositiveButtonText, and there’s matching methods for setting neutral and negative button texts. You can use any combination of the three on an alert dialog.

Displaying Dialogs

You display a dialog using dialogShow, and you can then dismiss the dialog with dialogDismiss.

Getting the Input

You can normally get any results using dialogGetResponse, which blocks until the user responds to the dialog. However, for certain types of dialogs, you may instead have to use the eventPoll method of the Events Facade to wait for a dialog event. Some dialogs, such as menus, are persistent features of an application, potentially generating multiple events over time, so they must be managed through the Events Facade.

If you create single-choice dialogs (radio buttons) or multi-choice dialogs (checklists), you must pass in a list of choices for the user to select from. You can find out which choices were selected using the dialogGetSelectedItems method. This method returns a list of integers, which map to the indices of the selected items in the list of choices you passed in. Obviously, for a single-choice dialog, there will only be one.

Say That Again in Python…

Let’s imagine we need to ask the user if they want to install a bunch of packages, then, assuming they do, we want to create a progress bar that shows how that installation process is doing. Let’s also say say we have 5 packages to install.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
import sys
 
# Create the droid object
from android import Android
droid = Android()
 
# Create an alert, setting a title and message
droid.dialogCreateAlert(
    ‘Install Packages?’,
    ‘You may want to use WiFi for this.’
)
 
# Set up a couple of buttons
droid.dialogSetPositiveButtonText(‘Yes’)
droid.dialogSetNegativeButtonText(‘No’)
 
# Now render the dialog to the user
droid.dialogShow()
 
# Get the result and dismiss the dialog
response = droid.dialogGetResponse().result
droid.dialogDismiss()
 
# Check to see if the user has pressed a button, as users can dismiss
# dialogs, and check if it was the positive one, otherwise we’re done
if not ‘which’ in response or response[‘which’] != ‘positive’: sys.exit()
 
# Now the checks are done, create and render the new progress bar dialog,
# setting a title, message and a maximum progress of 5
droid.dialogCreateHorizontalProgress(
    ‘Installing Packages…’,
    ‘This should just take a moment.’,
    5
)
 
# Render the dialog
droid.dialogShow()
 
# Now do the installation, updating the progress bar along the way…
 
# Import a couple of parsimonyms
import some_package_installing_function as install
import some_list_of_packages as packages
 
# Install each of the packages, incrementing the progress bar on each
progress = 0
for package in packages:
    install(package)
    progress += 1
    droid.dialogSetCurrentProgress(progress)
 
# Tidy up and exit
droid.dialogDismiss()

The screenshots to the right show the confirmation dialog and the progress dialog. The actual look and feel will be slightly different from device to device of course.

Android progress dialog

Android confirmation dialog

Note that, if you only want to ask the user for some text input, like Python’s input function would, or a password, you can use the dialogGetInput and dialogGetPassword methods, which are just convenient wrappers, allowing you to get these inputs in a single call.

Event Based Dialogs

The above example pretty much covered all the basics of using dialogs with SL4A, and the API Reference covers all the finer details. The only real exception to the normal way of doing dialogs (create-customise-render-read-dismiss) is when using menu items. As mentioned before, menu items are added to the native menus of applications; generally they’re always available to the user and may be clicked at any point, any number of times, so they are managed a bit differently.

For example, you can use addOptionsMenuItem to add an item to your application’s options menu. The method requires two arguments, a string that sets the text to display on the item, and a string that sets a name for the events that are produced whenever the item is clicked. You can optionally set the data that is passed with the events, and set an icon to be displayed on the menu item. Again, see the API docs for all the details.

If you’ve used the Events Facade before, this will already will make perfect sense. Either way, it’s not difficult to get started with. The following example will block, so it’d need another thread or something to be much use; this example just covers the SL4A API.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# addOptionsMenuItem takes two to four arguments:
# item_label, event_name, [event_data], [icon_name]
 
# The following calls add three items to the options menu…
droid.addOptionsMenuItem(‘Do A’, ‘a_event’, ‘Some event data.’)
droid.addOptionsMenuItem(‘Do B’, ‘b_event’, ‘Some other data.’)
droid.addOptionsMenuItem(‘Quit’, ‘kill’, None, ‘ic_menu_revert’)
 
while True:
    # Block until an event happens, then grab the result
    res = droid.eventWait().result
    
    # If it’s a kill event, exit the event loop
    if res[‘name’] == ‘kill’:
        break
 
    # Otherwise, print the event data
    print(res[‘data’])
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s