Sending an SMS

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.

How to do it...

Let's look at how to send an SMS.

  1. Create a new activity named 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);
    
    };
  2. Override the 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 +")";
        }
      }
    }
  3. Add the following three variables to the SendActivity class:
    private const int contact_code = 1;
    private String phone;
    private String name; 
  4. Create a .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>
  5. Modify the 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));
        }
      }
    }
  6. Modify the 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 ();
      }
    };
  7. Add the READ_CONTATCS and SEND_SMS permissions to your AndroidManifest.xml file.
  8. Launch your application!

    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:

    How to do it...

    Note

    It is 9:50 p.m. Why is the Equation activity triggered? This is because I've modified the condition in TimeReceiver so that I can test my application without changing the emulator time or waiting for 12 a.m.

    The Send activity is displayed.

    How to do it...
  9. Click on the first textView element of the send label and your agenda will open:
    How to do it...
  10. Choose a contact. We will be redirected to our application in which we can write our SMS:
    How to do it...
  11. Finally, when you click on the Send button and you will see the following screen:
    How to do it...

How it works...

In order to understand what happens in this application, let's have a look to the following transition diagram:

How it works...

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.

Tip

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.

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

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