With this fourth recipe on TheInternship
project, we will pick a contact from the contact list of the user and send an SMS to him/her.
Let's look at how to send an SMS.
SendActivity
and add the following code to the OnCreate()
method:// On click of the contact field, run a contact selection Intnet. FindViewById<TextView> (Resource.Id.ppl1).Click += delegate { //Concrete description of our Intent. Here we want to pick an User Intent contact_intent = new Intent(Intent.ActionPick, ContactsContract.Contacts.ContentUri); //More specifically, we would like the phone number contact_intent.SetType(ContactsContract.CommonDataKinds.Phone.ContentType); // Start the Intent and provide a response code. When the user has picked a contact, // OnActivityResult will be called. StartActivityForResult(contact_intent, contact_code); }; // When the send button is clicked, Send a sms to the elected contact and the text FindViewById<Button> (Resource.Id.send1).Click += delegate { var uri = Android.Net.Uri.Parse("sms:"+this.phone); // Abstract URI for sms Intent send_intent = new Intent(Intent.ActionSendto, uri); // Send to Action //Append the text with -Checked by the Internship and add it to the sms_body variable send_intent.PutExtra("sms_body", FindViewById<TextView> (Resource.Id.sms2).Text + "-Checked by the Internship"); //We don't expect anything back here StartActivity(send_intent); };
OnActivityResult()
method of the SendActivity
class with the following code:protected override void OnActivityResult(int requestCode, Result resultCode, Intent data) { base.OnActivityResult (requestCode, resultCode, data); //Are we called after a contact pick ? if (requestCode == contact_code) { //Build a cursor w/ the response we get Android.Net.Uri contactData = data.Data; Android.Database.ICursor contactCursor = ManagedQuery (contactData, null, null, null, null); StartManagingCursor (contactCursor); //If a user is in the response, get the name and the phone if (contactCursor.MoveToFirst ()) { this.name = contactCursor.GetString (contactCursor.GetColumnIndexOrThrow ("display_name")); this.phone = contactCursor.GetString (contactCursor.GetColumnIndexOrThrow ("data4")); FindViewById<TextView> (Resource.Id.ppl1).Text = this.name + " (" + this.phone +")"; } } }
SendActivity
class:private const int contact_code = 1; private String phone; private String name;
.axml
file named Send.axml
under the Resources
/Layout
folder, and add the following code in it in order to have two text fields and one button:<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/ppl1" /> <EditText android:inputType="textMultiLine" android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/sms2" /> <Button android:text="Send" android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/send1" /> </LinearLayout>
OnReceive()
method of the TextReceiver
class so that it starts the EquationActivity
instance if the SMS app is open:public override void OnReceive (Context context, Intent intent) { Console.WriteLine ("Time Received"); //If we are in the dangerous timeframe if (DateTime.Now.Hour >= 0 && DateTime.Now.Hour <= 6) { Console.WriteLine ("We are in the dangerous hours"); if (smsLaunched(context)) { context.StartActivity (typeof(EquationActivity)); } } }
OnCreate()
method of the Equation
class so that the sendActivity
class is called when the answer is correct:// Check the response of the equation on click via a delegate Button button = FindViewById<Button> (Resource.Id.send_eq); button.Click += delegate { // Convert the response to int32. We could use a try/catch here. if(Convert.ToInt32(FindViewById<TextView> (Resource.Id.response).Text) == current_equation.Value) { Console.WriteLine ("Answer is OK..."); StartActivity(typeof(SendActivity)); // Redirect the user tozards the Send Activity } else { Toast.MakeText (this, "Go to sleep!", ToastLength.Short).Show (); } };
READ_CONTATCS
and SEND_SMS
permissions to your AndroidManifest.xml
file.The following screens should appear if the SMS application is launched and the time is between 12 a.m. and 6 a.m. Answer the equation correctly:
textView
element of the send label and your agenda will open:In order to understand what happens in this application, let's have a look to the following transition diagram:
First of all, our broadcast receiver class named TimeReceiver
will receive a time change message from the Android operating system every minute. If the time is between 12 a.m. and 6 a.m., the Equation
activity will be launched. In this activity, we ask the user to solve a simple equation and launch SendActivity
in case the correct answer is given. In SendActivity
, we ask the user to pick a contact in their agenda and retrieve the picked contact. Finally, the user can write their SMS and send it.
In the OnCreate()
method of the send
activity, we have the following snippet, which will start the Agenda
application:
//Concrete description of our Intent. Here we want to pick an User Intent contact_intent = new Intent(Intent.ActionPick, ContactsContract.Contacts.ContentUri); //More specifically, we would like the phone number contact_intent.SetType(ContactsContract.CommonDataKinds.Phone.ContentType); //Start the Intent and provide a response code. When the user has picked a contact, // OnActivityResult will be called. StartActivityForResult(contact_intent, contact_code);
In this code, we first create a concrete action and build our intent with with ContactsContract.Contacts.ContentUri
. Here, concrete intent is used in opposition to the abstract intent, which we saw earlier in this chapter where a String built out of an URI was used. Using the ContactsContract.Contacts.ContentUri
instance, we can ensure that the returned URI
is correct and the agenda application will effectively be launched. We also set a type for our intent: ContactsContract.CommonDataKinds.Phone.ContentType
.
This content type specifies what we are after, that is, what we want to obtain with this intent. In our case, we would like to access the phone number of the picked contact. Finally, we call the StartActivityForResult()
method with the newly created intent and contact_code (1)
as arguments. The StartActivityForResult()
method is the same method as StartActivity()
except that we specify that we expect an answer from the launched activity. When the activity launched with our intent has an answer to give, the OnActivityResult()
method will be called.
Let's take a look at our overridden OnActivityResult()
method:
//Build a cursor w/ the response we get Android.Net.Uri contactData = data.Data; Android.Database.ICursor contactCursor = ManagedQuery (contactData, null, null, null, null); StartManagingCursor (contactCursor); //If a user is in the response, get the name and the phone if (contactCursor.MoveToFirst ()) { this.name = contactCursor.GetString (contactCursor.GetColumnIndexOrThrow ("display_name")); this.phone = contactCursor.GetString (contactCursor.GetColumnIndexOrThrow ("data4")); FindViewById<TextView> (Resource.Id.ppl1).Text = this.name + " (" + this.phone +")"; }
In this code, we first retrieved a URI
instance from the intent (named data) received as an argument with the data.Data()
method. Then, we obtain a cursor as a response of a ManagedQuery
instance. The signature of this method is as follows:
managedQuery (Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)
The parameters of the intent correspond to the following:
uri - The URI of the content provider to query. projection - List of columns to return. selection - SQL WHERE clause. selectionArgs - The arguments to selection, if any ?s are present sortOrder - SQL ORDER BY clause.
The ManagedQuery
instance is a wrapper around an existing cursor. The cursor can have any source—not necessarily an Android database. In this case, we query against the Android OS database. In our case, however, we already have a content provider that only contains what we are interested in, that is, a contact. Therefore, we have to set all other arguments to null
. We then move to the first item of the cursor and select the name and phone number of the picked contact:
this.name = contactCursor.GetString (contactCursor.GetColumnIndexOrThrow ("display_name")); this.phone = contactCursor.GetString (contactCursor.GetColumnIndexOrThrow ("data4"));
The values inside the cursor are accessed by the contactCursor.GetString()
method, which will return a String
value and take the ID of the targeted column as a parameter. As we don't know this ID, we use the contactCursor.GetColumnIndexOrThrow ("display_name")
and contactCursor.GetString (contactCursor.GetColumnIndexOrThrow ("data4")
methods. The data4
column contains the phone number without any added data, that is, 5145556666 and not (514) 555-6666.
To know what the column names and their data during the development phase are, you can use the following code:
foreach (String column in contactCursor.GetColumnNames) { Console.WriteLine (contactCursor.GetString (contactCursor.GetColumnIndexOrThrow (column))); }
This will output the name of the column and the value.
Now that we have the contact to which we want to send our SMS, we can grab the text typed by the user and send it. In the OnCreate()
method of the SendActivity
class, we have the following:
// When the send button is clicked, Send a SMS to the selected contact and the text FindViewById<Button> (Resource.Id.send1).Click += delegate { var uri = Android.Net.Uri.Parse("sms:"+this.phone); // Abstract URI for sms Intent send_intent = new Intent(Intent.ActionSendto, uri); // Send to Action //Append the text with -Checked by the Internship and add it to the sms_body variable send_intent.PutExtra("sms_body", FindViewById<TextView> (Resource.Id.sms2).Text + "-Checked by the Internship"); //We don't expect anything back here StartActivity(send_intent); };
For sending the SMS, we use an intent built out of a URI
object composed of the SMS string and the phone number and the phone number of the contact. We build an ActionSent
intent and call the PutExtra()
method on it. The PutExtra()
method will enable us to add extra information to the intent in addition to the bare URI
object. In our example, we concatenate the text of our TextView
with Checked by the Internship
into the sms_body
column into the SMS. Finally, we use the StartActivity
instance and not the StartActivityForResult
instance as we don't expect anything back.
In the previous four recipes, we created an application, based on Intents, that check the time and ask you to solve an equation before sending an SMS if it is between 12 p.m. and 6 a.m.
52.15.59.163