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

[polldaddy poll=9764234]

– Ở 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:

[code language=”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>

[/code]

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

– Class MyContact:

[code language=”java”]

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+"]";
}
}

[/code]

– Class xử lý MainActivity:

[code language=”java”]

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);
}
}

[/code]

-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:

[code language=”java”]

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();
}
}

[/code]

– 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.

17 thoughts on “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”

      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

    1. 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 ạ…

  1. 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ẻ.

  2. 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.

  3. 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 ạ…

  4. 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.

Leave a Reply