[安卓]手机管家(八)防盗之业务逻辑

一. 绑定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"/>


点那个联系人要退出,然后把结果给setup3

则启动时不能直接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);

 FLAG_ACTIVITY_NEW_TASK: 设置此状态, 首先会查找是否存在和被启动的Activity具有相同的亲和性的任务栈
如果有,刚直接把这个栈整体移动到前台,并保持栈中的状态不变,即栈中的activity顺序不变,如果没有,则新建一个栈来存放被启动的activity

关于播放音乐有两种写法,音乐文件放在SD卡上
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的文件夹

防止声音调的低,用代码调到最高,需要AudioManager,是一个service

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接口,获得坐标信息保存起来

网络定位在web早起用得比较多,由于现在IP的数量级巨大,通过子网链接,比较乱,定不准,无法精确定位,现在会用基站定位,根据与各个基站位置来定位
虽然只能与一个基站通信,其实可以连接到很多基站,基站的覆盖范围很广,会有交叉

不过更好的是GPS定位

由于启动location是要时间的,我们在代码里不能一声明了LocationManager就往下执行,这样会出错,所以需要一个callback,说我启动好了,更新了坐标,再往下执行
这里需要传一个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 {
	@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			
		}		
	}
}


receiver

 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




深度学习是机器学习的一个子领域,它基于人工神经网络的研究,特别是利用多层次的神经网络来进行学习和模式识别。深度学习模型能够学习数据的高层次特征,这些特征对于图像和语音识别、自然语言处理、医学图像分析等应用至关重要。以下是深度学习的一些关键概念和组成部分: 1. **神经网络(Neural Networks)**:深度学习的基础是人工神经网络,它是由多个层组成的网络结构,包括输入层、隐藏层和输出层。每个层由多个神经元组成,神经元之间通过权重连接。 2. **前馈神经网络(Feedforward Neural Networks)**:这是最常见的神经网络类型,信息从输入层流向隐藏层,最终到达输出层。 3. **卷积神经网络(Convolutional Neural Networks, CNNs)**:这种网络特别适合处理具有网格结构的数据,如图像。它们使用卷积层来提取图像的特征。 4. **循环神经网络(Recurrent Neural Networks, RNNs)**:这种网络能够处理序列数据,如时间序列或自然语言,因为它们具有记忆功能,能够捕捉数据中的时间依赖性。 5. **长短期记忆网络(Long Short-Term Memory, LSTM)**:LSTM 是一种特殊的 RNN,它能够学习长期依赖关系,非常适合复杂的序列预测任务。 6. **生成对抗网络(Generative Adversarial Networks, GANs)**:由两个网络组成,一个生成器和一个判别器,它们相互竞争,生成器生成数据,判别器评估数据的真实性。 7. **深度学习框架**:如 TensorFlow、Keras、PyTorch 等,这些框架提供了构建、训练和部署深度学习模型的工具和库。 8. **激活函数(Activation Functions)**:如 ReLU、Sigmoid、Tanh 等,它们在神经网络中用于添加非线性,使得网络能够学习复杂的函数。 9. **损失函数(Loss Functions)**:用于评估模型的预测与真实值之间的差异,常见的损失函数包括均方误差(MSE)、交叉熵(Cross-Entropy)等。 10. **优化算法(Optimization Algorithms)**:如梯度下降(Gradient Descent)、随机梯度下降(SGD)、Adam 等,用于更新网络权重,以最小化损失函数。 11. **正则化(Regularization)**:技术如 Dropout、L1/L2 正则化等,用于防止模型过拟合。 12. **迁移学习(Transfer Learning)**:利用在一个任务上训练好的模型来提高另一个相关任务的性能。 深度学习在许多领域都取得了显著的成就,但它也面临着一些挑战,如对大量数据的依赖、模型的解释性差、计算资源消耗大等。研究人员正在不断探索新的方法来解决这些问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值