这周做了一个来电知了的项目,具体需求如下:
1.可以设置黑名单号码,拒接电话和短信
2.来电归属地查询
在生活中我们用到这些东西的时候感觉挺简单,但是让我们实现这些功能时,还是非常麻烦的。下面是我在做这个项目时的实现过程。
<一>设计首页,显示黑名单号码,并能进行黑名单添加和删除及其归属地查询功能。具体代码如下:
main.xml:主界面的布局文件
1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:orientation="vertical" 4 android:layout_width="fill_parent" 5 android:layout_height="fill_parent" 6 android:background="#8A2BE2"> 7 <TextView 8 android:layout_height="wrap_content" 9 android:layout_width="fill_parent" 10 android:text="黑名单号码" 11 android:id="@+id/tv_blacknumber" 12 android:gravity="center" 13 android:textColor="#ff0000" 14 android:textSize="25px"/> 15 <ListView 16 android:layout_width="fill_parent" 17 android:layout_height="wrap_content" 18 android:id="@android:id/list" 19 android:cacheColorHint="#00000000" 20 android:layout_weight="1"/> 21 <TextView 22 android:id="@android:id/empty" 23 android:layout_width="fill_parent" 24 android:layout_height="fill_parent" 25 android:text="无黑名单号码,请添加!" 26 android:gravity="center" 27 android:textColor="#00CD00" 28 android:textSize="25px" 29 android:layout_weight="1"/> 30 <LinearLayout android:id="@+id/ll_bottom" 31 android:orientation="horizontal" 32 android:layout_width="fill_parent" 33 android:layout_height="wrap_content" 34 android:background="@drawable/buttonbackground"> 35 <Button android:id="@+id/btn_add" 36 android:layout_width="wrap_content" 37 android:layout_height="fill_parent" 38 android:layout_weight="1" 39 android:background="@drawable/button_selector" 40 android:text="添 加"/> 41 <Button android:id="@+id/btn_search" 42 android:layout_width="wrap_content" 43 android:layout_height="fill_parent" 44 android:layout_weight="1" 45 android:background="@drawable/button_selector" 46 android:text="归属地查询"/> 47 <Button android:id="@+id/btn_delete" 48 android:layout_width="wrap_content" 49 android:layout_height="fill_parent" 50 android:layout_weight="1" 51 android:background="@drawable/button_selector" 52 android:text="删 除"/> 53 <CheckBox android:id="@+id/cb_select_all" 54 android:layout_width="wrap_content" 55 android:layout_height="fill_parent" 56 android:layout_weight="1" 57 android:text="全 选"/> 58 </LinearLayout> 59 </LinearLayout>
这里我为BUTTON按键设置了一个背景色。代码如下:
button_selector.xml:
1 <?xml version="1.0" encoding="utf-8"?> 2 <selector 3 xmlns:android="http://schemas.android.com/apk/res/android"> 4 <item android:state_pressed="true" > <!-- 被按下的情况下 --> 5 <shape> 6 <!-- 渐变 --> 7 <gradient 8 android:startColor="#99FFFF" 9 android:endColor="#33FF00" 10 android:type="linear" 11 android:angle="270"/> 12 <!-- 描边 --> 13 <stroke 14 android:width="2dp" 15 android:color="#CCCC00" 16 android:dashWidth="5dp" 17 android:dashGap="3dp" /> 18 <!-- 圆角 --> 19 <corners 20 android:radius="5dp"/> 21 <!-- 内边距 --> 22 <padding 23 android:left="5dp" 24 android:top="5dp" 25 android:right="5dp" 26 android:bottom="5dp" /> 27 </shape> 28 </item> 29 30 <item android:state_focused="true" > <!-- 获得焦点的情况下 --> 31 <shape> 32 <gradient 33 android:startColor="#FF0099" 34 android:endColor="#FF0033" 35 android:angle="270" /> 36 <stroke 37 android:width="2dp" 38 android:color="#00FFFF" /> 39 <corners 40 android:radius="4dp" /> 41 42 <padding 43 android:left="5dp" 44 android:top="5dp" 45 android:right="5dp" 46 android:bottom="5dp" /> 47 </shape> 48 </item> 49 50 <item> <!-- 一般情况下 --> 51 <shape> 52 <solid android:color="#FFFACD"/> 53 <stroke 54 android:width="4dp" 55 android:color="#00FFFF" /> 56 <corners 57 android:topRightRadius="5dp" 58 android:bottomLeftRadius="5dp" 59 android:topLeftRadius="5dp" 60 android:bottomRightRadius="5dp"/> 61 <padding 62 android:left="5dp" 63 android:top="5dp" 64 android:right="5dp" 65 android:bottom="5dp" /> 66 </shape> 67 </item> 68 </selector>
ListView的设计:
blacknumber_list_item.xml:
1 <?xml version="1.0" encoding="utf-8"?> 2 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:orientation="horizontal" 4 android:layout_width="fill_parent" 5 android:layout_height="fill_parent"> 6 <TextView android:id="@+id/tv_item_number" 7 android:layout_width="wrap_content" 8 android:layout_height="40dip" 9 android:gravity="center" 10 android:textSize="20sp" 11 android:textColor="@drawable/itemcolor" 12 android:layout_weight="1" 13 android:layout_marginRight="6dip" /> 14 <CheckBox 15 android:id="@+id/cb_item_delete" 16 android:layout_width="wrap_content" 17 android:layout_height="40dip" 18 android:layout_weight="1" 19 android:focusable="false" 20 android:checked="false" 21 android:clickable="false" 22 android:layout_alignParentRight="true" 23 android:layout_marginLeft="2dip"/> 24 </RelativeLayout>
下面就是主界面的java代码:
TelPhoneMangerActivity:
1 package cn.yj3g.TelPhoneMangerActivity; 2 3 import java.util.ArrayList; 4 import java.util.HashMap; 5 import java.util.List; 6 import java.util.Map; 7 import cn.yj3g.TelPhoneMangerDb.TelphoneMangerDBHelper; 8 import cn.yj3g.TelphonemangerService.AddressService; 9 import cn.yj3g.dao.TelphoneDao; 10 import cn.yj3g.entity.TableContanst; 11 import cn.yj3g.entity.Telphone; 12 import android.app.AlertDialog; 13 import android.app.ListActivity; 14 import android.app.ProgressDialog; 15 import android.content.Context; 16 import android.content.DialogInterface; 17 import android.content.Intent; 18 import android.os.Bundle; 19 import android.util.Log; 20 import android.view.LayoutInflater; 21 import android.view.View; 22 import android.view.ViewGroup; 23 import android.view.View.OnClickListener; 24 import android.widget.Button; 25 import android.widget.CheckBox; 26 import android.widget.EditText; 27 import android.widget.ListView; 28 import android.widget.SimpleAdapter; 29 import android.widget.TextView; 30 import android.widget.Toast; 31 32 public class TelPhoneMangerActivity extends ListActivity implements 33 OnClickListener { 34 private TelphoneDao dao; 35 private TextView backNumberText; 36 private ListView listView; 37 private Button addButton; 38 private Button searchButton; 39 private Button deleteButton; 40 private CheckBox selectAllCheckBox; 41 private EditText numberEditText; 42 private HashMap<String, Boolean> checkBoxStatus; 43 private List<String> selectIds; 44 private AddressService addressService; 45 private ProgressDialog progressDialog; 46 private static final String ACTION = "cn.yj3g.TelphonemangerService.TelphoneMangerListenterService"; 47 48 @Override 49 public void onCreate(Bundle savedInstanceState) { 50 super.onCreate(savedInstanceState); 51 setContentView(R.layout.main); 52 dao = new TelphoneDao(new TelphoneMangerDBHelper(this)); 53 addressService = new AddressService(this); 54 listView = getListView(); 55 regist(); 56 57 // 数据库的拷贝事件 58 if (!addressService.dbIsexit()) { 59 new Thread(new DBcopyThread()).start(); 60 progressDialog = ProgressDialog.show(this, "初始化", "数据正在初始化,请稍等...", 61 true); 62 } 63 64 // 找到各个按键 65 addButton = (Button) findViewById(R.id.btn_add); 66 searchButton = (Button) findViewById(R.id.btn_search); 67 deleteButton = (Button) findViewById(R.id.btn_delete); 68 selectAllCheckBox = (CheckBox) findViewById(R.id.cb_select_all); 69 backNumberText = (TextView) findViewById(android.R.id.empty); 70 // 为按键设置监听 71 addButton.setOnClickListener(this); 72 searchButton.setOnClickListener(this); 73 deleteButton.setOnClickListener(this); 74 selectAllCheckBox.setOnClickListener(this); 75 backNumberText.setOnClickListener(this); 76 // 77 showListView(); 78 } 79 80 /** 81 * 注册来电黑名单拦截 82 */ 83 private void regist() { 84 startService(new Intent(ACTION)); 85 } 86 87 /** 88 * 拷贝数据库线程,为了避免程序无响应。 89 */ 90 private class DBcopyThread implements Runnable { 91 @Override 92 public void run() { 93 try { 94 addressService.copyDB(); 95 progressDialog.dismiss(); 96 } catch (Exception e) { 97 e.printStackTrace(); 98 } 99 } 100 } 101 102 /** 103 * 显示黑名单号码 104 */ 105 private void showListView() { 106 List<Map<String, Object>> data = dao.getAllTelphone(); 107 if (data.size() != 0) { 108 backNumberText.setClickable(false); 109 } else 110 backNumberText.setClickable(true); 111 String[] from = { TableContanst.NumberColumns.NUMBER, }; 112 int[] to = { R.id.tv_item_number }; 113 SimpleAdapter adapter = new TelphoneAdpter(this, data, 114 R.layout.blacknumber_list_item, from, to); 115 listView.setAdapter(adapter); 116 } 117 118 /** 119 * 监听事件处理 120 */ 121 @Override 122 public void onClick(View v) { 123 if (v == addButton || v == backNumberText) { 124 addTelphoneMethod(); 125 } else if (v == deleteButton) { 126 deleteSeleteData(); 127 selectAllCheckBox.setChecked(false); 128 } else if (v == searchButton) { 129 Intent intent = new Intent(); 130 intent.setClass(TelPhoneMangerActivity.this, SearchActivity.class); 131 startActivity(intent); 132 } else if (v == selectAllCheckBox) { 133 checkOrcancelAllbox(selectAllCheckBox.isChecked()); 134 } 135 } 136 137 /** 138 * 提示信息 139 */ 140 protected void showToast(String string) { 141 Toast.makeText(this, string, Toast.LENGTH_SHORT).show(); 142 } 143 144 /** 145 * 添加黑名单号码 146 */ 147 private void addTelphoneMethod() { 148 LayoutInflater inflater = (LayoutInflater) this 149 .getSystemService(Context.LAYOUT_INFLATER_SERVICE); 150 final View view = inflater.inflate(R.layout.dialog, null); 151 new AlertDialog.Builder(this) 152 .setTitle("黑名单添加") 153 .setView(view) 154 .setPositiveButton("添加", new DialogInterface.OnClickListener() { 155 @Override 156 public void onClick(DialogInterface dialog, int which) { 157 numberEditText = (EditText) view 158 .findViewById(R.id.et_number); 159 String number = numberEditText.getText().toString(); 160 if (number.trim().length() == 0) { 161 TelPhoneMangerActivity.this.showToast("请输入拦截号码!"); 162 } else if (dao.findTelphone(number).getCount() != 0) { 163 TelPhoneMangerActivity.this 164 .showToast("输入号码已存在,无需增加!"); 165 } else { 166 Telphone telphone = new Telphone(number); 167 long id = dao.addTelphone(telphone); 168 if (id < 0) { 169 TelPhoneMangerActivity.this.showToast("添加失败!"); 170 } else { 171 TelPhoneMangerActivity.this.showToast("添加成功!"); 172 showListView(); 173 } 174 } 175 } 176 }) 177 .setNegativeButton("取消", new DialogInterface.OnClickListener() { 178 @Override 179 public void onClick(DialogInterface dialog, int which) { 180 dialog.cancel(); 181 } 182 }).show(); 183 } 184 185 /** 186 * 黑名单号码删除 187 */ 188 private void deleteSeleteData() { 189 AlertDialog.Builder builder = new AlertDialog.Builder(this); 190 builder.setTitle("黑名单删除") 191 .setMessage("确定删除所选号码?") 192 .setCancelable(false) 193 .setPositiveButton("确定", new DialogInterface.OnClickListener() { 194 public void onClick(DialogInterface dialog, int id) { 195 int count = 0; 196 if (selectIds.size() <= 0) { 197 Toast.makeText(TelPhoneMangerActivity.this, 198 "无选中记录,请选择!", Toast.LENGTH_LONG).show(); 199 } else { 200 // Log.v("TAG", "selectIds=" + selectIds.size()); 201 for (int i = 0; i < selectIds.size(); i++) { 202 String deleteNumber = selectIds.get(i); 203 dao.deleteTelphoneById(deleteNumber); 204 count++; 205 } 206 showListView(); 207 if (count > 0) { 208 Toast.makeText(TelPhoneMangerActivity.this, 209 "删除成功!", Toast.LENGTH_LONG).show(); 210 } else 211 Toast.makeText(TelPhoneMangerActivity.this, 212 "删除失败!", Toast.LENGTH_LONG).show(); 213 } 214 } 215 }) 216 .setNegativeButton("取消", new DialogInterface.OnClickListener() { 217 public void onClick(DialogInterface dialog, int id) { 218 dialog.cancel(); 219 } 220 }); 221 AlertDialog alert = builder.create(); 222 alert.show(); 223 } 224 225 /** 226 * 点击ListView条目存储被点击的条目 227 */ 228 @Override 229 protected void onListItemClick(ListView l, View view, int position, long id) { 230 CheckBox box = (CheckBox) view.findViewById(R.id.cb_item_delete); 231 TextView idView = (TextView) view.findViewById(R.id.tv_item_number); 232 String deleteNumber = idView.getText().toString(); 233 box.toggle(); // 改变checkbox的选中状态 234 if (box.isChecked()) { 235 selectIds.add(deleteNumber); 236 checkBoxStatus.put(deleteNumber, true); 237 } else { 238 selectIds.remove(deleteNumber); 239 checkBoxStatus.put(deleteNumber, false); 240 } 241 } 242 243 /** 244 * 全选or取消全选 245 */ 246 private void checkOrcancelAllbox(boolean checked) { 247 int itemCount = listView.getCount(); 248 selectIds.clear(); 249 checkBoxStatus.clear(); 250 for (int i = 0; i < itemCount; i++) { 251 View view = listView.getChildAt(i); 252 Map<String, Object> data = (Map<String, Object>) listView 253 .getItemAtPosition(i); 254 String number = data.get(TableContanst.NumberColumns.NUMBER) 255 .toString(); 256 if (view != null) { 257 CheckBox cb = (CheckBox) view.findViewById(R.id.cb_item_delete); 258 cb.setChecked(checked); 259 } 260 checkBoxStatus.put(number, checked); 261 if (checked) { 262 selectIds.add(number); 263 } 264 } 265 } 266 267 /** 268 * 自定义SimpleAdapter显示ListView数据 269 */ 270 private class TelphoneAdpter extends SimpleAdapter { 271 public TelphoneAdpter(Context context, 272 List<? extends Map<String, ?>> data, int resource, 273 String[] from, int[] to) { 274 super(context, data, resource, from, to); 275 selectIds = new ArrayList<String>(); 276 checkBoxStatus = new HashMap<String, Boolean>(); 277 } 278 279 @Override 280 public View getView(int position, View convertView, ViewGroup parent) { 281 View view = super.getView(position, convertView, parent); 282 CheckBox box = (CheckBox) view.findViewById(R.id.cb_item_delete); 283 TextView idView = (TextView) view.findViewById(R.id.tv_item_number); 284 String number = idView.getText().toString(); 285 if (checkBoxStatus.containsKey(number)) { 286 box.setChecked(checkBoxStatus.get(number)); 287 } else { 288 box.setChecked(selectAllCheckBox.isChecked()); 289 } 290 return view; 291 } 292 } 293 }
以上就把主界面显示出来,运行效果如下:
<二>由于要对黑名单进行增删查操作,多归属地要进行查操作,所以我们需要创建一个数据库帮助类,还有就是要将数据库拷到应用文件目录下。下面就将实现代码附在下面,大家自己琢磨吧。
TelphoneMangerDBHelper:
1 package cn.yj3g.TelPhoneMangerDb; 2 3 import cn.yj3g.entity.TableContanst; 4 import android.content.Context; 5 import android.database.sqlite.SQLiteDatabase; 6 import android.database.sqlite.SQLiteDatabase.CursorFactory; 7 import android.database.sqlite.SQLiteOpenHelper; 8 import android.util.Log; 9 /** 10 * 11 *创建一个数据库帮助类 12 * 13 */ 14 public class TelphoneMangerDBHelper extends SQLiteOpenHelper { 15 private static final String TAG = "TelphoneMangerDBHelper"; 16 public static final String DB_NAME = "telphone_black.db"; 17 public static final int VERSION = 1; 18 19 public TelphoneMangerDBHelper(Context context, String name, 20 CursorFactory factory, int version) { 21 super(context, name, factory, version); 22 } 23 24 public TelphoneMangerDBHelper(Context context) { 25 this(context, DB_NAME, null, VERSION); 26 } 27 28 /** 29 * 创建数据库 30 */ 31 public void onCreate(SQLiteDatabase db) { 32 Log.v(TAG, "onCreate"); 33 db.execSQL("create table " 34 + TableContanst.BLACK_NUMBER_TABLE 35 + "(_id Integer primary key AUTOINCREMENT," 36 + "number char," 37 + "modify_time DATETIME)"); 38 } 39 @Override 40 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 41 Log.v(TAG, "onUpgrade"); 42 } 43 44 }
TelphoneDao:
1 package cn.yj3g.dao; 2 3 import java.util.ArrayList; 4 import java.util.HashMap; 5 import java.util.List; 6 import java.util.Map; 7 8 import android.content.ContentValues; 9 import android.database.Cursor; 10 import cn.yj3g.TelPhoneMangerDb.TelphoneMangerDBHelper; 11 import cn.yj3g.entity.TableContanst; 12 import cn.yj3g.entity.Telphone; 13 14 public class TelphoneDao { 15 private TelphoneMangerDBHelper dbHelper; 16 17 public TelphoneDao(TelphoneMangerDBHelper dbHelper) { 18 this.dbHelper = dbHelper; 19 } 20 21 /** 22 * 添加一个Telphone对象数据到数据库表 23 */ 24 public long addTelphone(Telphone phone) { 25 26 ContentValues values = new ContentValues(); 27 values.put(TableContanst.NumberColumns.NUMBER, phone.getNumber()); 28 return dbHelper.getWritableDatabase().insert( 29 TableContanst.BLACK_NUMBER_TABLE, null, values); 30 31 } 32 33 /** 34 * 删除一个number所对应的数据库表Telphone的记录 35 */ 36 public int deleteTelphoneById(String number) { 37 return dbHelper.getWritableDatabase().delete( 38 TableContanst.BLACK_NUMBER_TABLE, 39 TableContanst.NumberColumns.NUMBER + "=?", 40 new String[] { number + "" }); 41 } 42 43 /** 44 * 查询所有的记录 45 */ 46 public List<Map<String, Object>> getAllTelphone() { 47 List<Map<String, Object>> data = new ArrayList<Map<String, Object>>(); 48 Cursor cursor = dbHelper.getWritableDatabase().query( 49 TableContanst.BLACK_NUMBER_TABLE, null, null, null, null, null, 50 "_id desc"); 51 while (cursor.moveToNext()) { 52 Map<String, Object> map = new HashMap<String, Object>(8); 53 String number = cursor.getString(cursor 54 .getColumnIndex(TableContanst.NumberColumns.NUMBER)); 55 map.put(TableContanst.NumberColumns.NUMBER, number); 56 data.add(map); 57 } 58 cursor.close(); 59 return data; 60 } 61 /** 62 * 黑名单号码查询 63 */ 64 public Cursor findTelphone(String number) { 65 Cursor cursor = dbHelper.getWritableDatabase().query( 66 TableContanst.BLACK_NUMBER_TABLE, null, "number=?", 67 new String[] { number }, null, null, null, null); 68 return cursor; 69 } 70 71 public void closeDB() { 72 dbHelper.close(); 73 } 74 }
AddressService:
1 package cn.yj3g.TelphonemangerService; 2 3 import java.io.File; 4 import java.io.FileOutputStream; 5 import java.io.InputStream; 6 import java.util.regex.Pattern; 7 8 import cn.yj3g.entity.TableContanst; 9 import android.content.Context; 10 import android.database.Cursor; 11 import android.database.sqlite.SQLiteDatabase; 12 13 /** 14 * 定义一个归属地服务的类,为以后的归属地查询等提供方法。 15 */ 16 public class AddressService { 17 private Context context; 18 19 public AddressService(Context context) { 20 this.context = context; 21 } 22 23 /** 24 * 判断当前databases目录下有无phoneAddres.db 25 */ 26 public boolean dbIsexit() { 27 return context.getDatabasePath(TableContanst.ADDRESS_DB_NAME).exists(); 28 } 29 30 /** 31 * 将phoneAddres.db拷贝到datebases目录下 32 */ 33 public void copyDB() throws Exception { 34 File databases = new File(context.getFilesDir().getParentFile(), 35 "databases"); // 找到data目录下的databases文件夹 36 if (!databases.exists()) { 37 databases.mkdirs(); 38 } 39 File dbFile = new File(databases, TableContanst.ADDRESS_DB_NAME); 40 FileOutputStream fos = new FileOutputStream(dbFile); 41 InputStream is = this.getClass().getClassLoader() 42 .getResourceAsStream(TableContanst.ADDRESS_DB_NAME); // 得到phoneAddress.db 43 byte[] bs = new byte[1024]; 44 int length = 0; 45 while ((length = is.read(bs)) != -1) { 46 fos.write(bs, 0, length); 47 } 48 fos.flush(); 49 is.close(); 50 } 51 52 /** 53 * 获得来电的归属地 手机的正则表达式为:^1[358]\d{9}$ 54 */ 55 public String getAddress(String number) { 56 String address = null; 57 File file = context.getDatabasePath(TableContanst.ADDRESS_DB_NAME); 58 SQLiteDatabase db = SQLiteDatabase.openDatabase(file.getAbsolutePath(), 59 null, SQLiteDatabase.OPEN_READONLY); 60 if (db.isOpen()) { 61 if (Pattern.compile("^1[358]\\d{9}$").matcher(number).matches()) {// 手机来电匹配 62 String subNumber7 = number.substring(0, 7); 63 Cursor cursor = db 64 .rawQuery( 65 "select p.name as province,c.name as city from address as a " 66 + "inner join city as c on a.cityid=c._id " 67 + "inner join province as p on c.provinceid=p._id " 68 + "where a.mobileprefix=?", 69 new String[] { subNumber7 }); 70 address = getAddressInfo(cursor); 71 } else {// 座机电话匹配 72 Cursor cursor = null; 73 String subNumber4 = null; 74 String subNumber3 = null; 75 switch (number.length()) { 76 case 12: // 4位区号+8位电话号码 77 subNumber4 = number.substring(0, 4); 78 cursor = db 79 .rawQuery( 80 "select p.name as province,c.name as city from city c " 81 + "inner join province p on c.provinceid=p._id " 82 + "where c.areacode=? " 83 + "order by c._id asc limit 1", 84 new String[] { subNumber4 }); 85 address = getAddressInfo(cursor); 86 break; 87 case 11:// 4位区号+8位电话号码 或者 3位区号+8位电话号码 88 subNumber4 = number.substring(0, 4); 89 subNumber3 = number.substring(0, 3); 90 cursor = db 91 .rawQuery( 92 "select p.name as province,c.name as city from city c " 93 + "inner join province p on c.provinceid=p._id " 94 + "where c.areacode in(?,?) " 95 + "order by c._id asc limit 1", 96 new String[] { subNumber4, subNumber3 }); 97 address = getAddressInfo(cursor); 98 break; 99 case 10:// 3位区号+7位电话号码 100 subNumber3 = number.substring(0, 3); 101 cursor = db 102 .rawQuery( 103 "select p.name as province,c.name as city from city c " 104 + "inner join province p on c.provinceid=p._id " 105 + "where c.areacode=? " 106 + "order by c._id asc limit 1", 107 new String[] { subNumber3 }); 108 address = getAddressInfo(cursor); 109 break; 110 case 8: 111 case 7:// 本地号码 112 address = "本地号码"; 113 break; 114 case 4: 115 if (number.startsWith("555")) { 116 address = "模拟器"; 117 } else { 118 cursor = db 119 .rawQuery( 120 "select p.name as province,c.name as city from city c " 121 + "inner join province p on c.provinceid=p._id " 122 + "where c.areacode=? " 123 + "order by c._id asc limit 1", 124 new String[] { number }); 125 address = getAddressInfo(cursor); 126 } 127 break; 128 case 3: 129 cursor = db 130 .rawQuery( 131 "select p.name as province,c.name as city from city c " 132 + "inner join province p on c.provinceid=p._id " 133 + "where c.areacode=? " 134 + "order by c._id asc limit 1", 135 new String[] { number }); 136 address = getAddressInfo(cursor); 137 break; 138 default: 139 break; 140 } 141 } 142 db.close(); 143 } 144 return address; 145 } 146 147 /** 148 * 根据查询所得游标得到来电的具体归属地并返回 149 */ 150 private String getAddressInfo(Cursor cursor) { 151 if (cursor.moveToFirst()) { 152 String province = cursor.getString(0); 153 String city = cursor.getString(1); 154 if (province.equals(city)) { 155 return province; 156 } else 157 return province + "省" + city + "市"; 158 } 159 cursor.close(); 160 return ""; 161 } 162 163 /** 164 * 得到来电的类型 165 */ 166 public String getType(String number) { 167 if (Pattern.compile("^1[38][0126]\\d{8}$").matcher(number).matches()) { 168 return "联通"; 169 } else if (Pattern.compile("^1[358][1456789]\\d{8}$").matcher(number) 170 .matches()) { 171 return "移动"; 172 } else if (Pattern.compile("^1[358][039]\\d{8}$").matcher(number) 173 .matches()) { 174 return "电信"; 175 } else if (number.startsWith("555")) { 176 return "模拟器"; 177 } else if (getAddress(number).length() == 0) { 178 return "未知"; 179 } else 180 return "固话"; 181 } 182 183 /** 184 * 根据查询输入框输入的号码找到响应的归属地区号 185 */ 186 public String getAreacode(String number) { 187 String areacode = null; 188 File file = context.getDatabasePath(TableContanst.ADDRESS_DB_NAME); 189 SQLiteDatabase db = SQLiteDatabase.openDatabase(file.getAbsolutePath(), 190 null, SQLiteDatabase.OPEN_READONLY); 191 if (db.isOpen()) { 192 if (Pattern.compile("^1[358]\\d{9}$").matcher(number).matches()) {// 手机来电匹配 193 String subNumber7 = number.substring(0, 7); 194 Cursor cursor = db 195 .rawQuery( 196 "select c.areacode as areacode from city as c " 197 + "inner join address a on a.cityid=c._id " 198 + "where a.mobileprefix=? order by c._id asc limit 1", 199 new String[] { subNumber7 }); 200 areacode = getAreacodeInfo(cursor); 201 } else { 202 if (number.length() == 3) { 203 Cursor cursor = db 204 .rawQuery( 205 "select c.name as name from city as c " 206 + "where c.areacode =? order by c._id asc limit 1", 207 new String[] { number }); 208 areacode = getAreacodeInfo2(cursor, number); 209 210 } else if (number.length() >= 4) { 211 String subNumber4 = number.substring(0, 4); 212 Cursor cursor = db 213 .rawQuery( 214 "select c.name as name from city as c " 215 + "where c.areacode =? order by c._id asc limit 1", 216 new String[] { subNumber4 }); 217 areacode = getAreacodeInfo2(cursor, subNumber4); 218 } 219 } 220 } 221 db.close(); 222 return areacode; 223 } 224 225 /** 226 * 根据查询所得游标得到查询手机号码的归属地 227 */ 228 private String getAreacodeInfo(Cursor cursor) { 229 if (cursor.moveToFirst()) { 230 return cursor.getString(0); 231 } 232 cursor.close(); 233 return ""; 234 } 235 236 /** 237 * 根据查询所得游标得到查询固话号码的归属地 238 */ 239 private String getAreacodeInfo2(Cursor cursor, String number) { 240 if (cursor.moveToFirst()) { 241 return number; 242 } else 243 cursor.close(); 244 return ""; 245 246 } 247 }
<三>设置黑名单拦截和短信拦截以及归属地查询功能。具体代码如下:
TelphoneMangerListenterService:
1 package cn.yj3g.TelphonemangerService; 2 3 import java.lang.reflect.Method; 4 import android.app.Service; 5 import android.content.Context; 6 import android.content.Intent; 7 import android.database.Cursor; 8 import android.graphics.PixelFormat; 9 import android.net.Uri; 10 import android.os.IBinder; 11 import android.provider.ContactsContract.Contacts; 12 import android.telephony.PhoneStateListener; 13 import android.telephony.TelephonyManager; 14 import android.util.Log; 15 import android.view.LayoutInflater; 16 import android.view.View; 17 import android.view.WindowManager; 18 import android.widget.TextView; 19 import cn.yj3g.TelPhoneMangerActivity.R; 20 import cn.yj3g.TelPhoneMangerDb.TelphoneMangerDBHelper; 21 import cn.yj3g.dao.TelphoneDao; 22 23 import com.android.internal.telephony.ITelephony; 24 25 /** 26 * 实现来电拦截和归属地显示 27 */ 28 public class TelphoneMangerListenterService extends Service { 29 private TelphoneDao dao; 30 private AddressService addressService; 31 private WindowManager windowManager; 32 private LayoutInflater inflater; 33 private View addressView; 34 35 @Override 36 public IBinder onBind(Intent intent) { 37 Log.v("TAG", "onBind"); 38 return null; 39 } 40 41 @Override 42 public void onCreate() { 43 Log.v("TAG", "service onCreate()"); 44 super.onCreate(); 45 dao = new TelphoneDao(new TelphoneMangerDBHelper(this)); 46 addressService = new AddressService(this); 47 // 窗口界面管理 48 windowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE); 49 // View加载器 50 inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE); 51 // 电话服务管理 52 TelephonyManager manager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE); 53 // 监听电话状态 54 manager.listen(listener, PhoneStateListener.LISTEN_CALL_STATE); 55 } 56 57 private PhoneStateListener listener = new PhoneStateListener() { 58 @Override 59 public void onCallStateChanged(int state, String incomingNumber) { 60 super.onCallStateChanged(state, incomingNumber); 61 // 打印电话状态改变信息 62 Log.v("TAG", "onCallStateChanged state=" + state); 63 switch (state) { 64 case TelephonyManager.CALL_STATE_RINGING: // 响铃时 65 Cursor cursor = dao.findTelphone(incomingNumber); 66 // 67 if (cursor != null && cursor.getCount() != 0) { 68 stop(incomingNumber); 69 } else { 70 String number = getContactsName(incomingNumber); 71 String address = addressService.getAddress(incomingNumber) 72 +" "+addressService.getType(incomingNumber); 73 showAddress(address, number); 74 } 75 cursor.close(); 76 break; 77 case TelephonyManager.CALL_STATE_IDLE:// 挂断或者无电话时 78 removeAddressView(); 79 break; 80 case TelephonyManager.CALL_STATE_OFFHOOK:// 接起电话 81 break; 82 default: 83 break; 84 } 85 } 86 87 /** 88 * 来电号码和电话本里的号码进行匹配 89 */ 90 private String getContactsName(String incomingNumber) { 91 String number = incomingNumber; 92 Uri uri = Uri 93 .parse("content://com.android.contacts/data/phones/filter/" 94 + incomingNumber); 95 Cursor cursor = getContentResolver().query(uri, 96 new String[] { Contacts.DISPLAY_NAME }, null, null, null); 97 if (cursor.moveToFirst()) { 98 number = cursor.getString(0); 99 } 100 cursor.close(); 101 return number; 102 } 103 104 /** 105 * 显示来电归属地窗口 106 */ 107 private void showAddress(String address, String incomingNumber) { 108 WindowManager.LayoutParams params = new WindowManager.LayoutParams(); 109 params.height = WindowManager.LayoutParams.WRAP_CONTENT; 110 params.width = WindowManager.LayoutParams.WRAP_CONTENT; 111 params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE 112 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; 113 params.format = PixelFormat.TRANSLUCENT; 114 params.y += 24; 115 params.type = WindowManager.LayoutParams.TYPE_TOAST; 116 addressView = inflater.inflate(R.layout.address, null); 117 TextView shownumber = (TextView) addressView 118 .findViewById(R.id.shownumber); 119 TextView showaddress = (TextView) addressView 120 .findViewById(R.id.showaddress); 121 shownumber.setText(incomingNumber); 122 showaddress.setText(address); 123 windowManager.addView(addressView, params); 124 } 125 }; 126 127 /** 128 * 去除添加的来电显示界面 129 */ 130 private void removeAddressView() { 131 if (addressView != null) { 132 windowManager.removeView(addressView); 133 addressView = null; 134 } 135 } 136 137 /** 138 * 电话拦截 139 */ 140 public void stop(String s) { 141 Log.e("TAG", "来电" + s + "为黑名单号码,已拦截!"); 142 // 调用ITelephony.endCall()结束通话 143 try { 144 Method method = Class.forName("android.os.ServiceManager") 145 .getMethod("getService", String.class); 146 IBinder binder = (IBinder) method.invoke(null, 147 new Object[] { TELEPHONY_SERVICE }); 148 ITelephony telephony = ITelephony.Stub.asInterface(binder); 149 telephony.endCall(); 150 } catch (Exception e) { 151 e.printStackTrace(); 152 } 153 } 154 }
BootCompleteReceiver:
1 package cn.yj3g.TelPhoneMangerActivity; 2 3 import cn.yj3g.TelPhoneMangerDb.TelphoneMangerDBHelper; 4 import cn.yj3g.dao.TelphoneDao; 5 import android.app.Notification; 6 import android.app.NotificationManager; 7 import android.app.PendingIntent; 8 import android.content.BroadcastReceiver; 9 import android.content.Context; 10 import android.content.Intent; 11 import android.database.Cursor; 12 import android.net.Uri; 13 import android.telephony.SmsMessage; 14 import android.util.Log; 15 import android.widget.Toast; 16 17 /** 18 * 19 * 定义一个广播接受者实现短信拦截 20 * 21 */ 22 public class BootCompleteReceiver extends BroadcastReceiver { 23 private String sender; 24 25 public BootCompleteReceiver() { 26 Log.v("TAG", "开机了!"); 27 } 28 29 @Override 30 public void onReceive(Context context, Intent intent) { 31 /** 32 * 运用广播开启监听这个服务 33 */ 34 TelphoneDao dao = new TelphoneDao(new TelphoneMangerDBHelper(context)); 35 Object[] pdus = (Object[]) intent.getExtras().get("pdus"); 36 if (pdus != null && pdus.length > 0) { 37 SmsMessage[] messages = new SmsMessage[pdus.length]; 38 for (int i = 0; i < pdus.length; i++) { 39 byte[] pdu = (byte[]) pdus[i]; 40 messages[i] = SmsMessage.createFromPdu(pdu); 41 } 42 for (SmsMessage message : messages) { 43 sender = message.getOriginatingAddress();// 得到发信息的号码 44 String content = message.getMessageBody();// 得到短信内容 45 Cursor cursor = dao.findTelphone(sender); 46 if (cursor != null && cursor.getCount() != 0) { 47 abortBroadcast();// 中止发送 48 //实例化通知 49 Notification n = new Notification(R.drawable.ic_email_pending,"黑名单短信", 50 System.currentTimeMillis()); 51 Intent i = new Intent(); 52 i.setAction(Intent.ACTION_DIAL); 53 i.setData(Uri.parse("tel:"+sender)); 54 //创建延期意图 55 PendingIntent pi = PendingIntent.getActivity(context, 1, i, PendingIntent.FLAG_ONE_SHOT); 56 //设置通知的最新事件信息 57 n.setLatestEventInfo(context, "黑名单短信",content, pi); 58 //获得通知管理器系统服务 59 NotificationManager nm = (NotificationManager) context.getSystemService(context.NOTIFICATION_SERVICE); 60 nm.notify(1, n); 61 Toast.makeText(context, "通知发布完成", 1).show(); 62 Log.e("TAG", "号码" + sender + "为黑名单号码,已拦截!"); 63 cursor.close(); 64 } 65 } 66 } 67 } 68 }
运行效果如下:
黑名单短信通知:
显示归属地的运行效果如下:
<四>实现归属地查询功能
SearchActivity:
1 package cn.yj3g.TelPhoneMangerActivity; 2 3 import cn.yj3g.TelphonemangerService.AddressService; 4 import android.app.Activity; 5 import android.os.Bundle; 6 import android.view.View; 7 import android.view.View.OnClickListener; 8 import android.widget.Button; 9 import android.widget.EditText; 10 import android.widget.TextView; 11 import android.widget.Toast; 12 13 /** 14 * 实现归属地查询功能 15 */ 16 public class SearchActivity extends Activity implements OnClickListener { 17 private AddressService addressService; 18 private EditText numberEdit; 19 private Button sureButton; 20 private TextView numberText; 21 private TextView addressText; 22 private TextView typeText; 23 private String address; 24 private static final int COLOR = android.graphics.Color.RED; 25 26 @Override 27 protected void onCreate(Bundle savedInstanceState) { 28 super.onCreate(savedInstanceState); 29 setContentView(R.layout.search); 30 addressService = new AddressService(this); 31 numberEdit = (EditText) findViewById(R.id.et_search); 32 sureButton = (Button) findViewById(R.id.btn_sure); 33 numberText = (TextView) findViewById(R.id.tv_number); 34 addressText = (TextView) findViewById(R.id.tv_address); 35 typeText = (TextView) findViewById(R.id.tv_type); 36 // 设置监听 37 sureButton.setOnClickListener(this); 38 } 39 40 @Override 41 public void onClick(View v) { 42 String number = numberEdit.getText().toString(); 43 String areacode = addressService.getAreacode(number); 44 if (areacode.length() == 0) { 45 address = addressService.getAddress(number); 46 } else 47 address = addressService.getAddress(number) + "(" + areacode + ")"; 48 String type = "中国-" + addressService.getType(number); 49 if (number.trim().length() <= 2 || address.length() == 0) { 50 addressText.setText("未知地区"); 51 typeText.setText("未知"); 52 typeText.setTextColor(COLOR); 53 addressText.setTextColor(COLOR); 54 numberText.setText(number); 55 numberText.setTextColor(COLOR); 56 Toast.makeText(this, "请输入正确格式的电话号码", 0).show(); 57 numberEdit.setText(null); 58 } else { 59 numberText.setText(number); 60 numberText.setTextColor(COLOR); 61 addressText.setText(address); 62 addressText.setTextColor(COLOR); 63 typeText.setText(type); 64 typeText.setTextColor(COLOR); 65 numberEdit.setText(null); 66 } 67 } 68 }
归属地查询运行效果如下:
以上就把这个功能基本上就实现了,下来我将一些相关的常量定义,布局设计,权限等代码附在下面,供大家参考。
TableContanst:
1 package cn.yj3g.entity; 2 3 public final class TableContanst { 4 5 /** 6 * 自定义的一些常量 7 */ 8 public static final String BLACK_NUMBER_TABLE = "number"; 9 public static final String ADDRESS_DB_NAME="phoneAddress.db"; 10 public static final class NumberColumns { 11 public static final String ID = "_id"; 12 public static final String NUMBER = "number"; 13 } 14 }
Telphone:
1 package cn.yj3g.entity; 2 3 import java.io.Serializable; 4 /** 5 * 6 * 自定义一个Telphone类 7 * 8 */ 9 public class Telphone implements Serializable { 10 11 private long _id; 12 private String number; 13 private String modifyDateTime; 14 public Telphone(String number) { 15 this.number = number; 16 } 17 18 public Telphone(long _id, String number) { 19 super(); 20 this._id = _id; 21 this.number = number; 22 } 23 24 public Telphone(long _id, String number, String modifyDateTime) { 25 super(); 26 this._id = _id; 27 this.number = number; 28 this.modifyDateTime = modifyDateTime; 29 } 30 31 public Telphone() { 32 } 33 public long get_id() { 34 return _id; 35 } 36 public void set_id(long _id) { 37 this._id = _id; 38 } 39 public String getNumber() { 40 return number; 41 } 42 public void setNumber(String number) { 43 this.number = number; 44 } 45 public String getModifyDateTime() { 46 return modifyDateTime; 47 } 48 public void setModifyDateTime(String modifyDateTime) { 49 this.modifyDateTime = modifyDateTime; 50 } 51 @Override 52 public int hashCode() { 53 final int prime = 31; 54 int result = 1; 55 result = prime * result + (int) (_id ^ (_id >>> 32)); 56 result = prime * result 57 + ((modifyDateTime == null) ? 0 : modifyDateTime.hashCode()); 58 result = prime * result + ((number == null) ? 0 : number.hashCode()); 59 return result; 60 } 61 @Override 62 public boolean equals(Object obj) { 63 if (this == obj) 64 return true; 65 if (obj == null) 66 return false; 67 if (getClass() != obj.getClass()) 68 return false; 69 Telphone other = (Telphone) obj; 70 if (_id != other._id) 71 return false; 72 if (modifyDateTime == null) { 73 if (other.modifyDateTime != null) 74 return false; 75 } else if (!modifyDateTime.equals(other.modifyDateTime)) 76 return false; 77 if (number == null) { 78 if (other.number != null) 79 return false; 80 } else if (!number.equals(other.number)) 81 return false; 82 return true; 83 } 84 @Override 85 public String toString() { 86 return "Telphone [_id=" + _id + ", number=" + number + "]"; 87 } 88 }
view.xml:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent"> <ImageView android:id="@+id/image" android:layout_width="wrap_content" android:layout_height="fill_parent" android:layout_marginRight="10dp" /> <TextView android:id="@+id/text" android:layout_width="wrap_content" android:layout_height="fill_parent" android:textColor="#000" /> </LinearLayout>
search.xml:
1 <?xml version="1.0" encoding="utf-8"?> 2 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:orientation="horizontal" 4 android:layout_width="fill_parent" 5 android:background="#8A2BE2" 6 android:layout_height="fill_parent"> 7 <Button 8 android:id="@+id/btn_sure" 9 android:layout_width="wrap_content" 10 android:layout_height="wrap_content" 11 android:layout_weight="5" 12 android:text="查询" 13 android:layout_alignParentRight="true" 14 android:layout_marginLeft="2dip"/> 15 <EditText android:layout_height="wrap_content" 16 android:hint="可输入号码/区号" 17 android:id="@+id/et_search" 18 android:layout_width="wrap_content" 19 android:padding="5dip" 20 android:textSize="15sp" 21 android:inputType="phone" 22 android:maxLength="11" 23 android:layout_alignParentTop="true" 24 android:layout_alignParentLeft="true" 25 android:layout_toLeftOf="@+id/btn_sure"/> 26 <TextView android:layout_height="wrap_content" 27 android:text="号码:" 28 android:id="@+id/tv1" 29 android:layout_width="wrap_content" 30 android:layout_below="@+id/et_search" 31 android:layout_marginRight="15dip" 32 android:layout_alignParentLeft="true" 33 android:layout_marginTop="16dp"/> 34 <TextView 35 android:id="@+id/tv_number" 36 android:layout_height="wrap_content" 37 android:layout_width="fill_parent" 38 android:layout_toRightOf="@+id/tv1" 39 android:layout_below="@+id/et_search" 40 android:layout_alignBottom="@+id/tv1" 41 android:layout_marginTop="16dp"/> 42 <TextView android:layout_height="wrap_content" 43 android:text="归属:" 44 android:id="@+id/tv2" 45 android:layout_width="wrap_content" 46 android:layout_below="@+id/tv1" 47 android:layout_marginRight="15dip" 48 android:layout_alignParentLeft="true" 49 android:layout_marginTop="20dp"/> 50 <TextView 51 android:id="@+id/tv_address" 52 android:layout_height="wrap_content" 53 android:layout_width="fill_parent" 54 android:layout_toRightOf="@+id/tv2" 55 android:layout_below="@+id/tv_number" 56 android:layout_alignBottom="@+id/tv2" 57 android:layout_marginTop="20dp"/> 58 <TextView android:layout_height="wrap_content" 59 android:text="类型:" 60 android:id="@+id/tv3" 61 android:layout_width="wrap_content" 62 android:layout_below="@+id/tv2" 63 android:layout_marginRight="15dip" 64 android:layout_alignParentLeft="true" 65 android:layout_marginTop="25dp"/> 66 <TextView 67 android:id="@+id/tv_type" 68 android:layout_height="wrap_content" 69 android:layout_width="fill_parent" 70 android:layout_toRightOf="@+id/tv3" 71 android:layout_below="@+id/tv_address" 72 android:layout_alignBottom="@+id/tv3" 73 android:layout_marginTop="25dp"/> 74 </RelativeLayout>
dialog.xml:
1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout 3 xmlns:Android="http://schemas.android.com/apk/res/android" 4 Android:layout_width="fill_parent" 5 Android:layout_height="fill_parent" 6 Android:orientation="vertical"> 7 <EditText 8 Android:layout_width="fill_parent" 9 Android:layout_height="wrap_content" 10 Android:id="@+id/et_number" 11 Android:inputType="phone" 12 Android:hint="请输入电话号码" 13 Android:maxLength="11" 14 /> 15 </LinearLayout>
address.xml:
1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:orientation="vertical" 4 android:layout_width="wrap_content" 5 android:background="@drawable/addressbackground" 6 android:layout_height="wrap_content"> 7 <LinearLayout 8 android:orientation="horizontal" 9 android:layout_width="wrap_content" 10 android:layout_height="wrap_content"> 11 <ImageButton android:id="@+id/showimage" 12 android:layout_width="wrap_content" 13 android:layout_height="wrap_content" 14 android:background="@drawable/ic_launcher_vcard" 15 android:scaleType="center"/> 16 <TextView 17 android:id="@+id/showaddress" 18 android:layout_width="wrap_content" 19 android:layout_height="wrap_content" 20 android:gravity="center" 21 android:textSize="20sp" 22 android:textColor="#eee"/> 23 </LinearLayout> 24 <TextView 25 android:id="@+id/shownumber" 26 android:layout_width="fill_parent" 27 android:layout_height="wrap_content" 28 android:gravity="center" 29 android:textSize="20sp" 30 android:textColor="#eee"/> 31 </LinearLayout>
AndroidManifest.xml:
1 <?xml version="1.0" encoding="utf-8"?> 2 <manifest xmlns:android="http://schemas.android.com/apk/res/android" 3 package="cn.yj3g.TelPhoneMangerActivity" 4 android:versionCode="1" 5 android:versionName="1.0"> 6 <uses-sdk android:minSdkVersion="8" /> 7 8 <application android:icon="@drawable/phone" android:label="@string/app_name"> 9 <activity android:name=".TelPhoneMangerActivity" 10 android:label="@string/app_name"> 11 <intent-filter> 12 <action android:name="android.intent.action.MAIN" /> 13 <category android:name="android.intent.category.LAUNCHER" /> 14 </intent-filter> 15 </activity> 16 <activity android:name=".SearchActivity" 17 android:label="归属地查询"> 18 </activity> 19 <activity android:name=".ShowAvtivity"></activity> 20 <service android:name="cn.yj3g.TelphonemangerService.TelphoneMangerListenterService"> 21 <intent-filter> 22 <action android:name="cn.yj3g.TelphonemangerService.TelphoneMangerListenterService" ></action> 23 </intent-filter> 24 </service> 25 <receiver android:name=".BootCompleteReceiver"> 26 <intent-filter android:priority="1000"> 27 <action android:name="android.provider.Telephony.SMS_RECEIVED" /> 28 </intent-filter> 29 </receiver> 30 </application> 31 <!-- 读取电话状态权限--> 32 <uses-permission android:name="android.permission.READ_PHONE_STATE"/> 33 <!-- 开机启动广播的权限 --> 34 <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> 35 <!-- 挂断电话时需要的权限 --> 36 <uses-permission android:name="android.permission.CALL_PHONE" /> 37 <!-- 接收短信权限 --> 38 <uses-permission android:name="android.permission.RECEIVE_SMS"/> 39 <!-- 发送短信权限 --> 40 <uses-permission android:name="android.permission.SEND_SMS"/> 41 <!-- 读取联系人信息权限 --> 42 <uses-permission android:name="android.permission.READ_CONTACTS"/> 43 </manifest>
以上就是来电知了的全部代码和功能了,在做的过程中用到了许多的知识,比如数据库的增删查以及拷贝,线程的知识,广播机制,服务等知识。在做的过程中这些知识也就算是复习了一遍。如有有错误的地方,希望大家不吝指教。