Escolar Documentos
Profissional Documentos
Cultura Documentos
1.
2.
3.
4.
Page 1
5.
6.
7.
Project: GPS and the net SQL: Record your position online ................................. 56
Create a new database table ........................................................................................... 56
Create a new PHP script ................................................................................................. 57
Getting satellites .............................................................................................................. 59
Retrieving data from the database and displaying distance to saved GPS location ......... 60
8.
9.
10.
11.
12.
13.
Page 2
14.
15.
16.
17.
18.
Page 3
1. B4A Cheatsheet
Debug with a Toastmessage
ToastMessageShow("message
here",false) ' true=3sec , false=2
sec
File.WriteString(File.DirDefaultExter
nal, "mytextfile.txt", "text to
write")
http://developer.android.com
http://www.androidpatterns.com/
http://jgilfelt.github.com/android-actionbar
Nine patch images nine-patch-images-tutorial
API Interfaces
http://www.programmableweb.com/
http://cloudmade.com/
Dates
Button1_Click
Dim UserURL As String
UserURL = "http://www.google.com.au/"
WebView1.LoadUrl(UserURL)
End Sub
Page 4
Panel arrays
Open a PDF
Sub OpenPDF(FileName As String)
Dim i As Intent 'Requires a
reference to the Phone library
i.Initialize(i.ACTION_VIEW,
FileName)
i.SetType("application/pdf")
i.WrapAsIntentChooser("Choose PDF
Viewer")
StartActivity(i)
End Sub
Open an Excel file
Sub OpenExcel(FileName As String)
Dim i As Intent 'Requires a
reference to the Phone library
i.Initialize(i.ACTION_VIEW,
FileName)
i.SetType("application/vnd.msexcel")
i.WrapAsIntentChooser("Choose
Excel Viewer")
StartActivity(i)
End Sub
Running the Emulator through a proxy via
the Command prompt
c:\Android\androidsdk\tools>emulator.exe -avd
test -http-proxy
http://Username:PW@10.6.0.254
:3128
Page 5
Go to
http://developer.android.com/reference/androi
d/R.drawable.html images
http://androiddrawables.com/ put the number
in code below
Dim bd As BitmapDrawable
bd = p.GetResourceDrawable(17301555)
Msgbox2("Message", "OK",
"","",bd.Bitmap)
http://www.000webhost.com/
Getting two lines in a listview
Sub Globals
Type ListViewData (FirstRow As
String, SecondRow As String)
End Sub
For i = 0 to 100
Dim lvd As ListViewData
lvd.Initialize
lvd.FirstRow = "abc"
lvd.SecondRow= "def"
ListView1.AddTwoLines2(lvd.FirstRow,
lvd.SecondRow, lvd)
Basic For Android
Next
Sub ListView1_ItemClick(Position As
Int, Value As Object)
Dim lvd As ListViewData
lvd = Value
...
End Sub
Page 6
File.WriteString(File.DirInte
rnalCache,
"nettalk.txt",result)
'get it back from the file
reader.Initialize(File.OpenIn
put(File.DirInternalCache,
"nettalk.txt"))
Dim name As String
name = reader.ReadLine
Page 7
Create a layout with an Edittext box named WordBox and a button named SearchButton.
HttpRequest
Holds the target URL and other data sent to the web server. The initial time out is to 30000
milliseconds (30 seconds).
Sub Process_Globals
Dim hc As HttpClient
Dim req As HttpRequest
End Sub
Sub Globals
'define the views on the layout, a text box and a button
Dim WordBox As EditText
Dim SearchButton As Button
End Sub
Page 8
HttpResponse
An object that holds the response returned from the server. The object is passed in the
ResponseSuccess event. You can choose to read the response synchronously or
asynchronously. It is important to release this object when it is not used anymore by calling
Release.
'#### Routines ####
Sub hc_ResponseSuccess(Response As HttpResponse, TaskId As Int)
Dim SearchWord As String
SearchWord = Response.GetString("UTF8") 'Get the whole page
'The line below finds <div class="pbk"><span class="pg">
SearchWord = SearchWord.Replace(QUOTE, "'") 'Replace double quotes with
single quotes for easy handling.
SearchWord = SearchWord.SubString(SearchWord.IndexOf("<div
class='pbk'><span class='pg'>") + 34) 'Add 34 so we grab the definition
after the tag (there are 34 characters in the above string when you count
to the right) You can add 34 to the 0 substring start below instead
SearchWord = SearchWord.SubString2(0, SearchWord.IndexOf("</span>")) 'Grab
only the definition enclosed
Msgbox(WordBox.Text & " is a " & SearchWord, "") 'Voila!!
End Sub
Page 9
Sub Globals
Dim temp As String
Dim btnweather As Button
Dim edtweather As EditText
Dim lbltemperature As Label
Dim img As Bitmap
Set a default start city when there is nothing in the DB
Dim selectedcity As String :selectedcity ="Christchurch"
Dim townpath As String
Dim label1 As Label holds the temp
Dim imgtemp As ImageView
Dim pic As String 'holds the image
End Sub
Sub btnweather_click
strplace = "christchurch" 'note its lower case
townpath = "http://m.metservice.com/towns/"& strplace
'Log(townpath)
req.InitializeGet(townpath)
Basic For Android
Page 10
hc.Execute(req, 1)
End Sub
Sub hc_ResponseSuccess(Response As HttpResponse, TaskId As Int)
Dim temp As String
temp = Response.GetString("UTF8") 'Get the whole page
'Cut beginning and end to get the code for the temp itself
temp = temp.SubString(temp.IndexOf("<div class=" & QUOTE & "summary" &
QUOTE & ">")) 'cut to first occurance off
temp = temp.SubString2(21, temp.IndexOf("</ul></div></div>")) ' find last
occurance
temp = temp.Replace(QUOTE,"'") ' replace double with single quotes
edtweather.Text = temp 'show the downloaded code so you can work on it.
Dim temperature As String 'pull the temperature from the code
temperature = temp
temperature = temperature.SubString(temperature.IndexOf("ul'><h2>"))
temperature = temperature.SubString2(8, temperature.IndexOf("<span "))
lbltemperature.Text = temperature
pic = temp 'pull the pic from the code
pic = pic.SubString(pic.IndexOf("wx-icons/"))
'start position
pic = pic.SubString2(9, pic.IndexOf("' width")) ' 6 is the number from
counting the letters above
pic = pic.Trim
'looking for the image, is it already in the cache?
If File.Exists(File.DirInternalCache, pic) Then
'if so then load it
imgtemp.Bitmap = LoadBitmap(File.DirInternalCache, pic)
Log("image in cache")
Else 'otherwise go and get it from the net
Getimage run the get image sub
End If
Dim strtime As String 'pull the time from the code
strtime = temp
Dim timecolon As String
timecolon = strtime.IndexOf(":") 'find the colon between the time eg
11:23am
strtime = strtime.SubString2(timecolon -2, timecolon +5) 'take 2 off the
colon and add 5 on to get the whole time 11:23am
label1.Text = strtime
End Sub
Page 11
Page 12
End If
End Sub
At the end of Sub Activity_Create add the following code to load the spinner with the
cities Give it a default value SPcity.SelectedIndex = 1 so it loads a city at startup. AddCity
will load the cities above to the spinner.
addCity
SPcity.SelectedIndex = 1
Activity.Title="Mothership for weather app for " & selectedcity
This is the click event on the spinner, passing the value of what you clicked on to the
selectedcity variable. It also turns on a button to save the city to a text file.
Sub SPcity_ItemClick (Position As Int, Value As Object)
'pass the value you have selected to the variable
selectedcity = Value
btnsavecity.Enabled = True
End Sub
Change the Sub btnweather_click button click event so that it loads the spinner value. Note
that it has to be lower case for the url to work.
strplace = selectedcity.ToLowerCase 'note its lower case
townpath = "http://m.metservice.com/towns/"& strplace
If you want to save it so that it will open at that city later, and when you create a widget then
you need to save it to a text file. That is really easy.
Sub btnsavecity_click
Basic For Android
Page 13
Change the btnweather_click code to open the file that has been saved.
The first time you run it there is no file to draw from. So If File.Exists checks that the file is
there. If not it just uses the value that was given in the Dim selectedcity As String
:selectedcity ="Christchurch"
Sub btnweather_click
If File.Exists(File.DirInternal, "WeatherCity.txt") Then
selectedcity = File.ReadString(File.DirInternal, "WeatherCity.txt")
End If
strplace = selectedcity 'note its lower case
townpath = "http://m.metservice.com/towns/"& strplace
'Log(townpath)
req.InitializeGet(townpath)
hc.Execute(req, 1)
End Sub
Page 14
After you have installed SQLite manager in to Firefox open a new database and call it
Bikefit.
Create a new table using right click Create table from the Tables(0)
Click on ADD
Add the following fields. Also call the table bikefit (or any name you want).
Read about SQLlite datatypes here http://www.sqlite.org/datatype3.html
Page 15
Close out from your program and rename the file itself from bikefit.sqlite to bikefit.sql. (I
dont know why, considering that Android uses sqlite files and not sql, but it must be a bug
somewhere in the SQL Library ), and make sure its saved in your files folder.
Page 16
We are going to use the SQL library so need to load it in. There are two
types in this library.
An SQL object gives you access to the database. The Cursor object
allows you to process queries results.
Usually you will want to declare the SQL object as a process global
object. This way it will be kept alive when the activity is recreated. SQLite
stores the database in a single file. When we initialize the SQL object we
pass the path to a database file (which can be created if needed).
First we define our database variables.
Sub Process_Globals
Dim SQL1 As SQL
Dim cursor1 As Cursor
Now we need to start coding for it. In the Activity Sub, which runs when the program first
begins, we need to copy the database from the Assets folder to the Internals folder as files
cant be written to in the Assets folder.
Files distributed as part of an app cannot be written to in the default location. To move the
file(s) to a storage area which allows writing to the file, add the file to the app in
Activity_Create add the following code:
Sub Activity_Create(FirstTime As Boolean)
If File.Exists(File.DirInternal,"bikefit.sql") = False Then
File.Copy(File.DirAssets,"bikefit.sql",File.DirInternal,"bikefit.sql")
End If
If SQL1.IsInitialized = False Then
SQL1.Initialize(File.DirInternal, "bikefit.sql", False)
End If
Page 17
There are a number of ways to create your layout. The most obvious is to make a panel
and attach the objects to it.
Create the panel pnlbg first, The other objects will be stuck to the panel and can be
manipulated with the panel later. At this stage size is not an issue as it can be set
programmatically.
Labels just holding text dont need to be explicitly named as they wont be in the code.
Open the Designer and the Abstract Designer and click on the Status to connect it to the
emulator
Then you can see the design in the emulator and adjust it from there as well as using the
Abstract designer to find the names of the Views. If you are lucky enough to have your
phone plugged in you can see the layout on the phone and move it around by hand as well.
Page 18
In the Designer you can see the Views and their properties. Firstly set the pnlbg panel with
the values in the properties. Each of the Views you add to your layout then attaches to this
panel.
Page 19
Once you have made your layout you need to generate the
members. This mostly a shortcut way to declare the variables
that you are going to use.
Go Tools, in the Designer window and then click Generate
Members
This will create the Dims in Sub Globals
Sub Globals
'These global variables will be redeclared each time the activity is
created.
'These variables can only be accessed from this module.
Dim edtarm As EditText
Dim edtseam As EditText
Dim edtshoulder As EditText
Dim edtsternum As EditText ' height
Dim
Dim
Dim
Dim
Dim
panelbg As Panel
btncalculate As Button 'run
btndelete As Button 'delete
btnsave As Button ' change
btnnew As Button 'save new
btnarm As Button
btnseam As Button
btnshoulder As Button
btnsternum As Button
Page 20
After you have created your layout it needs to be added to the Sub
Activity_Create(FirstTime As Boolean) so that its loaded when the program runs.
You can replace Main with the name of whatever your layout is.
Activity.LoadLayout("Main")
We can also add the rest of the code that needs to run when the program is first created.
At the beginning of an object's life, the Java virtual machine (JVM) allocates enough
memory on the heap to accommodate the object's instance variables. When that memory is
first allocated, however, the data it contains is unpredictable.
If the memory were used as is, the behaviour of the object would also be unpredictable. To
guard against such a scenario, Java makes certain that memory is initialized, at least
to predictable default values, before it is used by any code.
Initialization is important because, historically, uninitialized data has been a common source
of bugs. The Java language, has built-in mechanisms that help you ensure proper
initialization of the memory occupied by a newly-created object. With proper use of these
mechanisms, you can prevent an object of your design from ever being created with an
invalid initial state.
Earlier we defined a bitmap image (Dim bmp As Bitmap). And now we have to initialise it
bmp.Initialize(File.DirAssets, "android48.png")
For our Edittext boxes we can specify what type of keyboard will be used. In this case we
only want numbers to be added to the boxes.
edtarm.InputType = edtarm.INPUT_TYPE_NUMBERS
Page 21
Now that we have the Views loaded into the layout we can start to write the code that loads
the database into the Listview. The ListView control is a very powerful control. It allows you
to show short or long lists in a very "sleek" way. Read more about it here.
First we get the data from the database and pass it to Cursor1 which we defined earlier.
Cursor is just the name of the object that holds the data from the database, it might also be
thought of as a datatable.
Pass the data to cursor1
cursor1 = SQL1.ExecQuery("SELECT * FROM bikefit")
Then we make a For next loop, starting at 0 and ending with the rowcount 1 (because we
started at 0 instead of 1)
For i = 0 To cursor1.RowCount 1
Then we just get the data we want and pass it as a long line of data, to the
Listview.AddSingleLine
LVdb.AddSingleLine(cursor1.GetString("ID")& " : "
&cursor1.GetString("Name")& " " & cursor1.GetLong("Sternum")& " " &
cursor1.GetLong("Inseam")& " " & cursor1.GetLong("Arm")& " " &
cursor1.GetLong("Shoulder"))
We then set the details for that line and finish with the next
LVdb.SingleLineLayout.ItemHeight = 40
etc
All code.
Sub DBload
LVdb.Clear'need to clear the list
cursor1 = SQL1.ExecQuery("SELECT * FROM bikefit")
For i = 0 To cursor1.RowCount - 1
cursor1.Position = i
LVdb.AddSingleLine(cursor1.GetString("ID")& " : "
&cursor1.GetString("Name")& " " & cursor1.GetLong("Sternum")& " " &
cursor1.GetLong("Inseam")& " " & cursor1.GetLong("Arm")& " " &
cursor1.GetLong("Shoulder"))
LVdb.SingleLineLayout.ItemHeight = 40
LVdb.SingleLineLayout.Label.TextSize = 20
LVdb.SingleLineLayout.label.TextColor = Colors.Black
LVdb.SingleLineLayout.label.Color = Colors.White
Next
End Sub
So that it runs at
Page 22
When we click on an item in the listview we want those numbers to be passed to the edittext
boxes in the layout. This is a Short Click event, there is also a Long Click event
Value is the data of the line that is being clicked. Value As Object It is passed to the idvalue.
idvalue = Value
We want to get the place of the first : and pass that number to countit. Then using Substring
we get the ID number by starting at 0 and going to the countit number.
countIt = idvalue.IndexOf(":") 'find location of separator
idvalue = idvalue.SubString2(0,countIt) 'find first part of label text
Now we have the ID of the row we can put it back into the database to pull out the values
again and pass them to the edittext boxes. We also could carry on using the code above to
find the next : and then getting the number from there as well.
Sub lvdb_ItemClick (Position As Int, Value As Object)' click on the entry
in the list
Dim idvalue As String
idvalue = Value
countIt = idvalue.IndexOf(":") 'find location of sperator
idvalue = idvalue.SubString2(0,countIt) 'find first part of label text
ID = idvalue
cursor1 = SQL1.ExecQuery("SELECT * FROM bikefit where ID = '" & ID & "' ")
For i = 0 To cursor1.RowCount - 1
cursor1.Position = i
edtarm.text=cursor1.getString("Arm")
edtseam.text=cursor1.getString("Inseam")
edtshoulder.text=cursor1.getString("Shoulder")
edtsternum.text=cursor1.getString("Sternum")
Next
End Sub
Page 23
Clicking on the listview row selected the ID for that row, as seen above, then when you have
that number you can easily delete the row or save it back to the database if you changed it.
Sub btndelete_click
SQL1.ExecNonQuery("DELETE FROM bikefit where ID = '" &ID & "' ")
DBload
End Sub
Saving the row by taking the text from the edittext boxes.
Sub btnsave_click
SQL1.ExecNonQuery("UPDATE bikefit set Sternum ='"& edtsternum.text &"',
Inseam ='"& edtseam.text &"', Arm ='"& edtarm.text &"' , Shoulder = '"&
edtshoulder.text &"' WHERE ID = " & ID)
DBload
End Sub
Adding a new record uses the Dialogs library to enter the name. This
means someone else did all the hard work for you.
This library contains several modal, that is blocking, dialogs by which the user can enter
data. Presently they are an InputDialog for text, a TimeDialog for times, a DateDialog for
dates, both a ColorDialog and a ColorPickerDialog for colors, a NumberDialog for
numbers,a FileDialog for folders and file names and a CustomDialog.
Sub btnnew_click ' save new
Dim dialog As InputDialog
dialog.Input = ""
dialog.HintColor = Colors.ARGB(196, 255, 140, 0)
Dim ret As Int
ret = DialogResponse.CANCEL
ret = dialog.Show("Enter Your name", "Bike Fit", "Save", "Exit", "", bmp)
Dim strname As String ' name of person
strname = dialog.Input
If strname = "" OR edtarm.text = "" OR edtseam.text = "" OR
edtshoulder.text = "" OR edtsternum.text ="" Then
Msgbox("You have to enter all fields","Missed data field")
Else
'Grab the last ID number which is the highest number
cursor1 = SQL1.ExecQuery("SELECT ID FROM bikefit ")
If cursor1.RowCount > 0 Then
For i = 0 To cursor1.RowCount - 1
Basic For Android
Page 24
cursor1.Position = i
Dim NewID As Int
NewID = cursor1.GetInt("ID")
Next
End If
NewID = NewID +1 ' add 1 to the ID number to make a new ID field
SQL1.ExecNonQuery("INSERT INTO bikefit VALUES('" & NewID & "','" & strname
& "','" & edtsternum.text & "','" & edtseam.text & "','"& edtarm.text
&"', '" & edtshoulder.text & "')")
DBload
End If
End Sub
helpselect As Int
lngsternum As Long
lnginseam As Long
lngarm As Long
lngshoulder As Long
ID As Int ' ID of each entry
The click event for the Run Button. Pass the data from the text boxes to the variables.
This loads the next activity called results that we make next.
StartActivity("results")
Sub btncalculate_click
lngsternum
=
edtsternum.Text
lnginseam
=
edtseam.Text
lngarm
=
edtarm.Text
lngshoulder =
edtshoulder.Text
StartActivity("results")
End Sub
Page 25
The modules tab on the right is really handy to use. The top section
shows you the activities in your project, while the bottom shows each
sub in your activity.. Just click on the Sub to go to that part of the code.
Easily find repeated code
If you are looking for all the places where a piece of your code, be it a
variable or view etc is repeated in your activity just double click on it to
select it. Then down the right you will see light blue lines. Scroll down to
the lines with the scrollbar and each duplicate entry will show up. Its a
really good tool.
Page 26
The Result and Results2 Activities uses one layout named results which has two panels
on it. pnlHelp and pnlHelp2. PnlHelp.Visible is set to True to show it for the results activity
while the second panel is set to .visible = False to hide it.
In the next Activity Results2, the panel visibility is reversed.
Sub Activity_Create(FirstTime As Boolean)
Activity.LoadLayout("results")
pnlHelp.Visible = True
pnlhelp2.Visible = False
pnlHelp.Top=0
pnlHelp.Left=0
pnlHelp.Height=Activity.Height
pnlHelp.Width=Activity.Width
Activity.Title="Bike Fit: Handlebar and Reach"
result
End Sub
The sub that calculates the results and passes it to the label
Sub result
lblhandlebar.text = (Main.lngshoulder * 0.875)&"cm" 'handlebar
Lblreach.text = ((((Main.lngsternum - Main.lnginseam) + Main.lngarm) / 2)
+ 4) &"cm"
End Sub
Basic For Android
Page 27
Sub btnnext_click
StartActivity("results2")
End Sub
Sub btnback_click
Activity.Finish
End Sub
Sub result
lblframe.text = (Main.lnginseam * 0.67)&"cm" 'frame
lblsaddle.text = (Main.lnginseam * 0.883)&"cm" 'saddle
End Sub
Sub btnnext2_click
StartActivity("results")
Basic For Android
Page 28
btnback2_click
End Sub
Sub btnback2_click
Activity.Finish
End Sub
This layout uses two panels, and the Views for each Activity are stuck on their panel. Then
the panels are either made visible or invisible.
Here are the Views to be added to each panel. This is taken directly from the Sub Globals
Create the panel first then make sure you stick the views on them.
Results Activity
Dim pnlHelp As Panel
Dim lblhandlebar As Label
Dim Lblreach As Label
Dim btnback As Button
Dim btnnext As Button
Results2 Activity
Dim pnlhelp2 As Panel
Dim lblframe As Label
Dim lblsaddle As Label
Dim btnback2 As Button
Dim btnnext2 As Button
Page 29
One layout with changing data depending on the case statement in the Activity.
In the Main Activity need to make a variable to hold the help number that will be accessed
later from the Help Activity. Therefore it needs to be declared in the Process Globals sub of
the Main Activity.
Sub Process_Globals
Dim helpselect As Int
In the Main activity add the code to activate each of the help buttons. We could use the
Sender property to get the value of the helpselect, which is smaller, however its nice to be
lazy sometimes.
Sub btnarm_click
helpselect = 1
StartActivity("help")
End Sub
Sub btnseam_click
helpselect = 3
StartActivity("help")
End Sub
Sub btnshoulder_click
helpselect = 4
Basic For Android
Page 30
StartActivity("help")
End Sub
Sub btnsternum_click
helpselect = 5
StartActivity("help")
End Sub
In the designer create a new layout called Help and layout the fields something like this.
Generate your Views into the Help Activity you made earlier, it should look something like
below. Its pretty obvious.
Sub Globals
Dim imgbox As ImageView
Dim lblhelp As Label
Dim lbltitle As Label
Dim panel1 As Panel
Dim btnclose As Button
Dim imgarm As Bitmap
Dim imgheight As Bitmap
Dim imgsternum As Bitmap
Dim imgshoulder As Bitmap
Dim imginseam As Bitmap
Dim lblcalc As Label
End Sub
Page 31
In Sub Activity_Create we need to create the select statement that will load which of the 4
help information clicked on by the button.
Sub Activity_Create(FirstTime As Boolean)
Activity.LoadLayout("help")
Select Main.helpselect
Case 1 'arm
lbltitle.Text ="Measure your arm length"
lblhelp.text = "Measure from your shoulder to your knuckles. "
imgarm.Initialize(File.DirAssets,"arm.jpg")
imgbox.Bitmap = imgarm
lblcalc.Text ="This helps give your reach. (((sternum - inseam) + arm) /
2) + 4)"
Activity.Title="Bike Fit: Arm measuring"
Case 2 'height
lbltitle.Text ="Measure your height"
lblhelp.text = "In your socks or bare feet, stand with your heels and
buttocks against the wall Measure from the ground to the top of your head"
imgheight.Initialize(File.DirAssets,"height.jpg")
imgbox.Bitmap = imgheight
lblcalc.Text ="???"
Case 3 'seam
lbltitle.Text ="Measure your inner leg"
lblhelp.text = "Wear your cycling shorts, and take the measurements in
bare feet. Place a book OR other solid Object up against the top of your
inner leg pelvic bone AND measure from the top of that To the Floor."
imginseam.Initialize(File.DirAssets,"inseam.jpg")
imgbox.Bitmap = imginseam
lblcalc.Text ="Frame size = inseam * 0.67, Saddle height = inseam *
0.883"
Activity.Title="Bike Fit: Inseam measuring"
Case 4 'shoulder
lbltitle.Text ="Measure your shoulder width"
lblhelp.text = "Measure your shoulder width by the outside of the bony
protrusions at the top of your shoulders"
imgshoulder.Initialize(File.DirAssets,"shoulder.jpg")
imgbox.Bitmap = imgshoulder
lblcalc.Text ="Handle Bar width = shoulder * 0.875"
Activity.Title="Bike Fit: Shoulder measuring"
Case 5 'sternum
lbltitle.Text ="Measure from your sternum to the floor"
Page 32
lblhelp.text = "In your socks or bare feet, stand with your heels and
buttocks against the wall. Measure from the ground to the sternum notch
at the top of your ribcage / bottom of your neck."
imgsternum.Initialize(File.DirAssets,"sternum.jpg")
imgbox.Bitmap = imgsternum
lblcalc.Text ="Used to calcualte Reach and Frame height, Saddle height"
Activity.Title="Bike Fit: Sternum measuring"
End Select
End Sub
Sub btnclose_click
'StartActivity("Main")
Activity.Finish
End Sub
Page 33
Page 34
Page 35
Android cannot directly access the internet based database so needs to go through a script.
This can be written in a number of languages such as PHP or ASP, we will use PHP as its
easy and very popular.
PHP can be written in many programming systems, even as simple as notepad. I use
Komodo Edit from http://www.activestate.com/komodo-edit however you might have another
program.
There are two ways to create your PHP page, one is to act to let Android pass directly
through and do whatever it wants to the database. This leaves the database open to
hacking and attacks, as any device can access the PHP script when you know the path so
its not a secure option.
The other way is to put your SQL code in the PHP page in functions and control what the
program does by controlling the function allowed to run. So you can stop people deleting
data by not having a delete function in the PHP code, or restricting it.
This is by far the best option. This is the code below, its quite easy to follow when you get it.
PHP starts and ends with <?php to ?> . Everything between these tags is seen as PHP
code.
Establish a connection string
This passes your DB details to 3 connection variables (created with a $ in front) which are
then passed to the connection string to gain access to the database. These 3 variables
could be named anything its the mysql_connect(Server, Username, Password) that is
the key here.
When you have a connection to the database you need to select the table in that database
you want. mysql_select_db("Table")
$mysqlDatabaseName = "mysql8.000webhost.com";
$mysqlUsername = "a5858161_gary";
$mysqlPassword = "PW";
mysql_connect($mysqlDatabaseName, $mysqlUsername, $mysqlPassword) or
die(mysql_error());
mysql_select_db("a5858161_test") or die(mysql_error());
Once this works then you can pass whatever SQL statements you want to the database and
get replies.
Page 36
In this case we send the data from the phone to the PHP of.
"http://androiddsed.host22.com/netdb.php?action=add&name=me&deviceID=deviceID&text=inputtext
The code in the PHP scans the url we send and extracts from it the values we want to pass
to the database, name, device and text.
Action is used to tell the PHP which function we are to run, Add or Getall. We can create
any number of functions and run them this way.
So here we run the Action function and get the name, device, text from the string passing it
to the variables $name, $deviceID, $text.
if($action == "add"){
$name = $_GET['name'];
$deviceID = $_GET['deviceID'];
$text = $_GET['text'];
Then we run an SQL query and pass those three variables into the database.
mysql_query("INSERT INTO webDB
(name, deviceid, text) VALUES('$name', '$deviceID', '$text') ") or die(mysql_error());
The or die(mysql_error()) is just to give an escape in case the query doesnt work, like Try
/ Catch.
Retrieving data from the database
When retrieving data from the database we just use a straight SQL statement again.
$result = mysql_query("SELECT name, text, deviceID FROM webDB") or die(mysql_error());
Data is formatted by line when it returns with "\r\n" being a line break. The string is
concatenated with a . (as opposed to a & or + that we are used to).
while($row = mysql_fetch_array($result)){
echo $row['name'];
echo "\r\n".$row['text'];
echo "\r\n".$row['deviceID']."\r\n";
Page 37
Here is the full PHP code, save it as netdb.php or any other name you can remember.
<?php
$mysqlDatabaseName = "mysql8.000webhost.com";
$mysqlUsername = "a5858161_gary";
$mysqlPassword = "PW";
mysql_connect($mysqlDatabaseName, $mysqlUsername, $mysqlPassword) or
die(mysql_error());
mysql_select_db("a5858161_test") or die(mysql_error());
if(isset($_GET['action'])){
$action = $_GET['action'];
}
if($action == "add"){
$name = $_GET['name'];
$deviceID = $_GET['deviceID'];
$text = $_GET['text'];
mysql_query("INSERT INTO webDB
(name, deviceid, text) VALUES('$name', '$deviceID', '$text') ")
or die(mysql_error());
}
if($action == "getall"){
$result = mysql_query("SELECT name, text, deviceID FROM webDB"
die(mysql_error());
) or
Page 38
Now we have a php script acting as a gateway to the database we need to upload it on to
the server. Thats easy.
Go to File Manager in your CPanel
Done!
Check your php is working by typing in the path to the DB as well as the Getall action.
Your path will have another name, instead of android-dsed below. This should return the
sample data you have in your database.
http://android-dsed.host22.com/netdb.php?action=getall
It wont look much, just raw data on your screen something like this although I have more
data in my Database.
Page 39
As a result it looks like ordinary text leaves the phone and ordinary text is shown back on
the phone.
Sub Process_Globals
Dim httpC As HttpClient 'the Connection client
End Sub
Sub Globals
Dim pnlbg As Panel
Basic For Android
Page 40
Dim
Dim
Dim
Dim
Dim
Page 41
File.WriteString(File.DirInternalCache, "nettalk.txt",result)
'get it back from the file
reader.Initialize(File.OpenInput(File.DirInternalCache, "nettalk.txt"))
'read it line by line to a string called line,
Dim name As String
name = reader.ReadLine this loads the username "me"
echo $row['name'];
Page 42
'SUBMIT MESSAGE
Sub btnsubmit_click
Activity.Title = "Submitted"
Dim inputtext As String
inputtext = txtinput.Text
If inputtext <>"" Then 'if there is something in the textbox
inputtext = inputtext.Replace(" ", "_")
ProgressDialogShow("Submitting data...")
Dim req As HttpRequest 'create a DB request
sendrequest = "http://androiddsed.host22.com/netdb.php?action=add&name=me&deviceID="
req.InitializeGet(sendrequest & deviceID &"&text=" & inputtext)
httpC.Execute(req, 1)
Else 'if empty show an error message
ToastMessageShow("Put a message in first", False)
End If
txtinput.Text = ""
'clear the text box
End Sub
To solve the first one we could send a time with your message which gets stored on the net,
however the problem with this is that if someone else is in another part of the world that
timestamp will be different to yours.
Lets make a timestamp that is on the server so that all messages are tagged with the same
timezone.
Go back to PhpAdmin, and open your database and find the Add New Field area, it appears
in a number of windows.
Page 43
The TIMESTAMP data type is used for values that contain both date and time parts.
TIMESTAMP has a range of '1970-01-01 00:00:01' UTC to '2038-01-19 03:14:07' UTC.
If the column is auto-updated, it is automatically updated to the current timestamp when the
value of any other data in the row is changed from its current value.
We can use the Timestamp as an index field as well if we want and we can perform time
calculations from it to get all the posts in the last 24 hours for example.
Using Limit
We can limit how many records are returned with the Limit command. In your PHP getall
code set the limit to 10 (LIMIT 10 ), or whatever number you wish.
Using our new Timestamp order the records by Timestamp and in reverse order (ORDER
BY TIMESTAMP DESC)
if($action == "getall"){
$result = mysql_query("SELECT name, text, deviceID FROM scoreTable
ORDER BY TIMESTAMP DESC LIMIT 10 " ) or die(mysql_error());
Notice that when you return the data to the phone it comes back with
two unwanted lines of code at lines 7 and 8 in the image.
We can easily remove this using indexof and substring commands
from our earlier exercise. Go ahead and make the changes.
Page 44
This is easy in theory but takes more work than you think.
First make a new button on your layout and call it Btndelete.
Declare the following under Sub Globals
Dim btndelete As Button
Dim message As String holds the message string
Full code.
Sub httpC_ResponseSuccess (Response As HttpResponse, TaskId As Int)
lvoutput.Clear
'download results
Dim result As String
result = Response.GetString("UTF8")
Basic For Android
Page 45
'strip out the end text with the annoying text at the end
Dim Endstring As Int
Endstring = result.IndexOf("<!")
result = result.SubString2(0, Endstring)
'strip out the underscores
result = result.Replace("_"," ")
'write it to a file
File.WriteString(File.DirInternalCache, "nettalk.txt",result)
'get it back from the file
reader.Initialize(File.OpenInput(File.DirInternalCache, "nettalk.txt"))
'Starts the download Get back the ID echo $row['ID'];
Dim ID As String
ID = reader.ReadLine
'run a loop while there is a still an ID - it gets the next ID at the end
of the loop
Do While ID <> Null
'read it line by line to a string called line this loads the user name
"name"
echo $row['name'];
Dim name As String
name = reader.ReadLine
'returns the message text echo "\r\n".$row['text'];
Dim linetext As String
linetext = reader.ReadLine
'returns the message text echo "\r\n".$row['text'];
Dim postdeviceID As String
postdeviceID = reader.ReadLine
'adds name and then text otherwise will be on seperate lines
lvoutput.SingleLineLayout.Label.TextSize = 16
lvoutput.SingleLineLayout.ItemHeight = 35
lvoutput.SingleLineLayout.Label.TextColor = Colors.Black
lvoutput.AddSingleLine(ID &": "& name & " "& linetext & " " &
postdeviceID)
ID = reader.ReadLine
Loop
reader.Close
ProgressDialogHide
lvoutput.SetSelection(0)
End Sub
Basic For Android
Page 46
The Listview Itemclick is the event that a touch on the text raises so this will be changed
adding message = Value to the variable so that message holds the string that is raised
when you click on it. We have to declare it under Globals as well Dim message As String
Sub lvoutput_ItemClick(Position As Int, Value As Object)
message = Value
Msgbox(Value, "Message") 'click on the message shows it in a msgbox
End Sub
Finally we need to add the code under the Delete Button. First it looks in the message for
the : eg in
Page 47
Sub btndelete_click
Dim IDdelete As String
IDdelete = message
'need to strip the message back to the first ID, by using the indexof
Dim stripstring As Int
stripstring = IDdelete.IndexOf(":")
IDdelete = IDdelete.SubString2(0, stripstring)
'this shows me in the code if I have it right
Log(IDdelete)
Dim req As HttpRequest ' requesting net data
req.InitializeGet("http://androiddsed.host22.com/netdb.php?&action=delete&ID="&IDdelete)
httpC.Execute(req, 1)
ProgressDialogShow("deleting message...")
End Sub
In the webDB.php add the following code, anywhere outside of the other functions.
First it looks for the action delete. When it finds that it pulls out the ID which is then passed
to $deleteID and run in the SQL.
//delete messages
if($action == "delete"){
$deleteID = $_GET['ID'];
mysql_query("DELETE FROM webDB
die(mysql_error());
}
WHERE ID = '$deleteID'"
) or
Page 48
Page 49
The difficulty with the compass is that the background image is static but the Arrow itself
rotates depending on the GPS bearings.
Its getting that rotation of the Arrow that is the issue, we need to create a zone for the
Arrow to rotate with the rectangle object and using canvas.
Sub Process_Globals
'create a bitmap to hold the compass and the arrow
Dim imgcompass, imgArrow As Bitmap
Dim Rect1 As Rect
End Sub
Sub Globals
Dim IVcompass As ImageView 'the compass background
Dim Canvas1 As Canvas
Dim Bitmap1 As Bitmap
End Sub
Page 50
The Location also includes other functionalities like calculating the distance and bearing
to another location and methods to convert the coordinates string formats.
Usually you will work with Location objects passed to you in the LocationChanged events.
However you can also initialize such objects yourself (this is useful for calculating distance
and bearing between locations).
The last one is GPSSatellite. This is a structure that holds information regarding the
currently known satellites. It is passed to you in GPSStatus event.
We are also going to create a location to save out GPS to called Dim SETloc As Location
and another using the Compass Dim Compass As PhoneSensors to show the direction
North Dim NPloc As Location
Lets create a new GPS and some storage places to record locations. Dim SETloc As
Location and Dim NPloc As Location so we can always find North again. To keep track of
the current location Dim Currentloc As Location. The locations are generated in the
LocationChanged sub later on.
Sub Process_Globals
'Create the GPS
Dim GPS1 As GPS
Dim SETloc As Location 'SET LOCATION
Dim NPloc As Location 'NORTH POLE
Dim Currentloc As Location 'CURRRENT LOC FROM THE GPS
Dim Compass As PhoneSensors
Dim GPSbearing, Compassbearing As Float
Dim Latitude, Longitude, lastlat, lastlon As Double
Page 51
GPS LocationChanged
This gives us the Location object named here loc. The heart of
the GPS
Loc can be broken down to all sorts of
properties such as Latitude and
Longitude.
'textlon =
'textlat =
Loc.Longitude
Loc.Latitude
textlat = Loc.ConvertToMinutes(Loc.Latitude)
textlon = Loc.ConvertToMinutes(Loc.Longitude)
All code
Sub GPS_LocationChanged (Loc As Location)
'This Is the main event. Loc holds the data for the new fix.
Longitude = Loc.Longitude
Basic For Android
Page 52
Latitude = Loc.Latitude ' Store the new latitude position in this string
Currentloc = Loc
' make a new location called Current LOC give it
current data
Dim degrees As Float
'bearing is the direction
If GPSbearing <> Loc.BearingTo(SETloc) Then ' change the compass to point
to the setLOC
GPSbearing = Loc.BearingTo(SETloc)
degrees = (GPSbearing - Compassbearing)
Canvas1.DrawBitmap(Bitmap1, Null, Rect1)
Canvas1.DrawBitmapRotated(imgArrow, Null, Rect1, degrees)
Activity.Invalidate()
End If
'work out speed
Dim locspeed As Double
locspeed = Loc.Speed * 3.6 '= kmh
lblspeed.Text = "Speed = " & Round2(locspeed ,2) &" KPH"
Dim textalt, textacc As Double
Dim textlat, textlon As String
'textlon =
'textlat =
textlat
textlon
textalt
textacc
=
=
=
=
Loc.Longitude
Loc.Latitude
Loc.ConvertToMinutes(Loc.Latitude)
Loc.ConvertToMinutes(Loc.Longitude)
Loc.Altitude
Loc.Accuracy
lbllonlat.Text =" Lat - " & textlat & CRLF & " Lon - " & textlon
lblaccalt.Text ="Altitude - " & Round2(textalt, 0) & " Meters" & CRLF &
"Accuracy - " & Round2(textacc, 0) & " Meters"
End Sub
The GPS turns off when you leave the activity, this is to save the battery. When you restart
the program, or reenter this activity it is turned on again. Obviously there might be times
when you dont want it turned off.
Sub Activity_Pause (UserClosed As Boolean)
'turn off the GPS to save the battery
GPS1.Stop
End Sub
Page 53
Sub Activity_Resume
'start listening for GPS - turn it on
If GPS1.GPSEnabled = False Then 'turn on your GPS
ToastMessageShow("Please enable the GPS device", True)
'Will open the relevant settings screen.
StartActivity(GPS1.LocationSettingsIntent)
Else
'Listen to GPS with no filters.
'The Start method receives two values which are the minimum time
(milliseconds) AND the minimum distance (meters) between events. An event
will be raised when at least one of these criterions are met. This can
help saving battery. In our case we are passing 0 AND therefore will get
all fix events.
GPS1.Start(0,0)
End If
Compass.StartListening("Orientation")
End Sub
Orientation_SensorChanged is used to expose the changes in the GPS to the arrow on the
compass. The code is trying to limit the compass reading to +/- 360 in quarter degrees units
by using an integer value for x where x Is the value of the compass bearing * 4, rather than
using the raw GPS values and so smoothing it out and saving on battery and CPU.
The If statement, If Compassbearing <> x/4.0 Then checks if the stored value for the
bearing has changed (that Is, has the bearing changed by more than a degree); If so, it
updates the stored value and moves the arrow.
Sub Orientation_SensorChanged(Values() As Float)
Dim degrees As Float, x As Int
x = ((2880 + Values(0) * 4) Mod 2880) - 1440
If Compassbearing <> x/4.0 Then
Compassbearing = x/4.0
degrees = GPSbearing - Compassbearing
Canvas1.DrawBitmap(Bitmap1, Null, Rect1)
Canvas1.DrawBitmapRotated(imgArrow, Null, Rect1, degrees)
Activity.Invalidate()
End If
End Sub
Page 54
We are going to add the Google map link as a menu item. You can easily use a button but
menus are good to develop
Add the following to Sub Activity_Create
Activity.AddMenuItem("Google Map Location", "Googlemap")
Then at the bottom of the code have a click event for that menu item. Sub Googlemap_click
Intent objects are messages which you can send to the OS in order to do some external
action in the phone. We want to open the Google maps on the cell phone.
Firstly you have define a new intent, Dim Intent1 As Intent
Then initialise it with the options you want Initialize (Action As String, Uri As String)
Intent1.Initialize(Intent1.ACTION_VIEW,URI)
ACTION_APPWIDGET_UPDATE As String
ACTION_CALL As String
ACTION_EDIT As String
ACTION_MAIN As String
ACTION_PICK As String
ACTION_SEND As String
ACTION_VIEW As String
Then we need a SetComponent (Component As String). Explicitly sets the component that
will handle this intent.
Intent1.SetComponent("googlemaps")
The Intent object should finally be started with StartActivity keyword StartActivity(Intent1)
Sub Googlemap_click
Dim Intent1 As Intent
URI= "geo:" & Latitude & "," & Longitude & "?q=" & Latitude & "," &
Longitude
Intent1.Initialize(Intent1.ACTION_VIEW,URI)
Intent1.SetComponent("googlemaps")
StartActivity(Intent1)
'streetview works as well
' URI= "google.streetview:cbll=" & Latitude & "," & Longitude & "&cbp=1"
'google.streetview:cbll= Latitude, Longitude
&cbp=1,yaw,,pitch,zoom&mz=mapZoom
End Sub
Basic For Android
Page 55
This should give you a start with working with GPS. From here
you could make a DB and save GPS locations then show the
distance between them and current position.
1. Create a new table in your SQL database named GPSLocation make 5 fields
Page 56
We could use the same PHP script we made before but lets make a new one so we can
keep it with our program in the same folder to make it easier updating. Copy and paste your
webDB.php file and save it as GPSLocation.php into your project.
Add a new function addgps
if($action == "addgps"){
$lat = $_GET['lat'];
$lon = $_GET['lon'];
$deviceID = $_GET['deviceID'];
mysql_query("INSERT INTO GPSlocation
(lat, lon, deviceid) VALUES('$lat', '$lon', '$deviceID') ")
or die(mysql_error());
}
We are using the INSERT command and this will make a new entry each time it saves.
However you might want to consider using an UPDATE command which will just change the
single saved GPS location if you only want to record the current location.
UPDATE table_name
SET column1=value, column2=value2,...
WHERE some_column=some_value
Use the Submit code from the last exercise to submit this to the DB.
First define the following under Sub Process_Globals
Dim phoneInfo As PhoneId
Dim deviceID As String
deviceID = phoneInfo.GetDeviceId ' getting the Phone ID
Dim httpC As HttpClient 'the Connection client
Click on the HTTP library and the Phone Library to add it to the project.
Add the Menu button code to the Activity_Create
Activity.AddMenuItem("Upload Location", "uploadlocation")
Page 57
Create a new sub, Sub uploadlocation_click that is the click event of the menu item
above, add the code full version below to it. And try it.
The 'sendrequest1 comment can be used to check if the php script is working, without
having to see if the rest is OK. Just change the request to req.InitializeGet(sendrequest1).
Here you can clearly see the 3 code blocks of Sending, Sub httpC_ResponseSuccess, and
Sub httpC_ResponseError needed to work with HTTP.
'SUBMIT GPS
Sub uploadlocation_click
variables to hold the lat and lon locations
Dim lat, lon As Double
lon = Currentloc.Longitude
lat = Currentloc.Latitude
Just a dialog to tell the user something is working
ProgressDialogShow("Submitting GPS ...")
Make a request
Dim req As HttpRequest
sendrequest = "http://androiddsed.host22.com/gpslocation.php?action=addgps&lat="
'sendrequest1 = "http://androiddsed.host22.com/gpslocation.php?action=addgps&lat=456&lon=123&deviceID=123
456"
Sending the request
req.InitializeGet(sendrequest & lat & "&lon=" & lon &"&deviceID=" &
deviceID)
httpC.Execute(req, 1)
Check to see what is going is OK
Activity.Title = lat &" "&lon &" " & deviceID
End Sub
Page 58
Getting satellites
Sub GPS_GpsStatus (Satellites As List)
'This event allows you To display information about the currently
available satellites. Note that Not all satellites in the List are
actually used For calculating the last fix. So it Is possible that the
List will include several satellites but still the reception Is Not good
enough For a fix.
Dim SatCount As Int
SatCount = 0
For i = 0 To Satellites.Size - 1
'loop through counting satellites
Dim Satellite As GPSSatellite
Satellite = Satellites.Get(i)
If Satellite.UsedInFix = True Then SatCount = SatCount + 1
Next
lblsatt.Text = "Satellites In View: " & Satellites.Size & "
SatCount
End Sub
Page 59
Retrieving data from the database and displaying distance to saved GPS location
Page 60
Then in a new click event for the menu I put the following which by now is quite
straightforward calling the getgps function in the gpslocation.php above.
'GET THE GPS BACK INTO THE PHONE FROM THE DB
Sub downloadgps_click
Dim req As HttpRequest ' requesting net data
req.InitializeGet("http://androiddsed.host22.com/gpslocation.php?&action=getgps")
'(req, 2) means it has a taskid of 2 see in the Sub httpC_ResponseSuccess
httpC.Execute(req, 2)
ProgressDialogShow("Fetching all data...")
End Sub
The result that is returned comes in via the httpC_ResponseSuccess. The pattern is the
same as the previous example. Read the data in line by line to a datafile, read it out to the
variables.
When we get the Lat and Lon, pass them to the savedlocation.Latitude to be used later. The
deviceID is downloaded but not used at this point. After getting the data we close the
reader with reader.Close.
Using the previous code for the GoogleMaps we pass the data to the maps. Finally with our
new SavedLocation we can see the distance from current GPS location to that point.
Sub httpC_ResponseSuccess (Response As HttpResponse, TaskId As Int)
'(req, 1) means that taskID = 1 the upload function only
If TaskId = 1 Then
ToastMessageShow("Success GPS uploaded", False)
ProgressDialogHide
Else
'Any other function with a taskID of 2 - the download function
Dim result As String result from the database being passed in
result = Response.GetString("UTF8")
'write it to a file
File.WriteString(File.DirInternalCache, " gpsdownload.txt",result)
'get it back from the file
reader.Initialize(File.OpenInput(File.DirInternalCache, "
gpsdownload.txt"))
Dim latgps As String make a latitude variable to hold lat
latgps = reader.ReadLine read the data to the variable
savedlocation.Latitude = latgps save it also to the savedlocation object
Dim longps As String
Basic For Android
Page 61
longps = reader.ReadLine
savedlocation.Longitude = longps
Dim deviceID As String
deviceID = reader.ReadLine
reader.Close
Dim Intent1 As Intent
URI= "geo:" & latgps & "," & longps & "?q=" & latgps & "," & longps
Intent1.Initialize(Intent1.ACTION_VIEW,URI)
Intent1.SetComponent("googlemaps")
StartActivity(Intent1)
Activity.Title = "Distance to location " &
Currentloc.DistanceTo(savedlocation)& " in meters"
End Sub
Here is a pic of the Google maps showing the saved location at and the current location
with the blue Arrow. (Note this this pre earthquake so there are far more buildings and cars).
You can see on the title bar that the distance is 80.2 meters to the saved location.
As the distance has a ridiculous amount of decimal spaces in it lets round it off to 2 decimal
places. Round2(distloc, 2) is the primary code for this.
Dim distloc As Long
distloc = Currentloc.DistanceTo(savedlocation)
distloc = Round2(distloc, 2)
Activity.Title = "Dist to saved location " & distloc & " meters"
Page 62
Page 63
Process_Globals
GPS1 As GPS
Parser As SaxParser
'Parser library
hc As HttpClient
'Required to connect to the Internet
req As HttpRequest
Sub
Sub
Dim
Dim
Dim
Dim
Dim
Globals
lblLon As Label
lblLat As Label
lblSpeed As Label
Button1 As Button
edtgeo As EditText
Sub Activity_Resume
If GPS1.GPSEnabled = False Then
ToastMessageShow("Please enable the GPS device.", True)
Basic For Android
Page 64
'when you get a GPS fix then make the button show
If Location1.Latitude <> 0 AND Location1.Longitude <> 0 Then
Button1.Visible = True
End If
End Sub
Sub Button1_Click
Items.Clear 'Empty the list
edtgeo.Text = "" ' empty the text box
'send the request to the server
req.InitializeGet("http://maps.googleapis.com/maps/api/geocode/xml?latlng=
" & gLatitude & "," & gLongitude & "&sensor=true")
hc.Execute(req, 1)
End Sub
Page 65
Geolocation
'when the GetGeoLocation from the Response above has finished
Sub GetGeoLocation_StreamFinish(Success As Boolean, TaskId As Int)
Dim in As InputStream
'read the file into the input stream variable
in = File.OpenInput(File.DirDefaultExternal, "Geo.xml")
edtgeo.Text= File.ReadString(File.DirDefaultExternal, "Geo.xml")
'parse it through the parser and name the event as "Parser"
Parser.Parse(in, "Parser")' below are the start and end events of the
parsing. Close the input stream
in.Close
'show the items list that is filled below in the Parser_EndElement
Msgbox(Items.Get(0), "")
End Sub
XML parser
The last two are happening at the start and the end of Parser.Parse(in, "Parser")
Sub Parser_StartElement(Uri As String, Name As String, Attributes As
Attributes)
End Sub
Page 66
Page 67
10.
Widgets are the little programs that run on the front of your phone. They are active
programs, and more than just shortcuts that open the program.
Widgets are created and managed in another process, different than the process that your
application is running in. So its not just a front end of your
program and they run when your program has turned off. They
use a Service Module rather than the Activity Module that we
are used to. Each widget is tied to their own Service Module.
Through this module the widget is created and updated.
In this case we are making the Widget alongside the same
temperature program we made previously, but it could be in
a new program. The program only shares the text file that holds
the city selected.
The home screen application (the front of your phone) hosts your widgets and means that it
is not possible to directly access the widgets views. Instead we use a special object named
RemoteViews which gives us indirect access to the widget views.
Widgets do not support all views types. The following views are supported:
-
To make a widget we have to add a Service module. Note that the service module
handling the widget is a standard service. Design the widget layout with the designer.
Page 68
A Service Module is good for scheduling a repeating task. By calling StartServiceAt you
can schedule your service to run at a specific time. You can call StartServiceAt in Sub
Service_Start to schedule the next time and create a repeating task (for example a task
that checks for updates every couple of minutes).
You can also run a service after the phone boots by checking Project - Service properties Start At Boot your service will run after boot is completed.
The Service Module has familiar areas to the Activity Module we have used to date.
Sub Process_Globals is the place to declare the service global variables. There is no
Globals sub like in Activity as Service doesn't support Activity objects. Sub process globals
should only be used to declare variables.
Note that Process_Global variables are kept as long as the process runs and are accessible
from other modules.
Sub Service_Create is called when the service is first started. This is the place to initialize
and set the process global variables. Once a service is started it stays alive until you call
StopService or until the whole process is destroyed.
Sub Service_Start is called each time you call StartService (or StartServiceAt). When
this subs runs the process is moved to the foreground state. Which means that the OS will
not kill your process until this sub finishes running. If you want to run some code every
couple of minutes / hours you should schedule the next task with StartServiceAt inside this
sub.
Sub Service_Destroy is called when you call StopService. The service will not be running
after this sub until you call StartService again (which will run Sub Service_Create followed
by Sub Service_Start).
Page 69
The code below is in the order that it can be placed on the Service Activity
Open your weather program and add a Service Module to it. Then add in the code.
'Service module
Sub Process_Globals
Dim rv As RemoteViews
Dim hc, hcimage As HttpClient
Dim req, reqimage As HttpRequest
Dim temp, strplace, townpath, pic, selectedcity, temperature As String
Dim oldtemp As Short : oldtemp = 0
' holds the old temperature
End Sub
Page 70
This checks the Intent message that caused this Service To start and is responsible for
raising the events related to the widget. It returns True If an event was raised.
Sub Service_Start (StartingIntent As Intent)
If rv.HandleWidgetEvents(StartingIntent) Then Return
End Sub
The widget raises two events. RequestUpdate is raised when the widget needs to update
itself. It will fire after adding the widget to the screen, after the device has booted, based on
the scheduled updating interval (If set) or after the application was updated.
Sub rv_RequestUpdate
GetTemp
End Sub
Sub rv_Disabled
StopService("")
End Sub
Sub imgNext_Click click event of the image
GetTemp
End Sub
Sub panel1_click click event of the panel
GetTemp
End Sub
Page 71
This is the main sub of the widget. I will comment it throughout the code. This is mostly the
same code as we used in our earlier exercise.
Sub GetTemp
we call the selected city that has been stored in the text file of the
weather program
selectedcity = File.ReadString(File.DirInternal, "WeatherCity.txt")
What if there isnt anything in the text file? Give it a default city
If selectedcity = "" Then
selectedcity = "Auckland"
End If
We want to get two temperatures, the current temp from the internet, and
the old temp from before the update. This means you can tell if the temp
is going up or down.
If temperature <>"" Then if there is a temp then pass it to oldtemp
before getting a new temp
oldtemp = temperature
End If
strplace = selectedcity.ToLowerCase
townpath = "http://m.metservice.com/towns/"& strplace
'Just to show its updating make the temp in the label go away and make a
message show
rv.SetText("lbltemperature", "")
rv.SetText("lbltime", "Updating ...")
Update the widget
rv.UpdateWidget
req.InitializeGet(townpath)
hc.Execute(req, 1)
End Sub
Sub Service_Destroy
End Sub
Page 72
city = temp
'start at the 4th letter and end with the /h1
city = city.SubString2(4, city.IndexOf("</h1>"))
temperature = temp 'pull the temperature from the code
temperature = temperature.SubString(temperature.IndexOf("ul'><h2>"))
temperature = temperature.SubString2(8, temperature.IndexOf("<span "))
Dim shtemp As Short
shtemp = temperature
'get the difference between the old temp and the new temp
Dim updowntemp As Short
updowntemp = shtemp - oldtemp
'set the colors red = up blue = down white no change
Dim temptext As String
If updowntemp > 0 Then
temptext = " Up"
rv.SetTextColor("lbltemperature", Colors.RGB(255,204,225))
Else
temptext = " Down"
rv.SetTextColor("lbltemperature", Colors.RGB(141,197,224))
End If
If updowntemp = 0 Then
temptext = ""
rv.SetTextColor("lbltemperature", Colors.White)
End If
'remote view passes the data to the label
rv.SetText("lbltemperature", temperature)
Page 73
End If
Dim strtime As String 'pull the time from the code
strtime = temp
Dim timecolon As String
timecolon = strtime.IndexOf(":") 'find the colon between the time eg
11:23am
strtime = strtime.SubString2(timecolon -2, timecolon +5) 'take 2 off and
add 5 on to get the whole time 11:23am
rv.SetText("lbltime", strtime & CRLF & city & temptext)
rv.UpdateWidget
End Sub
Sub getimage
Dim imagepath As String 'this gets the image from the net
imagepath = "http://m.metservice.com/sites/all/themes/mobile/images/wxicons/"& pic
reqimage.InitializeGet(imagepath)
hcimage.Execute(reqimage, 1)
End Sub
Page 74
Page 75
Page 76
This is a white square behind the temperature that is curved like a circle, its hard to make
out unless you see the entire widget.
Page 77
Back on your phone click your menu button (bottom left blank space on mine and click on
Add. Then click on Widgets and drag onto the phone the one we have created.
Page 78
11.
Project: Alarm scheduler sends
email to contacts
This program incorporates four main areas,
Imagine you wanted to send a message to some people in your contacts list
at a set time every day. This program does that.
There are two Modules, a Main Activity module and a Service Module. The
main module sets up the program while the service module runs when the
alarm time equals the cell phone time.
'Activity module
Sub Process_Globals
Dim alarmHours, alarmMinutes As Int
Dim noti As Notification 'shows in the notification window
End Sub
Sub
Dim
Dim
Dim
Dim
Globals
SetTime As Button
CancelAlarm As Button
lvphone As ListView
btnSavephone As Button
Page 79
Main Sub to get the alarm time. (Note that Alarm isnt defined thats because I dont know
what type it is. It still works, just gives a nice red color).
Sub SetTime_Click
Dim td As TimeDialog 'the dialog from the dialog library
td.Hour = alarmHours
td.Minute = alarmMinutes
If td.Show("Select time to activate alarm", "", "Ok", "Cancel", "",
Null) = DialogResponse.POSITIVE Then
alarmHours = td.Hour
alarmMinutes = td.Minute
Dim today As Long
today = DateTime.DateParse(DateTime.Date(DateTime.Now)) 'Sets today at
12:00 AM
alarm = today + td.Hour * DateTime.TicksPerHour + td.Minute *
DateTime.TicksPerMinute
If alarm < DateTime.Now Then alarm = DateTime.Add(alarm, 0, 0, 1)
Log(DateTime.Date(alarm) & " " & DateTime.Time(alarm)) 'check the logs to
see the set date and time
'Calculate time to alarm
Dim h, m As Int
h = Floor((alarm - DateTime.Now) / DateTime.TicksPerHour)
m = ((alarm - DateTime.Now) - h * DateTime.TicksPerHour) /
DateTime.TicksPerMinute
ToastMessageShow("Alarm will start after: " & NumberFormat(h, 2, 0) & "
hour(s) and " & NumberFormat(m, 2, 0) & " minute(s)", True)
'You should schedule the next task with StartServiceAt.Android will
eventually kill your process if you use a timer. By scheduling the Next
task with StartServiceAt you make sure that a new process will be created
when the scheduled time arrives. This Is Not the Case with a regular
Timer.
StartServiceAt(AlarmService, (DateTime.Now+((h*60*60*1000)+(m*60*1000))),
True) ' Schedule AlarmService will start by add
time to DateTime.Now (note that Android use
millisecond)
This sets out the notification features that
appear on the notification front part of your
phone
noti.Initialize
noti.Light = True
noti.Vibrate = False
Basic For Android
Page 80
noti.OnGoingEvent = True
noti.Sound = False
noti.Icon = "icon" set your own image if you want
noti.SetInfo("Alarm", "will start at " & DateTime.Date(alarm) & " " &
DateTime.Time(alarm), "")
noti.Notify(1) Displays the notification. Id This id can be used to later
update this notification (by calling Notify again with the same Id),
or to cancel the notification.
End If
End Sub
Main sub to get the contacts from the Phone I left the commented out section in case you
want to see whats happening, and grab them yourself
Sub getcontacts
Dim Contacts2 As Contacts2
listOfContacts = Contacts2.GetAll(True,False)
For i = 0 To listOfContacts.Size - 1
Dim Contact As Contact
Contact = listOfContacts.Get(i)
'Logging to check how it works can uncomment
Log(Contact) 'will print the fields to the LogCat
' Dim photo As Bitmap
' photo = Contact.GetPhoto
' If photo <> Null Then Activity.SetBackgroundImage(photo)
'
Dim emails As Map
'
emails = Contact.GetEmails
'
If emails.Size > 0 Then Log("Email addresses: " & emails)
'
Dim phones As Map
'
phones = Contact.GetPhones
'
If phones.Size > 0 Then Log("Phone numbers: " & phones)
If Contact.PhoneNumber <>"" Then If there is a contact number pass it to
the listview so you can see it
lvphone.SingleLineLayout.Label.TextSize = 15
lvphone.SingleLineLayout.ItemHeight = 40
lvphone.AddSingleLine(Contact.DisplayName &": " &Contact.PhoneNumber)
lvphone.ScrollingBackgroundColor =Colors.DarkGray
End If
Next
Basic For Android
Page 81
End Sub
This is the click event on the listview. We want to take the value that we click on (the name
and phone number) and add it to our Phonelist as a List object.
Sub lvphone_ItemClick (Position As Int, Value As Object)
pass the value to details and then save it to the phone list. Might be
able to bypass all this and just go phonelist.Add(Value)
Dim details As String
details = Value
Activity.Title = details Show the name at the top as a check
Log(details) Show the name in the logs as a check
phonelist.Add(details)
End Sub
Write to a file
The button save click saves two parts, the message that you want sent, and the phone list
that you have created. These text files are then opened and used by the service when the
alarm is activated.
Note the easy File.WriteString(File.DirInternal, "message.txt", edtmessage.text) structure.
Of Filename "message.txt" and Content. edtmessage.text.
Sub btnSavephone_Click
Check to see if a message has been written and a list has been made
If
edtmessage.text <>"" AND phonelist.Size >0 Then
Write the message and list to files to be accessed later
File.WriteString(File.DirInternal, "message.txt", edtmessage.text)
File.WriteList(File.DirInternal, "phonelist.txt", phonelist)
ToastMessageShow("List saved", False)
lvphone.Clear clear the listview screen ready to show its saved
Else
bozo notification
ToastMessageShow("Save a list and write a message first", True)
End If
End Sub
This button allows you to load the list you made to check that its the correct people in it.
This shows how easy a list is to use as well.
Sub btnloadlist_Click
Dim list1 As List
quit if no phonelist (If statements dont need an endif they are only on
one line.)
If File.Exists(File.DirInternal, "phonelist.txt") = False Then Return
Basic For Android
Page 82
'Service module
Sub Process_Globals
Dim mp As MediaPlayer
Dim noti As Notification
End Sub
Sub Service_Create
End Sub
Sending an SMS
Page 83
Page 84
12.
The beauty of this simple little program is not in its novelty value, but that it can be added to
any other program to add functionality and make a point of difference. Imagine you add it to
your Weather Widget, or your GPS locator, so that people can just click on the program and
hear the temperature and location without taking their eyes off the road.
As well it could be the heart of a program for disabled people, and later we will use it to read
emails as well.
Note that the text read is held in the edttext.text field, which
means that any strings can be read as well.
Sub Process_Globals
Dim TTS1 As TTS
End Sub
Sub Globals
Dim barPitch As SeekBar
Dim barSpeechRate As SeekBar
Dim btnSpeak As Button
Dim EditText1 As EditText
Dim spnrLanguages As Spinner
End Sub
Page 85
Activity.GetView(i).Enabled = True
Next
btnSpeak_Click 'play first sentence
Else
Msgbox("Error initializing TTS engine.", "")
End If
End Sub
Sub Activity_Resume
If TTS1.IsInitialized = False Then
TTS1.Initialize("TTS1")
End If
End Sub
Sub btnSpeak_Click
If EditText1.Text.Length > 0 Then
TTS1.Speak(EditText1.Text, True)
EditText1.SelectAll
End If
End Sub
Page 86
Return
End If
End Sub
Here is the stripped down version that you can just drop into your programs. Dont forget to
add the TTS library.
It doesnt have to come off the button click, thats just an example.
Dim TTS1 As TTS
Sub Activity_Resume
If TTS1.IsInitialized = False Then
TTS1.Initialize("TTS1")
TTS1.SetLanguage("en","")
End If
End Sub
Sub Activity_Pause (UserClosed As Boolean)
TTS1.Release
End Sub
Sub Button1_Click
If .yourtext.Text.Length > 0 Then
TTS1.Speak(yourtext.Text, True)
End If
End Sub
Page 87
13.
Project: Capture all SMS messages entering your
phone
Imagine that when a text message came into your phone that you didnt have to stop what
you are doing and have to look to see who sent it. Maybe you are driving, working, or busy
elsewhere and want to know if its important or not.
Thats what this program does. It tells you who sent the text message so you can decide if
you need to reply immediately. This is based on the previous lessons and looks at a few of
the many features of the phone you can use in programming.
When a text message comes in the number it comes from is checked against the contacts
list in your phone. If a match is made then it speaks out the name of the person in the
contact list.
For this to work you need to have the Phone library 1.8 installed. To do that
download it from B4A website, and put it into the internal library folder, not the
usual external one. The internal folder is usually at C:\Program Files\Anywhere
Software\Basic4android\Libraries
If you have a Phone library in the external library then you need to delete it as it will
overwrite the internal Phone Library.
Logs and Toastmessageshow are crucial to debugging
Debugging is crucially important and especially so in this exercise. I have used copious
amounts of Logs and Toastmessageshow to see what is happening in the code. What is the
number coming in? How does it change when you strip it? Does it match up with the
contacts? What happens next etc.
You need to do this as well. Debugging IS coding. Not just following this exercise.
Page 88
When working with a Service module you need to pass data to it from the Activity module
using text files. So if you make a setting in your activity module, you have to save it as a text
file then upload it into the service module. That way the settings are saved when you turn off
your program and only the service is running.
Saving and reading from text files is really easy, and I use it throughout the code.
Here for example is data held in the details variable being written to a file "from.txt"
From = File.WriteString(File.DirInternal, "from.txt",details)
And here is the data from that "from.txt" file being passed back into the From variable.
From = File.ReadString(File.DirInternal, "from.txt")
Sub
Dim
Dim
Dim
Dim
Dim
Dim
Dim
End
Globals
lvphone As ListView 'the listview holding the contacts
edtmessage As EditText 'messagebox that holds the phone number
Panel1 As Panel ' background panel
Button1 As Button ' the Simulator run button
listOfContacts As List 'holds the contacts list
btnservicestart As Button ' start the service button
btnservicestop As Button 'stop the service button
Sub
Page 89
Sub Activity_Resume
End Sub
Sub Activity_Pause (UserClosed As Boolean)
End Sub
'fills the listview with the data from the contact list
Sub getcontacts
'Create a Contacts to hold the contacts from your phone. Contacts2 object
allows you to access the device stored contacts. This type is based on a
new API supported by Android 2.0 and above.This type supersedes Contacts
type.
Dim Contacts2 As Contacts2
'pass the contacts to a list to hold them. Note that each contact has
about 6 or so fields, that at the moment you can't get to
listOfContacts = Contacts2.GetAll(True,False)
'loop through each of the contacts in your new list
For i = 0 To listOfContacts.Size - 1
'for each contact pass it to the Contact object. This object allows you to
extract out each field held in filed, so you can use Contact.phonenumber
and Contact.DisplayName as well as many others.
Basic For Android
Page 90
Sub btnservicestop_Click
StopService(Sms) ' stop the service running (turn it off)
End Sub
Sub btnservicestart_Click
StartService(Sms) ' start the service running (turn it on)
End Sub
Page 91
'I called this smscopy as its a copy of the sms main code
Sub smscopy
'this reads the file in from the from.txt. in the sms code it comes in via
the sms message
Dim From As String
From = File.ReadString(File.DirInternal, "from.txt")
'logs and toastmessages to see what is happening
ToastMessageShow("Text from " & From, True)
Log ("From before cut" & From)
'strips out the first numbers of the incoming phone number. The number
coming into the phone can have different prefixes on it to the one stored
in the phone. eg: number in is always 642.. country code and cellphone,
but the number in the contacts can be just cellphone 027.. we need to make
both equal. So stripping out the first numbers down to 7 digits fixes
this. Thats why empty entries and ones with 3 numbers are blocked earlier,
it crashes here. (took me hours to work out).
' From.Length-7 find the length of the number eg: 11, take of 7 and = 4,
so start number for the substring is 4.
'SubString2(startnumber, to end number)
From = From.SubString2(From.Length-7, From.Length)
'show me the chopped number as a check
ToastMessageShow("Chopped from " & From, True)
'same code as above getting the contacts2 list, passing it to a
listofcontacts and a contacts object to extract out the name and number.
Dim listOfContacts As List
Dim Contacts2 As Contacts2
listOfContacts = Contacts2.GetAll(True,False)
For i = 0 To listOfContacts.Size - 1
Dim Contact As Contact
Contact = listOfContacts.Get(i)
'just to see what the counter is doing
Log(i)
Dim phonenumber As String
Dim startphone, endphone As Int
If
Page 92
'this strips out the first numbers of the phone list. its the same as we
did above but I broke it down into its component parts to make it easier
for you to read
phonenumber = Contact.phonenumber
startphone = phonenumber.Length-7
endphone = phonenumber.Length
phonenumber = phonenumber.SubString2(startphone,endphone)
Log ("From after the cut" & From)
If From = phonenumber Then
'a whole bunch of testing going on
' ToastMessageShow("PH " & phonenumber & " From " & From, True)
Log("PH " & phonenumber & " From after cut " & From)
ToastMessageShow("Incoming text from " & Contact.Name, True)
'text to speech finally working
TTS1.Speak("Text from " & Contact.Name, True)
'this text file holds the name and message, it will go on the widget so
you can read it
File.WriteString(File.DirInternal, "body.txt","From " & Contact.Name &"
This is a test message, Its a really long one, I hope you can read it
all")
Else
'ToastMessageShow("No matching contact", True)
Log("PH " & phonenumber & " From after cut " & From)
End If
End If
Next
End Sub
Page 93
Sub Service_Create
'starting the service in the foreground means it won't get killed by the
Android system - it stays alive
Service.StartForeground(1,"SMSInterceptor running")
'You intercept SMS messages and prevent the messages from being handled by
the default messaging application by initializing SmsInterceptor with
Initialize2 AND setting the Priority parameter To 999 (highest application
priority For Intent filters).
'This then handles the Sub SI_MessageReceived part
SI.Initialize2("SI", 999)
'make sure text to speech is initialised and set the details
If TTS1.IsInitialized = False Then
TTS1.Initialize("TTS1")
TTS1.SetLanguage("en","")'language
End If
Log("Service initialized")
'Widget name - the name that will appear in the widgets List.
rv = ConfigureHomeWidget("smslayout", "rv", 0, "SMS Inteceptor")
End Sub
Page 94
'This code checks the Intent message that caused this service to start in
this case the text message recieved and is responsible for raising the
events related to the widget. It returns true if an event was raised.
If rv.HandleWidgetEvents(StartingIntent) Then Return
End Sub
Sub Service_Destroy
SI.StopListening()
Service.StopForeground(1)
ToastMessageShow("SMS inteceptor has stopped", False)
End Sub
Page 95
File.WriteString(File.DirInternal, "body.txt","From " & From & " " & Body)
If From = phonenumber Then
' ToastMessageShow("PH " & phonenumber & " From " & From, True)
Log("PH " & phonenumber & " From after cut " & From)
ToastMessageShow("Incoming text from " & Contact.Name, True)
TTS1.Speak("Text from " & Contact.Name, True)
File.WriteString(File.DirInternal, "body.txt","From " & Contact.Name & " "
& Body)
Else
'ToastMessageShow("No matching contact", True)
Log("PH " & phonenumber & " From after cut " & From)
End If
End If
Next
updateTheWidget
End Sub
Sub updatewidgettext
rv.SetText("lbltext","Working ...")
ToastMessageShow("Click event on lblclick?", True)
Dim message As String
Basic For Android
Page 96
Sub rv_RequestUpdate
rv.updatewidget
End Sub
Sub rv_Disabled
StopService("")
End Sub
The Activity(smstest)
This activity is just a tacked on piece, its working code but I think it might be better used
elsewhere. What I was trying to do is when a message is received and the Notification is
activated a text is placed in the Notification window.
This is loaded in with the code from the Service
'this runs the next Activity (smstext)
noti.SetInfo("SMS Interceptor","Running", "smstext")
If we want to see what the message is then we can click on the notification and it will run the
"smstext" activity which loads the messagebox with the message.
Page 97
Sub Globals
End Sub
Sub Activity_Create(FirstTime As Boolean)
If File.Exists(File.DirInternal, "body.txt") = False Then
ToastMessageShow("No message", False)
Else
Dim message As String
This widget is almost exactly the same as the last widget we made.
We have the following
Page 98
14.
This simple little program is easy to create and can add variety and value to your Android
programs.
All it requires is a layout with a button on it. The VR program generates its own interface.
The button doesnt have to be as big as it is it does not affect the VR layout.
We will use this program later back in our last program to allow you to talk in commands to
create text messages mostly by just adding this entire activity as a new activity to the
program.
Designer
Running
Page 99
'Activity module
Sub Process_Globals
Dim VR As VoiceRecognition
Dim TTS1 As TTS
End Sub
Sub Globals
End Sub
Sub Activity_Create(FirstTime As Boolean)
If FirstTime Then
VR.Initialize("VR")
TTS1.Initialize("TTS1")
End If
'load the layout named 1 (just a button)
Activity.LoadLayout("1")
'tells the user if they can use voice recognition
If VR.IsSupported Then
ToastMessageShow("Voice recognition is supported.", False)
Else
ToastMessageShow("Voice recognition is not supported.", True)
End If
'just a text message on the program neat the top
VR.Prompt = "Say your message"
End Sub
Sub Button1_Click
VR.Listen 'calls the voice recognition external activity
End Sub
Sub VR_Result (Success As Boolean, Texts As List)
'Texts is a list object, the VR program creates a list of potential
phrases it hears ie: You say "Today is hot" it lists "Today is not",
"Today is snot" "Today is a lot" etc, then lists it in order of preference
and at Texts.Get(0)gives the most likely choice "Today is Hot".
If Success = True Then
ToastMessageShow(Texts.Get(0), True)
TTS1.Speak(Texts.Get(0), True)
End If
End Sub
Page 100
15.
Project: Voice recognition in SMS messages
program.
The addition of voice recognition is actually pretty easy. Rather than writing the code from
scratch and embedding it into the existing program I merely copy it over to a new activity
icon that loads a button.
and then connected it through via the click on the widget
First of all lets get it working in your testbed the Main
bugs are ironed out make a link in your Service (SMS) Module.
We need a layout for the button to be clicked to activate the voice recognition. Its only one
button on a Layout. The new layout is called Voice.
Voice1 is the name of the new Activity we will make, not the name of the layout.
Page 101
When activated the button will appear to float over the top of the window, but in reality it just
has a transparent background.
At this stage we cant test it and see, you will just have to trust me.
Page 102
Back in the program go Project / Add New Module / Activity Module. Then create new
Activity Module named Voice1.
This activity module is a copy of the earlier exercise with added sections. The two new parts
are Sub smstextready which loads the SMS reply window ready for a message and Sub
readtext that reads back the incoming SMS message.
'Activity module
Sub Process_Globals
Dim vr As VoiceRecognition ' first time
Dim vrtext As VoiceRecognition ' for message
Dim TTS1 As TTS
End Sub
Sub
'if
Dim
End
Globals
people get it wrong, lets insult them.
insult As Int :insult = 0
Sub
Sub Button1_Click
vr.Listen 'calls the voice recognition external activity
End Sub
Basic For Android
Page 103
Sub Activity_Resume
End Sub
In the next section I used message.Contains("reply") which meant that it parses the text
looking for the word reply. This can be used to detect accents as well. Read can be Reed,
or Red etc. Surprisingly it is Case Sensitive, and will not return if you make the words
capital case (well not for me anyway).
This system could be expanded for any number of keywords or phrases. Even to loading an
SMS with a nickname for a person The Old Trout for your Mother in law. Nicknames could
be kept in a database attached to the contacts list.
This part insult = Rnd(1,5) gives a random number between 1 and 5 not including 5.
Page 104
Case 4
TTS1.Speak("Please don't gargle and talk at the same time. Spit it out
first then try again", True)
End Select
End If
End If
End Sub
In this section we get into the heart of the program. We load 2 text files, which we will have
to make later fromsms.txt and contactname.txt.
Note the If File.Exists(File.DirInternal, which is used to check that there is a file there to
start with. The first time its used there wont be one and the program will crash, its a good
bit of protection.
The Dim i As Intent i.Initialize(i.ACTION_VIEW, "sms:" & number) is part for creating and
accessing an Intent, opening the SMS reply window which is another program. You use
Intents to open other programs on your phone. The action we are going to perform is VIEW
adding the number.
Page 105
'start it
StartActivity(i)
End Sub
Finally we need to create the text files. Back in your Service Module (SMS) Find the
following areas and add the code. We save to a text file to get it back later.
Add File.WriteString(File.DirInternal, "Fromsms.txt",From) here.
'The heart of the program
Sub SI_MessageReceived (From As String, Body As String) As Boolean
'Body and From are the two parts of the text message that are passed into
the phone. write a file to open with the new text in txtreply on voice1
File.WriteString(File.DirInternal, "Fromsms.txt",From)
The contact name for the reply comes under the Sub SI_MessageReceived sub below If
From = phonenumber.
If From = phonenumber Then
File.WriteString(File.DirInternal, "contactname.txt",Contact.Name)
Finally we need a way to start the Voice1 Activity. We are going to do that off the click on
the heart is StartActivity("voice1")
the image
Sub ivimage_click
TTS1.speak("Press the Button. Then say Read or Reply", False)
StartActivity("voice1")
End Sub
Page 106
16.
Map is a structure that is used frequently in Java. Its listed as an advanced tool but it is very
versatile and useful.
A Map consists of two parts a KEY and a VALUE pair. The key is unique, while the value
can be anything. KEY VALUE are separated by a colon : If you enter a key/value pair and
the collection already holds an entry with the same key, the previous entry will be removed
from the map so it overwrites existing entries.
The idea is to look down the Key field for what you are seeking and take the data from the
value field. This is far faster than looping through all the entries in the ordinary way.
Fetching an item is done by looking for its key. This is usually a very fast operation (O(1)
compared to O(n) in a list).
The key could be a string or a number. The value can be any type of object. Eg:
Lists
1:chocolate
2:apple
3:orange
Phone numbers
345456:Susan
545678:Harvey
434565:Harold
Page 107
Here is a good example of saving and retrieving data from two text boxes using a map.
17.
Imagine you wanted to save all the text in a range of text boxes to a single file and then load
it back into the program later. It might be an edit option for long text entering, or an offline
option, or even to save a range of drafts. Its actually really easy to do with Maps
This very handy tool is easy to follow and uses PUT to save, and GET to retrieve.
The extra window shows the text file as saved and automatically saves with a data stamp.
This could create options for calling up versions.
Sub Globals
Dim map1 As Map
map1.Initialize
Dim btnsave As Button
Dim EditText1 As EditText
Dim EditText2 As EditText
Dim btnload As Button
Dim EditText3 As EditText
End Sub
Sub Activity_Create(FirstTime As Boolean)
Activity.LoadLayout("main")
End Sub
Sub btnsave_Click
map1.Clear'clear the map, empty the data
'put the data in the map (KEY, VALUE)
map1.Put("EditText1", EditText1.Text)
map1.Put("EditText2", EditText2.Text)
File.WriteMap(File.DirInternal, "btnset.set", map1) 'write to file
EditText1.Text = ""'clear text boxes
EditText2.Text = ""
ToastMessageShow("data saved", False)
End Sub
Sub btnload_Click
'load back to map1 as a map (file.Readmap)
map1 = File.ReadMap(File.DirInternal, "btnset.set")
'show back in text boxes
EditText1.Text = map1.Get("EditText1")
EditText2.Text = map1.Get("EditText2")
ToastMessageShow("data loaded", False)
'show the datafile as saved for interest
EditText3.text = File.ReadString(File.DirInternal, "btnset.set")
Basic For Android
Page 108
End Sub
18.
An ordered list of values. In most languages, this is realized as an array, vector, list,
or sequence.
An object is an unordered set of name/value pairs. An object begins with { (left brace) and
ends with } (right brace). Each name is followed by : (colon) and the name/value pairs are
separated by , (comma).
An array is an ordered collection of values. An array begins with [ (left bracket) and ends
with ] (right bracket). Values are separated by , (comma).
A value can be a string in double quotes, or a number, or true or false or null, or an object or
an array. These structures can be nested.
Here is a request to a server for some data that is returned in the JSON format.
http://www.recipepuppy.com/api/?i=onions,garlic&q=omelet&p=3
The data that is returned is in a string, to see the structure of it paste the link into
http://jsonformat.com/ and run.
Page 109
The structure is nested. Here is the first set of data returned, with the end added on to make
it a single unit. Subsequent sets have the same structure.
{"title":"Recipe Puppy","version":0.1,
"href":"http:\/\/www.recipepuppy.com\/",
"results":
[{
"title":"Vegetable-Pasta Oven Omelet",
"href":"http:\/\/find.myrecipes.com\/recipes\/recipefinder.dyn?action=disp
layRecipe&recipe_id=520763",
"ingredients":"tomato, onions, red pepper, garlic, olive oil, zucchini,
cream cheese, vermicelli, eggs, parmesan cheese, milk, italian seasoning,
salt, black pepper",
"thumbnail":"http:\/\/img.recipepuppy.com\/560556.jpg"},
}
],}
This data looks confusing on the first look, and the second, and the .
However look at the main text in terms of Maps. A Map is a Key:Value pair separated by a :
and this data is make up of maps with each map separated by a comma,
"title":"Vegetable-Pasta Oven Omelet"
Its the format of Key:Value , Key:Value , Key:Value , Key:Value , Key:Value ,
This is an array of maps
The main part the data
"results":
[{
Is again Key:Value, the Key being Result, the Value being everything inside of the [{
The next page gives a better idea of the structure using a Firefox addon below. You can
clearly see the Blue Green matched Key Value pairs
Page 110
This program requires us to access the net and download the JSON from the
http://www.recipepuppy.com website using their API (Application programming interface).
As a result we need the HTTP library.
We need
1 panel
2 Buttons
3 Labels
2 edit boxes
1 imageview
Edtcode is only to see if the
code is coming down OK
LBLhyperlink and IVpic are
not set up so far, the pic will
go in the pic box and the
hyperlink will take you to the
website.
Page 111
The code
'Activity module
Sub Process_Globals
Dim hc As HttpClient 'download the json
Dim req As HttpRequest
Dim JSON As JSONParser
Dim Map1 As Map
End Sub
Sub Globals
Dim btnrun As Button
Dim datamap As Map
Dim btnnext As Button
Dim edtsearch, edtcode As EditText
Dim lblhyperlink,lblingredients, lbltitle
Dim counter As Int :counter = 0
Dim ivpic As ImageView
Dim recipecode As String
End Sub
As Label
Sub
End
Sub
End
Activity_Resume
Sub
Activity_Pause (UserClosed As Boolean)
Sub
Sub btnrun_Click
Dim url, search As String
search = edtsearch.Text
url = "http://www.recipepuppy.com/api/?"& search
'i=onions,garlic&q=omelet&p=3"
'OPTIONS
'i=ingredients comma deliminated
'q=type of food eg omelet
Basic For Android
Monday, 11 June 2012
Page 112
'p= page number? -put page number in a counter so that it increments each
time you press run? 1, 2, 3 still to do
req.InitializeGet(url)
hc.Execute(req, 1)
ProgressDialogShow("downloading ...")
End Sub
Sub btnnext_Click
download
End Sub
Sub download
JSON.Initialize(recipecode)
'JSON.NextObject parses the string and returns a Map with the parsed
data. This method should be called when the top level value is an object
(which is usually the case).
Map1 = JSON.NextObject
Dim results As List 'list holds all the recipes
Page 113
Creating a link to a local webbrowser is simple. In the code above we directly passed the
html to the text box, lblhyperlink.Text = datamap.Get("href") giving us a string of text that
sort of looks like an url.
'http:\/\/find.myrecipes.com\/recipes\/recipefinder.dyn?action=displayReci
pe&recipe_id=520763",
To use this we need to remove the \\ symbols and turn it into an active URL.
The code for that is simple, create a new variable called hyperlink to hold the data and then
do a string replace to take out the unwanted symbols.
As I was feeling somewhat lazy I attached the url to the click event of the label box itself,
Sub lblhyperlink_Click it might go better under a button.
hyperlink = datamap.Get("href")
hyperlink = hyperlink.Replace("\","")
lblhyperlink.Text = hyperlink
End Sub
Sub lblhyperlink_Click
Dim p As PhoneIntents
StartActivity(p.OpenBrowser(hyperlink))
End Sub
Page 114
Page 115