zoukankan      html  css  js  c++  java
  • 手机卫士项目

    手机卫士项目

    下载地址http://download.csdn.net/detail/miaozhenzhong/9622004

    1. 项目功能描述:

    1. 手机防盗功能:远程销毁数据,远程锁屏,远程警报, SIM卡变更报警, GPS追踪

    2. 通讯卫士: 来电和短信黑名单的管理

    3. 软件管理: 应用的列表展示,应用的卸载,运行与分享

    4. 流量管理: 显示所有应用的上传和下载流量

    5. 进程管理: 显示所有运行进程列表和内存占用大小,对选中的进程进行一键清理

    6. 缓存清理:清理缓存

    7. 高级工具: 手机归属地查询,短信备份与还原,程序锁和常用电话查询

    8. 设置中心: 手机归属地服务,归属地显示风格,归属地显示位置,程序锁服务

    9. 手机杀毒: 对手机中安装的所有应用进行病毒查杀,发现危险应用进行卸载

    2. 项目功能与技术分解

    功能

    技术点

    功能一:欢迎界面及版本更新检查

    1. 使Activity界面没有标题或通知栏

    theme, style

    2. 显示界面布局

    LinearLayout

    3. 自定义旋转进度条

    <rotate>, indeterminateDrawable

    4. 得到应用的版本号

    PackageManger

    5. 显示透明,缩放,旋转动画

    AlphaAnimation,ScaleAnimation,RotateAnimation

    6. 拷贝assert的db文件到files

    AssertManager, 文件读写

    7. 版本更新流程

    画图分析

    8. 联网请求远程服务器数据

    URL, HttpUrlConnection/HttpClient/Volley

    9. 解析xml/json数据并封装到对象中

    XmlPullJSONObjectGSON

    10. 分线程网络请求后UI界面更新

    Thread + Handler

    11. 将apk保存在sd

    Environment, Context

    12. 读取手机联网状态

    ConnectivityManager

    功能二:主界面的显示相关功能

    显示主界面及操作

    GridView, BaseAdapter

    显示带输入框的修改名称Dialog

    AlertDialog

    自定义名称的存储与读取

    SharedPreference

    显示密码设置与登陆界面

    自定义内容布局的AlertDialog

    密码的存储与读取

    SharedPreference

    密码加密处理

    MD5加密

    连续2back才退出应用

    KeyEvent处理, Handler

    功能四:手机防盗的设置

    设置流程

    画图分析

    各个设置界面

    <RelativeLayout>, <LinearLayout>

    <style>, <shape><selector>

    设置界面之间的跳转动画

    <translate>, overridePendingTransition()

    绑定当前手机中的SIM

    TelephonyManager,SharedPreference, CheckBox

    显示手机联系人列表

    ContentResolver,Phone,Cursor,ListView,BaseAdapter,ProgressDialog, Handler, Thread

    设置页面得到选择的某个联系人号

    startActivityForResult(), onActivityResult(), setResult()

    使当前应用能获取设置管理权限

    DevicePolicyManager, DeviceAdminReceiver,

    <receiver>配置

    开机检查SIM卡有没有更换

    BroadcastReceiver及配置, SmsManager

    短信命令实现gps追踪,远程数据销毁,远程锁屏,远程报警功能

    短信BroadcastReceivere及配置,

    LocationManager,DevicePolicyManager, MediaPlayer

    功能:手机归属地查询与来电显示

    加载手机归属地数据库文件

    流程分析, AsyncTask, ProgressDialog,

    SD卡文件读写

    查询手机归属地

    APIDemo动画效果,SQLiteDatabase,

    手机号归属地规则

    设置显示风格

    AlertDialog, SharedPreference

    设置显示的位置

    TouchEvent,LayoutParams, SharedPreference

    来电显示归属地

    Service,TelephonyManager, WindowManager,LayoutParams,

    SharedPreference

    功能六:通讯卫士

    黑名单管理

    SqliteOpenHelper, SqliteDataBase

    ListActivity, ArrayAdapter

    ContextMenu, AlertDialog

    黑名单来电与短信拦截

    Service, AIDL挂断电话,

    短信BroadcastReceiver

    功能:软件管理

    应用的列表显示,卸载,运行与分享

    PackageManager,Map<Boolean, List<AppInfo>>,AsyncTask,

    BaseAdapter, PopupWindow,

    分享/卸载/运行Intent

    功能:程序锁

    应用的列表显示, 加锁与解锁

    SqliteDatabase, TranslateAnimation,

    ContentProvider, ContentResolver,

    ContentObsver, Service,

    Thread,ActivityManager

     

    功能: 任务管理

    显示系统和第三方应用进程列表

    PackageManager, ActivityManager,

    AsyncTask, ListView,BaseAdapter,

    Map<Boolean,List<TaskInfo>>

    内存的清理

    ActivityManager

    清理缓存的widget

    AppWidgetProvider,<appwidget-provider>

    RemoteView, Service,

    PendingIntent, Timer/TimerTask

    功能十:系统优化

    清理缓存

    PackageManager, AIDL,

    反射调用@hide的方法,锁定List,

    清理缓存的intent

    功能十一:流量管理

    应用流量列表显示

    SlidingDrawer, PackageManager,

    ResolveInfo, TrafficStats

    功能十二:高级工具

    常用手机号查询

    ExpandableListView, BaseExpandableListAdapter, AssetManager, SQLiteDatabase,

    打电话Intent

    备份手机中的所有短信数据

    ContentResolver, 短信Uri, Cursor,

    Gson, SD文件操作

    还原备份的短信数据

    同上, ProgressDialog

    功能十三:手机杀毒

    理解病毒与杀毒软件

    计算机病毒与手机病毒

    杀毒软件的基本原理

    手机杀毒的界面

    旋转动画RotateAnimation

    自定义ProgressBar

    动态添加视图viewgroup.addView(view, index)

    扫描应用, 查杀病毒

    拷贝包含病毒数据的db文件

    得到所有应用的名称和签名 PackageManager

    对应用签名进行MD5加密

    异步查找, 同步显示进度: AsyncTask毒应用

    3. 应用功能详解

    3.1. 功能一: 欢迎界面及版本更新检查()

    1) 应用结构分析

    创建一个新的应用时,需要整个应用的包结构进行一个设计, 应用包的组织大致有两种方法

    方式:模块来组织代码的包结构,大型的应用比较合适

    办公软件

    开会模块 com.atguigu.meeting

    发工资模块     com.atguigu.money

    出差模块 com.atguigu.travel

    方式二: 类型来组织代码的包结构小型应用比较合适

    手机卫士:

    应用界面相关    com.atguigu.ms. activity|ui

    显示列表的适配器   com.atguigu.ms.adapter

    数据对象封装       com.atguigu.ms.bean|domain|entity

    自定义视图    com.atguigu.ms.view|widget

    复杂业务   com.atguigu.ms.engine

    数据持久化    com.atguigu.ms.dao

    广播接收者    com.atguigu.ms.receiver  

    后台服务    com.atguigu.ms.service

                内容提供者         com.atguigu.ms.provider

    相关工具类   com.atguigu.ms.util

                访问网络的类       com.atguigu.ms.net|api  APIClient

    2) 界面布局

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

        android:id="@+id/ll_welcome_root"

        android:layout_width="fill_parent"

        android:layout_height="fill_parent"

        android:orientation="vertical" 

        android:gravity="bottom|center_horizontal"

        android:background="@drawable/logo">

        <TextView

            android:id="@+id/tv_welcome_version"

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:text="版本号: 1.0" 

            android:textSize="20sp"

            android:textColor="#000000"

            android:layout_marginBottom="20dp"/>

        <ProgressBar

            android:layout_width="wrap_content"

            android:layout_height="wrap_content" 

            android:layout_marginBottom="50dp"/>

    </LinearLayout>

    3) 定义旋转进度条

    定义进度条的旋转动画,指定旋转图片

    <rotate xmlns:android="http://schemas.android.com/apk/res/android"

        android:drawable="@drawable/progess"/>    //注意此属性不能提示

    引入定义的动画

    android:indeterminateDrawable="@anim/anim_loding_progress"  //进度动画

    android:indeterminateDuration="700"  //旋转一周持续的时间

    4) 动画效果

    AlphaAnimation animation =new AlphaAnimation(0.0f, 1.0f);

    animation.setDuration(2000);

    mLinearLayout.startAnimation(animation);

    5) 获取应用的当前版本号

    PackageManager packageManager =context.getPackageManager();

    PackageInfo packageInfo = packageManager.getPackageInfo(context.getPackageName(), 0);

    String version = packageInfo.versionName;

    6) 将界面设置为无标题或全屏显示

    动态编码的方式:

    // 去掉窗口标题

    requestWindowFeature(Window.FEATURE_NO_TITLE);

    // 隐藏顶部的状态栏

    getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);

    setContentView();

    配置方式:

    //方式(不建议使用)

    android:theme="@android:style/Theme.Black.NoTitleBar"

    android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen"

     

    //方式三

    <style name="AppTheme" parent="AppBaseTheme">

    <item name="android:windowNoTitle">true</item><!--没有标题-->

    </style>

    7) 拷贝assertdb文件files

    /**

     * assets目录下的assert下的address.db拷贝到

     * /data/data/com.atguigu.ms/files/

     * @param dbname

     */

    private void copyDB(String dbname) {

    File file = new File(getFilesDir(),dbname);

    if(file.exists()&&file.length()>0){

    Log.i (TAG, dbname+"数据库已经存在,不需要拷贝了...");

    }else{

    try {

    InputStream is = getAssets().opendbname);

    FileOutputStream fos = new FileOutputStream(file);

    int len = 0;

    byte buffer[] =new byte[1024];

    while((len = is.read(buffer))!=-1){

    fos.write(buffer, 0, len);

    }

    is.close();

    fos.close();

    } catch (IOException e) {

    e.printStackTrace();

    }

    }

    }

    8) 应用版本更新检查流程

    画图分析

    9) 读取手机联网状态:

    /**

     * 检查当前网络是否可用

    */

    public static boolean isNetConnected (Context context) {

         boolean connected = false;

    // 获取手机所有连接管理对象(包括对wi-fi,net等连接的管理)

    ConnectivityManager manager = (ConnectivityManager) context

    .getSystemService(Context.CONNECTIVITY_SERVICE);

    // 获取activeNetworkInfo对象

    NetworkInfo networkInfo = manager.getActiveNetworkInfo();

    if(networkInfo!=null) {

             // 得到是否连接状态

    connected = networkInfo.isConnected();

    }

    return connected;

    }

    10) 设计服务器端版本更新信息数据格式

    l XML数据格式

    <?xml version="1.0" encoding="UTF-8"?>

    <updateinfo>

        <version>1.0</version>

        <apkUrl>http://192.168.173.1:8080/SecurityServer/Security.apk</apkUrl>

        <desc>解决了上一个版本中的不少bug,优化了网络请求逻辑</desc>

    </updateinfo>

    l JSON数据格式

    {

    version:"1.1",

    apkUrl:"http://192.168.173.1:8080/SecurityServer/Security.apk",

    desc:"解决了上一个版本中的不少bug,优化了网络请求逻辑"

    }

    11) 联网请求远程服务器数据

    //创建url地址对象

    URL url =new URL(urlPath);

    //打开连接

    HttpURLConnection connection = (HttpURLConnection) url.openConnection();

    //设置可以从服务器端读取返回的数据

    connection.setDoInput(true);

    //设置连接超时的时间

    connection.setConnectTimeout(2000);//5000

    //得到服务器端返回的数据流

    InputStream is = connection.getInputStream();

    12) 使用XmlPull解析xml文件

    private UpdateInfo parseXml(InputStream is)throws Exception {

    UpdateInfo info = new UpdateInfo();

    XmlPullParser pullParser = XmlPullParserFactory.newInstance().newPullParser();

    pullParser.setInput(is, "utf-8");

    int eventType = pullParser.getEventType();

    while (eventType != XmlPullParser.END_DOCUMENT) {

    if (eventType == XmlPullParser.START_TAG) {

    String tagName = pullParser.getName();

    if ("version".equals(tagName)) {

    info.setVersion(pullParser.nextText());

    } else if ("apkUrl".equals(tagName)) {

    info.setApkUrl(pullParser.nextText());

    } else if ("desc".equals(tagName)) {

    info.setDesc(pullParser.nextText());

    }

    }

    eventType = pullParser.next();

    }

    return info;

    }

    13) 使用JsonObject解析json数据

    private UpdateInfo parseJson(InputStream is)throws Exception {

    //将数据流封装为json对象

    String jsonString = Utils.readString(is);

    JSONObject object = new JSONObject(jsonString);

    //得到json对象中的数据封装为updateInfo对象

    UpdateInfo info = new UpdateInfo();

    info.setVersion(object.getString("version"));

    info.setApkUrl(object.getString("apkUrl"));

    info.setDesc(object.getString("desc"));

     

    return info;

    }

     

    //使用Gson框架

    UpdateInfo = new Gson().fromJson(jsonString, new TypeToken<UpdateInfo>(){}.getType())

    14) 分线程网络请求后UI界面更新

    //handler在主线程中处理分线程发过来的结果消息

    private Handler handler =new Handler() {

    public void handleMessage(android.os.Message msg) {

    switch (msg.what) {

    case REQUEST_UPDATE_ERROR:  

    break;

    case REQUEST_UPDATE_SUCCESS:

    break;

    case REQUEST_APK_ERROR:

    break;

    case REQUEST_APK_SUCCESS:

    break;

    default:

    break;

    }

    }

    };

     

    //启动分线程去请求服务器得到最新版本信息

    new Thread(new Runnable() {

    @Override

    public void run() {

    try {

    info = APIClient.getUpdateInfo();

    handler.sendEmptyMessage(REQUET_UPDATE_SUCCESS);

    } catch (Exception e) {

    e.printStackTrace();

    handler.sendEmptyMessage(REQUEST_UPDATE_ERROR);

    }

    }

    }).start();

    15) 提示去下载和显示下载进度

    /**

     * 显示diaog,提示用户去下载

     */

    private void showDownloadDialog() {

    new AlertDialog.Builder(this)ddd.setTitle("版本更新")

    .setMessage("有更新的版本,是否立即下载更新?")

    .setPositiveButton("下载",new DialogInterface.OnClickListener() {

    @Override

    public void onClick(DialogInterface dialog,int which) {

    startDownloadApk();

    }

    }).setNegativeButton("取消",new DialogInterface.OnClickListener() {

    @Override

    public void onClick(DialogInterface dialog,int which) {

    toMain();

    }

    }).show();

    }

     

    /**

     * 开启分线程下载apk,并进行安装更新

     */

    private void startDownloadApk() {

    //下载的url

    final String apkUrl =info.getApkUrl();

    //保存apk的本地file对象

    createApkFile();

    //显示下载进度的progressDialog

    showDownloadProgress();

    new Thread(new Runnable() {

    @Override

    public void run() {

    try {

    APIClient.downloadAPK(apkUrl,apkFile,pd);

    handler.sendEmptyMessage(DOWNLOAD_APK_SUCCESS);

    } catch (Exception e) {

    e.printStackTrace();

    handler.sendEmptyMessage(REQUEST_APK_ERROR);

    }

    }

    }).start();

    }

    16) apk保存在sd卡中:

    File sdFile = Environment.getExternalStorageDirectory();

    apkFile = new File(sdFile,"update.apk");

    /**或者**/

    File filesDir = getExternalFilesDir(null);

    apkFile = new File(filesDir,"update.apk");

    17) 安装APK 

    Intent intent = new Intent();

    intent.setAction(Intent.ACTION_VIEW);

    intent.setDataAndType(Uri.fromFile(apkFile),"application/vnd.android.package-archive");

    context.startActivity(intent);

    18) 相关权限

    <!-- 读取手机联网状态的权限 -->

    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

    <!-- 读取wifi状态的权限-->

    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />

    <!-- 请求网络的权限 -->

    <uses-permission android:name="android.permission.INTERNET" />

    <!-- sd操作的权限-->

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

    3.2. 功能二: 主界面的显示和功能项名称修改

    1) 主界面的显示

    private static final String[]NAMES =new String[] {

    "手机防盗","通讯卫士","软件管理","流量管理","进程管理",

    "手机杀毒","缓存清理","高级工具","设置中心" };

    private static final int[]ICONS =new int[] { R.drawable.widget01,

    R.drawable.widget02,R.drawable.widget03, R.drawable.widget04,

    R.drawable.widget05, R.drawable.widget06,R.drawable.widget07,

    R.drawable.widget08, R.drawable.widget09 };

    <GridView

        android:id="@+id/gv_main"

        android:layout_width="match_parent"

        android:layout_height="wrap_content"

        android:numColumns="3" 

        android:verticalSpacing="8dip">

    </GridView>

    <?xml version="1.0" encoding="utf-8"?>

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

        android:layout_width="80dp"

        android:layout_height="80dp"

        android:orientation="vertical" 

        android:gravity="center">

        <ImageView

            android:id="@+id/iv_item_main_icon"

            android:layout_width="60dp"

            android:layout_height="60dp"

            android:src="@drawable/ic_launcher"

            android:scaleType="fitXY"/>

        <TextView

            android:id="@+id/tv_item_main_name"

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:text="手机防盗" 

            android:textSize="18sp"

            android:layout_marginTop="2dp"

            android:textColor="#000000"/>

    </LinearLayout>

    public View getView(int position, View convertView, ViewGroup parent) {

    if (convertView ==null) {

    convertView = inflater.inflate(R.layout.main_item,null);

    }

    ImageView imageView = (ImageView) convertView.findViewById(R.id.iv_item_main_icon);

    TextView textView = (TextView) convertView.findViewById(R.id.tv_item_main_name);

    imageView.setImageResource(ICONS[position]);

    textView.setText(NAMES[position]);

     

    return convertView;

    }

    2) 显示带输入框的Dialog

    final EditText editText =new EditText(this);

    editText.setHint("输入新的名称");

    new AlertDialog.Builder(this)

    .setView(editText)

    .setTitle("名称修改")

    .setPositiveButton("确定",new DialogInterface.OnClickListener() {

    @Override

    public void onClick(DialogInterface dialog,int which) {

                    

    }

    }).setNegativeButton("取消",null).show();

    3) 自定义名称的存储与读取

    SharedPreferences preferences= getSharedPreferences("config", Context.MODE_PRIVATE);

    //保存数据

    Editor edit = preferences.edit().putString("lost_name", name).commit();

    //读取数据

    String lostName = preferences.getString("lost_name",null);

    4) 显示进入手机防盗界面的Dialog

    设置过密码的判断

    通过SharedPreferences存储密码来实现

    设置密码的布局

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

        android:layout_width="300dip"

         android:background="#ffffff"

        android:layout_height="wrap_content"

        android:gravity="center_horizontal"

        android:orientation="vertical" >

        <TextView

            android:layout_width="fill_parent"

            android:layout_height="50dip"

            android:background="#E0EEEE"

            android:gravity="center"

            android:text="设置密码"

            android:textSize="18sp" />

        <EditText

            android:id="@+id/et_pwd_set_pwd"

            android:layout_width="280dip"

            android:layout_height="wrap_content"

            android:hint="请输入密码"

            android:inputType="textPassword" />

        <EditText

            android:id="@+id/et_pwd_set_confirm"

            android:layout_width="280dip"

            android:layout_height="wrap_content"

            android:hint="请再次输入密码"

            android:inputType="textPassword" />

        <LinearLayout

            android:layout_width="280dip"

            android:layout_height="wrap_content"

            android:gravity="center_horizontal"

            android:orientation="horizontal">

            <Button

                android:id="@+id/btn_pwd_set_confirm"

                android:layout_width="0dp"

                android:layout_height="wrap_content"

                android:layout_weight="1"

                android:text="确定" />

            <Button

                android:id="@+id/btn_pwd_set_cancel"

                android:layout_width="0dp"

                android:layout_height="wrap_content"

                android:layout_weight="1"

                android:text="取消" />

        </LinearLayout>

    </LinearLayout>

    登陆的布局

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

        android:layout_width="300dip"

         android:background="#ffffff"

        android:layout_height="wrap_content"

        android:gravity="center_horizontal"

        android:orientation="vertical" >

        <TextView

            android:layout_width="fill_parent"

            android:layout_height="50dip"

            android:background="#E0EEEE"

            android:gravity="center"

            android:text="登  陆"

            android:textSize="18sp" />

        <EditText

            android:id="@+id/et_pwd_login_pwd"

            android:layout_width="280dip"

            android:layout_height="wrap_content"

            android:hint="请输入密码"

            android:inputType="textPassword" />

        <LinearLayout

            android:layout_width="280dip"

            android:layout_height="wrap_content"

            android:gravity="center_horizontal"

            android:orientation="horizontal">

            <Button

                android:id="@+id/btn_pwd_login_confirm"

                android:layout_width="0dp"

                android:layout_height="wrap_content"

                android:layout_weight="1"

                android:text="确定" />

            <Button

                android:id="@+id/btn_pwd_login_cancel"

                android:layout_width="0dp"

                android:layout_height="wrap_content"

                android:layout_weight="1"

                android:text="取消" />

        </LinearLayout>

    </LinearLayout>

    5) 自定义Button

    l 9patch图片的制作

    1) 指定patch区域(复制区域)

    2) 指定能显示内容的区域

    l Selector多状态图片配置

    <selector xmlns:android="http://schemas.android.com/apk/res/android" >

        <item android:state_pressed="true"    //item必须在前面

             android:drawable="@drawable/button_pressed"/>

        <item android:drawable="@drawable/button_normal"/>

    </selector>

    6) 连续点击回退键,才退出应用

    监听back键的up事件

    使用Handler进行延迟消息处理

    private boolean exit =false;//只有它为true才退出

    private Handlerhandler =new Handler(new Handler.Callback() {

    @Override

    public boolean handleMessage(Message msg) {

    if(msg.what==1) {

    Log.e("TAG","2s内没有再点back");

    exit = false;//2s内没有再点back,下次点back不能退出

    }

    return false;

    }

    });

    @Override

    public boolean onKeyUp(int keyCode, KeyEvent event) {

    if(keyCode==KeyEvent.KEYCODE_BACK) {

    if(!exit) {

    exit = true;//标识再点一次back就退出

    handler.sendEmptyMessageDelayed(1, 2000);

    return true;

    } else {

    handler.removeMessages(1);

    }

    }

    return super.onKeyUp(keyCode, event);

    }

    7) 对密码进行MD5加密

    对于应用中保存的密码,需要做加密处理再保存起来,不至于将用户密码泄露

    项目中用得最多的一种加密方式: MD5加密  明文123456  密文

    l MD5加密是将指定字符加密为一个32位的字符串,一个不可逆的操作

    在线MD5解密是通过保存很多明文与密文的方式来实现解密的

    1. 先将指定的字符串转换为一个16位的byte[]

    2. 遍历取出数组中的每个byte元素

    3. 将取出的byte值与255(0xff)做与运算(&)后得到一个255以内的数值

    4. 将得到的数值转换为16进制的字符串,如果它只有一位,在它的前面补0

    5. 将生成的16个二位16进制形式的字符串连接起来,它就是md5加密后的32位字符串

    public static String md5(String pwd) {

    StringBuffer sb = new StringBuffer();

    try {

    //创建用于加密的加密对象

    MessageDigest digest = MessageDigest.getInstance("md5");

    //将字符串转换为一个16位的byte[]

    byte[] bytes = digest.digest(pwd.getBytes("utf-8"));

    for(byte b : bytes) {//遍历

    //255(0xff)做与运算(&)后得到一个255以内的数值

    int number = b & 255;//也可以& 0xff

    //转化为16进制形式的字符串,不足2位前面补0

    String numberString = Integer.toHexString(number);

    if(numberString.length()==1) {

    numberString = 0+numberString;

    }

    //连接成密文

    sb.append(numberString);

    }

    } catch (Exception e) {

    e.printStackTrace();

    }

    return sb.toString();

    }

    3.3. 功能三: 手机防盗设置()

    1) 设置流程

    画图分析

    2) 各个设置界面布局

    关键技术点:< style>, <shape>, < RelativeLayout>, < LinearLayout>

    布局文件

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

        android:layout_width="match_parent"

        android:layout_height="match_parent"

        android:background="@drawable/title_background"

        android:orientation="vertical" >

        <!--标题-->

        <TextView

         android:id="@+id/tv_title"

         android:layout_width="fill_parent"

         android:layout_height="50dp"

         android:text="1.欢迎使用手机防盗" 

         android:gravity="center"

         android:textSize="25sp"

         android:background="@color/title_text_color"

         android:layout_marginBottom="10dp"/>

    <TextView

         android:id="@+id/tv_guide_title"

         android:layout_width="fill_parent"

         android:layout_height="wrap_content"

         android:text="您的手机防盗卫士: "

         android:textSize="20sp" />

        <!-- 带星号图标的文本 -->

        <TextView 

            style="@style/SetupGuideContent"

            android:text="@string/guide1_content"/>

        <TextView 

            style="@style/SetupGuideItem"

            android:text="@string/guide1_item1"/>

        <TextView 

            style="@style/SetupGuideItem"

            android:text="@string/guide1_item2"/>

        <TextView 

            style="@style/SetupGuideItem"

            android:text="@string/guide1_item3"/>

        <TextView 

            style="@style/SetupGuideItem"

            android:text="@string/guide1_item4"/>

        <!-- 显示设置进度的图标 -->

        <LinearLayout 

            android:layout_width="match_parent"

            android:layout_height="wrap_content"

            android:layout_marginTop="8dip"

            android:gravity="center_horizontal"

            android:orientation="horizontal">

            <ImageView 

                android:layout_width="wrap_content"

                android:layout_height="wrap_content"

                android:src="@android:drawable/presence_online"

                android:contentDescription="@string/hello_world"/>

            <ImageView 

                android:layout_width="wrap_content"

                android:layout_height="wrap_content"

                android:src="@android:drawable/presence_invisible"

                android:contentDescription="@string/hello_world"/>

            <ImageView 

                android:layout_width="wrap_content"

                android:layout_height="wrap_content"

                android:src="@android:drawable/presence_invisible"

                android:contentDescription="@string/hello_world"/>

            <ImageView 

                android:layout_width="wrap_content"

                android:layout_height="wrap_content"

                android:src="@android:drawable/presence_invisible"

                android:contentDescription="@string/hello_world"/>

        </LinearLayout>

        <!—设置界面跳转的按钮 -->

        <RelativeLayout 

            android:layout_width="match_parent"

            android:layout_height="match_parent"

            android:paddingBottom="5dp">

            <Button

                android:id="@+id/btn_guide_next"

                android:text="@string/next"

                style="@style/SetupGuideNext"/>

        </RelativeLayout>

    </LinearLayout>

    l <style>的使用

    <!-- 防盗功能列表项-->

    <style name="SetupGuideItem">

        <item name="android:layout_width">match_parent</item>

        <item name="android:layout_height">wrap_content</item>

        <item name="android:textSize">18sp</item>

        <item name="android:drawableLeft">@android:drawable/btn_star_big_on</item>

        <item name="android:layout_marginTop">8dip</item>

        <item name="android:gravity">center_vertical</item>

    </style>

    <!-- 防盗设置界面"下一步"按钮-->

    <style name="SetupGuideNext">

        <item name="android:layout_width">wrap_content</item>

        <item name="android:layout_height">wrap_content</item>

        <item name="android:drawableRight">@drawable/next</item>

        <item name="android:layout_alignParentBottom">true</item>

        <item name="android:layout_alignParentRight">true</item>

    </style>

    <!-- 防盗设置界面"上一步"按钮-->

    <style name="SetupGuidePre">

        <item name="android:layout_width">wrap_content</item>

        <item name="android:layout_height">wrap_content</item>

        <item name="android:drawableRight">@drawable/previous</item>

        <item name="android:layout_alignParentBottom">true</item>

        <item name="android:layout_alignParentLeft">true</item>

    </style>

    l <shap>的使用

    <shape xmlns:android="http://schemas.android.com/apk/res/android"

        android:shape="rectangle" >

    <!-- 描边 -->

        <stroke

            android:width="0.51dip"

            android:color="#ffbc04e5" />

    <!-- 渐变 -->

        <gradient 

            android:startColor="#ffbc04e5"

            android:centerColor="#ffc823ed"

            android:endColor="#ffce30f2"/>

    </shape>

    3) 设置界面之间的跳转动画

    关键技术: <translate>, overridePendingTransition()

    <translate xmlns:android="http://schemas.android.com/apk/res/android"

        android:fromXDelta="-100%p"

        android:toXDelta="0"

        android:duration="400" >

    </translate>

     

    //启用Activity切换动画

    overridePendingTransition(R.anim.translate_right_in, R.anim.translate_left_out);

    4) 绑定当前手机中的SIM

    关键技术:  TelephonyManager, SharedPreference, CheckBox

    public static String getSimNumber(Context context) {

    TelephonyManager telephonyManager =

    (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);

    return telephonyManager.getSimSerialNumber();

    }

    5) 显示手机联系人列表:

    关键技术:  ContentResolver, Phone, Cursor, ListView, BaseAdapter, ProgressDialog, Handler, Thread

    /**

     * 得到所有联系人信息的集合

     */

    public List<ContactInfo> getContactInfos() {

    List<ContactInfo> list = new ArrayList<ContactInfo>();

    ContentResolver resolver =context.getContentResolver();

    String[] projection = { Phone.DISPLAY_NAME, Phone.NUMBER };

    Cursor cursor = resolver.query(Phone.CONTENT_URI, projection, null,null,null);

    while (cursor.moveToNext()) {

    String name = cursor.getString(0);

    String number = cursor.getString(1);

    list.add(new ContactInfo(name, number));

    }

    cursor.close();

    return list;

    }

    6) 设置页面得到选择的某个联系人号

    关键技术:  startActivityForResult(), onActivityResult(), setResult()

    protected void onActivityResult(int requestCode,int resultCode, Intent data) {

    if(requestCode==REQ_CONTACT_CODE && resultCode==2) {

    //显示选择的手机号

    String number = data.getStringExtra("number");

    et_guide_phoneNumber.setText(number);

    }

    }

    7) 开机检查SIM卡有没有更换

    关键技术:  开机BroadcastReceiver及配置, SmsManager

    public class BootCompleteReceiverextends BroadcastReceiver {

    @Override

    public void onReceive(Context context, Intent intent) {

    // 条件1:启动了防盗监听

    boolean isProtected = SpUtils.getInstance(context).getBoolean(SpUtils.IS_PROTECTED,false);

    if (!isProtected)

    return;

    // 条件2:当前手机SIM号与保存的SIM号不一致

    String currSimNumber = Utils.getSimNumber(context);

    String simNumber = SpUtils.getInstance(context).getString(SpUtils.SIM,null);

    if (simNumber !=null && simNumber.equals(currSimNumber))

    return;

    // 发送一个提示短信给保存的安全号

    String number = SpUtils.getInstance(context).getString(SpUtils.NUMBER,null);

    Log.e("TAG","number="+number);

    if (!Utils.isEmpty(number)) {

    SmsManager smsManager = SmsManager.getDefault();

    smsManager.sendTextMessage(number, null,"SIM卡有变更,手机可能被盗了!",null,null);

    }

    }

    }

    <receiver android:name=".receiver.BootCompleteReceiver">

        <intent-filter>

            <action android:name="android.intent.action.BOOT_COMPLETED" />

        </intent-filter>

    </receiver>

    8) 短信命令实现gps追踪,远程数据销毁,远程锁屏,远程报警功能

    关键技术:  短信BroadcastReceivere及配置, LocationManager, DevicePolicyManager, MediaPlayer

    读取接收到短信的BR

    public class SmsReceiverextends BroadcastReceiver {

    @Override

    public void onReceive(Context context, Intent intent) {

    Bundle bundle = intent.getExtras();

    Object[] pdus = (Object[]) bundle.get("pdus");

    byte[] pdu = (byte[]) pdus[0];

    SmsMessage smsMessage = SmsMessage.createFromPdu(pdu);

    String phoneNumber = smsMessage.getOriginatingAddress();

    String message = smsMessage.getMessageBody();

    if ("#location#".equals(message)) {//gps追踪

    abortBroadcast();

    Log.e("TAG","回送位置信息!");

    GpsUtils.sendLocation(context, safeNumber);

    } else if ("#reset#".equals(message)) {// 远程销毁数据(恢复出厂模式)

    abortBroadcast();

    Log.e("TAG","远程销毁数据!");

    Utils.resetPhone(context);

    } else if ("#lock#".equals(message)) {// 远程锁屏

    abortBroadcast();

    Log.e("TAG","远程锁屏!");

    Utils.lockScreen(context);

    } else if ("#alarm#".equals(message)) {// 报警音乐

    abortBroadcast();

    Log.e("TAG","报警音乐!");

    Utils.runAlarm(context, R.raw.jxmzf);

    }

    }

    }

    注册BR

    <receiver android:name=".receiver.SmsReceiver">

        <intent-filter android:priority="1000">

            <action android:name="android.provider.Telephony.SMS_RECEIVED" />

        </intent-filter>

    </receiver>

    远程销毁数据

    public static void resetPhone(Context context) {

    DevicePolicyManager manager = (DevicePolicyManager)

    context.getSystemService(Context.DEVICE_POLICY_SERVICE);

    manager.wipeData(0);

    }

    远程锁屏

    public static void lockScreen(Context context) {

    DevicePolicyManager manager = (DevicePolicyManager)

    context.getSystemService(Context.DEVICE_POLICY_SERVICE);

    manager.resetPassword("23456", 0);//重新设置密码

    manager.lockNow();//锁屏

    }

    警报音乐

    public static void runAlarm(Context context, int resourceId) {

    MediaPlayer mediaPlayer = MediaPlayer.create(context, resourceId);

    mediaPlayer.setVolume(1.0f, 1.0f);//设置最大音量

    mediaPlayer.start();

    }

    l GPS定位

    种定位方式:基于卫星(gps),基于网络(network),基于基站

    基于卫星: 定位慢,准确度高,受环境影响大

    北斗卫星导航系统(BDS)和美国GPS、俄罗斯GLONASS、欧盟GALILEO

    基于网络:定位快,准确度低,受环境影响小, 但手机必须联网

    基于基站:误差基站数量与远近有

    public void sendLocation(Context context, String number) {

    this.safeNumber = number;

    lm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);

    // 判断GPS是否正常启动

    if(!lm.isProviderEnabled(LocationManager.GPS_PROVIDER)) {

    MSUtils.showMsg(context,"GPS没有开启");

    return;

    }

    // 获取位置信息

    Location location = lm.getLastKnownLocation(LocationManager.GPS_PROVIDER);

    if(location!=null) {

    double longitude = location.getLongitude();

    double latitude = location.getLatitude();

    String result = "经度: "+longitude+",纬度: "+latitude;

    Log.e("TAG","发送经纬度: "+result);

    SmsManager.getDefault().sendTextMessage(number,null, result,null,null);

    }

    // 绑定监听

    // 参数1,设备:有GPS_PROVIDERNETWORK_PROVIDER两种

    // 参数2,位置信息更新周期,单位毫秒

    // 参数3,位置变化最小距离:当位置距离变化超过此值时,将更新位置信息

    // 参数4,监听

    // 备注:参数23,如果参数3不为0,则以参数3为准;参数30,则通过时间来定时更新;两者为0,则随时刷新

    lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 10000, 1,listener);

    }

    9) 激活应用的管理权限

    关键技术:  DevicePolicyManager, DeviceAdminReceiver, <receiver>

    对于第三方应用, 如果需要做锁屏,恢复出厂设置等操作,需要提前先激活当前应用的对应管理权限

    l Android 2.2 SDK提供了一个可管理和操作设备的APIDevicePolicyManager,使用可以接管手机的应用权限,对手机做出很多大胆的操作,比如锁屏恢复出厂设置设置密码、强制清除密码,修改密码、设置屏幕灯光渐暗时间间隔等操作。

    Manifest文件中定义配置

    <receiver

        android:name=".receiver.MyAdminReceiver"

        android:permission="android.permission.BIND_DEVICE_ADMIN" >

        <meta-data

            android:name="android.app.device_admin"

            android:resource="@xml/my_admin" />

        <intent-filter>

            <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />

        </intent-filter>

    </receiver>

    定义设备管理权限配置(/xml/my_admin)

    <device-admin xmlns:android="http://schemas.android.com/apk/res/android" >

        <uses-policies>

            <limit-password /> <!--设置密码的规则-->

            <watch-login /> <!--监控屏幕解锁尝试次数-->

            <reset-password /> <!--更改屏幕解锁密码-->

            <force-lock /> <!—强制锁屏-->

            <wipe-data /> <!--删除全部数据-->

            <expire-password /> <!—使用密码失效-->

            <encrypted-storage /> <!—存储数据进行加密 -->

            <disable-camera /> <!—使用相机失效-->

        </uses-policies>

    </device-admin>

    定义设备管理的receiver

    public class MyAdminReceiverextends DeviceAdminReceiver {

    }

    启动激活

    public static void activeDevince(Context context) {

    DevicePolicyManager manager = (DevicePolicyManager)

    context.getSystemService(Context.DEVICE_POLICY_SERVICE);

    ComponentName componentName = new ComponentName(context, MyAdminReceiver.class);

    if (!manager.isAdminActive(componentName)) {

    Intent intent = new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN);

    intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, componentName);

    context.startActivityForResult(intent, 1);

    }

    }

    判断是否激活

    private boolean isActive() {

    DevicePolicyManager manager = (DevicePolicyManager)

    getSystemService(Context.DEVICE_POLICY_SERVICE);

    ComponentName name = new ComponentName(this, DeviceAdminSampleReceiver.class);  

    return manager.isAdminActive(name);

    }

    10) 相关权限

    <!-- 请求电话状态信息 -->

    <uses-permission android:name="android.permission.READ_PHONE_STATE" />

    <!-- 读取手机联系人 -->

    <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" />

    <!-- 接收短信的权限 -->

    <uses-permission android:name="android.permission.RECEIVE_SMS" />

    <!-- 进行精确定位的权限 -->

    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

    3.4. 功能:手机归属地查询与来电显示

    1) 查询手机归属地

    关键技术:  APIDemo动画效果, SQLiteDatabase,手机号正则表达式,手机号归属地规则

    查询规则:

    手机号:11位数字, 第一个为: 1,第二位为: 3—8,7决定归属地

    匪警号码 : 3

    模拟器 : 4

    客服电话 : 5

    本地号码 : 6,7,8,9

    外地座机:大于或等于10, 0开头,2,32,3,4决定其归属地

    public static String getAddess(String number) {

    String address = number;

    SQLiteDatabase database = SQLiteDatabase.openDatabase(path,null,

    SQLiteDatabase.OPEN_READONLY);

    /*

     * 手机号:

     * 1. 11位数字

     *  2. 第一个为: 1

     *  3. 第二位为: 3--8

     */

    String reg = "^1[345678]\d{9}$";

    if(number.matches(reg)) {

    //手机号的归属地由其前7位来查询

    String sql = "select location from data2 where id=(select outkey from data1 where id=?)";

    Cursor cursor = database.rawQuery(sql,

    new String[]{number.substring(0, 7)});

    if(cursor.moveToNext()) {

    number = cursor.getString(0);

    } else {

    address = "未知地区手机号";

    }

    cursor.close();

    } else {

    switch (number.length()) {

    case 3:// 110,119,120

    address = "匪警号码";

    break;

    case 4:// 5554,5556

    address = "模拟器";

    break;

    case 5:// 10086,10010

    address = "客服电话";

    break;

    case 6:

    case 7:

    case 8:

    case 9:

    address = "本地号码";

    break;

    default://外地座机号

    if(number.startsWith("0") && number.length()>9) {

                       String sql = "select location from data2 where area =?";

    Cursor cursor = database.rawQuery(sql,

    new String[]{number.substring(1, 3)});

    if(cursor.moveToNext()) {

    String location = cursor.getString(0);

    address = location.substring(0, location.length()-2);

    break;

    }

    cursor = database.rawQuery("select location from data2 where area =?",

    new String[]{number.substring(1, 4)});

    if(cursor.moveToNext()) {

    String location = cursor.getString(0);

    address = location.substring(0, location.length()-2);

    break;

    }

    cursor.close();

    }

    break;

    }

    }

    return address;

    }

    2) 设置显示风格

    关键技术:  AlertDialog, SharedPreference

    private void setStyle() {

    String[] items = {"半透明","活力橙","苹果绿","孔雀蓝","金属灰"};

    new AlertDialog.Builder(this)

    .setTitle("选择颜色")

    .setSingleChoiceItems(items, 0,new DialogInterface.OnClickListener() {

    @Override

    public void onClick(DialogInterface dialog,int which) {

    SpUtils.getInstance(AToolActivity.this)

    .putInt(SpUtils.BG_COLOR_INDEX, which);

    }

    })

    .setPositiveButton(android.R.string.ok,null)

    .show();

    }

    3) 设置显示的位置

    关键技术:  TouchEvent,LayoutParams, SharedPreference

    iv_drag_location.setOnTouchListener(this);

     

    @Override

    public boolean onTouch(View v, MotionEvent event) {

    switch (event.getAction()) {

    case MotionEvent.ACTION_DOWN:

    firstX = (int) event.getRawX();

    firstY = (int) event.getRawY();

    break;

    case MotionEvent.ACTION_MOVE:

    int moveX = (int) event.getRawX();

    int moveY = (int) event.getRawY();

    int distanceX = moveX -firstX;

    int distanceY = moveY -firstY;

    int newLeft =iv_drag_location.getLeft() + distanceX;

    int newTop =iv_drag_location.getTop() + distanceY;

    int newRight =iv_drag_location.getRight() + distanceX;

    int newBottom =iv_drag_location.getBottom() + distanceY;

    iv_drag_location.layout(newLeft, newTop, newRight, newBottom);

    firstX = moveX;

    firstY = moveY;

    break;

    case MotionEvent.ACTION_UP:

    int x =iv_drag_location.getLeft();

    int y =iv_drag_location.getTop();

    SpUtils.getInstance(this).putInt(SpUtils.LOCATION_X, x);

    SpUtils.getInstance(this).putInt(SpUtils.LOCATION_Y, y);

    break;

    default:

    break;

    }

    return true;

    }

    4) 来电显示归属地

    关键技术:  Service,TelephonyManager, WindowManager,LayoutParams

    windowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);

    telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);

    // Listen for changes to the device call state. 监听电话状态

    telephonyManager.listen(listener, PhoneStateListener.LISTEN_CALL_STATE);

    private PhoneStateListenerlistener =new PhoneStateListener() {

    public void onCallStateChanged(int state, String incomingNumber) {

    switch (state) {

    case TelephonyManager.CALL_STATE_IDLE: //来电前或挂断电话后

    removeAdressView();

    break;

    case TelephonyManager.CALL_STATE_RINGING: //响铃中

    showAddress(incomingNumber);

    break;

    case TelephonyManager.CALL_STATE_OFFHOOK: //通话中

    removeAdressView();

    break;

    default:

    break;

    }

    }

    };

    WindowManager.LayoutParams params =new WindowManager.LayoutParams();

    params.width = WindowManager.LayoutParams.WRAP_CONTENT;//宽度自适应

    params.height = WindowManager.LayoutParams.WRAP_CONTENT;//高度自适应

    params.format = PixelFormat.TRANSLUCENT;//设置成透明的

    params.type = WindowManager.LayoutParams.TYPE_PHONE;//使addressView能移动

    params.flags = WindowManager.LayoutParams. FLAG_NOT_FOCUSABLE; //使addressView不用获得焦点

    // 根据设置的位置坐标定位

    int x = SpUtils.getInstance(this).getInt(SpUtils.LOCATION_X, -1);

    int y = SpUtils.getInstance(this).getInt(SpUtils.LOCATION_Y, -1);

    if (x != -1) {

         params.gravity = Gravity.LEFT | Gravity.TOP;

    params.x = x;

    params.y = y;

    }

    windowManager.addView(addressView, params);

    <!-- window添加一个视图(不是toast) -->

    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />

     

    判断服务否已经开启

    public static boolean isServiceRunning(Context context, String className) {

    ActivityManager am = (ActivityManager)

    context.getSystemService(Context.ACTIVITY_SERVICE);

    List<RunningServiceInfo> runningServices =

    am.getRunningServices(Integer.MAX_VALUE); //出所有运行的

    for(RunningServiceInfo info : runningServices) {

    String serviceClassName = info.service.getClassName();

    if(serviceClassName.equals(className)) {

    return true;

    }

    }

    return false;

    }

     

    3.5. 功能五: 通讯卫士

    1) 黑名单管理

    关键技术: SqliteOpenHelper, SqliteDataBase, Android单元测试, ListActivity, ArrayAdapter,

    ContextMenu, AlertDialog

    l Andorid单元测试的使用

    <!-- 配置测试插件 -->

    <instrumentation android:name="android.test.InstrumentationTestRunner"

            android:targetPackage="com.atguigu.my_ms" />

    <!-- 添加支撑测试的类库包 -->

    <uses-library android:name="android.test.runner" />

     

    //单元测试类

    public class BlackNumberDaoTestextends AndroidTestCase

    l ContextMenu使用

    @Override

    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {

    menu.add(1, 1, 1, R.string.update_number);

    menu.add(1, 2, 1, R.string.delete_number);

    }

    @Override

    public boolean onContextItemSelected(MenuItem item) {

    AdapterContextMenuInfo menuInfo = (AdapterContextMenuInfo) item.getMenuInfo();

    int position = menuInfo.position;

    switch (item.getItemId()) {

    case 1:

    showDeleteDialog(position);

    break;

    case 2:

    dao.deleteNumber(numbers.get(position));

    numbers.remove(position);

    adapter.notifyDataSetChanged();

    break;

    default:

    break;

    }

    return super.onContextItemSelected(item);

    }

    2) 黑名单来电与短信拦截

    关键技术: Service, AIDL挂断电话,短信BroadcastReceiver, ContentResolver, ContentObersver

    添加AIDL文件:


    挂断电话

    private void endCall() {//挂断电话

    try {

    // 通过反射拿到android.os.ServiceManager里面的getService这个方法的对象

    Class clazz = Class.forName("android.os.ServiceManager");

    Method method = clazz.getMethod("getService", String.class);

    // 通过反射调用这个getService方法,然后拿到IBinder对象,然后就可以进行aidl

    IBinder iBinder = (IBinder) method.invoke(null,

    new Object[] { Context.TELEPHONY_SERVICE });

    ITelephony telephony = ITelephony.Stub.asInterface(iBinder);

    telephony.endCall();

    } catch (Exception e) {

    e.printStackTrace();

    }

    }

     

    删除通话记录

    直接删除通话记录不可行,因为生成通话记录的过程是一个异步的过程, 在挂断电话的瞬间, 通话记录表数据还没有执行添加, 能通过Obersver删除

    private void deleteCallLog(final String number) {

    final Uri uri = CallLog.Calls.CONTENT_URI;

    getContentResolver().registerContentObserver(uri, true,

    new ContentObserver(null) {

    @Override

    public void onChange(boolean selfChange) {

    getContentResolver().delete(uri,

    "number=?", new String[] { number });

    getContentResolver().unregisterContentObserver(this);

    }

    }

    );

    }

    <!-- 打电话的权限:用于挂断电话-->

    <uses-permission android:name="android.permission.CALL_PHONE" />

    <!-- 读写通话记录:用在删除通话记录-->

    <uses-permission android:name="android.permission.READ_CALL_LOG" />

    <uses-permission android:name="android.permission.WRITE_CALL_LOG" />

    3) 判断骚扰电话显示通知

    响铃时间不超过1s

    是联系

    是黑名单

    private void showNotification(String incomingNumber) {

    NotificationManager manager =

    (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

    Intent intent = new Intent(this, NumberSecurityActivity.class);

    intent.putExtra("blackNumber", incomingNumber);

    PendingIntent pi = PendingIntent.getActivity(this, 0, intent, 0);

    Notification notification =new Notification.Builder(this)

    .setContentTitle("发现响一声电话!")

    .setContentText("点击添加"+incomingNumber+"为黑名单")

    .setSmallIcon(R.drawable.logo)

    .setContentIntent(pi)

    .build();

    manager.notify(0, notification );

    }

    <!-- 读取手机联系人 -->

    <uses-permission android:name="android.permission.READ_CONTACTS" />

    3.6. 功能:软件管理

    1) 应用的列表显示

    关键技术:  PackageManager, Map<Boolean, List<AppInfo>>, AsyncTask, BaseAdapter

    public Map<Boolean, List<AppInfo>> getAllAppInfos()throws Exception {

    Map<Boolean, List<AppInfo>> map =new HashMap<Boolean, List<AppInfo>>();

    List<AppInfo> systemInfos = new ArrayList<AppInfo>();

    map.put(true, systemInfos); //key否是系统应用

    List<AppInfo> customerInfos = new ArrayList<AppInfo>();//只存储非系统的第三方应用

    map.put(false, customerInfos);

    PackageManager packageManager =context.getPackageManager();

    Intent intent = new Intent();

    intent.setAction(Intent.ACTION_MAIN);

    intent.addCategory(Intent.CATEGORY_LAUNCHER);

    List<ResolveInfo> resolveInfos = packageManager.queryIntentActivities(intent, 0);

    for (ResolveInfo ri : resolveInfos) {

    String packageName = ri.activityInfo.packageName;

    Drawable icon = ri.loadIcon(packageManager);

    String appName = ri.loadLabel(packageManager).toString();

    boolean isSystemApp =isSystemApp(packageManager, packageName);

    AppInfo appInfo = new AppInfo(icon, appName, packageName, isSystemApp);

    if (appInfo.isSystemApp()) {

    systemInfos.add(appInfo);

    } else {

                   userInfos.add(appInfo);

    }

    }

    return map;

    }

    private boolean isSystemApp(PackageManager pm, String packageName) throws Exception {

    PackageInfo packageInfo = pm.getPackageInfo(packageName, 0);

    return (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) > 0;

    }

    2) 应用的卸载,运行与分享

    关键技术:  PopupWindow, 分享/卸载/运行Intent

    显示PopupWindow

    popupView = View.inflate(this, R.layout.popup_view,null);

    ll_app_uninstall = (LinearLayout)popupView.findViewById(R.id.ll_app_uninstall);

    ll_app_uninstall.setOnClickListener(this);

    ll_app_start = (LinearLayout)popupView.findViewById(R.id.ll_app_start);

    ll_app_start.setOnClickListener(this);

    ll_app_share = (LinearLayout)popupView.findViewById(R.id.ll_app_share);

    ll_app_share.setOnClickListener(this);

    popupWindow = new PopupWindow(popupView, 240, view.getHeight());

    popupWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));

    popupWindow.showAsDropDown(view, 50, 0 - view.getHeight());

    Animation animation = new ScaleAnimation(0f, 1f, 0f, 1f);

    animation.setDuration(500);

    popupView.startAnimation(animation);

    分享应用

    private void shareApp(String appName) {

    Intent intent = new Intent(Intent.ACTION_SEND);

    intent.setType("text/plain");//纯文

    //intent.putExtra(Intent.EXTRA_SUBJECT,"应用分享");

    intent.putExtra(Intent.EXTRA_TEXT,"分享一个不错的应用: " + appName);//内容

    startActivity(intent);

    }

    根据包名启动应用

    private void startApp(String packageName) {

    PackageManager packageManager = getPackageManager();

    Intent intent = packageManager.getLaunchIntentForPackage(packageName);

    if (intent ==null) {

    Utils.showToast(this,"此应用无法启动");

    } else {

    startActivity(intent);

    }

    }

    根据包名卸载应用

    private void uninStallApp(AppInfo appInfo) {

    if (appInfo.isSystemApp()) {

    Toast.makeText(this,"系统应用不能卸载!", 0).show();

    } else if(getPackageName().equals(appInfo.getPackageName())) {

    Toast.makeText(this,"当前应用不能卸载!", 0).show();

    }else {

    Intent intent = new Intent(Intent.ACTION_DELETE);

    intent.setData(Uri.parse("package:" + appInfo.getPackageName()));

    startActivity(intent);

    }

    }

    监视应用的卸载

    receiver = new UninstallReceiver();

    IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_REMOVED);

    filter.addDataScheme("package");// package:com.atguigu.ms

    this.registerReceiver(receiver, filter);

     

    private class UninstallReceiverextends BroadcastReceiver {

        @Override

        public void onReceive(Context context, Intent intent) {

        String dataString =intent.getDataString();  //package:com.atguigu.ms

        if(dataString!=null) {

            AppInfo appInfo =new AppInfo();

            appInfo.packageName = dataString.substring(dataString.indexOf(":")+1);

            userInfos.remove(appInfo);

            adapter.notifyDataSetChanged();

        }

        }

    }

    3.7. 功能:程序锁()

    1) 应用的列表显示, 加锁与解锁

    关键技术:   SqliteDatabase, ListView, BaseAdapter, TranslateAnimation

    Service, ActivityManager

    ContentProvider, ContentResolver,ContentObserver,

    @Override

    public void onItemClick(AdapterView<?> parent, View view,int position,long id) {

    // 添加动画效果,动画结束后,就把锁的图片改变

    TranslateAnimation animation =new TranslateAnimation(Animation.RELATIVE_TO_SELF,

    0f,Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0f,

    Animation.RELATIVE_TO_SELF, 0f);

    animation.setDuration(500);

    view.startAnimation(animation);//向右水平快速移动后复原

    AppInfo appInfo = appInfoList.get(position);

    ViewHolder viewHolder = (ViewHolder) view.getTag();

    boolean lock = (Boolean) viewHolder.lockIV.getTag();

    if (lock) {

    viewHolder.lockIV.setImageResource(R.drawable.unlock);

    viewHolder.lockIV.setTag(false);

    lockedApps.remove(appInfo.getPackageName());

    Uri uri = Uri.parse("content://com.atguigu.security.provider.applockprovider/delete");

    getContentResolver().delete(uri,null,new String[] { appInfo.getPackageName() });

    } else {

    viewHolder.lockIV.setImageResource(R.drawable.lock);

    viewHolder.lockIV.setTag(true);

    lockedApps.add(appInfo.getPackageName());

    ContentValues values = new ContentValues();

    values.put("packagename", appInfo.getPackageName());

    Uri uri = Uri.parse("content://com.atguigu.security.provider.applockprovider/insert");

    getContentResolver().insert(uri, values);

    }

    }

    2) 监听锁定应用的启动

    关键技术: 流程分析ContentProvider, ContentResolver, ContentObsver, Service, Thread,ActivityManager

    l AppLockMonitorService-----启动监听线程(直运行)

    获取最新启动的应用信息

    判断否需要锁定

    如果是, 启动解锁界面

    适当睡眠

    /**

     * 开启一直运行的子线程监听

     */

    private void startMonitor() {

    new Thread(new Runnable() {

    @Override

    public void run() {

    while (flag) {

    // 1. 得到当前最近启动的应用packageName

    String packageName = getCurrentPackageName();

    Log.e("TAG","start pn=" + packageName);

    try {

    // 2. 判断是否需要锁定应用

    // 判断是否在临时不锁定的列表中,如果是不用显示解锁界面

    // 如果在,启动一个锁屏界面(LockScreenActivity)

    if (!tempUnlockNames.contains(packageName) &&

    appLockNames.contains(packageName)) {

    startLockScreenActivity(packageName);

    }

    Thread.sleep(100);

    } catch (InterruptedException e) {

    e.printStackTrace();

    }

    }

    }

    }).start();

    }

     

    private StringgetTopPackageName() {

    return am.getRunningTasks(1).get(0).topActivity.getPackageName();

    }

     

    private void startLockScreenActivity(String packageName) {

    Intent intent = new Intent(this, LockScreenActivity.class);

    //intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);//必须是此flag

    intent.putExtra("packagename", packageName);

    startActivity(intent);

    }

    l AppLockProvider-----应用锁表数据编写ContentProvider

    @Override

    public Uriinsert(Uri uri, ContentValues values) {

    int match =matcher.match(uri);

    if (match ==1) {

    String packageName = values.getAsString("packagename");

    appLockDao.add(packageName);

    //通知所有监听在此URI上的obsever

    getContext().getContentResolver().notifyChange(URI,null);

    } else {

    throw new RuntimeException("格式不正确");

    }

    return null;

    }

    @Override

    public int delete(Uri uri, String selection, String[] selectionArgs) {

    int match =matcher.match(uri);

    if (match ==1) {

    appLockDao.delete(selectionArgs[0]);

    //通知所有监听在此URI上的obsever

    getContext().getContentResolver().notifyChange(URI, null);

    } else {

    throw new RuntimeException("格式不正确");

    }

    return 0;

    }

    l AppLockActiviy-----通过ContentResolver应用锁表中添加或删除记录

    //删除数据

    Uri uri = Uri.parse("content://com.atguigu.my_ms.provider.applockprovider/applock");

    getContentResolver().delete(uri, null,new String[] { appInfo.getPackageName() });

    //添加记录

    ContentValues values = new ContentValues();

    values.put("packagename", appInfo.getPackageName());

    Uri uri = Uri.parse("content://com.atguigu.my_ms.provider.applockprovider/applock");

    getContentResolver().insert(uri, values);

    l AppLockMonitorService-----监听应用锁表数据的变化

    Uri uri = Uri.parse("content://com.atguigu.security.provider.applockprovider");

    getContentResolver().registerContentObserver(uri, true, observer);

     

    protected ContentObserverobserver =new ContentObserver(new Handler()) {

    public void onChange(boolean selfChange) {

    appLockNames = appLockDao.getAll();

    Log.e("TAG","ContentObserver onChange()..");

    }

    };

    l LockScreenActivity ----密码验证与解锁通知

    Intent service = new Intent(this, AppLockMonitorService.class);

    service.putExtra("packageName",packageName);

    startService(service );

    3.8. 功能进程管理

    1) 显示系统和第三方应用进程列表

    关键技术: PackageManager, ActivityManager,AsyncTask, ListView,

    BaseAdapter, List<ProcessInfo>

    得到所有正在运行的进程的信息

    public static void getAllProcessInfos(Context context,

    List<ProcessInfo> systemProcessInfos, List<ProcessInfo> userProcessInfos) {

    ActivityManager am = (ActivityManager) context

    .getSystemService(Context.ACTIVITY_SERVICE);

    List<RunningAppProcessInfo> processInfos = am.getRunningAppProcesses();

    PackageManager pm = context.getPackageManager();

    for (RunningAppProcessInfo processInfo : processInfos) {

    ProcessInfo info = new ProcessInfo();

    // 包名

    String packageName = processInfo.processName;

    info.setPackageName(packageName);

    // 应用占用的内存  bit/byte

    MemoryInfo memoryInfo = am

    .getProcessMemoryInfo(new int[] { processInfo.pid })[0];

    long memInfoSize = memoryInfo.getTotalPrivateDirty() * 1024;

    info.setMemInfoSize(memInfoSize);

    try {

    // 图标

    Drawable icon = pm.getPackageInfo(packageName, 0).applicationInfo.loadIcon(pm);

    info.setIcon(icon);

    // 应用名称

    String name = pm.getPackageInfo(packageName, 0).applicationInfo

    .loadLabel(pm).toString();

    info.setAppName(name);

    // 是否是系统应用进程

    int flag = pm.getPackageInfo(packageName, 0).applicationInfo.flags;

    if ((flag & ApplicationInfo.FLAG_SYSTEM) == 0) {//用户进程

    info.setSystem(false);

    } else {//系统进程

    info.setSystem(true);

    }

    } catch (NameNotFoundException e) {//根据包名得到不到PackageInfo

    e.printStackTrace();

         info.setIcon(context.getResources().getDrawable(R.drawable.icon));

    info.setAppName(packageName);

    info.setSystem(true);

    }

    //同类型的Info保存到不同的集合中

    if(info.isSystem()) {

    systemProcessInfos.add(info);

    } else {

    userProcessInfos.add(info);

    }

    }

    }

     

    得到手机中可用内存大小

    public static long getAvailMem(Context context) {

    ActivityManager am = (ActivityManager) context

    .getSystemService(Context.ACTIVITY_SERVICE);

    ActivityManager.MemoryInfo outInfo = new ActivityManager.MemoryInfo();

    am.getMemoryInfo(outInfo);

    return outInfo.availMem;

    }

     

    得到手机总内存大小

    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)

    public static long getTotalMem(Context context) {

    long totalMem = 0;

    int sysVersion = VERSION.SDK_INT;//得到当前系统的版本号

    // 下面的方式只能在JELLY_BEAN(16)及以上版本才有用

    if (sysVersion >= Build.VERSION_CODES.JELLY_BEAN) {

    ActivityManager am = (ActivityManager) context

    .getSystemService(Context.ACTIVITY_SERVICE);

    ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();

    am.getMemoryInfo(memoryInfo);

    totalMem = memoryInfo.totalMem;

    } else {

    try {//在版本小于16,读取/proc/meminfo文件的第一行来获取总大小

    File file = new File("/proc/meminfo");

    FileInputStream fis = new FileInputStream(file);

    BufferedReader reader = new BufferedReader(

    new InputStreamReader(fis));

    String result = reader.readLine();// MemTotal: 510484 kB

    result = result.substring(result.indexOf(":") + 1,

    result.indexOf("k")).trim();// 510484

    reader.close();

    totalMem = Integer.parseInt(result) * 1024;

    } catch (Exception e) {

    e.printStackTrace();

    }

    }

    return totalMem;

    }

     

    文件大小格式化

    //返回格式化后的大小:1.5GB,12MB,16.66KB, 0.00B      101010101byte

    String Formatter.formatFileSize(context,byteSize);

     

    2) 进程的清理

    关键技术: ActivityManager

    //根据包名杀死对应的进程

    activityManager.killBackgroundProcesses(packageName)

    <!-- 杀死后台进程 -->

    <uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES" />

    3) 清理进程widget

    关键技术: AppWidgetProvider,<appwidget-provider>, RemoteView, Service,

    PendingIntent, Handler

    l AppWidgetProvider : 接收widget工具添加到桌面或从桌面移除等广播的receiver

    public class ProcessWidgetextends AppWidgetProvider {

    private Intentintent;

    @Override

    public void onEnabled(Context context) {//长按产生一个widget

    intent = new Intent(context,UpdateWidgetService.class);

    context.startService(intent);

    }

    @Override

    public void onDeleted(Context context,int[] appWidgetIds) {//移除桌面的widget

    if (intent !=null) {

    context.stopService(intent);

    intent = null;

    }

    }

    }

    注册receiver

    <receiver android:name=".receiver.ProcessWidget" >

        <intent-filter>

            <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />     </intent-filter>

        <meta-data

            android:name="android.appwidget.provider"

            android:resource="@xml/process_widget" />

    </receiver>

    应用小工具的配置文件

    <appwidget-provider 

        xmlns:android="http://schemas.android.com/apk/res/android"

        android:initialLayout="@layout/process_widget"

        android:minHeight="72dp"

        android:minWidth="294dp">

    </appwidget-provider>

    l UpdatewidgetService 于更新widget服务

    @Override

    public void onCreate() {

    super.onCreate();/*

    //创建用于更新widget的管理器

    manager = AppWidgetManager.getInstance(this);

    //包含widget视图布局的远程视图对象

    remoteViews = new RemoteViews(getPackageName(),

    R.layout.process_widget_view);

    //widget中的button添加点击监听

    Intent intent = new Intent(this,UpdatewidgetService.class);

    intent.putExtra("clear",true);

    PendingIntent pendingIntent = PendingIntent.getService(this, 0, intent,

    0);

    remoteViews.setOnClickPendingIntent(R.id.btn_widget_clear,

    pendingIntent);

    //准备用于更新widget的组件对象

    componentName = new ComponentName(this, ProcessWidget.class);

    //更新widget

    updateWidget();

    //发送延迟消息,使用widget能每隔2秒更新一次

    handler.sendEmptyMessageDelayed(1, 2000);

    }

    private void updateWidget() {

    MSUtils.log("updateWidget()...");

    processCount = MSUtils.getProcessCount(this);//进程大小

    remoteViews.setTextViewText(R.id.tv_widget_process_count,"进程数为  "

    + processCount);

    availMem = MSUtils.getAvailMem(this);//可用内存大小

    remoteViews.setTextViewText(R.id.tv_widget_process_memory,"可用内存为  "

    + Formatter.formatFileSize(this,availMem));

    manager.updateAppWidget(componentName,remoteViews);

    }

    使用BroadcastReceiver使应用省电

    private ScreeenReceiverreceiver;

    private void registScreenReceiver() {

    receiver = new ScreeenReceiver();

    IntentFilter filter = new IntentFilter();

    filter.addAction(Intent.ACTION_SCREEN_ON);  //开屏

    filter.addAction(Intent.ACTION_SCREEN_OFF);//锁屏

    registerReceiver(receiver, filter );

    }

    private class ScreeenReceiverextends BroadcastReceiver {

    @Override

    public void onReceive(Context context, Intent intent) {

    String action = intent.getAction();

    if(Intent.ACTION_SCREEN_ON.equals(action)) {

    Log.e("TAG","开屏....");

    handler.removeCallbacksAndMessages(null);

    handler.sendEmptyMessage(1);

    } else {

    Log.e("TAG","锁屏....");

    handler.removeCallbacksAndMessages(null);

    }

    }

    }

    应用生成桌面快捷方式

    private void createShortcut() {

    //得到是否生成快捷图标的标识

    boolean shortcut = SpUtils.getInstance(this)

    .getBoolean(SpUtils.SHORT_CUT,false);

    if(!shortcut) {

    Intent intent = new Intent("com.android.launcher.action.INSTALL_SHORTCUT");

    //图标

    intent.putExtra(Intent.EXTRA_SHORTCUT_ICON,

    BitmapFactory.decodeResource(getResources(), R.drawable.logo));

    //名称

    intent.putExtra(Intent.EXTRA_SHORTCUT_NAME,"手机卫士");

    //点击快捷键,启动哪个界面

    Intent callIntent = new Intent("com.atguigu.my_ms.action.Main");

    intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, callIntent);

    //发送广播,桌面(laucher)应用有Receiver接收并生成桌面图标

    sendBroadcast(intent);

    //保存已生成快捷图标的标识

    SpUtils.getInstance(this).put(SpUtils.SHORT_CUT,true);

    }

    }

    <!-- 生成应用快捷方式 -->

    <uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />

    3.9. 功能九: 缓存清理

    1) 得到应用的安装包,数据和缓存大小

    关键技术:  PackageManager, AIDL, 射调用@hide的方法

    得到应用的cache大小


    //得到安装的所有应用

    List<ApplicationInfo> applications = pm.getInstalledApplications(0);

     

    //得到某个应用的缓存数据

    Method method = PackageManager.class.getMethod("getPackageSizeInfo",

    String.class, IPackageStatsObserver.class);

    method.invoke(pm, packageName,new IPackageStatsObserver.Stub() {

    @Override

    public void onGetStatsCompleted(PackageStats pStats,boolean succeeded) {

    long cacheSize = pStats.cacheSize);

    }

    });

    权限:  android.permission.GET_PACKAGE_SIZE

    2) 清理缓存

    通过反射+AIDL调用PackageManagerhide方法实现

    能是系统应用使用,三方应用不能使用

    Method method = PackageManager.class.getMethod("deleteApplicationCacheFiles",

    String.class, IPackageDataObserver.class);

    method.invoke(pm, info.packageName,new IPackageDataObserver.Stub(){

    @Override

    public void onRemoveCompleted(String packageName,

    boolean succeeded)throws RemoteException {

    }

    }});

    调用系统设置应用清理缓存

    Intent intent = new Intent();

    intent.setAction("android.settings.APPLICATION_DETAILS_SETTINGS");

    intent.setData(Uri.parse("package:" +cacheInfos.get(position).getPackageName()));

    startActivity(intent);

    3.10. 功能十: 流量管理

    1) 应用流量列表显示:

    关键技术: SlidingDrawer, PackageManager, ApplicationInfo, TrafficStats

    /**

     * 得到应用的所有流量信息

    */

    public static List<TrafficInfo> getAllTrafficInfos(Context context) {

    List<TrafficInfo> list = new ArrayList<TrafficInfo>();

    PackageManager pm = context.getPackageManager();

         //安装的所有应用(包含没有主界面的)

    List<ApplicationInfo> infos = pm.getInstalledApplications(0);

    for(ApplicationInfo info : infos) {

    TrafficInfo trafficInfo = new TrafficInfo();

    //appName

    String appName = info.loadLabel(pm).toString();

    trafficInfo.setName(appName);

    //icon

    Drawable icon = info.loadIcon(pm);

    trafficInfo.setIcon(icon);

    int uid = info.uid;   //userID

    //inSize 下载流量

    long inSize =TrafficStats.getUidRxBytes(uid); //receive

    trafficInfo.setInSize(inSize);

    //outSize 上传流量

    long outSize =TrafficStats.getUidTxBytes(uid);

    trafficInfo.setOutSize(outSize);

    list.add(trafficInfo);

    }

    return list; 7

    }

    //根据应用的id得到其下载流量和上传流量

    long uidRxBytes =TrafficStats.getUidRxBytes(uid);

    long uidTxBytes = TrafficStats.getUidTxBytes(uid);

    //得到手机总的下载流量和上传流量(2g/3g/wifi)

    long totalRxBytes = TrafficStats.getTotalRxBytes();  //receive

    long totalTxBytes = TrafficStats.getTotalTxBytes();

    //得到手机的下载流量和上传流量(2g/3g)

    long mobileRxBytes = TrafficStats.getMobileRxBytes();

    long mobileTxBytes = TrafficStats.getMobileTxBytes();

    3.11. 功能十一: 高级工具

    1) 常用手机号查询

    关键技术: ExpandableListView, BaseExpandableListAdapter, SQLiteDatabase,打电话Intent

    <ExpandableListView

        android:id="@+id/elv_list"

        android:layout_width="match_parent"

        android:layout_height="match_parent"

    android:groupIndicator="@drawable/expendable_group_selector"/>

     

    <selector xmlns:android="http://schemas.android.com/apk/res/android">

        <!-- 展开时显示 -->

        <item android:drawable="@drawable/group_list"

            android:state_expanded="true"/>

        <!-- 不展开显示 -->

        <item android:drawable="@drawable/group_list_pressed"/>

    </selector>

    2) 备份手机中的所有短信数据

    技术: ContentResolver, 短信Uri, Cursor, XmlSerializer, XmlPullParser Gson

    保存为xml文件格式

    <?xml version="1.0" encoding="utf-8" standalone="yes" ?>

    <smses>

      <sms>

        <address>445</address>

        <date>1423316911894</date>

        <type>2</type>

        <body>R56yy</body>

      </sms>

      <sms>

        <address>234</address>

        <date>1423316902099</date>

        <type>2</type>

        <body>Wrtt</body>

      </sms>

    </smses>

    读取短信数据(查看mmssms.db数据)

    ContentResolver resolver = context.getContentResolver();

    Uri uri = Uri.parse("content://sms");

    String[] projection = {"address","date","type","body"};

    Cursor cursor = resolver.query(uri , projection , null,null,null);

    l XmlSerializer使用样例

    // 创建用于生成xml数据的对象

    XmlSerializer serializer =Xml.newSerializer();

    try {

    //设置文件输出流

    OutputStream os = new FileOutputStream(smsFile);

    serializer.setOutput(os,"utf-8");

    //开始写文档

    serializer.startDocument("utf-8",true);

    //<smses>

    serializer.startTag(null,"smses");

    while (cursor.moveToNext()) {

    //<sms>

    serializer.startTag(null,"sms");

    String address = cursor.getString(0);

    String date = cursor.getString(1);

    String type = cursor.getString(2);

    String body = cursor.getString(3);

    //<address>abc</address>

    createTag(serializer, "address", address);

    createTag(serializer, "date", date);

    createTag(serializer, "type", type);

    createTag(serializer, "body", body);

    //</sms>

    serializer.endTag(null,"sms");

    }

    //</smses>

    serializer.endTag(null,"smses");

    //结束写文档

    serializer.endDocument();

    } catch (Exception e) {

    e.printStackTrace();

    }

     

     

    private void createTag(XmlSerializer serializer, String tagName,

    String value) throws Exception {

    serializer.startTag(null, tagName);

        //文本标签体

    serializer.text(value);

    serializer.endTag(null, tagName);

    }

    3) 还原备份的短信数据

    技术: ContentResolver, 短信Uri, XmlPullParser, ProgressDialog

    l XmlPullParser使用样例

    try {

    //创建pull解析器

    XmlPullParser pullParser = Xml.newPullParser();

    //设置xml文件流

    pullParser.setInput(fis ,"utf-8");

    //读取第一个事件类型

    int eventType = pullParser.getEventType();

    //不断循环读取,直到文档最后

    while(eventType!=XmlPullParser.END_DOCUMENT) {

    String tagName = null;

    switch (eventType) {

    case XmlPullParser.START_TAG://开始标签

    //得到标签名

    tagName = pullParser.getName();

    if("address".equals(tagName)) {

    //保存<address>的文本标签体内容

    values.put("address", pullParser.nextText());

    } else if("date".equals(tagName)) {

    values.put("date", pullParser.nextText());

    }  else if("type".equals(tagName)) {

    values.put("type", pullParser.nextText());

    }  else if("body".equals(tagName)) {

    values.put("body", pullParser.nextText());

    }

    break;

    case XmlPullParser.END_TAG://结束标签

    tagName = pullParser.getName();

    if("sms".equals(tagName)) {

    //如果读到</sms>,就将数据保存到短信表中

    resolver.insert(uri, values);

    }

    break;

    default:

    break;

    }

    //解析下一个单元数据,并保存其事件类型

    eventType = pullParser.next();

    }

    } catch (Exception e) {

    e.printStackTrace();

    }

    3.12. 功能十二: 手机杀毒

    1) 计算机病毒与手机病毒

    计算机病毒

    对电脑有破坏性的程序

    蠕虫病毒  熊猫烧香

    利用网络进行复制和传播,传染途径是通过网络电子邮件

    目地: 显摆技术,验证技术

    木马病毒

    指通过特定的程序(木马程序)来控制另一台计算机

    目的:利益,账号:银行账号,游戏账号。

    手机病毒

    一种具有传染性、破坏性的手机程序. 其可利用发送短信彩信电子邮件,浏览网站,下载铃声蓝牙等方式进行传播,会导致用户手机死机、关机、个人资料被删、向外发送垃圾邮件泄露个人信息、自动拨打电话、发短(彩)信等进行恶意扣费,甚至会损毁SIM卡、芯片等硬件,导致使用者无法正常使用手机

    目地:利益

    2) 杀毒软件

    作用: 用来定位出带病毒的软件应用,并提示用户将它们给删除。

    基本原理:

    收集病毒保存起来形成强大的病毒库, 如果安装的应用在病毒库中有记录, 杀毒软件就会提示其是病毒(手机杀毒)

    它会监视软件的行为来判断其是否可能是病毒

    1.监听是否开机启动

    2.监听软件是否有打开摄像头

    3.是否发邮件

    4.是否很特别占用资源

    3) 得到安装应用的信息

    //得到所有包(包括已删除但安装目录还存在的)

    List<PackageInfo> packages = pm.getInstalledPackages(PackageManager.GET_SIGNATURES);

    for(PackageInfo packInfo : packages){

    //应用名称

    info.name = packInfo.applicationInfo.loadLabel(pm).toString();

        //应用

    info.packacgeName = packInfo.packageName;

        //应用签名

    String signature = packInfo.signatures[0].toCharsString();

    }

    4) 判断是否是病毒

    //应用签名进行md5加密

    signature = MSUtils.md5(signature);

    //查询病毒库表

    String desc = AntiVirusQueryDao.getDesc(getApplicationContext(), signature);

    if(desc==null) {//

    info.isVirus =false;

    } else {//

    info.isVirus =true;

    }

    5) 扫描杀毒时的旋转动画

     

    RotateAnimation ra =new RotateAnimation(0, 360,

    Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,0.5f);

    ra.setDuration(1000);

    ra.setRepeatCount(RotateAnimation.INFINITE);//播放无限次

    iv_antivirus_scanning.startAnimation(ra);

    6) 自定义水平进度条

       

    定义包含进度条图片的drawable文件

    <layer-list xmlns:android="http://schemas.android.com/apk/res/android" >

        <item android:id="@android:id/background"

            android:drawable="@drawable/security_progress_bg">

        </item>

        <item android:id="@android:id/secondaryProgress"

            android:drawable="@drawable/security_progress_bg">

        </item>

        <item android:id="@android:id/progress"

            android:drawable="@drawable/security_progress">

        </item>

    </layer-list>


  • 相关阅读:
    NOIP2014飞扬的小鸟[DP][WRONG]
    POJ2184 Cow Exhibition[DP 状态负值]
    Quantum Bogo sort浅谈
    POJ3211 Washing Clothes[DP 分解 01背包可行性]
    VIJOS P1426兴奋剂检查[DP 状态哈希]
    VIJOS P1037搭建双塔[DP]
    NOIP2006金明的预算方案[DP 有依赖的背包问题]
    POJ1742 Coins[多重背包可行性]
    NOIP水题合集[3/未完待续]
    单调队列
  • 原文地址:https://www.cnblogs.com/miaozhenzhong/p/5931054.html
Copyright © 2011-2022 走看看