Android项目实战 您所在的位置:网站首页 android手机安全卫士 Android项目实战

Android项目实战

2024-07-08 22:55| 来源: 网络整理| 查看: 265

###1.骚扰拦截需求分析1.界面1.1 黑名单列表界面1.2 添加黑名单界面2.功能2.1 黑名单的添加、删除2.2 拦截电话2.3 拦截短信

###2.黑名单数据库的创建1.分析需要的字段id 主键自增长,phone 电话号码,mode 拦截模式2.创建数据库打开类BlackNumberDBOpenHelper,继承SQLiteOpenHelperpublic class BlackNumberDBOpenHelper extends SQLiteOpenHelper {

public BlackNumberDBOpenHelper(Context context) {super(context, "address.db", null, 1);}

//数据库第一次被创建的时候调用,适合初始化数据库的表结构@Overridepublic void onCreate(SQLiteDatabase db) {//id 主键自增长, phone 电话号码 mode 拦截模式db.execSQL("create table blacknumber (_id integer primary key autoincrement, phone varchar(20),mode varchar(2))");}

@Overridepublic void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

}

}3.创建数据库数据操作类BlackNumberDao,实现增删改查方法

###3.增删改查单元测试1.创建测试类TestBlackNumberDao,继承AndroidTestCase,测试增删改查方法2.在清单文件中对测试类进行如下配置:2.1 manifest节点下添加2.2 application节点下添加

###4.android:layout_weight的用法 1.android:layout_weight:权重比例,将剩余空间按比例分配。只可在线性布局中使用 2.指定android:layout_weight属性后, 如果线性布局是水平的,View的宽度=原有宽度+线性布局剩余空间的占比 如果线性布局是竖直的,View的高度=原有高度+线性布局剩余空间的占比 3.Android官方推荐,在使用android:layout_weight时, 如果线性布局是水平的,要将android:layout_width设置为0dp 如果线性布局是竖直的,要将android:layout_height设置为0dp

###5.9patch图片(.9.png拼接图片)![](http://i.imgur.com/A63gxy8.jpg) 1号黑色条位置向下覆盖的区域表示图片横向拉伸时,只拉伸该区域 2号黑色条位置向右覆盖的区域表示图片纵向拉伸时,只拉伸该区域 3号黑色条位置向左覆盖的区域表示图片纵向显示内容的区域 4号黑色条位置向上覆盖的区域表示图片横向显示内容的区域

###6.shape图形

###2.挂断电话 //加入权限

/** * 挂断电话 */ public void endCall() {

//系统内部调用方式 //ITelephony.Stub.asInterface(ServiceManager.getService(Context.TELEPHONY_SERVICE)); try {

//ServiceManager获取不到,需要反射调用 Class clazz = getClassLoader().loadClass("android.os.ServiceManager"); Method method = clazz.getDeclaredMethod("getService", String.class); IBinder iBinder = (IBinder) method.invoke(null, Context.TELEPHONY_SERVICE);

//挂断电话需要用到AIDL,拷贝需要用到的AIDL文件,ITelephony.aidl和NeighboringCellInfo.aidl,包名要与原包名一致 ITelephony iTelephony = ITelephony.Stub.asInterface(iBinder); iTelephony.endCall(); } catch (Exception e) { e.printStackTrace(); } }

###3.删除呼叫记录 //加入权限

/** * 删除黑名单号码的呼叫记录 * @param incomingNumber 来电黑名单号码 */ public void deleteCallLog(final String incomingNumber) { final ContentResolver resolver = getContentResolver();

//CallLog.Calls.CONTENT_URI 等价于 Uri.parse("content://call_log/calls"); final Uri uri = Uri.parse("content://call_log/calls");

//利用内容观察者 观察呼叫记录的数据库,如果生成了呼叫记录就立刻删除呼叫记录 resolver.registerContentObserver(uri, true, new ContentObserver(new Handler()) { @Override public void onChange(boolean selfChange) { //当内容观察者观察到数据库的内容变化的时候调用的方法. super.onChange(selfChange); resolver.delete(uri, "number=?", new String[]{incomingNumber}); } }); }

###4.拦截短信 1.注册在清单文件中的广播接收者,无论应用是否启动都会接收到广播,想用开关控制拦截短信的功能,则在代码中注册短信广播接收者 receiver = new InnerSmsReceiver(); IntentFilter filter = new IntentFilter(); filter.addAction("android.provider.Telephony.SMS_RECEIVED"); filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); registerReceiver(receiver, filter);

private class InnerSmsReceiver extends BroadcastReceiver{ @Override public void onReceive(Context context, Intent intent) { Log.i(Tag,"服务内部广播接受者接收到了短信"); Object[] objs = (Object[]) intent.getExtras().get("pdus"); for(Object obj: objs){ SmsMessage smsMessage = SmsMessage.createFromPdu((byte[]) obj); String body = smsMessage.getMessageBody(); if(body.contains("fapiao")){ //你的头发票亮的很 分词技术 Log.i(Tag,"发现发票垃圾短信,拦截"); abortBroadcast(); return; } String sender = smsMessage.getOriginatingAddress(); String mode = dao.find(sender); if("2".equals(mode)||"3".equals(mode)){ Log.i(Tag,"发现黑名单短信,拦截"); abortBroadcast(); } } } }

2.onDestroy中注销 unregisterReceiver(receiver); receiver = null;

###5.导入已存在的数据库 //assert资产目录里面的文件会原封不动的打包到apk里,不生成id

/** * 拷贝归属地的数据库 */ private void copyAddressDB() { File file = new File(getFilesDir(), "address.db"); //判断数据库文件是否存在 if (file.exists() && file.length() > 0) { Log.i(TAG, "数据库存在,无需拷贝"); } else { new Thread() { public void run() { // 把asset资产目录里面的数据库文件(在apk里面的)拷贝到手机系统里面 try { InputStream is = getAssets().open("address.db"); File file = new File(getFilesDir(), "address.db"); FileOutputStream fos = new FileOutputStream(file); byte[] buffer = new byte[1024]; int len = -1; while ((len = is.read(buffer)) != -1) { fos.write(buffer, 0, len); } fos.close(); is.close(); } catch (Exception e) { e.printStackTrace(); } }; }.start(); } }

###6.查询号码归属地 /** * 查询手机号码的归属地信息 * @param mobilenumber * @return */ public static String findLocation(String mobilenumber) { String path = "/data/data/com.hb.mobilesafe/files/address.db"; //打开已存在的数据库 SQLiteDatabase db = SQLiteDatabase.openDatabase(path, null, SQLiteDatabase.OPEN_READONLY); Cursor cursor = db.rawQuery( "select location from data2 where id = (select outkey from data1 where id = ?)", new String[]{mobilenumber.substring(0, 7)}); String location =""; if(cursor.moveToNext()){ location = cursor.getString(0); } cursor.close(); db.close(); return location; }

###7.判断一个号码是否是手机号码 // ^1[34578]\d{9}$ // ^ 匹配输入字符串的开始位置。 // [] 字符集合。匹配所包含的任意一个字符。 // \d 匹配一个数字字符。 // {} n 是一个非负整数。匹配确定的 n 次。 // $ 匹配输入字符串的结束位置。 boolean result = number.matches("^1[34578]\\d{9}$");

###8.给EditText添加文本变化监听器 // 给文本输入框注册一个内容变化的监听器. et_number.addTextChangedListener(new TextWatcher() {

//当文本变化之前调用的方法,s为改变前字符串,可获取被替换内容 //在s中从start开始的count个字符即将被after个字符替换 @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) {

}

//当文本变化之后调用的方法,s为改变后字符串,可获取替换内容 //在s中从start开始的before个字符刚刚被count个字符替换 @Override public void onTextChanged(CharSequence s, int start, int before, int count) { if (s.length() >= 10) { String location = AddressDBDao.findLocation(s.toString()); tv_location.setText("归属地为:" + location); } }

//当文本变化之后调用的方法,s为改变后字符串,操作s可直接改变EditText内容,EditText内容改变会继续调用beforeTextChanged和onTextChanged方法 //s中有内容被改变 @Override public void afterTextChanged(Editable s) {

} });

每次输入都会调用3个方法,调用顺序为beforeTextChanged-->onTextChanged-->afterTextChanged

###9.CharSequence、String、Editable 1.CharSequence:接口,只有length()、charAt(int index)、subSequence(int start, int end)、toString()四个方法 2.String:实现了CharSequence接口,具有很多操作字符串的方法,不可修改 3.Editable:实现了CharSequence接口,具有增删改等修改的方法,可修改

###10.动画插值器Interpolator 1.interpolator定义一个动画的变化率(the rate of change)。这使得基本的动画效果(alpha, scale, translate, rotate)得以加速,减速,重复等。 2.常用Interpolator LinearInterpolator 以常量速率改变

AccelerateInterpolator 加速 DecelerateInterpolator 减速 AccelerateDecelerateInterpolator 先加速后减速

AnticipateInterpolator OvershootInterpolator AnticipateOvershootInterpolator

BounceInterpolator 弹跳

CycleInterpolator 循环播放特定的次数,速率改变沿着正弦曲线

###11.监听外拨电话 1.添加权限 2.注册广播接收者 receiver = new OutCallReceiver(); IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_NEW_OUTGOING_CALL); registerReceiver(receiver, filter);

private class OutCallReceiver extends BroadcastReceiver{ @Override public void onReceive(Context context, Intent intent) { String number = getResultData(); String address = AddressDBDao.findLocation(number); Toast.makeText(ShowAddressService.this, address, 1).show(); } } 3.释放资源 @Override public void onDestroy() { unregisterReceiver(receiver); receiver = null; super.onDestroy(); }

###12.通过WindowManager添加自定义View到窗体 1.添加权限 2.获取WindowManager WindowManager mWM = (WindowManager) getSystemService(WINDOW_SERVICE); 3.自定义View View mView; 4.设置布局参数 final WindowManager.LayoutParams params = mParams; params.height = WindowManager.LayoutParams.WRAP_CONTENT; params.width = WindowManager.LayoutParams.WRAP_CONTENT; params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON; params.format = PixelFormat.TRANSLUCENT; params.type = WindowManager.LayoutParams.TYPE_TOAST; 5.添加到窗体 mWM.addView(view, mParams); 6.移除View mWM.removeView(view);

 

代码:

1 package com.hb.mobilesafe.activities; 2 3 import java.util.List; 4 5 import android.annotation.SuppressLint; 6 import android.app.Activity; 7 import android.content.Intent; 8 import android.os.Bundle; 9 import android.os.SystemClock; 10 import android.view.View; 11 import android.view.View.OnClickListener; 12 import android.view.ViewGroup; 13 import android.view.Window; 14 import android.widget.BaseAdapter; 15 import android.widget.ImageView; 16 import android.widget.LinearLayout; 17 import android.widget.ListView; 18 import android.widget.TextView; 19 import android.widget.Toast; 20 21 import com.hb.demo_mobilesafe.R; 22 import com.hb.mobilesafe.bean.BlackInfo; 23 import com.hb.mobilesafe.dbdao.BlackNumberDao; 24 25 public class BlackNumberActivity extends Activity { 26 private ImageView iv_empt; 27 private BlackNumberDao dao; 28 private List list; 29 private ListView lv_blacknumber; 30 private MyAdapter adapter; 31 private BlackInfo info; 32 private LinearLayout ll_progressbar; 33 @Override 34 protected void onCreate(Bundle savedInstanceState) { 35 // TODO Auto-generated method stub 36 super.onCreate(savedInstanceState); 37 requestWindowFeature(Window.FEATURE_NO_TITLE); 38 setContentView(R.layout.activity_blacknumber); 39 lv_blacknumber=(ListView) findViewById(R.id.lv_blacknumber); 40 iv_empt=(ImageView) findViewById(R.id.iv_empt); 41 ll_progressbar=(LinearLayout) findViewById(R.id.ll_progressbar); 42 dao=new BlackNumberDao(this); 43 ll_progressbar.setVisibility(View.VISIBLE); 44 new Thread(){ 45 public void run() { 46 SystemClock.sleep(2500); 47 runOnUiThread(new Runnable() { 48 public void run() { 49 ll_progressbar.setVisibility(View.INVISIBLE); 50 updateUI(); 51 adapter=new MyAdapter(); 52 lv_blacknumber.setAdapter(adapter); 53 } 54 55 }); 56 }; 57 }.start(); 58 59 60 61 } 62 private void updateUI() { 63 list = dao.queryAll(); 64 if(list.size()>0){ 65 iv_empt.setVisibility(View.INVISIBLE); 66 }else{ 67 iv_empt.setVisibility(View.VISIBLE); 68 } 69 } 70 private class MyAdapter extends BaseAdapter{ 71 72 73 74 @Override 75 public int getCount() { 76 77 return list.size(); 78 } 79 @SuppressWarnings("null") 80 @SuppressLint("ViewHolder") @Override 81 public View getView(final int position, View convertView, ViewGroup parent) { 82 View view; 83 ViewHolder holder = null; 84 if(convertView!=null){ 85 view=convertView;//复用历史缓存抄作 86 holder=(ViewHolder) view.getTag(); 87 }else { 88 holder=new ViewHolder(); 89 view=View.inflate(BlackNumberActivity.this, R.layout.blacknumber_item, null); 90 holder.tv_number=(TextView) view.findViewById(R.id.tv_number); 91 holder.tv_mode=(TextView) view.findViewById(R.id.tv_mode); 92 holder.iv_del=(ImageView) view.findViewById(R.id.iv_delete); 93 view.setTag(holder); 94 } 95 96 /** 97 * 删除黑名单 98 */ 99 holder.iv_del.setOnClickListener(new OnClickListener() { 100 101 @Override 102 public void onClick(View v) { 103 String num = list.get(position).getNumber(); 104 dao.delete(num); 105 list.remove(num); 106 updateUI(); 107 adapter.notifyDataSetChanged(); 108 } 109 }); 110 String mode = list.get(position).getMode(); 111 if(mode.equals("1")){ 112 holder.tv_mode.setText("电话拦截"); 113 }else if(mode.equals("2")){ 114 holder.tv_mode.setText("短信拦截"); 115 }else{ 116 holder.tv_mode.setText("全部拦截"); 117 } 118 holder.tv_number.setText(list.get(position).getNumber()); 119 return view; 120 } 121 122 @Override 123 public Object getItem(int position) { 124 return null; 125 } 126 127 @Override 128 public long getItemId(int position) { 129 return 0; 130 } 131 132 133 134 } 135 class ViewHolder{ 136 TextView tv_number; 137 TextView tv_mode; 138 ImageView iv_del; 139 140 } 141 142 public void addnumber(View view){ 143 Intent intent=new Intent(BlackNumberActivity.this, AddNumberActivity.class); 144 startActivityForResult(intent, 0); 145 } 146 @Override 147 protected void onActivityResult(int requestCode, int resultCode, Intent data) { 148 super.onActivityResult(requestCode, resultCode, data); 149 if(data!=null){ 150 boolean result = data.getBooleanExtra("addnumber", false); 151 if(result){ 152 Toast.makeText(BlackNumberActivity.this, "添加成功!", 0).show(); 153 String number = data.getStringExtra("number"); 154 String mode = data.getStringExtra("mode"); 155 info = new BlackInfo(); 156 info.setNumber(number); 157 info.setMode(mode); 158 list.add(0, info);//减少数据库查询的操作 159 updateUI(); 160 adapter.notifyDataSetChanged(); 161 }else{ 162 Toast.makeText(BlackNumberActivity.this, result+"添加失败!", 0).show(); 163 } 164 165 } 166 } 167 } 1 package com.hb.mobilesafe.service; 2 3 import java.lang.reflect.Method; 4 5 import com.android.internal.telephony.ITelephony; 6 import com.hb.mobilesafe.dbdao.BlackNumberDao; 7 8 import android.app.Service; 9 import android.content.BroadcastReceiver; 10 import android.content.ContentResolver; 11 import android.content.Context; 12 import android.content.Intent; 13 import android.content.IntentFilter; 14 import android.database.ContentObserver; 15 import android.net.Uri; 16 import android.os.Handler; 17 import android.os.IBinder; 18 import android.telephony.PhoneStateListener; 19 import android.telephony.SmsMessage; 20 import android.telephony.TelephonyManager; 21 import android.util.Log; 22 23 public class BlackNumberSafeService extends Service { 24 private static final String TAG = "BlackNumberSafeService"; 25 private TelephonyManager tm; 26 private CallStatic listener; 27 private BlackNumberDao dao; 28 private SmsReceiver smsreceiver; 29 30 @Override 31 public IBinder onBind(Intent intent) { 32 return null; 33 } 34 @Override 35 public void onCreate() { 36 37 Log.i(TAG, "黑名单服务已经开启了"); 38 System.out.println("黑名单服务已经开启了"); 39 tm=(TelephonyManager) getSystemService(TELEPHONY_SERVICE); 40 listener=new CallStatic(); 41 dao=new BlackNumberDao(this); 42 tm.listen(listener, PhoneStateListener.LISTEN_CALL_STATE); 43 44 smsreceiver=new SmsReceiver(); 45 46 IntentFilter filter = new IntentFilter(); 47 filter.addAction("android.provider.Telephony.SMS_RECEIVED"); 48 filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); 49 registerReceiver(smsreceiver, filter); 50 super.onCreate(); 51 } 52 @Override 53 public void onDestroy() { 54 super.onDestroy(); 55 Log.i(TAG, "黑名单服务已经销毁"); 56 System.out.println("黑名单服务已经销毁"); 57 //销毁时关闭监听 58 tm.listen(listener, PhoneStateListener.LISTEN_NONE); 59 listener=null; 60 61 //注销广播 62 unregisterReceiver(smsreceiver); 63 smsreceiver=null; 64 } 65 private class CallStatic extends PhoneStateListener { 66 67 @Override 68 public void onCallStateChanged(int state, String incomingNumber) { 69 super.onCallStateChanged(state, incomingNumber); 70 switch (state) { 71 //空闲状态 72 case TelephonyManager.CALL_STATE_IDLE: 73 break; 74 //响铃状态 75 case TelephonyManager.CALL_STATE_RINGING: 76 String mode = dao.query(incomingNumber); 77 if("1".equals(mode) || "3".equals(mode)){ 78 System.out.println("电话已经响铃"); 79 //挂断电话 80 endcall(); 81 //删除记录 82 delteCallLog(incomingNumber); 83 } 84 break; 85 //关闭状态 86 case TelephonyManager.CALL_STATE_OFFHOOK: 87 break; 88 89 } 90 } 91 92 93 94 95 } 96 private void endcall() { 97 //ServiceManager获取不到,需要反射调用 98 try { 99 Class clazz=getClassLoader().loadClass("android.os.ServiceManager"); 100 Method method=clazz.getDeclaredMethod("getService", String.class); 101 IBinder binder=(IBinder) method.invoke(null, Context.TELEPHONY_SERVICE); 102 103 //挂断电话需要用到AIDL,拷贝需要用到的AIDL文件,ITELEPHONY.AIDL和NeighboringcellInfo.aidl包名需要和原名一致 104 ITelephony iTelephony=ITelephony.Stub.asInterface(binder); 105 iTelephony.endCall(); 106 System.out.println("电话挂断了"); 107 } catch (Exception e) { 108 // TODO Auto-generated catch block 109 e.printStackTrace(); 110 } 111 } 112 /** 113 * 114 * @param 删除电话记录 115 */ 116 private void delteCallLog(final String incomingNumber) { 117 final ContentResolver resolver = getContentResolver(); 118 final Uri parse = Uri.parse("content://call_log/calls"); 119 //利用内容观察者,观察呼叫数据库的内容,如果有记录就删除 120 resolver.registerContentObserver(parse, true,new ContentObserver(new Handler()) { 121 122 @Override 123 public void onChange(boolean selfChange) { 124 super.onChange(selfChange); 125 //当内容观察者观察到数据库的内容变化时调用的方法 126 resolver.delete(parse, "number=?", new String[]{incomingNumber}); 127 System.out.println("删除电话记录"); 128 } 129 130 } ); 131 } 132 /** 133 * @pargram 短信拦截 134 */ 135 private class SmsReceiver extends BroadcastReceiver{ 136 137 @Override 138 public void onReceive(Context context, Intent intent) { 139 Object[] objects=(Object[]) intent.getExtras().get("pdus"); 140 for (Object object : objects) { 141 SmsMessage sms = SmsMessage.createFromPdu((byte[]) object); 142 String address = sms.getOriginatingAddress(); 143 String mode = dao.query(address); 144 if("2".equals(mode) || "3".equals(mode)){ 145 System.out.println("123456789"); 146 abortBroadcast(); 147 Log.i(TAG, "短信已经拦截了"); 148 149 } 150 } 151 } 152 153 } 154 155 }

 



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有