Chapter 5: AndroidDown: A Location-Aware Panic Button
In This Chapter
• Using LocationSensor for GPS location information
• Using TinyDB for persistent data
• Using SMS texting capabilities
• Using deferred processing to avoid force closures while in a wait state
The AndroidDown application gives you a solid introduction to utilizing the LocationSensor to pull GPS coordinates for your application. The LocationSensor component can use GPS, network, or Wi-Fi location systems. In this application, you use the GPS provider. The LocationSensor needs to have a “lock” on the signals from GPS satellites before it can provide coordinates. If you just told the application to wait until the LocationSensor had a strong enough signal, the Android operating system would very likely decide your application had crashed.
When an application does not accept input from the user, it assumes the application is dead and force-closes the application. To avoid this, you will learn how to use deferred processing. Deferred processing uses a Clock timer component and a procedure to check for the desired state (in this case, the GPS lock) on a timed basis. As your application attempts to get a signal lock for the LocationSensor, it bounces back and forth between a timer and a procedure. Each time the timer calls the procedure, you increment a counter. Incrementing a counter is an important programming concept that is used to count repeated events. You can use the incrementing steps found in this project to count the number of times a certain thing happens. You can also use incrementing to break out of a loop. In other words, you can count every time a certain thing happens and put a limit on the number of times it can happen.
The AndroidDown project is your first introduction to persistent data using the TinyDB component. The TinyDB component is a simple database that can store key/value pairs. TinyDB stores data with an index word called a tag. The tag is attached to the data you place in TinyDB. Your data can then be recalled from the database using the tag word. TinyDB is simple but also very powerful. Using the text
split
blocks, you can store multi-dimensional arrays or lists of data in TinyDB. For the AndroidDown application, you use TinyDB to store the applications settings. This is a common use of TinyDB; however, you can store and retrieve data in TinyDB for anything you can imagine. The only limitation of TinyDB is the storage memory on your device.
The Texting component gives you complete control over sending and receiving text messages via the SMS (Short Message Service) standard. The Texting component accesses the phone’s native SMS texting capability with simple function calls. Use this project to learn how to incorporate SMS capabilities into your applications. The ability to send and receive SMS texts is a valuable level of functionality to many applications.
You need to download the Chapter 5 project files from the companion Web site. See this book’s Introduction for more details on the Web site.
Creating the AndroidDown Application
The AndroidDown application is a panic button program. The 1.0 version sends the phone or device’s physical address to a contact selected from the device contacts. It uses the LocationSensor to report the address. The LocationSensor uses the GPS coordinates of the device to determine the physical address. It does this by sending the coordinates via network (either the phone data network or Wi-Fi) to Google Maps, which returns the address to the component. The SMS component is used to send a text message with the information gathered from the LocationSensor.
Be careful while building and testing this application. If your carrier or data package charges for SMS text messages, you will be charged when the SMS component sends a message.
Use your device’s SMS number or a Google Voice SMS number to test panic messages. Sending a flurry of SOS and panic messages to a friend or relative may not be advisable. (Or if you do, at least tell them what you’re doing first!)
Your design
Figure 5-1 shows the design sketch for the first user interface of AndroidDown. You can use the design sketch to help you while beginning the process of building the user interface.
The AndroidDown application is a location-aware panic button. It records your current address using a GPS sensor and a network data connection to Google. When the panic button is pushed, it lets the user pick a contact to send a pre-built panic SMS (Short Message Service, or text) message with the user’s location. It keeps the panic button disabled until it gets a solid fix on the current location: If there is no data in the LocationSensor, there is nothing to send in the panic message. It also lets the user know that it is still actively attempting to get a location fix.
Figure 5-1: The design sketch for AndroidDown 1.0 user interface
Your primitives
These are the simple logic and algorithms needed to accomplish your design goals:
• A phone number picker
• A way to get physical address of device
• A way to disable panic button until a fix on address is obtained
• A way to track the phones attempt to get a fix and update user
• A way to notify the user that an SMS message has been sent
• A way to send SMS messages
Your progression
These are the logical or easiest steps to build the major design goals and primitives:
1. Build the PhoneNumberPicker to select the number to which to send an SMS panic message.
2. Build the centering methods you have learned to center the AndroidDown user interface (UI) components.
3. Build the LocationSensor component to access the GPS signal and retrieve the user’s current physical address.
4. Build the process to use deferred processing to keep the phone number picker disabled until the user’s position is known.
5. Build the labels and a sequence of button image updates to keep the user informed of the status of the app.
New components
These are the new components introduced in the AndroidDown application:
• LocationSensor
• Texting
• PhoneNumberPicker
Getting Started on AndroidDown 1.0
You should design your user interface first. Your design sketches are always a good way to start the process of putting the user interface elements onto the Viewer. You can refer to them to get an idea of what buttons, labels, and components your interface requires. Keep this version of the AndroidDown application flexible for future improvements. The primary interface element of the AndroidDown application is the giant Help button in the middle of the screen. That button not only plays an integral part in the user interaction, but it’s also a primary status indicator to the user. As the AndroidDown application is looking for the current location of the user, it changes the image for the PhoneNumberPicker button to indicate it is still looking. When the location is found and fixed, the PhoneNumberPicker is enabled and the button image is changed.
Here’s how to get started on the interface:
1. Start a new project from your My Projects view and name the project AndroidDown1_0
.
2. Select the Screen1 component in the Components column. In the Properties column, change the Title
property to AndroidDown 1.0
.
3. Drag a VerticalArrangement from the Screen Arrangement palette and drop it into the Viewer. In the Components column, rename the VerticalArrangement as VirtualScreen1
.
This VerticalArrangement you have renamed VirtualScreen1 will be the primary container for all of the user interface elements. Using VirtualScreens provides for future expansion into more VirtualScreens for your 2.0 version — all you will need to do is add a new VerticalArrangement for a new virtual screen.
4. In the Properties column, set the Width
and Height
properties to Fill Parent
.
When you use padding elements to center components, the Screen1 Width
and Height
of all Arrangement containers should be set to Fill Parent
for the centering and padding elements to work. This is the easiest way to get dynamic centering of components on App Inventor interfaces.
5. Next, drag and drop a HorizontalArrangement into the VirtualScreen1.
This HorizontalArrangement is the container for the large panic button. You use the empty padding labels trick to keep it centered on the screen. In the Properties column, set the Width
and Height
properties to Fill Parent
.
6. Drag a Label component from the Basic palette into the HorizontalArrangement.
This is your left side padding element. In the Components column, rename the Label1 component to padLabel1
. For this project, you simply sequentially number all the padding elements.
Wait until your PhoneNumberPicker is in place before changing the properties on this padding element. If you remove the default text from the Text
property, the HorizontalArrangement shrinks down until it’s almost impossible to place your other components into it.
7. Open the Social palette, drag out a PhoneNumberPicker, and place it next to the padLabel1 component.
For this project, because you are learning the PhoneNumberPicker component and activities, you should leave its name unchanged. The PhoneNumberPicker is not available unless the location has been determined by the LocationSensor component. In other words, the starting state of the PhoneNumberPicker is visible but not enabled.
8. Deselect the Enabled property check box for the PhoneNumberPicker in the Properties column.
The PhoneNumberPicker takes its shape and look from the image that is loaded into the button. However, the PhoneNumberPicker Image property is populated by the property blocks in the Blocks Editor. For any image to be used as a property in the Blocks Editor, it must be first uploaded into the Media column.
9. Go ahead and upload the images for the PhoneNumberPicker button now. Click the Add button in the Media column. Click the Choose button in the Upload pop-up. Navigate to where you downloaded the project files for Chapter 5. Select the getloc.png image and click the Open button. This is the image for when the AndroidDown app is attempting to get the current location.
10. Click the Add button again and upload the help.png image file. When you see getloc.png and help.png in the Media column, you know that the files have been added to your project and will be available to assign to the PhoneNumberPicker from the property blocks.
11. Set the BackgroundColorPicker to None
.
This allows the PhoneNumberPicker button to take its shape from the nice rounded edges of the images you just uploaded. At least, they have the appearance of nice rounded edges. In reality, the images you uploaded were made with a transparent background and rounded edges on the visible part of the image. If a background color is set on the button, it won’t look as nice. So, wherever there is no image, the button doesn’t appear to be there. You can use this effect to create visually striking buttons for your user interfaces in App Inventor.
12. Delete the default text in the Text
property. The text for your button is in the images you uploaded.
13. In the Properties column, set the Width
property of the PhoneNumberPicker to 200
pixels. Set the Height
property to 250
pixels.
14. Drag a new Label component from the Basic palette to the right side of the PhoneNumberPicker. Rename this Label component as padLabel2
. Remove the default text in the Text
property. Set the Width
property to Fill Parent
. Do the exact same thing for the padLabel1. Remove the default text and set the Width
property to Fill Parent
.
If one of your padding elements becomes hard to select because it is not visible or it is too small, you can always make a component active to change its properties by clicking on it in the Components column.
You should see your PhoneNumberPicker is nicely centered left and right now, but it’s a little scrunched up at the top of the phone screen. We can use two padding elements above and below the HorizontalArrangement that contains PhoneNumberPicker to center it up and down:
1. Drag a Label from the Basic palette into the VirtualScreen1 above the HorizontalArrangement. You may need a couple of tries to get it in the right place. Remember to watch the blue line indicator to judge where on the Viewer your component will drop. Refer to Figure 5-2 if you get confused about component placement.
2. Rename the Label to padLabel3
. In the Properties column, remove the default text from the Text
property. Set the Height
property to Fill Parent
.
3. Drag another Label below the HorizontalArrangement. Rename the Label padLabel4
. Remove the default text from the Text
property. Set the Height
property to Fill Parent
.
4. Your PhoneNumberPicker in its HorizontalArrangement should be centered left and right and up and down.
Refining the interface
Your user interface is shaping up nicely, but you need the labels for status updates and labels for tracking how many times AndroidDown has tried to get a fix on its location. User interface design requires thinking about how a user might feel or think while using your application. We have disabled the panic send button until the device has a fix on the address so a “null” address isn’t sent in the panic message. Because the user cannot select who to send the panic message to until the phone has a location, you need to give some real-time feedback to the user about your application’s status:
1. Drag a HorizontalArrangement below the padLabel4 component on the Viewer. Watch where the blue line is when placing the component. Make sure it is below the padLabel4 component but still inside the VirtualScreen1 container (see Figure 5-2).
Depending on your computer screen resolution, you may have to scroll the Viewer down to see the bottom of the padLabel4 component.
2. Drag a Label component into the HorizontalArrangement2. Rename the Label as lblStatusLabel
. Change the Text
property to read Last Message Sent:
.
3. Drag a Label component to the right of the lblStatusLabel component. Rename the Label lblStatusDisplay
. Remove the default text in the Text
property.
Now you place the screen arrangement for the location fix counter and buttons:
1. Drag a new HorizontalArrangement below HorizontalArrangement2. Make sure it stays within the VirtualScreen1 container.
2. Drag a new Label component into the HorizontalArrangment3 that you just placed. Rename the label lblTrysLabel
. Change the default text in the Text
property to read Try number:
.
3. Drag a second Label component to the right of the lblTrysLabel. Rename the Label lblTriesDisplay
. Delete the default text in the Text
property.
Now you need to place the non-visible components:
1. Drag a Clock component from the Basic palette and drop it on the Viewer. Make sure it is the active component by clicking it below the Viewer or in the Components column. In the Properties column, deselect the TimerEnabled
property. You will control when and how the clock fires from the blocks. Set the TimerInterval component to 5000
. Leave the TimerAlwaysFires
property checked.
When the Clock is enabled, it waits 5,000 milliseconds (5 seconds), fires off whatever instructions the Clock1.Timer component has snapped into its block, and then waits 5,000 milliseconds and does it again.
2. Open the Social palette, drag out the Texting component, and drop it on the Viewer.
3. Open the Sensors palette, drag out the LocationSensor, and drop it on the Viewer.
Your user interface for AndroidDown 1.0 is completed. It should look like Figure 5-2. Notice that the indention of the component names in the Components column indicates their relationship with each other. You can clearly see that VirtualScreen1 is the container for HorizontalArrangement1, 2, and 3 because they are each indented to the same level beneath the VirtualScreen1. Use this behavior when troubleshooting complex or very troublesome App Inventor interfaces.
Figure 5-2: The completed AndroidDown 1.0 user interface
Locating the user’s position with LocationSensor
The LocationSensor has the capability to use multiple location methods. You use the following method to wake up the GPS sensor and see whether it has a location fix. Remember that when you use the LocationSensor, you need to tell the sensor which provider to use (in this case, GPS) and then wait for that provider to get a location fix.
1. Switch over to the Blocks Editor.
When the user starts the AndroidDown application, it needs to immediately start attempting to get a fix on its position. The Screen1.Initialize
block is the starting gate for any App Inventor application. When you need to do something when the application starts, the Screen1.Initilize
block is the block you will use.
2. Open the Screen1 blocks drawer on the My Blocks tab. Drag the Screen1.Initialize
block out onto the Blocks Editor workspace.
The LocationSensor component must have its source set. The Android operating system can use a combination of Wi-Fi and carrier network location awareness and GPS coordinates to determine location. The carrier location awareness is not very accurate because it relies on rough triangulation of your carrier signal. Wi-Fi location awareness requires a Wi-Fi signal that has been placed previously and the location remembered. For greatest accuracy, you’ll use GPS to get location for this application. The AndroidDown application depends on the user having the GPS turned on in the Location settings of his phone. Currently, App Inventor does not allow you to turn on the GPS functionality of the phone if it has been disallowed by the user.
3. Open the LocationSensor1
blocks. Drag the set LocationSensor1.ProviderName to
block and snap it in the Screen1.Initialize
block. Typeblock a text
block and replace the default text with gps
. Snap the gps
text
block into the set
LocationSensor1.ProviderName to
block.
When this block sequence is activated, the provider block is set to gps
. The GPS activates and attempts to lock onto the GPS signal. (You use this sequence again in your deferred processing procedure to keep GPS on and attempting to lock.) If you right-click the set LocationSensor1.ProviderName to
block and then select the Do It option from the menu that appears, you should see the GPS indicator on your phone. If you do not see the GPS indicator, check to make sure that GPS is enabled in your phone’s settings.
If you do not specify GPS as the provider, LocationSensor attempts to use any location-aware method, including Wi-Fi and carrier network triangulation.
When the application first starts, you want to notify your user that the application is currently attempting to get an address and location fix. You do this using the getloc.png image file you uploaded into the Media column. Set the Image
property of the PhoneNumberPicker1 to the getloc.png file using the Screen1.Intialize
event.
4. Open the PhoneNumberPicker blocks drawer. Locate the set PhoneNumberPicker1.Image to
, drag it out, and snap it into the Screen1.Initialize
block. Typeblock a text
block and change the default text to getloc.png
. Drag the text
block with the filename and snap it into the socket on the set PhoneNumberPicker1.Image to
block.
The button displays the Getting Location image on start-up. You use a procedure to determine when the location has been fixed and then set the button image to the Help image.
The procedure checks the status of the LocationSensor1.CurrentAddress
to see if there is currently a fix on the address of the device. If the phone does not have a fix on the address, it enables the Clock component, which takes further steps to activate the GPS and attempt to get a fix on the address. The Clock component disables itself and activates the procedure, which checks the status of the current address again. The clock and the procedure bounce back and forth until the procedure determines that there is a good fix on the address. Because these two components will do most of the work, you should place them on the workspace and build them together.
5. Open the Definitions blocks drawer on the Built-In tab. Drag a new procedure onto the workspace. Rename it procLocationWait
.
6. Open the Clock1 blocks drawer, drag out the when Clock1.Timer do
block, and place it on the workspace.
The Clock component is a multifunction component, a bit of “Swiss army knife” component. It has many built-in methods to call to get dates, times, and make calculations. The Clock component also has an event handler. The event is, “When the clock timer counts down, do this stuff.” The amount of time that the timer counts is set with the TimerInterval property. When the clock is enabled, it starts counting the number of milliseconds set in the TimerInterval property. If the TimerAlwaysFires property is enabled, it immediately starts the countdown again after counting down. If the TimerAlwaysFires property is not enabled, it only counts down once.
You use the procLocationWait
procedure to repeatedly enable the clock, which counts down, attempts to make the phone get a location fix, disables itself, and calls the procedure again. The procLocationWait
needs to check whether the address has been found yet. To do this, use the familiar IfElse
control block.
7. Open the Control blocks drawer on the Built-In tab. Drag an IfElse
block and snap it into the procLocationWait
procedure.
The test for the IfElse
block checks the LocationSensor1.CurrentAddress
block. If the LocationSensor
does not have a fix on the address, it reports No Address Available
in the LocationSensor1.CurrentAddress
block. Because this is an condition that will never change, we can easily test for it changing using a comparison operator.
Now to learn some advanced typeblocking and continue the deferred process method. Read through the following sequence before you do it and try to get the feel of typing entire blocks of code blocks without using the mouse:
1. Make the IfElse
control block active by clicking it on the workspace. You can tell which block is active by the orange halo effect around the block. With the IfElse
block active, typeblock a comparison operator by typing =
and pressing Enter.
The comparison block is created and automatically snapped into the test
socket on the IfElse
block. Now the comparison operator block is active and highlighted. Without clicking anything, typeblock the LocationSensor1.CurrentAddress
block.
Because you know what block you want to use in the comparison operator, you can start typeblocking it, starting with its component name. Remember that your blocks start with the component name you gave them in the Design view.
2. Start typing the component name LocationSensor1
. As you start typing, the drop-down box starts to narrow down the choices of blocks. Keep typing up to the LocationSensor1.C
. The only option left is LocationSensor1.CurrentAddress
. At this point, press the Enter key.
The LocationSensor1.CurrentAddress
block is created and automatically snapped into the first empty socket on the comparison operator.
Now the LocationSensor1.CurrentAddress
block is active, but it’s in a comparison operator block and App Inventor knows that you need something to compare the LocationSensor1
block to.
3. Without clicking anything, typeblock a text
block by typing text
and pressing Enter. The text
block is automatically created and socketed in to the last open socket on the comparison operator. The default text is automatically highlighted and you can fluidly and without stopping continue typing the text for the text
block. Type No address available
and press Enter.
You just typeblocked an entire block sequence.
If your comparison operator evaluates as true
, the Location.Sensor
does not have an address fixed. Then you enable the Clock1.Timer for another cycle:
1. Open the Clock1 blocks drawer. Scroll down through the blocks in the drawer. Notice the set Clock1.TimerEnabled to
block. It’s right next to the Clock1.TimerEnabled
block. The first block, Clock1.TimerEnabled
, reports the state of the property. The set Clock1.TimerEnabled to
block puts a value in the property.
2. Click on the workspace and start typeblocking Clock1.TimerEnabled
. Typeblocking either the reporting
block or the setting
block starts with the block name. In other words, to typeblock the set
block, you do not start by typing set
. Instead, you start with the name of the block. The block that sets a property has the component and property name appended with [to]
.
To get a property setting block when typeblocking, use the name of the block and property and a square bracket. Alternatively, when you get to only the two options left in the drop-down block, you can use the arrow keys or mouse to select the block you want to create.
From this point on, I indicate the set
blocks as you see them when typeblocking, like this: Typeblock a
“Clock1.TimerEnabled [to]”
block. (Notice that there is a space between the component name and the first square bracket.) This allows you to rapidly typeblock the required blocks by following the text.
3. Continue building your procLocationWait
and Clock1.Timer
blocks by typeblocking a Clock1.TimerEnabled[to]
block. Snap the Clock1.TimerEnabled [to]
block into the then-do
socket on your IfElse
block.
4. Make sure the Clock1.TimerEnabled
block is active and typeblock a Boolean true
block by typing the word true
and pressing Enter. The true
block should snap into the to
socket on the Clock1.TimerEnabled
block.
If your comparison operator evaluates as false
, something other than No address available
is being reported by the LocationSensor1.CurrentAddress
block. When that happens, you want the PhoneNumberPicker to be enabled so that the emergency SMS can be sent.
The enable block is the same no matter what the component name is, so you can typeblock the set PhoneNumberPicker1.Enabled to by starting to type PhoneNumberPicker.Enabled [to] and pressing Enter. (You can actually press Enter after you enter the first square bracket because there are no other blocks with that name and a to.)
5. Snap the PhoneNumberPicker1.Enabled [to]
block into the second case else-do
of your IfElse
control block. Typeblock a true
block and snap it into the to
socket on the PhoneNumberPicker
block.
6. When your LocationSensor gets a location fix and enables the PhoneNumberPicker, you need to indicate the status change to the user. Do so by changing the Image
property on the PhoneNumberPicker button.
7. Typeblock a PhoneNumberPicker1.Image [to]
block. Snap the PhoneNumberPicker.Image
block into the else-do
under the PhoneNumberPicker1.Enabled
block.
8. Typeblock a text
block and replace the default text with help.png
. This is the name of the image that you uploaded to the Media column. Remember that no matter what the text in a text
block will be, you always typeblock a text
block by typing the word text
.
9. Snap the help.png
text
block into the PhoneNumberPicker1.Image [to]
block. Now when the PhoneNumberPicker1 is enabled, its button is changed to the help.png button image.
Finalizing the location and phone number functionality
You will use the PhoneNumberPicker1.AfterPicking
event to handle what happens after a user selects a phone number. First, however, you need to build the clock routine to continue attempting to get the GPS signal and address fix. When the Clock1.Timer
counts down, you want the GPS to be activated and to attempt to get a location lock. You do this by using the set provider
block for the set LocationSensor1.ProviderName to
block:
1. Drag out the set LocationSensor1.ProviderName to
block and snap it into the Clock1.Timer
block on your workspace. Typeblock a text
block and replace the default text with gps
. Snap the gps
text
block into the LocationSensor1.ProviderName to
socket.
Every time the clock counts down and processes its blocks, the first thing it does is to set the location provider to gps
. When you set the provider,
the location sensor turns on the provider and attempts to get a position fix. Unfortunately, if it doesn’t get a fix the first time, it tends to stop trying. This is why we use the procLocationWait
procedure to check for location fix and then try again.
After setting the ProviderName, you don’t want the clock processing again until the procLocationWait
has checked the status, so you disable the Clock1.Timer
with the Clock1.Timer
.
2. Typeblock a Clock1.TimerEnabled [to]
block and snap it in below the LocationSensor1.ProviderName
block in the Clock1.Timer
block.
3. Typeblock a false
block and snap it into the to
socket on the Clock1.TimerEnabled
[to]
block.
You want to allow your user to see that the application is actively attempting to get a lock. When you designed the user interface, you created a label called Try Number
. Each time the clock processes, you need to advance a count and display that count. To do so, you use a variable that keeps track of the number of times the process has run. I show you how to increment a variable with this Try Number
process. Incrementing a variable is incredibly useful in many ways. You will often find yourself needing to count, sum, or otherwise track data in your applications. You can use some form of the process that you are using here to increment the Try Number
variable:
1. Typeblock a new variable by typing the word variable
and pressing Enter. A new variable is created and the variable name is highlighted, ready for you to change the variable name. Rename the variable to varTryNumber
.
2. Typeblock a number block by typing the number 0
and pressing Enter. Snap the number block into the varTryNumber
block.
You can typeblock your My Definitions blocks as well, although sometimes it is easier to drag them from the My Definitions drawer. To typeblock the set varTryNumber to
block, start typing varTryNumber
. The drop-down box populates with your defined blocks with that name just like any other block. The block to set the variable has the square brackets just like property set
blocks.
3. Typeblock the varTryNumber [to]
block and snap it in the Clock1.Timer
event handler below the Clock1.TimerEnabled [to]
block.
Each time the Clock1.Timer
block processes, you want to take whatever number is in the varTryNumber
variable and add one more number to it. To do so, use the varTryNumber
reporting block socketed into an addition operator block with a number block:
1. Make the varTryNumber [to]
block active by clicking it. Typeblock an addition operator by typing +
and pressing the Enter key. The +
addition operator block should be created and socketed into the varTryNumber [to]
block.
2. With the addition operator block active, typeblock the varTryNumber
global value block.
When you start typing the varTryNumber
text, the global value reporting block is the one that does not have the [to]
next to it. The square bracketed to
means that is a set
to
block.
3. When you typeblock the global
varTryNumber
, it should automatically snap into the first socket on the addition operator (see Figure 5-3). If it doesn’t, drag it and snap it into place.
4. Typeblock a number 1 block by typing the numeral 1
on your keyboard and pressing Enter. Snap the numeral 1
block into the second socket on the addition operator.
Now whenever the Clock1.Timer
blocks process, the varTryNumber
variable is incremented by one. You can now display the contents of the varTryNumber
variable in the Try Number
status label to indicate how many times AndroidDown has attempted to lock its position:
1. Open the lblTriesDisplay blocks drawer and locate the set lblTriesDisplay.Text to
block. This block allows you to set what is displayed in the label. Snap the block directly below the varTryNumber [to]
block. (See Figure 5-3.)
2. Typeblock the varTryNumber
global
block by typing varTryNumber
and pressing Enter. Snap the global
varTryNumber
block into the lblTriesDisplay.Text [to]
block. Now after the varTryNumber
variable is incremented by one, the Try Number
status label is updated with the new number.
The very last thing the Clock1.Timer
does after it counts down is call the procLocationWait
procedure so the address lock can be checked. If no address is available, run the process all over again.
3. Open the My Definitions blocks drawer and drag out the call procLocationWait
block. Snap it in as the last block in the Clock1.Timer
event handler.
4. Drag out another call procLocationWait
block and snap it in as the last block in the Screen1.Initialize
block.
Figure 5-3: The completed Clock1, procLocationWait, and Screen1 blocks
Now you have two processes that bounce back and forth until the current address is available with address information. When the address has been established, the PhoneNumberPicker component is enabled. The user can tap it to select the phone number to send the text SMS message to. Next, you need to build the event handler to handle what your application will do after the user has selected a phone number:
1. Open the PhoneNumberPicker1 blocks drawer. Locate the when
PhoneNumberPicker1.AfterPicking
do
event handler. Drag it out on a clean workspace area.
You could also typeblock this block by typing PhoneNumberPicker1.A
and pressing Enter.
PhoneNumberPicker1.AfterPicking
is the event that you will use; however, most of the functionality in the event comes from the Texting1 component. Basically, you are using the picking of the phone number as an event to do all the stuff you want to do with the texting component.
2. Open the Texting1 blocks drawer. Drag out the set Texting1.PhoneNumber to
block. Snap it into the PhoneNumberPicker1.AfterPicking
event handler block.
Just like the list picker you used in the previous project, the PhoneNumberPicker has a block that holds and reports the number the user selected. You use that block to set the Texting component’s PhoneNumber
property with the Texting1.PhoneNumber [to]
block.
3. Open the PhoneNumberPicker1 blocks drawer. Scroll down through the drawer and drag out the PhoneNumberPicker1.PhoneNumber
block. Snap this block into the set
Texting1.PhoneNumber to
block in your event handler.
Next, use text
blocks to assemble and send the message to be sent when the number is picked.
4. Open the Texting1 blocks drawer and locate the set Texting1.Message to
block. Drag it out and snap it under the Texting1.PhoneNumber
block in the AfterPicking
event handler.
5. Typeblock a call make text
block by typing make
text
and pressing Enter. Snap the make text
block into the to
socket on the Texting1.Message
block.
6. With the make text
block active, typeblock a join
text
block by typing join
and pressing Enter. Snap the join
block into the make
text
block open socket. The make text
block create a new socket.
7. With the join
block active, typeblock a text
block and replace the default text with HELP! I am at
. Make sure to leave a trailing space at the end of the text. The text
block should snap into the first open socket on the join
block.
You will be expanding on this panic message significantly in the next version of AndroidDown. Try to think ahead when planning for feature expansion.
You want the text phrase you just created to be followed by the address where the LocationSensor
block has determined the user is.
8. Open the LocationSensor1 blocks drawer. Locate the LocationSensor1.CurrentAddress
block. Drag the block out and snap it into the second socket on the join
text
block. A text string like “Help! I am at 14 Any Street, Anytown, OH 44235” is stored in preparation for being sent.
Before sending the message, you want to make sure the message has an embedded time stamp so that the recipient knows when the message was sent out from the person signaling for help. Use the make
text
to add a newline character and then a line indicating the time from the Clock1 component.
9. Typeblock a text
block and replace the default text with
. This is the newline character. Snap the newline text
block into the next open text
socket on the make
text
block.
10. Typeblock a join
text
block snap it into the next text
socket on the make text
block. Typeblock a text
block and replace the default text with Sent at:
. Again, make sure you have a trailing space after the text so that the formatting looks nice. Snap the text
block into the first socket on the join text
block.
Now use another of the Clock1’s functions. Not only does the Clock1 component provider an event handler that will tick down milliseconds and execute blocks, but it also allows you to format times and dates.
11. Open the Clock1 block drawer and locate the call Clock1.FormatDateTime instant
block. Drag it out onto the workspace. The calls to the Clock component in App Inventor tell the Clock component to return a certain formatting of time and date. But Android needs to know not only how you want the time and date formatted, but what time and date.
App Inventor uses an instant to mark a specific point in time. The .Now block creates an instant at the point in time that the block is executed. You can also create your own “instant” by using the Make Instant blocks and specifying a particular point in time. The .Now block is the one most commonly used to capture a time or date.
The way it asks for this information is called an instant. You can create and manipulate different instants for some pretty complex behaviors. But in this situation, you just need the instant returned in the form of a time and date.
12. Open the Clock1 blocks drawer again and locate the call Clock1.Now
block. Drag out the Clock1.Now
block and snap it into the instant
socket on the Clock1.FomatDateTime
block. Drag the Clock1.FormatDateTime
with its connected instant block and snap it into the second open socket on the join
block.
Now you need to update and send the message you have built and update the status message to indicate that you have successfully sent the message:
1. Open the Texting1 blocks drawer and locate the call Texting1.SendMessage
block. Drag the SendMessage
block and snap it in below the make
text
block in your AfterPicking
event handler. This block takes whatever text has been placed in the Texting1.Message
block and sends it using Android’s native SMS capability.
Now you need to update the status label to show the panicking user that their message has been sent.
2. Open the lblStatusDisplay blocks drawer and drag out the set lblStatusDisplay.Text to
block. Snap it into the PhoneNumberPicker1.AfterPicking
event handler below the Texting1.SendMessage
block.
3. Copy the entire make
text
block and all its attached blocks and paste a copy. Make the make text
block that is socketed in the Texting1.Message
block active by clicking on it. Press Ctrl+C. This makes a copy of the blocks in memory. Now, press Ctrl+V to paste a copy of the blocks. Drag the copy of the make
text
and all its blocks and snap it into the socket on the lblStatusDisplay.Text [to]
block.
Your PhoneNumberPicker1.AfterPicking
event should now look like Figure 5-4.
Package the AndroidDown 1.0 application to your phone from the Design view. Make sure the GPS settings have GPS enabled. Test the functionality of AndroidDown. If AndroidDown has difficulty getting a fix on the location, be patient: It can take a few minutes. Remember that some cell phone carrier plans charge for SMS text messages. Know your smartphone plan and be aware that you could incur charges testing the AndroidDown application.
Now, time to move on to making the AndroidDown application a more practical, full-fledged, and usable panic button application.
Figure 5-4: The completed PhoneNumberPicker1.AfterPicking event handler
Creating AndroidDown 2.0
AndroidDown 2.0 adds to the functionality of the previous version. AndroidDown 2.0 sends its emergency SMS text message as soon as the application is started. The first time the application starts it will ask for and stores the contact number that the user designates as the emergency contact, as well as storing the way the user wants the application to behave (such as whether the application should send the SMS at application start). The 2.0 version retains all of the functionality of the previous version, with the ability to select a contact from the address book and send the SMS emergency message to the selected contact.
Your design
AndroidDown 2.0 (Figure 5-5) ramps up the usability of the application. It also introduces a level of complexity you haven’t experienced yet. It uses multiple state checks to determine the application’s process flow. You will see how you can create the ability to store settings for your applications. AndroidDown 2.0 allows the user to select the behavior they desire. Using the TinyDB component, you store the user’s selections between sessions of the AndroidDown application. The idea of storing data for your application between instances of the application running is known as data persistence. AndroidDown 2.0 is your first exposure to data persistence with App Inventor. I cover local data persistence and network data persistence in Chapter 7.
Figure 5-5: The design sketch for AndroidDown 2.0
The complexity of AndroidDown 2.0 requires that you build a fairly involved logic flow. This chart isn’t a literal yes/no decision chart, nor is it to build from, but instead shows you the relationship of each part of the application’s logic flow. Read through it carefully before you start and refer back to it to keep in mind a good overall view of what you are trying to accomplish while you are building the individual block components. Come back to this flow chart when you have finished the project and read through it again. Both the flow and the project will be clearer. Unlike previous applications, this application has some fairly non-linear decisions and flow. After you complete this project, you should have an understanding of some of the things you will need to take into account when building very complex applications. When you are designing applications with lots of functionality, your job is easier if you take the time to sit down and create a logic flow chart like the one in Figure 5-6. A better flow chart would map each decision and the actual flow of the programming. The chart in Figure 5-6 is a polished recreation of a hand-drawn flowchart I sketched out while designing the AndroidDown application. Without this hand-drawn logic flow, I would have been lost fairly quickly when building the AndroidDown 2.0 application.
Figure 5-6: The program flow and logic for AndroidDown 2.0
Your primitives
These are the new pieces of functionality you will build into the AndroidDown application:
• A new VirtualScreen for the Settings screen
• A way to store the Emergency contact number
• A way to store and detect the AutoSend setting
• A database to store settings
• An algorithm to set settings only on the first run
• An algorithm to check and load settings on subsequent runs
• AutoSend message delay
• An algorithm to send a Google Maps link to device current location
Your progression
The following is a list of basic steps towards creating the new primitives, algorithms, and logic:
1. Create the VirtualScreen2 settings screen.
2. Add user interface elements to VirtualScreen1 and VirtualScreen2.
3. Create variables to store settings.
4. Create button events for Save Settings DB.
5. Create button events for Open settings.
6. Create button event for the Exit button.
7. Create Screen.Init
to check for settings and load settings or to start the main app.
8. Create a procedure for SendMessage
.
9. Create a procedure for SaveSettings
.
10. Create a procedure for LoadSettings
.
11. Alter procLocWait
.
New components
Only one new component is introduced in this version of the app:
• TinyDB
New blocks
Only one new block is introduced in this version of the app:
• If
Getting Started on AndroidDown 2.0
You will build AndroidDown 2.0 a little bit differently than you built previous projects in this book. The goal with AndroidDown 2.0 is to begin to think holistically to understand how various individual parts of an application work in relationship to each other to accomplish the application’s design goals. Instead of building a complete procedure or event before moving on to the next one, you define all of the procedures and variables initially as barebones programming structures with no instructions in them. Then, you move through each defined procedure or event handler, fleshing it out with the instructions it needs to accomplish the design goals. This allows you to both see the program grow organically and also allows you to call a procedure before it is completely built.
The AndroidDown 1.0 application changes fairly radically in its 2.0 version. However, you still use the procedures and logic already in place in version 1.0. You adjust and change them somewhat as you move along:
1. Begin by opening the AndroidDown 1.0 application and saving a copy by using the Checkpoint button in Design view. Change the default checkpoint name to AndroidDown2_0
.
2. Drag a HorizontalArrangement onto the VirtualScreen1 below the lblTriesDisplay
label. This HorizontalArrangement holds the buttons at the bottom of your main application screen. One button is to open to the Settings screen. The other is to exit the AndroidDown program entirely.
3. Drag a Button component from the Basic palette into the new HorizontalArrangement. Rename the button btnSettings
in the Components column. Change the Text
property to Settings
.
4. Drag a second Button component to the right of the Settings button. Rename the Button component btnExit
in the Components column. Change the default Text
property to Exit
.
Now create the second VirtualScreen to act as the settings page for your AndroidDown application. The settings for AndroidDown 2.0 consist of the emergency contact number and the setting for whether to auto-send when the application starts. Your application checks on startup to see whether the settings have been set. If they have been set, VirtualScreen1 is visible; if the settings have not been set, VirtualScreen2 is visible. This enables the AutoSend feature and the emergency contact to be set from the first time the application ever runs. You store the settings in TinyDB.
5. Drag a new VerticalArrangement onto the Viewer below the VirtualScreen1. Rename the VerticalArrangement VirtualScreen2
.
6. Drag a Label into the VirtualScreen2. Rename the Label component lblContactDisplay
. Change the default text in the Text
property to Emergency Contact Number
.
7. Drag a TextBox component into the VirtualScreen2. Rename the text box txtContactNumber
. This text box is where your user enters the number they want the emergency SMS text number sent to when AndroidDown starts. You store the user’s entry in this text box, first in a variable and then in TinyDB.
8. In the Properties column, change the Hint
property to Enter Emergency Contact
. This prompts your user for the number when the setting screen is open.
Ask the user if she wants the AndroidDown application to automatically send the emergency message on application startup. For a yes/no question, you can use a CheckBox component.
9. Drag a new CheckBox component below the txtContactNumber text box. Rename the CheckBox component chkAutoSend
. Change the default text in the Text
property to Automatically
send panic message at app start?
.
Now you need a button to save the user’s setting choices. The single Save button saves the settings and exits back to VirtualScreen1.
10. Drag a new Button component onto the VirtualScreen2 below the chkAutoSend check box. Rename the button btnSaveSettings
. Change the text in the Text
property to Save
.
11. Drag a TinyDB component from the Basic palette and drop it onto the Viewer. It drops below the Viewer in the Non-Visible Components area.
The TinyDB component is a very simple database storage component. It allows you to store data with a tag. The tag can be used to retrieve the data. In other words, you could store the emergency contact number with the tag number. When the program starts again, instead of the user having to reenter the number, your application calls the number up from the TinyDB storage area using the tag number
. TinyDB is a very simple and very effective way to store small amounts of data and settings. TinyDB can contain as much data as you have memory on in your phone in plain text and numbers. That data exists from one session of your application to the next session.
Your user interface changes have been made at this point. You should have the elements as you see in Figure 5-7.
Figure 5-7: The user interface components for AndroidDown 2.0
Building your button event handlers
Launch and switch over to the Blocks Editor. You will build all the button event handlers first. However, to do that, you need to have all your procedure calls available. You do this by creating procedures and leaving them empty for the moment. That way, you can put the procedure calls into the button event handlers. When the procedures are built, the calls will be in the right place. As you place the procedure calls, you can refer back to the application logic flow diagram to see how you are creating the skeleton of the flow that you will flesh out with its muscles later.
1. Scroll the Blocks Editor workspace to an empty place. Typeblock a procedure by typing procedure
and pressing Enter. Rename the procedure procSaveSettings
.
2. Typeblock a new procedure and rename it procLoadSettings
.
3. Typeblock a new procedure and rename it procSendMessage
.
4. You should now have a total of four defined procedures and their call
blocks in your My Definitions drawer. One is from the AndroidDown 1.0 version named procLocationWait
, which you continue to use in the AndroidDown 2.0 application (see Figure 5-8).
Figure 5-8: Your skeletal procedures and their calls
Now you can use the calls from the skeletal procedures to build up your button event handlers. The logic of your application says that the application should check on start up to see whether the program has ever had the contact number and AutoSend settings set before. You use a variable to store the answer to the question, “Is this the first time AndroidDown has ever run?” If the answer is true
, the Settings page on VirtualScreen2 is shown so that the contact number and AutoSend settings can be set. When the settings are set the first time, the variable is set to false
. If the answer to the preceding question is false
, depending on whether the AutoSend
variable is set to true
or false
, the main VirtualScreen1 is activated and the emergency SMS is sent.
When you are making decisions related to your application’s logic flow, you always use some form of a Control
block from the Control drawer on the Built-In tab.
The following steps use the Screen1.Initialize
block to query TinyDB and then the first start variable. You rebuild the Screen1.Initialize
and make the changes to query and load settings from TinyDB:
1. Locate the Screen1.Initialize
block on your workspace. Currently it sets the LocationProvider name, sets the PhoneNumberPicker button image, and calls the procLocationWait
. These steps significantly change Screen1.Initialize
.
2. Remove and delete the call
LocationWait
block from the Screen1.Initialize
block.
3. Remove and delete the set LocationSensor1.ProviderName
to
block.
4. Leave the set PhoneNumberPicker1.Image to
block in the Screen1.Initialize
block.
Now you start to rebuild the Screen1.Initialize
block. Refer to Figure 5-9 if you get confused or lost while working through the steps. The very first thing the application should do after setting the PhoneNumberPicker button image is load the settings from TinyDB, if the settings are available:
1. Drag the call procLoadSettings
block from your My Definitions drawer and snap it into the Screen1.Initialize
block below the PhoneNumberPicker
block. Currently the procLoadSettings
is empty and doesn’t do anything, but you change that when you build up the procLoadSettings
block.
Next, your application needs to decide based on the settings that have been loaded whether this is the first time the application has been run. It does that by evaluating the settings that have been loaded into your variables. Currently you don’t have any variables defined. Take this opportunity to think through what settings need to be stored and to define all the variables you will need for the AndroidDown 2.0 application.
You need to store all the user input from VirtualScreen2 in your Settings page: the Emergency contact number and the AutoSend settings.
2. Typeblock a new variable by typing variable
and pressing Enter. Rename the variable varContactNumber
. Typeblock a text
block by typing text
and pressing Enter. Remove the default text from text
block, leaving an empty text
block. Snap the empty text
block into the varContactNumber
block.
You now need to store whether the value of the AutoSend check box is true
or false
.
3. Typeblock a new variable and rename it varAutoSend
. Typeblock a false
block by typing false
and pressing Enter. Snap the false block into the varAutoSend
block.
You need to track one unseen setting and that is whether this is the first time the application has been run. You store this true
or false
value in a variable as well.
Typeblock a variable and rename it varFirstRun
. Typeblock a true
block by typing true
and pressing Enter. Snap the true
block into the varFirstRun
block. The varFirstRun
variable now read as true,
indicating it is the first run of the application unless the procLoadSettings
process has loaded a false
value into the varFirstRun
.
You should now have three new variables defined:
• varContactNumber
• varAutoSend
• varFirstRun
You evaluate the varFirstRun
variable as the next step in the Screen1.Intialize
block:
1. Drag an IfElse
block from the Control blocks drawer on the Built-In tab and snap it in below the procLoadSettings
.
With the IfElse
block selected, begin to build the test condition.
2. Typeblock a comparison operator by typing =
and pressing Enter. The comparison operator block should snap into the test
socket on the IfElse
block.
3. With the Comparison block selected, typeblock the global
varFirstRun
block by typing varFirstRun
and pressing Enter. The varFirstRun
block should snap into the first socket on the comparison operator.
4. With the comparison operator selected, typeblock a false
block. The false
block should snap into the final empty socket on the comparison operator. You are now comparing the contents of the varFirstRun
variable with the value false
. If the contents of the variable are false
, the then-do
blocks execute. The varFirstRun
being false
means that this is not the first time AndroidDown has run and you should start the process of establishing location. You also want to enable the VirtualScreen1 main screen.
5. Drag the call procLocationWait
block from the My Definitions drawer and snap it into the then-do
socket in your IfElse
block. The procLocationWait
procedure is the procedure from AndroidDown 1.0 that begins the process of establishing and fixing address and location.
6. Typeblock the set VirtualScreen1.Visible to
block by typing VirtualScreen1.Visible [to]
and pressing Enter. Snap the VirtualScreen1.Visible
block under the call LocationWait
block in the then-do
socket on your IfElse
block.
7. With the VirtualScreen1.Visible
block still selected, typeblock a true
block. The true
block should snap into the VirtualScreen1.Visible
block.
8. Typeblock the set VirtualScreen2.Visible to
block by typing VirtualScreen2.Visible [to]
and pressing Enter. Snap the VirtualScreen2.Visible
block under the VirtualScreen1.Visible
block.
You can press Enter as soon as the block you want is the only one left in the Typeblock drop-down list. Usually, by the time you type the [, you can press Enter.
9. With the VirtualScreen2.Visible
block selected, typeblock a false
block. The false
block should snap into the VirtualScreen2.Visible
block.
At this point, if the application starts and the varFirstRun
reports a value of false,
the procLocationWait
is started. The VirtualScreen2 is made invisible and VirtualScreen1 is made visible.
Now you need to set up the case for when the varFirstRun
has a value of true
, indicating a first-time run. If this is the first run, you need to make the Settings page visible so the AutoSend and emergency contact settings can be set and saved to TinyDB:
1. Typeblock VirtualScreen1.Visible [to]
and press Enter. Right after you press Enter, start typeblocking a false
block and press Enter. This should create the set VirtualScreen1.Visible to
block and then immediately created a false
block and socket it into the VirtualScreen1.Visible
block.
2. Snap the VirtualScreen1.Visible
block with its false
block and into the else-do
socket on your IfElse
block.
3. Typeblock a VirtualScreen2.Visible [to]
block and immediately typeblock a true
block into it. Drag the VirtualScreen2.Visible
block under the VirtualScreen1.Visible
block in the else-do
socket.
4. If the test condition determines there is anything other than false
in the varFirstRun
variable, it enables the Settings screen on startup.
At this point, your completed Screen1.Initialize
block should look like Figure 5-9.
Figure 5-9: The completed Screen1.Intialize block
Creating your button events
You have three buttons on your user interface. On VirtualScreen2, you have the Save settings button that saves the contact number and AutoSend settings to the database and makes VirtualScreen1 visible. On VirtualScreen1, you have a Settings button to access the Settings screen. You also have an Exit button to gracefully leave AndroidDown without it continuing to attempt to locate itself and send its SMS text:
1. The Settings button on the VirtualScreen1 makes VirtualScreen2 visible. It also loads whatever is stored in the varContactNumber
into the TextBox component and whatever value is in the varAutoSend
into the CheckBox component. That way, if there are stored settings, the user sees what they are.
2. Open the btnSettings blocks drawer. Drag out the when btnSettings.Click do
event handler onto your workspace. You use the VirtualScreens .Visible
blocks to make VirtualScreen1 invisible and VirtualScreen2 visible.
3. Typeblock a VirtualScreen1.Visible [to]
block by typing VirtualScreen1.Visible [
and pressing Enter. Without a pause, continue typing a false
block. The false
block should socket into the VirtualScreen1.Visible
block. Snap the VirtualScreen1.Visible
block into the btnSettings.Click
block. (See Figure 5-10.)
4. Typeblock a VirtualScreen2.Visible [to]
block and a true
block into the VirtualScreen2.Visible
block. Snap the VirtualScreen2.Visible
block under the VirtualScreen1.Visble
block.
5. Typeblock the txtContactNumber.Text [to]
block and, without pausing, start typeblocking the varContactNumber
global variable block into it. Snap the txtContactNumber.Text
block with its varContactNumber
block into the btnSettings
event handler under the VirtualScreen
blocks.
6. Typeblock the chkAutoSend.Value [to]
block and immediately typeblock the varAutoSend
global variable block into it. Snap the chkAutoSend.Value
block into the btnSettings
event handler under the txtContactNumber.Text
block.
7. Open the btnExit blocks drawer. Drag out the when btnExit click
event handler.
8. Open the Control blocks drawer on the Built-In tab. Locate the call close screen
block. Snap the close screen
block into the btnExit.Click
event handler. Whenever the btnExit button is tapped, it closes all the AndroidDown processes and exits the program.
The Save Settings button from VirtualScreen2 is a little more complex. When the button is tapped, it stores all the settings from the screen into their respective variables and then save the contents of the variables into TinyDB. The Settings button event also sets the varFirstRun
variable to false
because if the settings have been set, it can’t continue to say that AndroidDown has never run before. The varFirstRun
variable contents also must be saved to TinyDB. All of these actions, however, are handled by the procSaveSettings
procedure. For now, you simply call the procedure in the button event.
9. Open the btnSaveSettings blocks drawer on the My Blocks tab. Drag the when
btnSaveSettings.Click do
onto your Blocks Editor workspace.
10. With the btnSaveSettings.Click
block selected, typeblock the call procSaveSettings
block by typing procSaveSettings
and pressing Enter. The procSaveSettings
block should snap into the btnSaveSettings.Click
event handler.
After the settings are saved, the user exits back to the VirtualScreen1 main screen:
1. With the btnSaveSettings.Click
block selected, typeblock a VirtualScreen2.Visible [to]
block and immediately typeblock a false
block. The VirtualScreen2.Visible
block should auto-snap into the btnSaveSettings.Click
event handler and the false
block should auto-snap into the socket on the VirtualScreen2.Visible
block.
2. Typeblock a VirtualScreen1.Visible [to]
block and typeblock a true
block into the VirtualScreen1.Visible
block. Make sure that the VirtualScreen1.Visible
block is snapped in below the VirtualScreen2.Visible
block in the btnSaveSettings.Click
event handler.
At this point, you should be getting fairly proficient at typeblocking chains of blocks. Remember, though, that sometimes auto-snap snaps a block into the wrong socket and either generates an error or winds up in the wrong place. Always double-check typeblocked blocks visually.
All of your button events should be handled at this point.
Figure 5-10: All of the button events for AndroidDown 2.0
Sending the message
Next you alter the PhoneNumberPicker.AfterClicking
event. In the AndroidDown 1.0, the PhoneNumberPicker.AfterClicking
event handled the task of sending the SMS. In the 2.0 version, the PhoneNumeberPicker.AfterPicking
event only sets the SMS number. Your procSendMessage
procedure is the workhorse of your SMS activity. Your procSendMessage
is responsible for sending the SMS when appropriate, so you strip the logic from the AfterPicking
event and place it in the procSendMessage
. When you get to the procSendMessage
procedure, you significantly alter these blocks. Because you have most of the SMS logic built in, moving the blocks to the procSendMessage
saves you time when it’s time to build the procSendMessage
procedure:
1. Drag the empty procSendMessage
procedure close to the PhoneNumberPicker1.After
picking
block.
2. Click on the first block in the AfterPicking
event handler (it should be the Texting1.PhoneNumber
block), drag and snap it into the procSendMessage
block. All of the blocks in the AfterPicking
event should drag over to the procSendMessage
block and snap in. All of the blocks that were in the PhoneNumberPicker1.AfterPicking
event should now be in the procSendMessage
procedure block. (See Figure 5-11.)
When the user taps the Help button on the VirtualScreen1 main screen, you want whatever phone number they picked to be stored in the varContactNumber
so the procSendMessage
procedure can use it as the SMS contact number.
Figure 5-11: The incomplete procSendMessage and completed AfterPicking event handler
3. Make the PhoneNumberPicker1.After
picking event handler active by clicking it.
4. Typeblock the set varContactNumber to
by typing varContactNumber
[to]
and pressing Enter. Immediately typeblock the PhoneNumberPicker1.PhoneNumber
block. It should auto-snap into the varContactNumber [to]
block.
The set varContactNumber to
block should have auto-snapped into the PhoneNumberPicker1.AfterPicking
event handler.
5. Typeblock the call procSendMessage
block by typing procSendMessage
and pressing Enter. Snap it in below the varContactNumber [to]
block in the AfterPicking
event handler.
Now, when a user clicks the PhoneNumberPicker button with the word Help
on it, the selected phone number is placed in the varContactNumber
and the procSendMessage
process is called to send the emergency SMS.
Next, start fleshing out the internal logic and instructions for your procedures:
1. Locate the procSaveSettings
procedure and drag it to a clean workspace. If your workspace gets cluttered, make use of the Organize All Blocks function. Right-click any empty workspace on the Blocks Editor and click the Organize All Blocks option.
The procSaveSettings
procedure takes the settings from txtContactNumber
and chkAutoSend
and stores them in their variables and then saves them to TinyDB.
2. Make the procSaveSettings
procedure block active by clicking it.
3. Typeblock the varContactNumber [to]
block. It should auto-snap into the procedure. Typeblock the block to report the contents of the txtContactNumber
TextBox. Type txtContactNumber.Text
and press Enter. It should auto-snap into the varContactNumber [to]
block.
4. Typeblock the varAutoSend [to]
and make sure it snaps in under the previous variable set-to
block. Typeblock the block to report the value of the chkAutoSend CheckBox by typing chkAutoSend.Value
. Snap the chkAutoSend.Value
block into the varAutoSend [to]
block.
5. Typeblock the varFirstRun [to]
block and snap it under the previous two variable setting blocks. Typeblock a false
block and snap it into the varFirstRun [to]
block. See Figure 5-12 for the variable block configuration.
Figure 5-12: The completed procSaveSettings procedure
Next you use the Store.Value
block from TinyDB to store the contents of the variables for long-term storage. TinyDB uses a tag for every value you store in it. You can retrieve that value by using the .GetValue
block and referencing the tag it was stored under. The tag is just a text
block with text in it that you choose to reference the data you store. You use a tag that refers to the data you stored. When stored, your data will look like Table 5-1:
Table 5.1 Tags and Values for the AndroidDown TinyDB
Tag |
Value |
contactnumber |
varContactNumber |
autosend |
varAutoSend |
firstrun |
varFirstRun |
Follows these steps for building up the procedure and using TinyDB to store the contact number and auto send settings.
1. Open the TinyDB1 blocks drawer on the My Blocks tab. Drag out the call TinyDB1.StoreValue
block and drop it on your workspace. Copy the block by selecting it and press Ctrl+C to copy. Press Ctrl+V twice to paste two copies.
You should now have three call TinyDB1.StoreValue
blocks. When you want to store something in TinyDB, use a .StoreValue
block.
2. Snap the three .StoreValue
blocks into the procSaveSettings
procedure block (see Figure 5-12).
3. Select the first TinyDB1.StoreValue
block. Typeblock a text
block. It should auto-snap into the tag
socket on the TinyDB1.StoreValue
block and be ready to receive the tag name for this StoreValue
. Replace the highlighted text in the text
block with contactnumber
and press Enter.
4. Without clicking anything, typeblock the global varContactNumber
block by typing varContactNumber
and pressing Enter. The varContactNumber
reporting block should auto-snap into the valueToStore
socket on the TinyDB1.StoreValue
block.
5. Select the next .StoreValue
block. Typeblock a text
block and change the default text to autosend
. It should auto-snap into the tag
socket on the .StoreValue
block.
6. Typeblock the global varAutoSend
block by typing varAutoSend
and pressing Enter. It should auto-snap into the valueToStore
socket below the tag.
You can make the next TinyDB1.StoreValue block active by pressing Tab on your keyboard.
7. Make the next .StoreValueBlock
active. You can click it or press Tab if the previous block is still active.
8. Typeblock a text
block and change the default text to firstrun
. It should auto-snap into the tag
socket.
9. Typeblock the global varFirstRun
block by typing varFirstRun
and pressing Enter. It should auto-snap into the valueToStore
socket.
Now whenever the procSaveSettings
procedure is called, it takes the settings from the Settings screen and store it first in the variables and then in TinyDB for long-term retrieval.
After the data has been stored in TinyDB, it can be retrieved at any point instantaneously using the .GetValue
blocks. Follow these steps to build up the procedure for loading the application settings from TinyDB:
1. Locate the procLoadSettings
procedure in your Blocks Editor workspace.
The TinyDB .GetValue
blocks can be used to store the contents of a tag directly into a variable or process. In other words, using the .GetValue
blocks with a tag of contactnumber
immediately returns the result of whatever was stored with that tag.
2. Make the procLoadSettings
block active. In quick succession, typeblock varContactNumber [to]
and press Enter. Typeblock varAutoSend [to]
and then press Enter. Typeblock varFirstRun [to]
and press Enter.
All three blocks set
blocks for your variables should auto-create and auto-snap into the procLoadSettings
block.
3. Open the TinyDB1 blocks drawer and drag out a call TinyDB1.GetValue tag
block and place it on your workspace. Select the block and copy it by pressing Ctrl+C. Make two copies of the .GetValue
block by pressing Ctrl+V twice.
You should now have three TinyDB1.GetValue
blocks. Snap a TinyDb1.GetValue
block into each of the variable set-to
blocks in the procLoadSettings
block.
This block configuration places into each of the variables whatever value is returned from the .GetValue
blocks. The .GetValue
blocks return whatever was stored under the tag
that is socketed into the .GetValue
blocks.
4. Select the .GetValue
block in the varContactNumber
block. Typeblock a text
block and replace the default text with contactnumber
. This is the tag you used to store the contact number variable.
5. Select the .GetValue
block in the varAutoSend
block. Typeblock a text
block and replace the default text with autosend
. This is the tag you used to store the AutoSend
variable.
6. Select the .GetValue
block in the varFirstRunblock
. Typeblock a text
block and replace the default text with firstrun
. This is the tag you used to store the varFirstRun
variable. The completed procLoadSettings
should look like Figure 5-13.
Figure 5-13: The completed procLoadSettings procedure block
Next, build up the procSendMessage
procedure that is called whenever a message needs to be sent:
1. Locate the procSendMessage
procedure block on your Blocks Editor workspace and drag it to an open area of your workspace. If you begin to run out of workspace, moving a block to the farthest right side of the workspace increases the workspace horizontally.
The current procSendMessage
block contains the blocks that were in the AfterPicking
event handler. The set Texting1.PhoneNumber to
block should be the first block in the procSendMessage
block. It should have the PhoneNumberPicker1.PhoneNumber
block snapped into its socket.
2. Remove the PhoneNumberPicker1.PhoneNumber
block from the Texting1.PhoneNumber
block and delete it.
3. Make the Texting1.PhoneNumber
block active and typeblock varContactNumber
. Press Enter. The global varContactNumber
block should be created and auto-snapped into the to
socket on the Texting1.PhoneNumber
block.
You expand the Texting1.Message
block to include a Google Maps link to the devices current location. The URL for the Google Maps link must conform to the following format:
http://maps.google.com/maps?q=latitude,longitude
You use text
blocks to build up this link with
text
blocks and the latitude and longitude from the LocationSensor.
4. Typeblock a text
block and change the default text to
— this is the newline character. Socket the newline text
block in the open text
socket on the make text
block.
5. Typeblock a text
block and change the default text to Map link:
. Make sure to leave a trailing space after the text. Snap the Map link:
text
block into the open text
socket on the make text
block.
6. Typeblock a text
block and change the default text to http://maps.google.com/maps?=
. Snap the URL block into the next open text
socket on the make
text
block.
7. Open the LocationSensor1 blocks drawer and locate the LocationSensor1.Latitude
block. Drag the LocationSensor1.Latitude
block and snap it into the next text
socket on the make
text
block.
8. Typeblock a text
block and change the default text to a single comma (,
). Snap the comma text block into the next text
socket on the make
text
block.
9. Open the LocationSensor1 blocks drawer and locate the LocationSensor1.Longitude
block. Drag the Longitude block and snap it into the next text
socket on the make
text
block.
Now remove the make text
block directly below the one you just altered:
1. Select the make text
block that is socketed into the lblStatusDisplay
.Text
block. Delete the entire make text
and all its blocks. You will duplicate the previous make
text
you have altered.
2. Select the make
text
block socketed into the Texting1.Message
block. Press Ctrl+C to copy the block and then press Ctrl+V to paste it.
3. Drag the copied make text
block and snap it into the socket on the lblStatusDisplay.Text
block.
Your completed procSendMessage
procedure should look like Figure 5-14.
Figure 5-14: The completed procSendMessage procedure
Finalizing the procLocationWait procedure
The procLocationWait
procedure needs to be altered slightly. If the test for the IfElse
block in the procLocationWait
evaluates to true
, the location has been fixed, in which case we need to send the message if the AutoSend setting is set to true
. Use a simple If
block to test whether the varAutoSend
is indeed set to true
. If it is not, the application acts just as it did in AndroidDown 1.0. Regardless of whether the AutoSend is enabled, the procLocationWait
still enables the PhoneNumberPicker and changes its button image:
1. Locate the procLocationWait
procedure on your Blocks Editor workspace and drag out an If
block from the Control blocks drawer on the Built-In tab. Snap the If
block into the else-do
socket on the IfElse
block in the procLocationWait
procedure.
2. With the If
block selected, typeblock a comparison operator by typing =
and pressing Enter. The comparison operator should snap into the test
socket on the If
block.
Continue building the If
test by typeblocking the varAutoSend
global variable block. Make sure it snaps into the first open socket on the comparison operator.
3. Typeblock a true
block and make sure it snaps into the second socket on the comparison operator.
4. If varAutoSend
is true
, you need to call the procSendMessage
procedure. Typeblock a callprocSendMessage
block by typing procSendMessage
. Snap the procedure call
block into the If
block.
Your altered procLocationWait
block should look like Figure 5-15.
Figure 5-15: The altered procLocationWait block
Package your AndroidDown application (see Chapter 1 for more on packaging and installing applications) and install it on your phone. Test each level of functionality. Make sure that is saving settings and restoring them when you exit the application and restart it. Store a string of text such as qwerty
, rather than a number, in the Emergency Contact setting to keep the application from sending an SMS while testing.
You explored three important concepts in this application. The first concept is that of persistent data. You can store settings, user input, application state, or whatever you like in TinyDB using a simple tag system, thus making data persist. As you create more applications, TinyDB becomes more and more useful. The second very useful concept is that of cycling through processes until you obtain a desired result. You used the Clock1.Timer
and the procLocationWait
to keep the phone looking for its location without locking up the application or the phone. This is known as deferred processing and is a concept you will use many times. The third concept you used is that of incrementing a counter variable. The variable increment can be used in tasks such as breaking out of a loop after a certain number of passes or keeping score in a game.
Congratulations! You have completed a very complex application that you can now give to your teenagers, your girlfriend, or mother, or anyone else. It will prove useful in situations as diverse as avoiding a creepy stalker to getting rescued from a bad party.