2017년 7월 16일 일요일

No Texting While Driving


This chapter walks you through the development of No Texting While Driving, an app that autoresponds to text messages you receive while you're driving. The app, first created with App Inventor by a beginning computer science student, is similar to a now-mass-produced app developed by State Farm Insurance. It is a prime example of how App Inventor provides access to some of the great features of the Android phone, including SMS text processing, database management, text-to-speech, and the location sensor.



In January 2010, the National Safety Council (NSC) announced the results of a study that found that at least 28 percent of all traffic accidents-close to 1.6 million crashes every year-are caused by drivers using cell phones, and at least 200,000 of those accidents occurred while drivers were texting 

(http://www.nsc.org/pages/nscestimates16millioncrashescausedbydriversusingcellphonesandtexting.aspx). As a result, many states have banned drivers from using cell phones altogether.
Daniel Finnegan, a student in the Fall 2010 session of the University of San Francisco App Inventor programming class, came up with a great app idea to help with the driving and texting epidemic. The app he created, which is shown in Figure 4-1, responds automatically (and hands-free) to any text with a message such as "I'm driving right now, I'll contact you shortly."

Some in-class brainstorming led to a few additional features that were developed for a tutorial posted on the App Inventor site:
The user can change the response for different situations

  For example, if you’re going into a meeting or a movie instead of driving, the response can be modified accordingly.

The app speaks the text aloud
  Even if you know the app will autorespond, the jingle of incoming texts can kill you with curiosity.
The response message can contain your current location

Figure 4-1. The No Texting While Driving app

  If your partner is at home making dinner, he or she would probably like to know how much longer your commute will last, without endangering you by having you answer the text.
Some weeks after the app was posted on the App Inventor site, State Farm Insurance created an Android app called "On the Move," which has similar functionality to No Texting While Driving (http://www.statefarm.com/aboutus/newsroom/20100819.asp). The service is free to anyone, as part of State Farm's updated Pocket Agent for AndroidTM application, which the company announced in a YouTube video that can be found here: http://www.youtube.com/watch?v=3xtjzO0-Hfw.

We don't know if Daniel's app or the tutorial on the App Inventor site influenced "On the Move," but it's interesting to consider the possibility that an app created in a beginning programming course (by a creative writing student, no less!) might have inspired this mass-produced piece of software, or at least contributed to the ecosystem that brought it about. It certainly demonstrates how App Inventor has lowered the barrier of entry so that anyone with a good idea can quickly and inexpensively turn his idea into a tangible, interactive app.

What You'll Learn

This is a more complex app than those in the previous chapters, so you'll build it one piece of functionality at a time, starting with the autoresponse message. You'll learn about:

⦁ The Texting component for sending texts and processing received texts.
⦁ An input form for submitting the custom response message.
⦁ The TinyDB database component for saving the customized message even after the app is closed.
⦁ The Screen.Initialize event for loading the custom response when the app launches.
⦁ The Text-to-Speech component for speaking the texts aloud.
⦁ The LocationSensor component for reporting the driver’s current location.

Getting Started

For this app to work, you need a text-to-speech module, Text-To-Speech Extended, on your phone. This module is included in Android version 2 or higher, but if you are running an Android 1.x operating system, you'll need to download it from the Android Market. On your phone:

1. Open the Market app.
2. Search for TTS.
3. Select the app Text-To-Speech Extended to install.

Once the Text-To-Speech module is installed, open it to test its features. When it opens, set the default language as desired. Then select "Listen to Preview." If you don't hear anything, make sure the volume on your phone is turned up. You can also change the way the voice sounds by changing the setting for the TTS Default Engine property.

After you've set up the Text-To-Speech module to your liking, connect to the App Inventor website and start a new project. Name it "NoTextingWhileDriving" (project names can't have spaces) and set the screen's title to "No Texting While Driving". Once the screen title has been changed open the Blocks Editor and connect to the phone through WiFi.

Designing the Components

The user interface for the app is relatively simple: it has a label that displays the automated response, along with a text box and a button for submitting a change. You'll also need to drag in a Texting component, a TinyDB component, a TextToSpeech component, and a LocationSensor component, 
all of which will appear in the "Nonvisible components" area. You can see how this should look in the snapshot of the Component Designer shown in Figure 4-2.

Figure 4-2. The No Texting While Driving app in the Component Designer

You can build the user interface shown in Figure 4-2 by dragging out the components listed in Table 4-1.

Set the properties of the components in the following way:

⦁ Set the Text of PromptLabel to "The text below will be sent in response to all SMS texts received while this app is running."
⦁ Set the Text of ResponseLabel to "I'm driving right now, I'll contact you shortly." Check its boldness property.
⦁ Set the Text of NewResponseTextbox to " ". (This leaves the text box blank for the user's input.)
⦁ Set the Hint of NewResponseTextbox to "Enter new response text."
⦁ Set the Text of SubmitResponseButton to "Modify Response."

Adding Behaviors to the Components

You'll start by programming the basic text autoresponse behavior, and then successively add more functionality.

Table 4-1. All the components for the No Texting While Driving app

Programming an autoresponse

For the autoresponse behavior, you'll use App Inventor's Texting component. You can think of this component as a little person inside your phone that knows how to read and write texts. For reading texts, the component provides a Texting.MessageReceived event block. You can drag this block out and place blocks inside it to show what should happen when a text is received. In the case of this app, we want to automatically send back a prewritten response text.

To program the response text, you'll place Texting1.SendMessage block within the Texting1.MessageReceived block. Texting1.SendMessage actually sends the text-so you'll first need to tell the component what message to send, and who to send it to, before calling Texting1.SendMessage. Table 4-2 lists all the blocks you'll need for this autoresponse behavior, and Figure 4-3 shows how they should look in the Blocks Editor.

Table 4-2. The blocks for sending an autoresponse

Figure 4-3. Responding to an incoming text

How the blocks work

When the phone receives a text message, the Texting1.MessageReceived event is triggered. As shown in Figure 4-3, the phone number of the sender is in the argument number, and the message received is in the argument messageText. For the autoresponse, the app needs to send a text message to the sender. To send the text, you first need to set the two key properties of the Texting component: PhoneNumber and Message.TextingPhoneNumber is set to the number of the sender, and Texting.Message is set to the text you typed into ResponseLabel: “I’m driving right now, I’ll contact you shortly.” Once these are set, the app calls Texting.SendMessage to actually send the response.
Comments are a very important part of programming, they can be used to inform other programmers of important information about the code. You can add comments by right-clicking a block and selecting Add Comment. 

Once you add a comment, you can show or hide it by clicking the blue question mark that appears. You don’t have to add comments in your app-we've simply included them here to help describe each block and what it does.

Most people use comments to document how they are building their app; comments explain how the program works, but they won't make the app behave differently. Comments are important, both for you as you build the app and modify it later, and for other people who might customize it. The one thing everyone agrees on about software is that it changes and transforms often. For this reason, commenting code is very important in software engineering, and especially so with open source software like App Inventor.

Test your app. You'll need a second phone to test this behavior. If you don't have one, you can register with Google Voice or a similar service and send texts from that service to your phone. From the second phone, send a text to the phone running the app. Does the second phone receive the response text?

Entering a Custom Response

Next, let's add blocks so the user can enter her own custom response. In the Component Designer, you added a TextBox component named NewResponseTextbox; this is where the user will enter the custom response. When the user clicks on the SubmitResponseButton, you need to copy her entry (NewResponseTextbox) into the ResponseLabel, which is used to respond to texts. Table 4-3 lists the blocks you'll need for transferring a newly entered response into the ResponseLabel.

Table 4-3. Blocks for displaying the custom response

How the blocks work

Think of how a typical input form works: you first enter something in a text box, and then click a submit button to tell the system to process it. The input form for this app is no different. Figure 4-4 shows how the blocks are programmed so that when the user clicks the SubmitResponseButton, the SubmitResponseButton.Click event is triggered.

Figure 4-4. Setting the response to the user's entry

The event handler in this case copies (or sets, in programming terms) what the user has entered in NewResponseTextbox into the ResponseLabel. Recall that ResponseLabel holds the message that will be sent out in the autoresponse, so you want to be sure to place the newly entered custom message there.

Test your app.Enter a custom response and submit it, and then use the second phone to send another text to the phone running the app. Was the custom response sent?

Storing the Custom Response in a Database

You've built a great app already, with one catch: if the user enters a custom response, and then closes the app and relaunches it, the custom response will not appear (instead, the default one will). This behavior is not what your users will expect; they'll want to see the custom response when they restart the app. To make this happen, you need to store that custom response persistently.

You might think that placing data in the ResponseLabel.Text property is technically "storing" it, but the issue is that data stored in component properties is transient data. Transient data is like your short-term memory; the phone "forgets" it as soon as an app closes. If you want your app to remember something persistently, you have to transfer it from short-term memory (a component property or variable) to long-term memory (a database).

To store data persistently, you'll use the TinyDB component, which stores data in a database that's already on the Android device. TinyDB provides two functions: StoreValue and GetValue. The former allows the app to store information in the device's database, while the latter lets the app retrieve information that has already been stored.

For many apps, you'll use the following scheme:

1. Store data to the database each time the user submits a new value.
2. When the app launches, load the data from the database into a variable or property.

You'll start by modifying the SubmitResponseButton.Click event handler so that it stores the data persistently, using the blocks listed in Table 4-4.

Table 4-4. Blocks for storing the custom response with TinyDB 

How the blocks work

This app uses TinyDB to take the text it just put in ResponseLabel and store it in the database. As shown in Figure 4-5, when you store something in the database, you provide a tag with it; in this case, the tag is "responseMessage." Think of the tag as the name for the data's spot in the database; it uniquely identifies the data you are storing. As you'll see in the next section, you'll use the same tag ("responseMessage")when you load the data back in from the database.
Figure 4-5. Storing the custom response persistently

Retrieving the Custom Response When the App Opens

The reason for storing the custom response in the database is so it can be loaded back into the app the next time the user opens it. App Inventor provides a special event block that is triggered when the app opens: Screen1.Initialize (if you completed MoleMash in Chapter 3, you've seen this before). If you drag this event block out and place blocks in it, those blocks will be executed right when the app launches.
For this app, your Screen1.Initialize event handler should check to see if a custom response has been put in the database. If so, the custom response should be loaded in using the TinyDB.GetValue function. The blocks you'll need for this are shown in Table 4-5.

Table 4-5A. Blocks for loading the data back in when the app is opened

Figure 4-5B. Blocks for loading the data back in when the app is opened (continued)

How the blocks work

The blocks are shown in Figure 4-6. To understand them, you must envision a user opening the app for the first time, entering a custom response, and opening the app subsequent times. The first time the user opens the app, there won't be any custom response in the database to load, so you want to leave the default response in the ResponseLabel. On successive launches, you want to load the previously stored custom response from the database and place it in the ResponseLabel.
Figure 4-6. Loading the custom response from the database upon app initialization

When the app begins, the Screen1.Initialize event is triggered. The app calls the TinyDB1.GetValue with a tag of "responseMessage," the same tag you used when you stored the user's custom response entry earlier. The retrieved value is placed in the variable response so that it can be checked before we place it as the ResponseLabel. Can you think of why you'd want to check what you get back from the database before displaying it as the custom message to the user? TinyDB returns empty text if there is no data for a particular tag in the database. There won't be data the first time the app is launched; this will be the case until the user enters a custom response. Because the variable response now holds the returned value, we can use the if block to check if the length of what was returned by the database is greater than 0. If the length of the value contained in response is greater than 0, the app knows that TinyDB did return something, and the retrieved value can be placed into the ResponseLabel. If the length isn’t greater than 0, the app knows there is no previously stored response, so it doesn’t modify the ResponseLabel (leaving the default response in it).

Test your app.You cannot test this behavior through live testing, as the database gets emptied each time you "Connect AI Companion" to restart the app.

Instead, select "Build" then "App (provide QR code)" scan the barcode, and then download the app to your phone. Once the app is installed, enter a new response message in the NewResponseTextbox and click the SubmitResponseButton. Then close the app and restart it. Does your custom message appear?

Speaking the Incoming Texts Aloud

In this section, you'll modify the app so that when you receive a text, the sender's phone number, along with the message, is spoken aloud. The idea here is that when you’re driving and hear a text come in, you might be tempted to check the text even if you know the app is sending an autoresponse. With text-to-speech, you can hear the incoming texts and keep your hands on the wheel.

Android devices provide text-to-speech capabilities and App Inventor provides a component, TextToSpeech, that will speak any text you give it. (Note that here "text" is meant in the general sense of the word-a sequence of letters, digits, and punctuation-not an SMS text.)
In the "Getting Started" section of this app, we asked you to download a text-to-speech module from the Android Market. If you didn’t do so then, you’ll need to now. Once that module is installed and configured as desired, you can use the TextToSpeech component within App Inventor.

The TextToSpeech component is very simple to use-you just call its Speak function and plug in the text you want spoken into its message slot. For instance, the function shown in Figure 4-7 would say, "Hello World."
Figure 4-7. Blocks for speaking "Hello World" aloud

For the No Texting While Driving app, you'll need to provide a more complicated message to be spoken, one that includes both the text received and the phone number of the person who sent it. Instead of plugging in a static text object like the "Hello World" text block, you'll plug in a join block. An incredibly useful function, joinallows you to combine separate pieces of text (or numbers and other characters) into a single text object.

You'll need to make the call to TextToSpeech.Speak within the Texting.MessageReceived event handler you programmed earlier. The blocks you programmed previously handle this event by setting the PhoneNumber and Message properties of the Texting component appropriately and then sending the response text. You'll extend that event handler by adding the blocks listed in Table 4-6.

Table 4-6. Blocks for speaking the incoming text aloud

How the blocks work

After the response is sent, the TextToSpeech1.Speak function is called, as shown at the bottom of Figure 4-8. You can plug any text object into the message slot of the TextToSpeech1.Speak function. In this case,join is used to build the words to be spoken-it concatenates (or adds) together the text "SMS text received from" and the phone number from which the message was received (value number), plus the text ".The message is," and finally the message received (value messageText). So, if the text "hello" was sent from the number "111-2222," the phone would say, "SMS text received from 111-2222. The message is hello."

Figure 4-8. Speaking the incoming text aloud

Test your app.You’ll need a second phone to test your app. From the second phone, send a text to the phone running the app. Does the phone running the app speak the text aloud? Does it still send an automated response?

Adding Location Information to the Response

Apps like Facebook's Place and Google's Latitude use GPS information to help people track one another’s location. There are major privacy concerns with such apps, one reason being that location tracking kindles people's fear of a "Big Brother" apparatus that a totalitarian government might set up to track its citizens' whereabouts. But apps that use location information can be quite useful-think of a lost child, or hikers who've gotten off the trail in the woods.

In the No Texting While Driving app, location tracking can be used to convey a bit more information in response to incoming texts. Instead of just "I’m driving," the response message can be something like "I'm driving and I'm at 3413 Cherry Avenue." For someone awaiting the arrival of a friend or family member, this extra information can be helpful.

App Inventor provides the LocationSensor component for interfacing with the phone's GPS (or geographical positioning system). Besides latitude and longitude information, the LocationSensor can also tap into Google Maps to provide the driver's current street address.
It's important to note that LocationSensor doesn't always have a reading. For this reason, you need to take care to use the component properly. Specifically, your app should respond to the LocationSensor.LocationChanged event handler. 

LocationChanged event occurs when the phone’s location sensor first gets a reading, and when the phone is moved to generate a new reading. Using the blocks listed in Table 4-7, our scheme will respond to the LocationChanged event by placing the current address in a variable we'll name lastKnownLocation. Later, we'll change the response message to incorporate the address we get from this variable.

Table 4-7. Blocks to set up the location sensor

How the blocks work

The LocationSensor1.LocationChanged event is triggered the first time the sensor gets a location reading and when the device is moved so that a new reading is generated. Since you eventually want to send a street address as part of the response message, Figure 4-9 shows how the LocationSensor1.CurrentAddress function is called to get that information and store it in the lastKnownLocation variable. Behind the scenes, this function makes a call to Google Maps (via an API, something you’ll learn about in Chapter 24) to determine the closest street address for the latitude and longitude that the sensor reads.
Figure 4-9. Recording the phone's location in a variable each time the GPS location is sensed

Note that with these blocks, you've finished only half of the job. The app still needs to incorporate the location information into the autoresponse text that will be sent back to the sender. Let's do that next.

Sending the Location As Part of the Response

Using the variable lastKnownLocation, you can modify the Texting1.MessageReceived event handler to add location information to the response. Table 4-8 lists the blocks you'll need for this.

Table 4-8. Blocks to display location information in the autoresponse

How the blocks work


This behavior works in concert with the LocationSensor1.LocationChanged event and the variable lastKnownLocation. As you can see in Figure 4-10, instead of directly sending a message containing the text in ResponseLabel.Text, the app first builds a message using make text. It combines the response text in ResponseLabel.Text with the text “My last known location is:” followed by the variable lastKnownLocation.
Figure 4-10. Including location information in the response text

The default value of lastKnownLocation is "unknown," so if the location sensor hasn't yet generated a reading, the second part of the response message will contain the text "My last known location is: unknown." If there has been a reading, the second part of the response will be something like "My last known location is: 876 Willard Street, San Francisco, CA 95422."

Test your app.p. From the second phone, send a text to the phone running the app. Does the second phone receive the response text with the location information? If it doesn't, make sure you've turned GPS on in the first phone's Location settings.

The Complete App: No Texting While Driving


Figure 4-11 shows the final block configuration for No Texting While Driving.

Figure 4-11. The complete No Texting While Driving app (with all comments showing)

Variations

Once you get the app working, you might want to explore some variations. For example:

⦁ Write a version that lets the user define custom responses for particular incoming phone numbers. You'll need to add conditional (if) blocks that check for those numbers. For more information on conditional blocks, see Chapter 18.
⦁ Write a version that sends custom responses based on whether the user is within certain latitude/longitude boundaries. So, if the app determines that you're in room 222, it will send back "Bob is in room 222 and can’t text right now." For more information on the LocationSensor and determining boundaries, see Chapter 23.
⦁ Write a version that sounds an alarm when a text is received from a number in a "notify" list. For help working with lists, see Chapter 19.

Summary

Here are some of the concepts we've covered in this tutorial:

⦁ The Texting component can be used to both send text messages and process the ones that are received. Before calling Texting.SendMessage, you should set the PhoneNumber and Message properties of the Textingcomponent. To respond to an incoming text, program the Texting.MessageReceived handler.
⦁ The TinyDB component is used to store information persistently—in the phone's database-so that the data can be reloaded each time the app is opened. For more information on TinyDB, see Chapter 22.
⦁ The TextToSpeech component takes any text object and speaks it aloud.
⦁ make text is used to piece together (or concatenate) separate text items into a single text object.
⦁ The LocationSensor component can report the phone's latitude, longitude, and current street address. To ensure that it has a reading, you should access its data within the LocationSensor.LocationChanged event handler, which is triggered the first time a reading is made and upon every change thereafter. For more information on the LocationSensor, see Chapter 23.

If you're interested in exploring SMS-processing apps further, check out the Broadcast Hub app in Chapter 11.



ex voice application


I have come up with an idea that
when we call to deaf and dumb person, as they cant hear and give a reply to us
so i want to develop an app like this " when we call a deaf person the information which we give should be converted into text format and there text should be converted into voice or it can be either in text itself people can read can read the text.

Can we develop such app using MIT App inventor. is there a possibility in this 

--
How does the deaf person know he is getting a phone call or receiving am sms (text) message?   That is a problem.

1)  when we call a deaf person the information which we give should be converted into text format   .  For this you would have to use the speech recognizer object.  It converts spoken
words into text.  However, I so no to implement that with AI2.  Perhaps someone else has an idea?

2) there text should be converted into voice.  You can convert a text that is inside a TextBox by using the TextToSpeech Component, but I do not know if the phone would be able to use it.  You would have to try.  I expect this is not possible to use in conjunction with the phone, but you could try.

3) or it can be either in text itself people can read can read the text.     Why not just send the person an sms text message  and let them reply with a text message.  Have you thought about developing a Chat app with the  FirebaseDB t?  This is not a phone call but a chat app using WIFI.

Assuming you can solve some problems here is an example you might be able to modify to allow the person that receives a text message

No Text While Driving for AI2
Busy driving or in a meeting? Set this app to auto-respond to incoming texts by sending a reply text and also speaking the incoming text out loud.

This MIT app does NOT do what you want to do but the tutorial does use some of the components that would be necessary to use sms messaging.

-- 

I can't delete a component


I can't a component,I click on component and click in delete button and nothing happens.

--
type chrome://settings/   in the browser's URL box and get then press "reset settings". 

Did that get you working again?

-- 

All the projects are disappered from my account.


All the projects are disappered from my account. I have not deleted, what to do in getting them back?

--
Switch browsers, reset your browser if chrome, search this forum. This has been asked before.

--

How to fix this situation? 받은편지함 x


Some of the pictures and icons are too big to fit in my interface, they cannot be shown in the bottom of the interface but can be shown correctly on the phone. How to fix this kind of situation? 



--
Set scrolling to true in your Screen component. Then, when you are finished designing, set it to false again, unless you really like the scrolling.

--

Help for hire? Cannot seem to generate 3 unlike random integers.


I am still having trouble generating three random numbers that are not alike. I have tried a bunch of things, but everything I try other than the solution posted (which on very rare occasions turns up with two alike answers) changes my three answer buttons to read 'true' instead of 3 random integers that are not alike. 

Are any of the moderators of this forum available to hire to fix this problem for me? (I am a teacher so the rate must be very reasonable. I know this is an easy fix....I just cannot seem to find a way to do it.)







--
Thank you for your quick reply. I can see how your example would be beneficial for a game with fixed answers. My game is a multiplication game and I would like to generate random integers for two buttons and one fixed 'answer' button. I would also like the 'answer' button to vary in position (button 1, button 2, button 3) so that the user can't pick the answer based on the knowledge that the correct answer will always be button 1 (example.)

Attached is a pic the latest try that I have attempted (and logicTest.aia file) I am getting a runtime error. 



If you like, we have an extension that can perform useful list operations. If interested, we can add feature to remove duplicates and return a list containing unique items:
--
..And here is the correct url address:
do you store the correct answer in a list?
you example is not so much different from my example...

--
I store the correct answers in a csv file (attached) I pull the multiplication problems out of the csv file first as a row then as a column (index items). So while there is a temp list for the correct multiples and product, there is not a complete list of answers only. (I hope this makes sense.)

MultiplePairs_Level1.csv

--
Here is a working .aia which solves your problem (as I think it is). It is surprisingly complex,
- you want the questions in random order
- you want the answers to be random and randomly assigned to buttons
- there should be no duplicates in the possible answers
- you should check if all questions are asked
- you should check if the answer is correct, then ask the next question
etc.
See if you can make sense out of it, otherwise ask. And make a donation to App Inventor if you like (see the donation button at the front page).

logicTest_copy.aia

--
Thank you so much. I am working on this today. I tried Taifun's idea but it still rendered duplicate answers on the button labels (due to the nature of the necessary set up of random problems and random answers. See attached.) I will report back when I have tried your solution! (Thank you again.....this has been driving me crazy.lol.)




--
My solution does much more than just finding three different numbers for the buttons. It also sets random questions from your csv list and checks the answers. It is a complete app, that just needs some brushing up with nicer buttons and so on.

Anyway, I realized that i checked that the correct answer could not be among the random answers, but that I also should check that there are no duplicate random answers. Therefore I changed the app slightly. Here is a procedure that sets three random different numbers on the three buttons. How do you do it?

- Generate a list of numbers between 1 and 100 (or whatever the answer space for your numbers is. The highest I saw in your csv was 72, so I took 100, but of course you can take another number.
- Remove the correct answer from this list. It will be added to a random button later.
- Use the any blocks to go through the list of buttons (you have only three, but in this setup you could as easily have 5 or 7 or whatever).
- Take a random item from the number list, set the button text to it.
- Remove the item from the list.

To set the random button with the correct answer: choose a random number from 1 to length button list. Remember it in a global variable because you need it while checking whether the answer given is right.
Then, set the text of that button (using the any blocks) to the correct answer.
Try it using the attached .aia!

logicTest_copy_2.aia

--
Yes, I noticed that your original version did much more than my original thought. I am currently working on splicing your version "1" with my original work to make my game. This portion is only the second part to the entire game. I did quite a bit of work already when I noticed your additional message. I will need to take a look at your version"2" above again tomorrow morning. If I understand your notes correctly you are saying that version"1" could possibly still have repeated number labels?

--
Yes. And thinking about it, there is still a problem with the second solution too. I will correct it later.
But for you it should be easy to adapt later, because the random number stuff is in a procedure, so if you change the procedure, you do not need to change anything else.


--



This is my last attempt at getting this right, I hope ;-)
Let's start from the beginning, in the hope that you understand what is happening and can use it in your game.

At Screen1.initialize, the buttonList is defined. You cannot define this at initialization of the global, because the components are not defined at that time.
Next, the csv file is read.

Then, at when File1.GotText, you read the text into a list of lists, global QuestionList. Each element in the list is a list itself. For example the, 20th line in MultiplePairs_Level.csv looks like this: 5,2,10
It will become the element with index 20 in the list global QuestionList, and this element is a list itself consisting of three elements: the two numbers to be multiplied and the answer to this multiplication. In fact, you do not need the third element, as AppInventor can easily calcultate it, but I used the values in the hope they are right.
Then, still in the when File1.GotText event block, the number of questions is displayed in a label (the number of elements in global questionList) and the nextQuestion procedure is called.

Procedure nextQuestion:
- Find a random question from the questionList (this question is removed from the list when checking the answer, so no question will be asked twice)
- Retrieve the question list. So, for example, if the random number we found, and set in de globalQuestionIndex, were 20, the global currentQuestion would become the list (5,2,10).
- For convenience, set the current answer in global currentAnswer. It is the 3rd element in global currentQuestion.
- Set a label with the exercise text. Self explanatory I hope.
- Then, set the random button where the correct answer should be shown. It is a random number between 1 and 3, because our button list has length 3. Save it in global rightAnswerNr, because we need it later.
- The procedure setButtons is called. The result of this will be three random answers in the three buttons, but the right answer will not be one of them.
- We overwrite the number in the button with index rightAnswerNr in the buttonlist with the right answer. We are doing it this way because otherwise we would have to do many checks to see if the right answer is in one of the other buttons already. Doable if you have three, but very complex later.
- Then we wait until the user presses a button. But let's look first at setButtons, in our 3rd attempt to get it right.

Procedure setButtons
It assumes that you have the right answer to the multiplication question in global currentAnswer. This global is set in the nextQuestion procedure as we saw, before calling setButtons.
- We start with creating a list of all possible random answers. Here a list of 100 numbers, from 1 to 100. We use a local variable to store this list, because we do not need it elsewhere and it is recreated everytime we cal setButtons.
- Next, we need to remove the correct answer from this list. We check whether the answer is indeed within the range of the random numbers. Otherwise, we would get a runtime error trying to remove it. I thought this would be true by design, but because you are saying it is part of a larger game. I am not so sure. Here, the index is the same as the value of the list element, therefore we remove it from the list by index number.
- This was my last mistake (a classical stupid), after we removed one element from the list, the element indexes are not necessarily the same as the element values.
- anyway, for each item in the buttonList, find a random answer index, set the current button the the value of that element and remove the element from the list.

That's it.

If  you have question about checking the answer, please ask. 


logicTest_copy_3.aia

--
Thank you so much. I am still re-reading your notes above to make sure I understand and learn from your work. You make it sound so easy!!!! I am working on this now and will report back on how it is meshing with the larger game. So far I have integrated your original idea with just a few bumps. I am hoping that the last iteration of the 'no repeat' random buttons above works. Thank you so much for all of your time and help.

p.s. I will be donating from my monthly paycheck to MIT App Inventor. :)


--
I got a runtime error the first time I tried to play. I disabled the piece of code that you explain like this above: " Next, we need to remove the correct answer from this list. We check whether the answer is indeed within the range of the random numbers. Otherwise, we would get a runtime error trying to remove it. I thought this would be true by design, but because you are saying it is part of a larger game. I am not so sure. Here, the index is the same as the value of the list element, therefore we remove it from the list by index number." ...And it is working. The occurrence of repeated buttons with your original solution was so infrequent. So far I have played with you most recent revision (and the block disabled) and I have not found duplicates. Do you think that the block I disabled is needed? (Sorry for my ignorance...I am still studying your work for complete understanding.)

(The runtime error said something like: Trying to find "0" in a list of 1, 2, 3,....100.)

--
I just came across a duplicate. The block I disabled is needed to prevent the duplicates. I am not sure how to resolve the runtime error.

--
The runtime error is there for a reason and usually the error message says what the reason is, also in this case.
It says that you are trying to remove an element with index 0 from the list of possible random answers. But lists do not have an index 0. They start at 1.
What you have tried to remove is the index that is the value of global currentAnswer, the right answer to the question. If it is 0, you did not set it where it should be set: before calling setButtons.
You could prevent the runtime error by checking whether the value of currentAnswer is > 0 but that would just mask a problem elsewhere, and you would get duplicates of the right answer eventually.
Set the global currentAnswer and you should be fine.
Cheers, Ghica.
When one generates pseudo random numbers and the range of possibilities is not large, sooner or later there IS going to be a DUPLICATE.
The solution is to compare the three 'random' values and provide logic to determine if any are identical values; if identical then determine which one cannot change and change 
the other with a random number in the appropriate range. 

An alternative method is to use Saj 's methodology    http://www.imagnity.com/tutorials/app-inventor/shuffle-list-unique-random-numbers/   . He uses the  Fisher–Yates shuffle    algorithm to shuffle then randomly REMOVE one of the possibilities from the List so the result is random without repeats .   If the list is a List of integers, this could work for you.          

The difficulty is to integrate one of these possible solution into your code.  Either select the random number and eliminate the possibility of possible duplicates or after all three values are selected, to ensure using conditional statements that ALL three are different but within the limits you require.

App Inventor's random numbers are NOT truly random.  Unless the developer sets the random seed a sequence of what is generated will actually replicate.  Use the random set seed to block  with a puzzle piece representing  an supposedly random value, perhaps  the Clock seconds  or the day of the year etc..  The random seed is a number used to initialize a pseudor andom number generator. For a seed to be used in a pseudo random number generator, it does not need to be random. If one wants the best available random value, the developer must set the seed.

--
Hello again. I have tried to use conditional statements to check that all three numbers are different but the button values turn up with "true" or "false" on them instead of numbers. I am really struggling with this. As it stands Ghica's solution works fairly well to return repeat values very seldomly. (It still happens though.) I have spent two, twelve hour days reworking the entire game around Ghica's solution. I really want this to be 'perfect' but I am not sure if there is a way.

--
Oh, "all three numbers are different but the button values turn up with "true" or "false" on them instead of numbers."  this means you have a coding issue with your conditionals, show you blocks and there might be a recommendation.

Again, "I really want this to be 'perfect' but I am not sure if there is a way",   my previous post just presented a way to ensure each of the three buttons does not have the same random number.  Look at Saj's example.  There will be NO duplicates.  Your List in this case will be 1,2,3,4,5 ...etc to the range limit you set.  You shuffle the List of integers, the select possibly the first three .  If one of the values has to be a specific value, then take the value that has a higher index for the one button than the required number and the other the lower index value item.

You are attempting to do some very complex coding with very little previous experience and actually are doing fine.  When something doesn't work, move on to the next possibility. 

--
Here is a probable solution based on Saj's example tutorial::
Three buttons, each with a unique non duplicating random integer.  The csv embeded is 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,31,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50      
Extend the csv if higher random values are required,   

I am not so happy the way this discussion is going.
My method guarantees that there are no duplicates and you do not have to do if statements. It is based on Taifun's method of removing elements from a list after having chosen a random one.
Veronica, that you still have duplicates must be a programming bug. If you want I can look into it, but then you should post the relevant blocks or an .aia (you could also send me this privately if you wish).


--
Oh Ghica....thank you. When I have 'cleaned-up' the program (lots of random blocks around and disabled...and a few screens to delete) I will send the aia to you privately. While I appreciate SteveJG's help (more than he knows) I just don't know how I can integrate what he has done into what is going on right now with my app. I am working on this today and will PM you later. Thank you again!!!! :)

--
I am sure it is a simple mistake of integrating your stuff with my little procedure, we will see.

--
Thank you for looking over my file. I actually resolved the runtime error I mentioned in pm on my own. (I forgot to enable the block in the chk answer procedure. Unfortunately upon the first two rounds of the game I got a repeated button. This problem is a 'hair pulling' mess. At first glance it seems easy enough to do....and then all of this. See attached.

Thank you again for all of your help. I really appreciate your efforts.



--