文章目录

1.手机防盗——手势移动 & 抽取到父类中统一处理手势

我们基本上完成了手机防盗模块的功能,现在需要进行进一步优化——即在跳转页面的时候使用手势进行移动

手势移动的原理图如图所示:

Android开发实战《手机安全卫士》——4.“手机防盗”模块拓展 & 手势移动_android

  1. 修改SetupOneActivity,重写onTouchEvent()方法,并且定义一个GestureDetector类,用来完善跳转逻辑,代码如下:
package com.example.mobilesafe.activity;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.os.Bundle;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;

import com.example.mobilesafe.R;

public class SetupOneActivity extends AppCompatActivity {

/**
* 手势管理对象
*/
private GestureDetector mGestureDetector;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_setup_one);

// 创建手势管理的对象,用作管理在onTouchEvent(event)中传递过来的手势
mGestureDetector = new GestureDetector(this, new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
// 监听手势的移动
if (e1.getX() - e2.getX() > 0) {
// 由右向左,移动到下一页
Intent intent = new Intent(getApplicationContext(), SetupTwoActivity.class);
startActivity(intent);
finish();
// 开启平移动画
overridePendingTransition(R.anim.next_in_anim,R.anim.next_out_anim);
}
if (e1.getX() - e2.getX() < 0) {
// 由左向右,移动到上一页

}
return super.onFling(e1, e2, velocityX, velocityY);
}
});
}

/**
* 1.“下一页”按钮的点击方法
* @param view
*/
public void nextPage(View view){
Intent intent = new Intent(getApplicationContext(), SetupTwoActivity.class);
startActivity(intent);
finish();
// 开启平移动画
overridePendingTransition(R.anim.next_in_anim,R.anim.next_out_anim);
}

/**
* 2.监听屏幕上响应的事件类型(按下1次,移动多次,抬起1次)
* @param event
* @return
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
// 通过手势处理类,接收多钟类型的事件,用作处理
mGestureDetector.onTouchEvent(event);
return super.onTouchEvent(event);
}
}
  1. 为了体现代码的复用性,在activity包下新建BaseSetupActivity,作为SetupOneActivity,SetupTwoActivity,SetupThreeActivity,SetupFourActivity的父类,抽取公共方法,代码如下:
package com.example.mobilesafe.activity;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;

import com.example.mobilesafe.R;
import com.example.mobilesafe.constant.ConstantValue;
import com.example.mobilesafe.utils.SharedPreferencesUtil;
import com.example.mobilesafe.utils.ToastUtil;

public abstract class BaseSetupActivity extends AppCompatActivity {

/**
* 手势管理对象
*/
private GestureDetector mGestureDetector;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_base_setup);

// 创建手势管理的对象,用作管理在onTouchEvent(event)中传递过来的手势
mGestureDetector = new GestureDetector(this, new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
// 监听手势的移动
if (e1.getX() - e2.getX() > 0) {
// 由右向左,移动到下一页,直接调用子类的下一页方法
showNextPage();
}
if (e1.getX() - e2.getX() < 0) {
// 由左向右,移动到上一页,直接调用子类的上一页方法
showPrePage();
}
return super.onFling(e1, e2, velocityX, velocityY);
}
});
}


/**
* 1.监听屏幕上响应的事件类型(按下1次,移动多次,抬起1次)
* @param event
* @return
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
// 通过手势处理类,接收多钟类型的事件,用作处理
mGestureDetector.onTouchEvent(event);
return super.onTouchEvent(event);
}

/**
* 2.展示下一页的方法,由子类决定具体跳转到哪个页面
*/
protected abstract void showNextPage();

/**
* 3.展示上一页的方法,由子类决定具体跳转到哪个页面
*/
protected abstract void showPrePage();

/**
* 4.“下一页”按钮的点击方法
* @param view
*/
public void nextPage(View view) {
showNextPage();
}

/**
* 5.“上一页”按钮的点击方法
* @param view
*/
public void prePage(View view) {
showPrePage();
}

}
  1. 修改SetupOneActivity,继承BaseSetupActivity,简化代码,代码如下:
package com.example.mobilesafe.activity;

import android.content.Intent;
import android.os.Bundle;

import com.example.mobilesafe.R;

public class SetupOneActivity extends BaseSetupActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_setup_one);
}

// /**
// * 1.“下一页”按钮的点击方法
// * @param view
// */
// public void nextPage(View view){
// Intent intent = new Intent(getApplicationContext(), SetupTwoActivity.class);
// startActivity(intent);
// finish();
// // 开启平移动画
// overridePendingTransition(R.anim.next_in_anim,R.anim.next_out_anim);
// }


@Override
protected void showNextPage() {
Intent intent = new Intent(getApplicationContext(), SetupTwoActivity.class);
startActivity(intent);
finish();
// 开启平移动画
overridePendingTransition(R.anim.next_in_anim,R.anim.next_out_anim);
}

@Override
protected void showPrePage() {
// 空实现
}
}
  1. 其他三个界面同理,均继承父类,然后复制粘贴相关代码即可,以此来简化代码

2.手机防盗——功能列表界面布局编写

之前我们完成了4个导航界面的编写,现在来完成最后一个界面,即手机防盗功能列表界面的编写,如图所示:

Android开发实战《手机安全卫士》——4.“手机防盗”模块拓展 & 手势移动_android_02

  1. 修改activity_setup_over.xml,添加相应控件,代码如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".activity.SetupOverActivity">

<TextView
android:text="手机防盗"style="@style/TitleStyle"/>

<RelativeLayout
android:padding="5dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">

<TextView
android:text="安全号码"
android:textSize="18sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>

<TextView
android:id="@+id/tv_phone"
android:textSize="18sp"
android:text="0000"
android:layout_alignParentRight="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>

<ImageView
android:background="@drawable/listview_divider"
android:layout_below="@id/tv_phone"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</RelativeLayout>

<RelativeLayout
android:padding="5dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">

<TextView
android:text="防盗保护是否开启"
android:textSize="18sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>

<ImageView
android:id="@+id/iv_lock"
android:background="@drawable/lock"
android:layout_alignParentRight="true"
android:layout_width="25dp"
android:layout_height="25dp"/>

<ImageView
android:background="@drawable/listview_divider"
android:layout_below="@id/iv_lock"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</RelativeLayout>

<TextView
android:background="@drawable/gradient_box"
android:text="重新进入设置向导"
android:textSize="18sp"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>

</LinearLayout>
  1. 在res/drawable下新建gradient_box.xml,作为圆角图标的样式文件,代码如下:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">

<gradient
android:startColor="#ccc"
android:endColor="#ccc"
android:angle="45"/>

<padding
android:left="7dp"
android:top="7dp"
android:right="7dp"
android:bottom="7dp"/>

<corners android:radius="8dp"/>

</shape>

3.手机防盗——手机防盗界面逻辑编写

之前我们完成了4个导航界面的编写,现在来完成最后一个界面,即手机防盗界面的编写

  1. 新建selector_reset_setup_bg.xml,作为该布局的一个按钮中的状态选择器,代码如下:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" android:drawable="@drawable/gradient_box"/>
<!-- 使用android提供的透明色 -->
<item android:drawable="@android:color/transparent"/>
</selector>
  1. 修改activity_setup_over.xml,完善布局,代码如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".activity.SetupOverActivity">

<TextView
android:text="手机防盗"style="@style/TitleStyle"/>

<RelativeLayout
android:padding="5dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">

<TextView
android:text="安全号码"
android:textSize="18sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>

<TextView
android:id="@+id/tv_phone"
android:textSize="18sp"
android:text="0000"
android:layout_alignParentRight="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>

<ImageView
android:background="@drawable/listview_divider"
android:layout_below="@id/tv_phone"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</RelativeLayout>

<RelativeLayout
android:padding="5dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">

<TextView
android:text="防盗保护是否开启"
android:textSize="18sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>

<ImageView
android:id="@+id/iv_lock"
android:background="@drawable/lock"
android:layout_alignParentRight="true"
android:layout_width="25dp"
android:layout_height="25dp"/>

<ImageView
android:background="@drawable/listview_divider"
android:layout_below="@id/iv_lock"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</RelativeLayout>

<TextView
android:id="@+id/tv_reset_setup"
android:background="@drawable/selector_reset_setup_bg"
android:text="重新进入设置向导"
android:textSize="18sp"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>

<TextView
android:background="@android:color/darker_gray"
android:text="功能简介"
android:textSize="18sp"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#000"
android:textSize="18sp"
android:gravity="center_vertical"
android:drawableLeft="@android:drawable/star_big_on"
android:layout_margin="5dp"
android:text="GPS追踪#*location*#"/>

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#000"
android:textSize="18sp"
android:gravity="center_vertical"
android:drawableLeft="@android:drawable/star_big_on"
android:layout_margin="5dp"
android:text="播放报警音乐#*alarm*#"/>

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#000"
android:textSize="18sp"
android:gravity="center_vertical"
android:drawableLeft="@android:drawable/star_big_on"
android:layout_margin="5dp"
android:text="数据销毁#*wipedata*#"/>

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#000"
android:textSize="18sp"
android:gravity="center_vertical"
android:drawableLeft="@android:drawable/star_big_on"
android:layout_margin="5dp"
android:text="远程锁屏#*lockscreen*#"/>

</LinearLayout>
  1. 修改SetupOverActivity,给TextView注册点击事件,代码如下,
package com.example.mobilesafe.activity;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;

import com.example.mobilesafe.R;
import com.example.mobilesafe.constant.ConstantValue;
import com.example.mobilesafe.utils.SharedPreferencesUtil;

public class SetupOverActivity extends AppCompatActivity {

private TextView tv_phone;

private TextView tv_reset_setup;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
boolean setup_over = SharedPreferencesUtil.getBoolean(this, ConstantValue.SETUP_OVER, false);
if (setup_over){
// 密码输入成功,并且四个导航界面均设置完成,才停留在设置完成后的功能列表
setContentView(R.layout.activity_setupover);
// 初始化UI
initUI();
}else {
// 密码输入成功,若四个导航界面没有全部设置完成,则跳转到第一个导航界面
Intent intent = new Intent(this, SetupOneActivity.class);
startActivity(intent);
finish();
}
}

/**
* 1.初始化UI
*/
private void initUI() {
tv_phone = findViewById(R.id.tv_phone);
tv_reset_setup = findViewById(R.id.tv_reset_setup);
tv_reset_setup.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {

}
});
}
}

4.手机防盗——功能列表界面业务逻辑

之前我们完善了功能列表界面,现在需要进一步完善其点击事件逻辑

修改SetupOverActivity,完善相应逻辑,代码如下:

package com.example.mobilesafe.activity;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;

import com.example.mobilesafe.R;
import com.example.mobilesafe.constant.ConstantValue;
import com.example.mobilesafe.utils.SharedPreferencesUtil;

public class SetupOverActivity extends AppCompatActivity {

private TextView tv_phone;

private TextView tv_reset_setup;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
boolean setup_over = SharedPreferencesUtil.getBoolean(this, ConstantValue.SETUP_OVER, false);
if (setup_over){
// 密码输入成功,并且四个导航界面均设置完成,才停留在设置完成后的功能列表
setContentView(R.layout.activity_setupover);
// 初始化UI
initUI();
}else {
// 密码输入成功,若四个导航界面没有全部设置完成,则跳转到第一个导航界面
Intent intent = new Intent(this, SetupOneActivity.class);
startActivity(intent);
finish();
}
}

/**
* 1.初始化UI
*/
private void initUI() {
tv_phone = findViewById(R.id.tv_phone);
// 1.设置联系人号码
String phone = SharedPreferencesUtil.getString(this, ConstantValue.CONTACT_PHONE, "");
tv_phone.setText(phone);
// 2.重新设置条目被点击
tv_reset_setup = findViewById(R.id.tv_reset_setup);
tv_reset_setup.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(getApplicationContext(),SetupOneActivity.class);
startActivity(intent);
finish();
}
});
}
}

5.手机防盗——监听重启手机广播

现在手机防盗的跳转逻辑我们已经完成了,现在需要逐步实现相应的功能,即第二个导航界面的功能——下次重启手机,如果发现SIM卡变化,就会发送报警短信

实现原理如下:

  • 重启手机发送重启广播,编写广播接受者,接收系统重启广告
  • 接收到了广播后,调用onReceiver(),获取重启后的sim卡的序列号和存储在sp中的序列号
  • 比对一致,电话卡没有替换
  • 比对不一致,发送报警短信
  1. 在包下新建一个receiver包,用来存储广播接收器,然后新建一个BootReceiver,作为广播接收器
  2. 修改清单文件,对BootReceiver进行过滤器配置,并添加相应权限,代码如下:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.mobilesafe"
android:versionCode="1"
android:versionName="1.0.0">

<!-- android:versionCode 本地应用版本号是1,版本号是2,有必要提示用户更新 -->
<!--
android:versionName 本地应用版本名,假设版本名为1.0.0,它们所代表的意义如下:
第一位:项目有重大更新(代码重构,大部分功能添加,界面整体添加)
第二位:更新部分功能
第三位:一般代表修复原有版本的bug
-->
<!-- 添加网络权限 -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.SEND_SMS"/>

<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme"
android:usesCleartextTraffic="true">
<receiver
android:name=".receiver.BootReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</receiver>

<activity android:name=".activity.BaseSetupActivity" />
<activity android:name=".activity.ContactListActivity" />
<activity android:name=".activity.SetupFourActivity" />
<activity android:name=".activity.SetupThreeActivity" />
<activity android:name=".activity.SetupTwoActivity" />
<activity android:name=".activity.SetupOneActivity" />
<activity android:name=".activity.SetupOverActivity" />
<activity android:name=".activity.SettingActivity" />
<activity android:name=".activity.HomeActivity" />
<activity android:name=".activity.SplashActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

<uses-library
android:name="org.apache.http.legacy"
android:required="false" />
</application>

</manifest>

6.手机防盗——sim卡变更报警

上一节里,我们新建了一个广播接收器。在这一节中,我们将完善这个逻辑

修改BootReveicer,重写onReceive()方法,完善相应逻辑,代码如下:

package com.example.mobilesafe.receiver;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.telephony.SmsManager;
import android.telephony.TelephonyManager;

import com.example.mobilesafe.constant.ConstantValue;
import com.example.mobilesafe.utils.SharedPreferencesUtil;

public class BootReceiver extends BroadcastReceiver {

@Override
public void onReceive(Context context, Intent intent) {
// 1.获取开启后手机的sim卡的序列号
TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
//String simSerialNumber = tm.getSimSerialNumber();
String simSerialNumber = "SIM卡序列号变化";
// 2.sp中存储的序列卡号
String sim_number = SharedPreferencesUtil.getString(context, ConstantValue.SIM_NUMBER, "");
// 3.比对
if (!simSerialNumber.equals(sim_number)){
// 4.发送短信给选中联系人号码
SmsManager sms = SmsManager.getDefault();
sms.sendTextMessage("5556",null,"sim Change!!",null,null);
}
}
}