Bài tập 26: Dùng Implicit Intent để viết chương trình gọi điện thoại và nhắn tin SMS


– Ở bài tập 24bài tập 25 Tôi đã hướng dẫn rất kỹ về cách sử dụng Intent (các intent này còn gọi là Explicit Intent).

– Trong bài tập 26 Tôi sẽ hướng dẫn bạn cách sử dụng Implicit Intent (bạn cứ hiểu nôm na là những Intent được xây dựng sẵn, được cung cấp sẵn trong hệ điều hành Android). Tạm thời bạn cứ hiểu như vậy đi, nếu như Tôi sai thì Tôi sẽ sửa lại sau, vì có thể có nhiều cách hiểu khác hay hơn Tôi nhiều.

– Tôi đặt vấn đề như sau:

+ Một ngày đẹp trời khủng khiếp nào đó chẳng hạn 3h giờ ngày 13 tháng 3 năm 2013, “Dế” đáng ghét của bạn bị rớt xuống nền nhà cái bạch bạch bạch…. bị mẻ, méo mấy miếng và hư luôn chương trình gọi điện thoại và nhắn tin SMS (bị hư 2 chức năng này, nhưng mà “Dế Mẻ” đó vẫn hoạt động). Không ai thèm sửa Dế cho bạn, xui cái bạn đang học Android lớp của Tôi, Tôi yêu cầu bạn phải tự lập trình ra chức năng Gọi điện thoại và nhắn tin SMS cho Dế đó (dĩ nhiên thiết bị của bạn sử dụng Android OS). Vậy bạn phải làm rồi, vì không làm sẽ bị 0 điểm.

+ Vậy dùng những kỹ thuật nào để có thể viết được chức năng nghe gọi+ nhắn tin SMS thay thế cho chương trình có sẵn của Android?

+ Tôi sẽ hướng dẫn các bạn vào buổi sau, bạn hãy chú ý theo dõi. Trong thời gian chờ đợi thì Tôi khuyên các bạn phải làm đi làm lại bài tập 24 và bài tập 25.

Tôi giới hạn bài tập này như sau: Bài tập này đơn thuần chỉ là cho phép nhập tên và số điện thoại vào bộ nhớ (không phải danh bạ điện thoại) sau đó hiển thị danh sách này vào ListView, ListView sẽ cung cấp ContextMenu có 2 mục: “Gọi điện thoại” và “Nhắn tin”. Qua phần Content Provider và Telephony API các bạn sẽ được học kỹ hơn về cách lấy danh bạ từ điện thoại ra, cách đọc tin nhắn trong inbox ra, cách tương tác với danh bạ và tin nhắn… Nên bài tập này các bạn xem nó như là “Chơi chơi” vui thôi.

– Mấu chốt của bài này là các bạn phải tự biết cách tạo một cuộc gọi, cách gửi tin nhắn trong Android như thế nào, mấy phần “râu ria” khác các bạn đừng bận tâm.

– Để có thể gọi điện thoại và nhắn tin thì các bạn phải khai báo trong Manifest các permission sau:

<uses-permission android:name=”android.permission.CALL_PHONE” />
<uses-permission android:name=”android.permission.SEND_SMS” />

– Bạn xem giao diện của chương trình:

26_sms_0– Nhấn “Save Contact” để lưu thông tin vào ListView như hình.

– Xử lý context menu cho ListView:

26_sms_1– Chức năng “Call to …” để gọi, màn hình gọi sẽ hiện ra như bên dưới:

26_sms_2– Chức năng “Send Sms to …“, cho ra màn hình gửi tin nhắn như bên dưới:

26_sms_3– Nhấn “Send Message” để gửi. Ở đây Tôi muốn nói các bạn rằng có 2 hành vi gửi tin nhắn.

1) gửi tin nhắn mà không biết kết quả thành công hay không (dễ dàng, những mà không nên. Trường hợp này thường xuyển sảy ra. Tôi lấy cụ thể trường hợp của Tôi, nhà Tôi ở trên Núi sóng thường yếu và không liên lạc được, nếu viết theo cách này thì Bạn sẽ không biết là gửi cho Tôi thành công hay không.)

Ví dụ: Viết như bên dưới thì có thể gửi được tin nhắn ở trường hợp bình thường, không kiểm tra kết quả trả về (Còn kiểm tra kết quả trả về bạn xem trong coding đầy đủ).

final SmsManager sms = SmsManager.getDefault();

sms.sendTextMessage(  0987773061″, null, “Hello teo teo!”, null, null);

2) gửi tin nhắn có kiểm tra kết quả thành công (ta nên dùng cách này, nhưng mà khó vì các bạn chưa học IntentFilter, nhưng Tôi vẫn đưa vào, có gì các bạn tìm hiểu sau)

– Bây giờ bạn xem cấu tạo chương trình:

26_sms_4– Giao diện chính activity_main.xml:

26_sms_5

– Xem source XML activity_main.xml:


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:tools="http://schemas.android.com/tools"
 android:id="@+id/LinearLayout1"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:orientation="vertical"
 tools:context=".MainActivity" >

<TableLayout
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:stretchColumns="*" >

<TableRow
 android:id="@+id/tableRow1"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content" >

<TextView
 android:id="@+id/textView1"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:layout_span="2"
 android:background="#008000"
 android:gravity="center"
 android:text="&quot;Chơi Chơi&quot; Phone Utility"
 android:textColor="#FFFFFF"
 android:textSize="15sp" />
 </TableRow>

<TableRow
 android:id="@+id/tableRow2"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content" >

<TextView
 android:id="@+id/textView2"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:text="Name:" />

<EditText
 android:id="@+id/editName"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:ems="10" >

<requestFocus />
 </EditText>
 </TableRow>

<TableRow
 android:id="@+id/tableRow3"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content" >

<TextView
 android:id="@+id/textView3"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:text="Phone:" />

<EditText
 android:id="@+id/editPhone"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:ems="10"
 android:inputType="phone" />
 </TableRow>

<TableRow
 android:id="@+id/tableRow4"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content" >

<Button
 android:id="@+id/btnSaveContact"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:layout_column="1"
 android:text="Save Contact" />
 </TableRow>
 </TableLayout>

<TextView
 android:id="@+id/textView4"
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:background="#008000" />

<ListView
 android:id="@+id/lvContact"
 android:layout_width="match_parent"
 android:layout_height="wrap_content" >
 </ListView>

</LinearLayout>

– Các XML resource khác các bạn tự xem trong project.

– Class MyContact:


package tranduythanh.com;

import java.io.Serializable;

public class MyContact implements Serializable{
 /**
 *
 */
 private static final long serialVersionUID = 1L;
 private String name;
 private String phone;
 public String getName() {
 return name;
 }
 public void setName(String name) {
 this.name = name;
 }
 public String getPhone() {
 return phone;
 }
 public void setPhone(String phone) {
 this.phone = phone;
 }
 public MyContact(String name, String phone) {
 super();
 this.name = name;
 this.phone = phone;
 }
 public MyContact() {
 super();
 }
 @Override
 public String toString() {
 return this.name+"["+this.phone+"]";
 }
}

– Class xử lý MainActivity:


package tranduythanh.com;

import java.util.ArrayList;

import android.net.Uri;
import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;
import android.view.ContextMenu;
import android.view.MenuItem;
import android.view.View;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;

public class MainActivity extends Activity {

EditText editName,editPhone;
 Button btnSave;
 ListView lvContact;
 //Danh sách contact để đưa vào ListView
 ArrayList<MyContact>arrContact=new ArrayList<MyContact>();
 ArrayAdapter<MyContact>adapter=null;
 MyContact selectedContact=null;
 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);
 doGetFormWidgets();
 doAddEvents();
 }
 public void doGetFormWidgets()
 {
 btnSave=(Button) findViewById(R.id.btnSaveContact);
 editName=(EditText) findViewById(R.id.editName);
 editPhone=(EditText) findViewById(R.id.editPhone);
 lvContact=(ListView) findViewById(R.id.lvContact);
 //tạo đối tượng adapter
 adapter=new ArrayAdapter<MyContact>
 (this, android.R.layout.simple_list_item_1,arrContact);
 //gán Adapter vào cho ListView
 lvContact.setAdapter(adapter);
 //thiết lập contextmenu cho ListView
 registerForContextMenu(lvContact);
 }
 public void doAddEvents()
 {
 btnSave.setOnClickListener(new OnClickListener() {

@Override
 public void onClick(View arg0) {
 // TODO Auto-generated method stub
 doSaveContact();
 }
 });
 //lấy contact được chọn trước đó trong ListView
 //Vì khi mở context menu sẽ làm mất focus nên ta phải lưu lại trước
 //khi mở context menu
 lvContact.setOnItemLongClickListener(new OnItemLongClickListener() {

@Override
 public boolean onItemLongClick(AdapterView<?> arg0, View arg1,
 int arg2, long arg3) {
 //lưu vết contact được chọn trong ListView
 selectedContact=arrContact.get(arg2);
 return false;
 }
 });
 }
 /**
 * mỗi lần nhấn Save contact thì gọi hàm này
 * để cập nhạt contact vào List view
 * bạn lưu ý là ta chỉ làm trong bộ nhớ
 * không phải lưu vào Danh Bạ (phần này học sau)
 */
 public void doSaveContact()
 {
 MyContact ct=new MyContact();
 ct.setName(editName.getText()+"");
 ct.setPhone(editPhone.getText()+"");
 arrContact.add(ct);
 adapter.notifyDataSetChanged();
 }
 @Override
 public void onCreateContextMenu(ContextMenu menu, View v,
 ContextMenuInfo menuInfo) {
 // TODO Auto-generated method stub
 super.onCreateContextMenu(menu, v, menuInfo);
 //gắn context menu vào
 getMenuInflater().inflate(R.menu.phonecontextmenu, menu);
 menu.setHeaderTitle("Call- Sms");
 menu.getItem(0).setTitle("Call to "+selectedContact.getPhone());
 menu.getItem(1).setTitle("Send sms to "+selectedContact.getPhone());
 }
 @Override
 public boolean onContextItemSelected(MenuItem item) {
 //kiểm tra xem Menu Item nào được chọn
 switch(item.getItemId())
 {
 case R.id.mnuCall:
 doMakeCall();
 break;
 case R.id.mnuSms:
 doMakeSms();
 break;
 case R.id.mnuRemove:
 arrContact.remove(selectedContact);
 adapter.notifyDataSetChanged();
 break;
 }
 return super.onContextItemSelected(item);
 }
 /**
 * Thực hiện gọi điện thoại
 */
 public void doMakeCall()
 {
 Uri uri=Uri.parse("tel:"+selectedContact.getPhone());
 Intent i=new Intent(Intent.ACTION_CALL, uri);
 startActivity(i);
 }
 /**
 * thực hiện mở giao diện gửi tin nhắn
 * Truyền thông tin contact đang chọn qua
 * activity mới
 */
 public void doMakeSms()
 {
 Intent i=new Intent(this, MySMSActivity.class);
 Bundle b=new Bundle();
 b.putSerializable("CONTACT", selectedContact);
 i.putExtra("DATA", b);
 startActivity(i);
 }
}

-Bạn xem dòng lệnh 96 – thiết lập tiêu đề cho context menu

– Dòng lệnh  97,98  để sửa lại title cho các menuitem ứng với mỗi contact.

– Dòng lệnh 121 có hàm doMakeCall để gọi điện thoại cho số nào đó. Bạn nhìn vào nội dung bên trong để xem quy tắc tạo lệnh gọi.

– Class xử lý gửi tin nhắn MySMSActivity:


package tranduythanh.com;

import android.os.Bundle;
import android.app.Activity;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.telephony.SmsManager;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

public class MySMSActivity extends Activity {

Button btnSendSMS;
 EditText editContent;
 TextView txtSendTo;
 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_my_sms);
 btnSendSMS =(Button) findViewById(R.id.btnSendSms);
 editContent =(EditText) findViewById(R.id.editSMS);
 txtSendTo=(TextView) findViewById(R.id.txtSendTo);
 //Lấy thông tin từ Intent
 Intent i =getIntent();
 Bundle b=i.getBundleExtra("DATA");
 final MyContact c=(MyContact) b.getSerializable("CONTACT");
 btnSendSMS.setOnClickListener(new OnClickListener() {

@Override
 public void onClick(View v) {
 // TODO Auto-generated method stub
 sendSms(c);
 }
 });
 txtSendTo.setText("Send to : "+c.getPhone());
 }
 /**
 * hàm dùng để gửi tin nhắn có kiểm tra kết quả trả về
 * Tôi chưa giải thích ở đây được vì nó liên quan rất nhiều
 * kiến thức, khi nào tới Broadcast Receiver, telephony Tôi sẽ
 * giải thích lại
 * @param c
 */
 public void sendSms(MyContact c)
 {
 //lấy mặc định SmsManager
 final SmsManager sms = SmsManager.getDefault();
 Intent msgSent = new Intent("ACTION_MSG_SENT");
 //Khai báo pendingintent để kiểm tra kết quả
 final PendingIntent pendingMsgSent =
 PendingIntent.getBroadcast(this, 0, msgSent, 0);
 registerReceiver(new BroadcastReceiver() {
 public void onReceive(Context context, Intent intent) {
 int result = getResultCode();
 String msg="Send OK";
 if (result != Activity.RESULT_OK) {
 msg="Send failed";
 }
 Toast.makeText(MySMSActivity.this, msg,
 Toast.LENGTH_LONG).show();
 }
 }, new IntentFilter("ACTION_MSG_SENT"));
 //Gọi hàm gửi tin nhắn đi
 sms.sendTextMessage(c.getPhone(), null, editContent.getText()+"",
 pendingMsgSent, null);
 finish();
 }
}

– Dòng lệnh 51 có hàm sendSms để gửi tin nhắn đi. hàm này Tôi viết có kiểm tra kết quả gửi thành công hay không. Tôi không giải thích nhiều vì nó liên quan tới quá nhiều kiến thức. Tạm thời bạn cố gắng hiểu từng dòng lệnh Tôi giải thích ở bên trong là ok rồi.

– Bạn có thể tải coding mẫu đầy đủ ở đây:http://www.mediafire.com/?ilpeqrycsbdswzg

– Bài này là tiền đề để làm các ứng dụng khác liên quan tới Telephony.

– Đến đây coi như bạn đã tạm ổn vê Intent. Bài tập kế tiếp Tôi sẽ hướng dẫn các bạn làm về Đa ngôn ngữ trong Android, đã nói tới Mobile thì thường nó phải hỗ trợ đa ngôn ngữ (cả thế giới đều sài, với những ngôn ngữ khác nhau).

– Chúc các bạn thành công.

16 responses

  1. Hiếu trần | Reply

    thầy ơi…học hết 26 bài tập android này thì đi xin việc được chưa thầy?

    1. dễ vậy tui đi xin việc lâu rồi hehe

      1. Tâm tích cực đi chứ.
        26 bài đã đủ đi xin việc nếu bạn tự tin vào khả năng và hướng phát triển của mình.Lập trình học ko bao nhiêu là đủ, vào cty phải học hỏi thêm rất nhiều, kiến thức chỉ là nền tảng thôi quan trọng là cách nhìn nhận vấn đề và cách làm của bạn

    2. thầy ơi ! cho em hỏi khi mình đang gọi điện thì làm sao để hiện giao diện của mình thay vì giao diện có sẵn ạ…. tại em định vừa gọi điện vừa có thể làm việc trên giao diện mình cài đặt ạ…

  2. Hà Quách Văn | Reply

    e cảm ơn thầy về những topic này, nhờ có topic của thầy mà em hiểu và làm
    thành thạo về android.

  3. Cám ơn Thầy về bài viết này.
    Chúc Thầy một ngày làm việc vui vẻ.

  4. Phạm Minh Phường | Reply

    Thầy ơi. Cho em hỏi là làm sao khi gửi tin nhắn đi rồi nó vẫn còn lưu lại. Giống như là Hộp thư đi ấy ạ. Em tham khảo nhiều rồi mà vẫn chưa làm chạy được thầy ạ
    Chúc thầy một ngày vui vẻ.

    1. Bạn tạo database rồi mỗi lần gửi lưu vào đấy, tạo thêm 1 màn hình để xem tin nhắn đã gửi là được

  5. Chương trình của thầy OK lắm. Câu giảng rất hay, dễ hiểu.
    Nhưng Thầy ơi cho em hỏi tí: tại sao khi soạn tin nhắn dài hơn 160 kí tự bằng chương trình của thầy thì nó không nhắn được. Còn khi soạn bằng chương trình nhắn tin của máy ảo thì nó nhắn được nhưng kí tự bên nhận bị mã hóa không đọc được.
    Em muốn viết một ứng dụng nhắn được tin nhắn dài bất kì (có thể chi làm nhiều tin nhỏ) và ko bị mã hóa. Vậy phải làm sao đây thầy?
    Em có thắc mắc vậy có gì thầy bỏ qua cho. Mong nhận được hồi âm.

  6. thầy ơi ! cho em hỏi làm sao khi mình đang gọi điện thì làm sao hiện giao diện của mình tạo thay vì giao diện có sẵn ạ…. tại em định vừa gọi điện vừa làm việc trên giao diện của mình muốn ạ…

  7. Em chào Thầy
    Em cám ơn Thầy về những bài viết hữu ích, Em đang tìm hiểu về biểu đồ trên android, chủ yếu là Pie, nếu có thể 3D thì tốt, em tìm tài liệu mà thấy ít nói quá. Thầy có thể viết 1 bài về loại này không Thầy.

  8. Lê Xuân Đoàn | Reply

    Học mấy bài bên thầy thấy dễ hiểu quá,nhất là kĩ năng làm 😀

  9. Cho em hỏi cái dùng để làm j vậy ạ.

  10. cho e hỏi cái notifyDataSetChanged() có tác dụng gì ?

    1. nó dùng để cập nhật lại giao diện!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: