[安卓]手机管家(八)防盗之业务逻辑
一. 绑定SIM卡
获取SIM卡信息并保存起来
找到控件、处理click事件、选中则绑定
layout里改一下id,具体点,是绑定sim
<com.rjl.mobilephonemanager.ui.SettingItemandroid:id="@+id/settingitem_bindsim"android:layout_width="fill_parent"android:layout_height="wrap_content"rjl:itemtitle="点击绑定sim卡"rjl:desc_checkbox_on="已经绑定"rjl:desc_checkbox_off="尚未绑定"/>
这里需要一个checkbox,我们最好在settingItem里暴露一个方法出来,自己调用checkbox,外面只需要调用这个settingitem组合控件就能调用到checkbox了
init里初始化,然后暴露一个方法,返回是否勾选的状态isCheck()
private void init() {// TODO Auto-generated method stub/*View view= View.inflate(getContext(), R.layout.setting_item, null); //将控件的view加载到这个view上this.addView(view);*/View v= View.inflate(getContext(), R.layout.setting_item, this);tv_setting_title = (TextView) v.findViewById(R.id.tv_setting_title);tv_setting_description = (TextView) v.findViewById(R.id.tv_setting_description);cb_settingitem = (CheckBox) v.findViewById(R.id.cb_settingitem);}
public boolean getChecked(){return cb_settingitem.isChecked();}
OK,然后在activity里调用
看一下逻辑,判断是否绑定,然后根据用户的点击去更改他的状态。
用户要点击,也就是说原来isChecked为true,点击后变为false,原来是false,点击后变为true,这就需要在settingItem里暴露一个方法,能够接受用户在activity2的点击,然后去改变boolean
同时点击后显示的text也要改变
settingitem_bindsim.setOnClickListener(new MySettingItemListener()); }class MySettingItemListener implements OnClickListener{@Overridepublic void onClick(View v) {// TODO Auto-generated method stubif(settingitem_bindsim.getChecked()){//check为true,则要设为false,这个setcheck也要去settingItem里暴露settingitem_bindsim.setCheck(false);settingitem_bindsim.setdescriptionoff(); }else{settingitem_bindsim.setCheck(true);settingitem_bindsim.setdescriptionon();}} }
settingItem里的方法接收状态的改变
public void setCheck(boolean checked){cb_settingitem.setChecked(checked);}
这里也可以更近一步,随着状态的改变,显示自动变了,而不是在代码里手动加上description,故而在settingItem的接收里面添加上就好,方便复用
public void setCheck(boolean checked){cb_settingitem.setChecked(checked);if(checked){setdescriptionon();}else{setdescriptionoff();}}
settingitem_bindsim.setOnClickListener(new MySettingItemListener()); }class MySettingItemListener implements OnClickListener{@Overridepublic void onClick(View v) {// TODO Auto-generated method stubif(settingitem_bindsim.getChecked()){//check为true,则要设为false,这个setcheck也要去settingItem里暴露settingitem_bindsim.setCheck(false); }else{settingitem_bindsim.setCheck(true); }} }
接下里实现绑定,这要用到telephonyManager,拿到sim卡序列号,并传入private SharedPreferences
telephonyManager = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);sp = getSharedPreferences("config", MODE_PRIVATE);}class MySettingItemListener implements OnClickListener{@Overridepublic void onClick(View v) {// TODO Auto-generated method stubEditor editor = sp.edit();if(settingitem_bindsim.getChecked()){//check为true,则要设为false,这个setcheck也要去settingItem里暴露settingitem_bindsim.setCheck(false);//不获取,为空就好,参数为 ""editor.putString("simserial", ""); }else{settingitem_bindsim.setCheck(true); //绑定sim卡的序列号,拿到,并传到SharedPreferencesString simserial= telephonyManager.getSimSerialNumber(); editor.putString("simserial", simserial);}editor.commit();} }
注意:这里需要readphone权限
这里要做一个数据的回显,每次进来的时候需要判断下是否有保存数据,否则每次进来都是未保存
telephonyManager = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);sp = getSharedPreferences("config", MODE_PRIVATE);if (sp.getString("simserial", "").length()!=0) {settingitem_bindsim.setCheck(true);}else {settingitem_bindsim.setCheck(false);}}
新功能,当重启手机后,sim卡变动,则发送短信提醒给一个联系人,重启会发出广播,要捕获到;当发出广播的时候,我们要同时知道是否sim发生变动,然后再调用系统API发送短信
获取已保存的,动态获取当前的,然后对比
若当前的序列号和保存的号不一样,则发送短信给一个绑定的手机号,而这个手机号是在activity3里完成的
还有一个问题,如果用户没有绑定sim卡,下一步进入3,此时为空,没法判断是卡变了还是没设置,所以应该在2里点击下一步时最好要判断下是否绑定了卡
@Overridepublic void next() {// TODO Auto-generated method stub//判断用户是否已经绑定,如果已经绑定,再继续执行,否则,提示一下用户,sim卡需要绑定。然后直接retrunif (sp.getString("simserial", "").length()==0) {Toast.makeText(this, "sim卡尚未绑定,请先绑定!", 0).show();return;} Intent intent = new Intent(this, Setup3Activity.class);startActivity(intent);overridePendingTransition(R.anim.enteranim, R.anim.exitanim);finish();}
现在要在3里获取号码
给edittext加一个id
<EditTextandroid:id="@+id/et_setup3_phonenumber"android:layout_width="fill_parent"android:layout_height="wrap_content"android:hint="请输入安全号码"/>
然后要在Oncreate里获取
et_setup3_phonenumber = (EditText) findViewById(R.id.et_setup3_phonenumber);
从保存文件中获取号码,需要先判断用户是否获取联系人,若进来后直接next,应该提示用户,注意要return回到当前activity
@Overridepublic void next() {// TODO Auto-generated method stub//去获取电话号码,然后保存到sp中String phonenumber = et_setup3_phonenumber.getText().toString();if(phonenumber.isEmpty()){ Toast.makeText(this, "安全号码不能为空,请输入!", 0).show();return;}else {SharedPreferences sp =getSharedPreferences("config", MODE_PRIVATE);Editor editor=sp.edit();editor.putString("safenum", phonenumber);editor.commit();} Intent intent = new Intent(this, Setup4Activity.class);startActivity(intent);overridePendingTransition(R.anim.enteranim, R.anim.exitanim);finish();}
这里需要一个新的包receiver,包含一个receiver,继承于broadcastreceiver,四大组件,需要去manifest声明
这里用静态注册
<receiver android:name="com.rjl.mobilephonemanager.receiver.BootCompleteReceiver"><intent-filter ><action android:name="android.intent.action.BOOT_COMPLETED"/></intent-filter></receiver></application>
</manifest>
重启之后,会call到该方法;这里面需要实现的是,要获取之前保存的sim卡 序列号;获取当前插入的sim卡的序列号;对比,如果发现不一致,则向指定号码发送报警短信
注意,这里无法直接调用SharedPreferences,之前的比如setup2里面能使用,虽然他自己没有定义这样的方法,但是他的父类或者父的父当中应该有,而这里的receiver里是没有的,但是可以通过上下文去获取,他本身就传递一个上下文
如果没设置,置空,就不会发通知
public class BootCompleteReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {// TODO Auto-generated method stub//重启之后,会call到该方法//这里面需要实现的是,要获取之前保存的sim卡 序列号 System.out.println("BootCompleteReceiver.onReceive() 开机重启事件收到");SharedPreferences sp = context.getSharedPreferences("config", context.MODE_PRIVATE);if (sp.getBoolean("enable_protect", false)) {String simserial_saved = sp.getString("simserial", "");String safenum = sp.getString("safenum", "");//获取当前插入的sim卡的序列号TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(context.TELEPHONY_SERVICE);String simserial_now= telephonyManager.getSimSerialNumber();// 对比,如果发现不一致,则向指定号码发送报警短信if (!simserial_now.equals(simserial_saved)) {//发送报警短信//SmsManager smsManager ;//= context.getSystemService(context.)SmsManager smsManager = SmsManager.getDefault();//调用该类的如下API去发送短信//其中,目前仅需要了解第一个参数为短信发送号码,第二个参数为短信内容,其他可以不填 smsManager.sendTextMessage(safenum, null, "我是报警短信!", null, null); System.out.println("BootCompleteReceiver.onReceive() 检测到sim变更");}}}
}
权限
<uses-permission android:name="android.permission.SEND_SMS"/><uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
这里也有回显问题,要在setup3里面oncreate时判断下
@Overrideprotected void onCreate(Bundle savedInstanceState) {// TODO Auto-generated method stubsuper.onCreate(savedInstanceState);setContentView(R.layout.activity_setup3);et_setup3_phonenumber = (EditText) findViewById(R.id.et_setup3_phonenumber);//et的数据回显操作SharedPreferences sp =getSharedPreferences("config", MODE_PRIVATE);et_setup3_phonenumber.setText(sp.getString("safenum", "")); }
要去4里面保存设置,需要checkbox
ID
<CheckBox android:id="@+id/cb_setup4_enableprotect"android:layout_width="fill_parent"android:layout_height="wrap_content"android:text="您还没有开启手机防盗保护"/>
找到
public class Setup4Activity extends SetupBaseActivity {private SharedPreferences sp ;CheckBox cb_setup4_enableprotect;@Overrideprotected void onCreate(Bundle savedInstanceState) {// TODO Auto-generated method stubsuper.onCreate(savedInstanceState);setContentView(R.layout.activity_setup4);cb_setup4_enableprotect = (CheckBox) findViewById(R.id.cb_setup4_enableprotect);}
listener 这里有两个,一个是状态改变的,一个是点击的,都可以,但前者更适用一点,返回当前状态,后者是返回一个view,再通过view找到状态
另外还需要回显
public class Setup4Activity extends SetupBaseActivity {private SharedPreferences sp ;CheckBox cb_setup4_enableprotect;@Overrideprotected void onCreate(Bundle savedInstanceState) {// TODO Auto-generated method stubsuper.onCreate(savedInstanceState);setContentView(R.layout.activity_setup4);cb_setup4_enableprotect = (CheckBox) findViewById(R.id.cb_setup4_enableprotect);//回显sp = getSharedPreferences("config", MODE_PRIVATE);if (sp.getBoolean("enable_protect", false)) {cb_setup4_enableprotect.setChecked(true);cb_setup4_enableprotect.setText("防盗保护已经开启!");}else {cb_setup4_enableprotect.setChecked(false);cb_setup4_enableprotect.setText("防盗保护尚未开启!");}cb_setup4_enableprotect.setOnCheckedChangeListener(new OnCheckedChangeListener() { @Overridepublic void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {// TODO Auto-generated method stubsp=getSharedPreferences("config", MODE_PRIVATE);Editor editor = sp.edit();if (isChecked) {//说明用户开启了防盗保护,需要保存状态 editor.putBoolean("enable_protect", true);cb_setup4_enableprotect.setText("防盗保护已经开启!");}else {//说明用户没开启防盗保护,需要保存状态editor.putBoolean("enable_protect", false);cb_setup4_enableprotect.setText("防盗保护尚未开启!");}editor.commit();}});}
再回到lostfind完善设置过的显示
if (sp.getBoolean("setupcomplete", false)) {//设置过TextView tv_lostfind_safenum = (TextView) findViewById(R.id.tv_lostfind_safenum);tv_lostfind_safenum.setText(sp.getString("safenum", "")); ImageView iv_lostfind_lockstatus = (ImageView) findViewById(R.id.iv_lostfind_lockstatus);if (sp.getBoolean("enable_protect", false)) {iv_lostfind_lockstatus.setImageResource(R.drawable.lock);}else {iv_lostfind_lockstatus.setImageResource(R.drawable.unlock);}
最后获取联系人信息,需要contentprovider,通过URI访问数据库返回一个cursor,遍历cursor,转到bean里,再在bean里获取
会弹出一个listview,在这个view里选择,选好了要关掉自己回到当前activity,选好了要放到textview里,这就是两个activity之间的数据传递,这又用到intent
首先需要一个联系人列表list
layout
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical" > <TextViewandroid:layout_width="fill_parent"android:layout_height="60dp"android:text="联系人列表"android:textSize="25sp"android:gravity="center"/><ListViewandroid:id="@+id/listview_contactslist"android:layout_width="fill_parent"android:layout_height="fill_parent"/>
</LinearLayout>
activity,需要一个adapter
public class ContactsListAcitvity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {// TODO Auto-generated method stubsuper.onCreate(savedInstanceState);setContentView(R.layout.actvity_contactslist);ListView listview_contactslist = (ListView) findViewById(R.id.listview_contactslist);listview_contactslist.setAdapter(new MylistAdapter());}class MylistAdapter extends BaseAdapter{@Overridepublic int getCount() {// TODO Auto-generated method stubreturn 0;}@Overridepublic Object getItem(int position) {// TODO Auto-generated method stubreturn null;}@Overridepublic long getItemId(int position) {// TODO Auto-generated method stubreturn 0;}@Overridepublic View getView(int position, View convertView, ViewGroup parent) {// TODO Auto-generated method stubreturn null;} }
}
弹出来的view 布局 contactslist_item
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical" ><TextViewandroid:id="@+id/tv_contactlist_name"android:layout_width="match_parent"android:layout_height="wrap_content"/><TextViewandroid:id="@+id/tv_contactlist_number"android:layout_width="match_parent"android:layout_height="wrap_content"/><TextViewandroid:id="@+id/tv_contactlist_email"android:layout_width="match_parent"android:layout_height="wrap_content"/>
</LinearLayout>
要在adapter的getView里去获取然后填充
@Overridepublic View getView(int position, View convertView, ViewGroup parent) {// TODO Auto-generated method stubView v = View.inflate(ContactsListAcitvity.this, R.layout.contactslist_item, null);TextView tv_contactlist_name = (TextView) v.findViewById(R.id.tv_contactlist_name);TextView tv_contactlist_number = (TextView) v.findViewById(R.id.tv_contactlist_number);TextView tv_contactlist_email = (TextView) v.findViewById(R.id.tv_contactlist_email);return null;}
list里是一个bean,之前在contentprovider里写过,套件,拿来用
public class Contact {//这里必须要给个空值"",有别于null,null会报空指针异常private String name="";private String number="";private String email="";public String getName() {return name;}public void setName(String name) {this.name = name;}public String getNumber() {return number;}public void setNumber(String number) {this.number = number;}public String getEmail() {return email;}public void setEmail(String email) {this.email = email;}public Contact(String name, String number, String email) {super();this.name = name;this.number = number;this.email = email;}public Contact() {super();// TODO Auto-generated constructor stub}@Overridepublic String toString() {return "Contact [name=" + name + ", number=" + number + ", email="+ email + "]";}
}
现在这个可以拿来查,但是可以抽出来作为一个单独的业务逻辑,让别人用,抽成一个类放到工具类,返回联系人列表
public class GetContactsList {//getContentResolver需要在上下文中获取,需要在get时传进一个contextpublic static List<Contact> get(Context context){List<Contact> list = new ArrayList<Contact>();ContentResolver cr = context.getContentResolver(); Cursor c =cr.query(Uri.parse("content://com.android.contacts/raw_contacts"), new String[]{ "contact_id"}, null, null, null);while(c.moveToNext()){int id = c.getInt(0); Cursor c2 =cr.query(Uri.parse("content://com.android.contacts/data"), new String[]{"mimetype" ,"data1"}, "raw_contact_id=?", new String[]{id+""}, null); //c2Contact contact = new Contact();while (c2.moveToNext()) {String type = c2.getString(0);String data1 = c2.getString(1); if ("vnd.android.cursor.item/name".equals(type)) {contact.setName(data1);}if ("vnd.android.cursor.item/phone_v2".equals(type)) {contact.setNumber(data1);}if ("vnd.android.cursor.item/email_v2".equals(type)) {contact.setEmail(data1);} }//防止数据库里有空数据if (!contact.getName().isEmpty()) {list.add(contact);}Log.i("getContact", contact.toString());}return list; }
}
在contactlistactivity里晚上获取
ublic class ContactsListAcitvity extends Activity {List<Contact> list ;@Overrideprotected void onCreate(Bundle savedInstanceState) {// TODO Auto-generated method stubsuper.onCreate(savedInstanceState);setContentView(R.layout.actvity_contactslist);ListView listview_contactslist = (ListView) findViewById(R.id.listview_contactslist);list= GetContactsList.get(this);listview_contactslist.setAdapter(new MylistAdapter());}class MylistAdapter extends BaseAdapter{@Overridepublic int getCount() {// TODO Auto-generated method stubreturn list.size();}@Overridepublic Object getItem(int position) {// TODO Auto-generated method stubreturn null;}@Overridepublic long getItemId(int position) {// TODO Auto-generated method stubreturn 0;}@Overridepublic View getView(int position, View convertView, ViewGroup parent) {// 根据position来获取联系人Contact contact = list.get(position);View v = View.inflate(ContactsListAcitvity.this, R.layout.contactslist_item, null);TextView tv_contactlist_name = (TextView) v.findViewById(R.id.tv_contactlist_name);TextView tv_contactlist_number = (TextView) v.findViewById(R.id.tv_contactlist_number);TextView tv_contactlist_email = (TextView) v.findViewById(R.id.tv_contactlist_email);tv_contactlist_name.setText(contact.getName());tv_contactlist_number.setText(contact.getNumber());tv_contactlist_email.setText(contact.getEmail());return v;} }
}
在activity3拿到联系人信息
public void selectpeople(View v){//需要实现从系统的联系人里获取一个联系人信息Intent intent = new Intent(this,ContactsListAcitvity.class);startActivity(intent); }
activity的声明
<activity android:name=".ContactsListAcitvity"></activity>
访问系统联系人的权限
<uses-permission android:name="android.permission.READ_CONTACTS"/>
点那个联系人要退出,然后把结果给setup3
则启动时不能直接intent,而是forresult
public void selectpeople(View v){//需要实现从系统的联系人里获取一个联系人信息Intent intent = new Intent(this,ContactsListAcitvity.class);startActivityForResult(intent, 100);}@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {// TODO Auto-generated method stub super.onActivityResult(requestCode, resultCode, data);}
弹出的list里面需要listener
listview_contactslist.setOnItemClickListener(new MyOnItemClickListener());}class MyOnItemClickListener implements OnItemClickListener{@Overridepublic void onItemClick(AdapterView<?> parent, View view, int position,long id) {//根据位置获取联系人Contact contact= list.get(position);//只需显示numberString number = contact.getNumber(); //通过intent返回Intent intent = new Intent();intent.putExtra("number", number);//resultcode自己定setResult(200, intent); finish();} }
activity3要接收这边的返回
@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {// TODO Auto-generated method stub if (requestCode==100&&resultCode==200) {String number =data.getStringExtra("number");et_setup3_phonenumber.setText(number); }super.onActivityResult(requestCode, resultCode, data);}
丛实际应用来说,当联系人过多的时候,显示列表的时候,因为是在oncreate里,有可能会引发主线程的阻塞,最好放在子线程里面操作
public class ContactsListAcitvity extends Activity {List<Contact> list ;@Overrideprotected void onCreate(Bundle savedInstanceState) {// TODO Auto-generated method stubsuper.onCreate(savedInstanceState);setContentView(R.layout.actvity_contactslist);ListView listview_contactslist = (ListView) findViewById(R.id.listview_contactslist);//当联系人过多的时候,此处有可能会引发主线程的阻塞//最好放在子线程里面操作list= GetContactsList.get(this); listview_contactslist.setAdapter(new MylistAdapter());listview_contactslist.setOnItemClickListener(new MyOnItemClickListener()); }
最后来实现监听广播
防盗保护开启,换了卡,收到短信,回一条短信
要location;或者让他播音乐,方便发现;或者删除数据;或者锁屏
故而本手机上需要一个短信拦截小助手,要知道紧急联系人回的短信里附带了什么样的指令
broadCastReceiver,需要在manifest里注册和权限,在声明里面需要加上最高权限1000,否则有可能被系统看到,那么小偷就能收到
<receiver android:name="com.rjl.mobilephonemanager.receiver.SMSReceiver"><intent-filter android:priority="1000"><action android:name="android.provider.Telephony.SMS_RECEIVED"/></intent-filter></receiver>
<uses-permission android:name="android.permission.RECEIVE_SMS"/>
看看之前的短信拦截,copy过来改动一下,加上trace看一下
public class SMSReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {// TODO Auto-generated method stubSystem.out.println("MySmsReceiver. onReceive() 我收到新的短信了");Bundle bundle = intent.getExtras();//pdus是一个object数组,短信数组,被分成多条的短信再组合起来Object[] obj = (Object[]) bundle.get("pdus");//将短信取出来,需要把object强转成数组for (Object object : obj) {SmsMessage sms = SmsMessage.createFromPdu((byte[])object);String addr = sms.getOriginatingAddress();String body = sms.getMessageBody();System.out.println("MySmsReceiver. onReceive()短信的具体内容是" +addr+":"+body); if ("10086".equals(addr)) {abortBroadcast(); System.out.println("SMSReceiver.onReceive()"+body);} else if("#*alarm*#".equals(body)){abortBroadcast(); System.out.println("SMSReceiver.onReceive()"+body);} else if("#*wipedata*#".equals(body)){abortBroadcast(); System.out.println("SMSReceiver.onReceive()"+body);} else if("#*lockscreen*#".equals(body)){abortBroadcast(); System.out.println("SMSReceiver.onReceive()"+body);} } }
}
但是注意
在4.3和4.3以下版本,可以收到短信,也可以拦截
在4.4 及以上版本,可以收到短信,但是无法拦截
安卓将接口隐藏了,但是也可以通过代码去调动这个接口
Intent intent = new Intent();
intent.setClassName("com.android.settings","com.android.settings.Settings");
intent.setAction(Intent.ACTION_MAIN);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK| Intent.FLAG_ACTIVITY_CLEAR_TASK| Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
intent.putExtra(PreferenceActivity.EXTRA_SHOW_FRAGMENT,"com.android.settings.applications.AppOpsSummary");
startActivity(intent);
else if("#*alarm*#".equals(body)){abortBroadcast(); System.out.println("SMSReceiver.onReceive()"+body);MediaPlayer mp = new MediaPlayer(); mp.setAudioStreamType(AudioManager.STREAM_MUSIC);try {mp.setDataSource("storage/sdcard/bajie.mp3");mp.setLooping(true);mp.prepare();mp.start(); } catch (IllegalArgumentException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (SecurityException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IllegalStateException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();} }
音乐文件放在工程里,或者说APP里,需要新建一个raw的文件夹
else if("#*alarm*#".equals(body)){abortBroadcast(); System.out.println("SMSReceiver.onReceive()"+body);MediaPlayer player = MediaPlayer.create(context,R.raw.bajie);// 不需要重新准备player.setLooping(true);//对音乐的管理,用代码调到最大AudioManager manager=(AudioManager) context.getSystemService(Context.AUDIO_SERVICE);int max=manager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);// 1 声音的类型 2 声音的大小manager.setStreamVolume(AudioManager.STREAM_MUSIC, max, 0);player.start();// 播放 }
获取location,调用当前GPS接口,获得坐标信息保存起来
这里需要传一个locationListener
这整个过程比较耗时,不应该放到广播的onReceive里面,而短信的这个广播是一个有序广播,按照优先级,安卓要求必须很快传递数据,可以去写一个service
这里可以用线程,但是线程安全性低一些,可能会被干掉
我们要在service里获取到经纬度信息,保存到SharedPreferences,然后在receiver里读取到这个经纬度,通过短信发送出去
location需要权限
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/><uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/><uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION"/>
service
public class LocationService extends Service {@Overridepublic IBinder onBind(Intent intent) {// TODO Auto-generated method stub return null;}@Overridepublic void onCreate() {// TODO Auto-generated method stubLocationManager manager =(LocationManager) getSystemService(LOCATION_SERVICE); manager.requestLocationUpdates("gps",0, 0, new MyLocationListener());super.onCreate();}class MyLocationListener implements LocationListener{@Overridepublic void onLocationChanged(Location location) {// TODO Auto-generated method stub//获取经纬度double Latitude = location.getLatitude();double Longitude = location.getLongitude();//保存起来SharedPreferences sp = getSharedPreferences("config", MODE_PRIVATE);Editor editor = sp.edit();editor.putString("Latitude", Latitude+"");editor.putString("Longitude", Longitude+"");editor.commit();}@Overridepublic void onStatusChanged(String provider, int status, Bundle extras) {// TODO Auto-generated method stub }@Overridepublic void onProviderEnabled(String provider) {// TODO Auto-generated method stub }@Overridepublic void onProviderDisabled(String provider) {// TODO Auto-generated method stub } }
}
receiver
if ("#*location*#".equals(addr)) {abortBroadcast(); System.out.println("SMSReceiver.onReceive()"+body);//获取到这个serviceIntent service = new Intent(context, LocationService.class);context.startService(service);//从SharedPreferences中读取SharedPreferences sp = context.getSharedPreferences("config", context.MODE_PRIVATE);String Latitude = sp.getString("Latitude", "");String Longitude = sp.getString("Longitude",""); System.out.println("SMSReceiver.onReceive()"+Latitude+"/"+Longitude);//获取系统提供的短信管理类SmsManager smsManager = SmsManager.getDefault();//调用该类的如下API去发送短信//其中,目前仅需要了解第一个参数为短信发送号码,第三个参数为短信内容,其他可以不填smsManager.sendTextMessage("5556", null, Latitude+"/"+Longitude, null, null);}
这里启动时,就去获取经纬度,很可能是无法获取到的,因为还在启动,可以让他在线程里等一会,但是讨巧的做法是发送一个短信去启动后,过一会再发一条,这时就可以接收到
擦除数据和锁屏都要DevicePolicyManager
这里肯定要权限,但是不是常见的permission,而是超级管理员
这一部分以一个一键锁屏的demo演示一下 点击一个button就能锁屏
layout
<Buttonandroid:id="@+id/button1"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignLeft="@+id/textView1"android:layout_below="@+id/textView1"android:layout_margin="36dp"android:text="Button"android:onClick="lockscreen"/>
mainactivity
public class MainActivity extends Activity {private DevicePolicyManager manager;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);manager =(DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE); }public void lockscreen(View v){manager.lockNow();}
}
此时若点击按钮,显然会出错,要超级管理员
首先他需要一个广播接收者,DeviceAdminReceiver,然后要一个子类继承他,新建一个AdminReceiver,这里面什么代码都不需要,为什么要放到这个receiver里?激活管理员权限,系统会发一个广播给应用,这个子类的父类会去修改权限
import android.app.admin.DeviceAdminReceiver;public class AdminReceiver extends DeviceAdminReceiver {}
这时候要去manifest里声明
<receiver android:name=".AdminReceiver" android:label="@string/sample_device_admin" android:description="@string/sample_device_admin_description" android:permission="android.permission.BIND_DEVICE_ADMIN"> <meta-data android:name="android.app.device_admin" android:resource="@xml/device_admin_sample" /> <intent-filter> <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" /> </intent-filter> </receiver>
这里面需要注意,有几个要在values下的string下声明
<?xml version="1.0" encoding="utf-8"?>
<resources><string name="app_name">锁屏小应用</string><string name="hello_world">Hello world!</string><string name="action_settings">Settings</string><string name="sample_device_admin">一键锁屏小应用</string><string name="sample_device_admin_description">一键锁屏小应用:给力</string>
</resources>
需要一个权限,已经在里面了
然后metadata,一般在head里定义的源信息,里面有一个resource,需要新建一个folder
<?xml version="1.0" encoding="utf-8"?>
<device-admin xmlns:android="http://schemas.android.com/apk/res/android"> <uses-policies> <reset-password /> <force-lock /> <wipe-data /> </uses-policies>
</device-admin>
现在声明好了,还需要去激活
不过这个在模拟器上会重启,在真机上可以
OK,现在来完成锁屏和除数据
将锁屏小应用的相关信息弄过来,string,manifest声明,xml文件夹
注意改一下name
<receiver android:name=".receiver.AdminReceiver" android:label="@string/sample_device_admin" android:description="@string/sample_device_admin_description" android:permission="android.permission.BIND_DEVICE_ADMIN"> <meta-data android:name="android.app.device_admin" android:resource="@xml/device_admin_sample" /> <intent-filter> <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" /> </intent-filter> </receiver>
<?xml version="1.0" encoding="utf-8"?>
<resources><string name="app_name">MobilePhoneManager</string><string name="hello_world">Hello world!</string><string name="action_settings">Settings</string><string name="sample_device_admin">手机管家</string><string name="sample_device_admin_description">开启远程锁屏和擦除数据</string>
</resources>
要在SMSReceiver里去实现,但是要判断用户是否激活了
else if("#*wipedata*#".equals(body)){abortBroadcast(); System.out.println("SMSReceiver.onReceive()"+body);ComponentName who=new ComponentName(context, AdminReceiver.class);if(manager.isAdminActive(who)){manager.wipeData(0);} } else if("#*lockscreen*#".equals(body)){abortBroadcast(); System.out.println("SMSReceiver.onReceive()"+body);ComponentName who=new ComponentName(context, AdminReceiver.class);if(manager.isAdminActive(who)){manager.wipeData(0);}}
需要提前激活这个手机管家的权限,各种权限是在xml那个文件里定义的
这一块就基本完成了,但是最好能用代码去开启权限,而不是让用户自己开启,一般都不愿意,在原来的setup4里面有个textview,可以加上一个onclick响应
<TextViewandroid:layout_width="fill_parent"android:layout_height="wrap_content"android:text="激活超级管理员\n您就可以远程擦除数据"android:padding="5dp" android:background="@drawable/textbg_setup4"android:textSize="18sp" android:layout_margin="5dp"android:onClick="active"android:clickable="true"android:focusable="true"/>
public void active(View v){Intent intent = new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN); ComponentName mDeviceAdminSample=new ComponentName(this, AdminReceiver.class);intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, mDeviceAdminSample); intent.putExtra(DevicePolicyManager.EXTRA_ADD_EXPLANATION,"激活后才可以锁屏,如果不激活罚2000块钱");startActivity(intent);}
此时就直接跳转到激活,这里其实可以做一个判断,如果之前激活过,给一个提示。
获得了管理员权限后就不能直接卸载了,需要反激活再卸载,但是用户会嫌麻烦
可以在APP里加一个button,让他自己卸载,
卸载就是给一个包名然后destroy(),
关键是反激活,需要在SMSreceiver里调用removeActiveAdmin
[安卓]手机管家(八)防盗之业务逻辑相关推荐
- 安卓强制恢复出厂_看过来!这是让安卓手机十八个月不卡的秘诀
虽然苹果手机售价高昂,外观设计万年不变,但是却仍然有着不少消费者选择使用iPhone,为什么这些消费者会选择iPhone?个人觉得还是因为苹果系统的体验实在太流畅. 反观安卓阵营,尽管安卓手机早已摆脱 ...
- [安卓]手机管家(十)正则表达式 号码归属地
校验QQ号码 必须5-15位数字 0不能开头 纯代码式 import java.util.Scanner; public class RegExpDemo {public static void ma ...
- 【腾讯TMQ】【测试左移专栏】手机管家PiTest测试左移实践
作者:CC 团队:腾讯移动品质中心TMQ [引入] 说起"测试左移"相信对于大家来说已经不再陌生,左移的也手段非常多,无论是使用NLP来做需求分析,还是使用ACC来做测试建模,目的 ...
- 安全管家安卓_手机丢失后可能背负巨额债务,腾讯手机管家提醒注意手机安全防护 -...
之前骗子偷手机是为了卖手机换钱,现在骗子偷手机,是为了用你的信息各平台套现.近期,一篇名为<一部手机失窃而揭露的窃取个人信息实现资金盗取的黑色产业链>引发广泛关注,工信部约谈相关单位,并提 ...
- 手机发送验证码的业务逻辑探究-主要是安全性,响应性
手机发送验证码的业务逻辑探究-主要是安全性,响应性 这样一来,只要知道静态的验证码是什么,脚本就可以轻松填写正确的验证码. 解决方法: 1后台是否可以限制一个IP发送的次数 2限定发送验证码的一分钟的 ...
- 安全管家安卓_安卓手机自带的管家好,还是另外获取的管家好呢?这4点你要知道...
安卓手机自带的管家好,还是另外获取的管家好呢?这4点你要知道 目前使用安卓手机朋友们,应该都很熟悉自己的手机带有手机管家这个功能(不同的手机有可能叫法不同),但是也是有不少用户,因为某些原因会另外获取 ...
- 安卓最新版本_腾讯手机管家下载最新版本-腾讯手机管家2020新版本下载v8.8.1 安卓官方版...
2020腾讯手机管家安卓版是一款功能强大的安全优化软件,让你的手机处在安全的网络环境中,抵抗外界的干扰,还能智能拦截骚扰电话,给你一个干净舒适的环境,更多功能尽在腾讯手机管家客户端.喜欢的朋友就来22 ...
- qq手机令牌 for android3.3 官方安装版,腾讯手机管家app下载 腾讯手机管家(原QQ手机管家) for Android v8.8.3 官方安卓版 下载-脚本之家...
腾讯手机管家(原QQ手机管家)是一款手机安全客户端软件,QQ手机管家主要功能是防QQ帐号被盗.防骚扰.防泄密,以及颇具创新的"云端保护精准拦截"功能,但并没有加入上网流量监控.手机 ...
- android10禁用华为桌面,[原创]简单分析华为emui10对第三方桌面的禁用逻辑(华为手机管家app) + 求助新rom的分析入手思路...
华为开启emui10的公测后, 之前一直禁止切换默认launcher的情况有了新的解决办法 : 冻结 手机管家 即可设置 第三方launcher 这里简单分析华为手机管家中 相关逻辑 求助: 在 最新 ...
最新文章
- 关于commonjs,AMD,CMD之间的异同
- boot的几个依赖 spring_Spring boot依赖管理和数据库使用
- linux命令的基本操作
- android系统底层驱动多个物理按键上报同一个键值给app层,app层如何区分
- Kotlin中的接口回调
- SpringBoot——@Scheduled的自定义周期性线程池解决任务延时执行问题
- 计算机视觉基础-图像处理(图像分割/二值化)cpp+python
- python内核死亡的原因_Python xgboost:内核死亡
- R语言如何并行处理[parallel package][向量化操作并行优化]
- 如何注册苹果开发者账号
- 使用dsoFramer开始Office应用程序
- 【滤波器】基于时变维纳滤波器实现语音去噪含Matlab源码
- Python替换月份为英文缩写
- 谷粒学院P21所需的maven jar包
- Solr高级查询Facet
- PMP考试 工作绩效数据 工作绩效信息 工作绩效报告 区别与联系
- 中国程序员的真实工资亦或幸福指数
- minio服务器在win10的上传与下载,以及修改头像Minio速看免费本地文件服务器
- 【嵌入式】——串口实验——实现芯片串口收发数据,按键中断串口发送数据,串口接收数据中断来控制LED亮/灭
- mean shift:从图像分割到特征空间分析