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.

Note.eps

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

9781119991335-fg0501.eps

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.

Tip.eps

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.

Remember.eps

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

9781119991335-fg0502.tif

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.

Remember.eps

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.

Note.eps

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.

Remember.eps

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.

Note.eps

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.

Remember.eps

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

9781119991335-fg0503.tif

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.

Note.eps

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.

Note.eps

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

9781119991335-fg0504.tif

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

9781119991335-fg0505.eps

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

9781119991335-fg0506.eps

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

9781119991335-fg0507.tif

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

9781119991335-fg0508.tif

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.

Remember.eps

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

9781119991335-fg0509.tif

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.

Warning.eps

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

9781119991335-fg0510.tif

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

9781119991335-fg0511.tif

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

9781119991335-fg0512.tif

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.

Note.eps

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

9781119991335-fg0513.tif

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

9781119991335-fg0514.tif

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

9781119991335-fg0515.tif

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.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
35.170.81.33