一. 绑定SIM卡
获取SIM卡信息并保存起来
找到控件、处理click事件、选中则绑定
layout里改一下id,具体点,是绑定sim
<com.rjl.mobilephonemanager.ui.SettingItem
android: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{
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
if(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{
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
if(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{
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
Editor 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卡的序列号,拿到,并传到SharedPreferences
String 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里点击下一步时最好要判断下是否绑定了卡
@Override
public void next() {
// TODO Auto-generated method stub
//判断用户是否已经绑定,如果已经绑定,再继续执行,否则,提示一下用户,sim卡需要绑定。然后直接retrun
if (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
<EditText
android: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
@Override
public 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 {
@Override
public 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时判断下
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.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;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.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;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.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() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
// TODO Auto-generated method stub
sp=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" >
<TextView
android:layout_width="fill_parent"
android:layout_height="60dp"
android:text="联系人列表"
android:textSize="25sp"
android:gravity="center"/>
<ListView
android:id="@+id/listview_contactslist"
android:layout_width="fill_parent"
android:layout_height="fill_parent"/>
</LinearLayout>
activity,需要一个adapter
public class ContactsListAcitvity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.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{
@Override
public int getCount() {
// TODO Auto-generated method stub
return 0;
}
@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return null;
}
@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
return 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" >
<TextView
android:id="@+id/tv_contactlist_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/tv_contactlist_number"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/tv_contactlist_email"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
要在adapter的getView里去获取然后填充
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
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);
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
}
@Override
public String toString() {
return "Contact [name=" + name + ", number=" + number + ", email="
+ email + "]";
}
}
现在这个可以拿来查,但是可以抽出来作为一个单独的业务逻辑,让别人用,抽成一个类放到工具类,返回联系人列表
public class GetContactsList {
//getContentResolver需要在上下文中获取,需要在get时传进一个context
public 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);
//c2
Contact 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 ;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.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{
@Override
public int getCount() {
// TODO Auto-generated method stub
return list.size();
}
@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return null;
}
@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return 0;
}
@Override
public 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"/>
则启动时不能直接intent,而是forresult
public void selectpeople(View v){
//需要实现从系统的联系人里获取一个联系人信息
Intent intent = new Intent(this,ContactsListAcitvity.class);
startActivityForResult(intent, 100);
}
@Override
protected 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{
@Override
public void onItemClick(AdapterView<?> parent, View view, int position,long id) {
//根据位置获取联系人
Contact contact= list.get(position);
//只需显示number
String number = contact.getNumber();
//通过intent返回
Intent intent = new Intent();
intent.putExtra("number", number);
//resultcode自己定
setResult(200, intent);
finish();
}
}
activity3要接收这边的返回
@Override
protected 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 ;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.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 {
@Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
System.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 block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.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接口,获得坐标信息保存起来
这整个过程比较耗时,不应该放到广播的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 {
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
@Override
public void onCreate() {
// TODO Auto-generated method stub
LocationManager manager =(LocationManager) getSystemService(LOCATION_SERVICE);
manager.requestLocationUpdates("gps",0, 0, new MyLocationListener());
super.onCreate();
}
class MyLocationListener implements LocationListener{
@Override
public 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();
}
@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
}
}
}
if ("#*location*#".equals(addr)) {
abortBroadcast();
System.out.println("SMSReceiver.onReceive()"+body);
//获取到这个service
Intent 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
<Button
android: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;
@Override
protected 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响应
<TextView
android: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