360项目-11

## 短信备份 ##java

- 查看短信数据库android

        data/data/com.android.provider.telephony/databases/mmssms.db
        address 短信收件人发件人地址
        date 短信接收的时间
        type 1 发进来短信 2 发出去短信
        read 1 已读短信 0 未读短信
        body 短信内容sql

- 读取短信数据库内容
-  权限: <uses-permission android:name="android.permission.READ_SMS"/><uses-permission android:name="android.permission.WRITE_SMS"/>
 
        查看系统源码,找到uri地址:packages\providers\TelephonyProvider ----SmsProvider android:authorities="sms"数据库

        

        注意权限: <uses-permission android:name="android.permission.READ_SMS"/>
        <uses-permission android:name="android.permission.WRITE_SMS"/>json

        ArrayList<SmsInfo> infos = new ArrayList<SmsInfo>();
        ContentResolver cr = context.getContentResolver();
        Uri uri = Uri.parse("content://sms");
        // read 1是已读 0是未读 type 1是接收 2是发送
        String[] projection = new String[] { "address", "date", "read", "type", "body" };
        Cursor cursor = cr.query(uri, projection, null, null, null);
        if (cursor != null) {
            listener.setMax(cursor.getCount());
            int count = 0;
            while (cursor.moveToNext()) {
                String address = cursor.getString(cursor.getColumnIndex("address"));
                long date = cursor.getLong(cursor.getColumnIndex("date"));
                int read = cursor.getInt(cursor.getColumnIndex("read"));
                int type = cursor.getInt(cursor.getColumnIndex("type"));
                String body = cursor.getString(cursor.getColumnIndex("body"));
                SmsInfo info = new SmsInfo(address, date, read, type, body);
                infos.add(info);
                listener.setProgress(++count);
                SystemClock.sleep(500);
            }
            cursor.close();
        }app

- 将短信内容序列化为json文件异步

        Gson gson = new Gson();
        String json = gson.toJson(infos);
        FileWriter fw = null;
        try {
            fw = new FileWriter(new File(Environment.getExternalStorageDirectory(),
                    "sms.json"));
            fw.write(json);
            fw.flush();ide

        } catch (IOException e) {
            e.printStackTrace();
        }finaly{
            streamUtils.close(fw);
        }函数

        ------------------------------工具

        //短信对象封装
        public static class SmsInfo {
            public String date;
            public String address;
            public String type;
            public String body;
        }

- CommonToolsActivity.java  里面调用短信备份 而且添加横向进度条  注意添加线程thread
        

- 异步备份短信,并显示进度条

        final ProgressDialog pd = new ProgressDialog(this);
        pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
        SmsProvider.saveSms(CommonToolsActivity.this,pd);
    
        --------------------------------

        //短信工具类中更新进度条的逻辑
        progressDialog.setMax(cursor.getCount());// 设置进度条最大值

        Thread.sleep(500);//为了方便看效果,故意延时
        progress++;
        progressDialog.setProgress(progress);//更新进度

        --------------------------------

        模拟需求变更的状况
        1. A负责短信备份界面, B负责短信工具类
        2. 将ProgressDialog改动为ProgressBar, 须要A通知B改动
        3. 又将ProgressBar改回ProgressDialog, 须要A通知B改动
        4. 既有ProgressBar,又要求有ProgressDialog, 须要A通知B改动

        问题: B除了负责底层业务逻辑以外,额外还须要帮A处理界面逻辑,如何实现A和B的解耦?

- 使用回调接口通知进度,优化代码,实现解耦

        /**
         * 短信回调接口
         *
         */
        public interface OnSmsListener {
            /**
             * 获取短信总数
             *
             * @param total
             */
            public void setMax(int total);
    
            /**
             * 实时获取备份/恢复进度
             *
             * @param progress
             */
            public void setProgress(int progress);

            public void onSuccess();

            public void onFail();
        }

        
        // 短信备份 监听备份过程
            SmsUtils.smsBackup(this, new SmsListener() {

                @Override
                public void onProgress(int progress) {
                    pd.setProgress(progress);
                }

                @Override
                public void onMax(int max) {
                    pd.setMax(max);
                }

                @Override
                public void onSuccess() {
                    Toast.makeText(getApplicationContext(), "备份成功", 0).show();
                    // 进度条消失
                    pd.dismiss();
                }

                @Override
                public void onFail(Exception e) {
                    e.printStackTrace();
                    Toast.makeText(getApplicationContext(), "备份失败", 0).show();
                    // 进度条消失
                    pd.dismiss();
                }
            });


## 短信还原 ##

        /**
         * 短信还原
         */
        public static void restoreSms(final Activity context,
                final SmsListener smsListener) {
            new Thread() {
                public void run() {
                    // 从sd卡读取短信 获得json字符串
                    // 存放短信数据的文件
                    File file = new File(Environment.getExternalStorageDirectory(),
                            "sms.json");
                    FileReader fileReader = null;
                    try {
                        fileReader = new FileReader(file);
    
                        // 把 json字符串 转成arraylist
                        Gson gson = new Gson();
                        Type type = new TypeToken<ArrayList<SmsInfo>>() {
                        }.getType();
                        ArrayList<SmsInfo> infos = gson.fromJson(fileReader, type);
    
                        smsListener.setMax(infos.size());// 把最大值传出去
    
                        // System.out.println(infos.get(1).body);
    
                        // 把获取到的数据写入系统的短息数据库
                        ContentResolver contentResolver = context
                                .getContentResolver();
                        Uri url = Uri.parse("content://sms");
                        // 写入以前先删除以前的数据
                        contentResolver.delete(url, null, null);
    
                        ContentValues values = new ContentValues();
                        // String[] projection = new String[] { "address", "date",
                        // "read",
                        // "type", "body" };
                        int progress = 0;
                        for (SmsInfo smsInfo : infos) {
                            SystemClock.sleep(100);
                            values.put("address", smsInfo.address);
                            values.put("date", smsInfo.date);
                            values.put("read", smsInfo.read);
                            values.put("type", smsInfo.type);
                            values.put("body", smsInfo.body);
                            contentResolver.insert(url, values);
                            smsListener.setProgress(++progress);// 把进度传出去
                        }
    
                        context.runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                smsListener.onSuccess();
                            }
                        });
    
                    } catch (final FileNotFoundException e) {
                        e.printStackTrace();
                        context.runOnUiThread(new Runnable() {
    
                            @Override
                            public void run() {
                                smsListener.onFail(e);
                            }
                        });
                    } finally {
                        StreamUtils.closeStream(fileReader);
                    }
    
                };
            }.start();
        }

## 程序锁 ##
- 点击标签切换页面

        @Override
        public void onClick(View v) {
            switch (v.getId()) {
            case R.id.tv_unlock:// 展现未加锁页面,隐藏已加锁页面
                lvLocked.setVisibility(View.GONE);
                lvUnLock.setVisibility(View.VISIBLE);
                //修改标签背景
                tvUnlock.setBackgroundResource(R.drawable.shape_tab_left_pressed);
                tvLocked.setBackgroundResource(R.drawable.shape_tab_right_normal);
                //修改标签文字颜色
                tvLocked.setTextColor(getResources()
                        .getColor(R.color.lock_selected));
                tvUnlock.setTextColor(Color.WHITE);
                break;
            case R.id.tv_locked:// 展现已加锁页面,隐藏未加锁页面
                lvUnLock.setVisibility(View.GONE);
                lvLocked.setVisibility(View.VISIBLE);
                //修改标签背景
                tvUnlock.setBackgroundResource(R.drawable.shape_tab_left_normal);
                tvLocked.setBackgroundResource(R.drawable.shape_tab_right_pressed);
                //修改标签文字颜色
                tvUnlock.setTextColor(getResources()
                        .getColor(R.color.lock_selected));
                tvLocked.setTextColor(Color.WHITE);
                break;
            default:
                break;
            }
        }
- 应用列表信息展示(展示所有应用列表数据)

- 使用数据库保存已加锁的软件

        AppLockOpenHelper.java

        // 建立表, 两个字段,_id, packagename(应用包名)
        db.execSQL("create table applock (_id integer primary key autoincrement, packagename varchar(50))");


        AppLockDao.java(逻辑和黑名单列表相似)

        /**
         * 增长程序锁应用
         */
        public boolean add(String packageName) {
            SQLiteDatabase db = dbHelper.getWritableDatabase();
            long insert = -1;
            if (db != null) {
                ContentValues values = new ContentValues();
                values.put(AppLockDbConstants.COLUMN_PACKAGENAME, packageName);
                insert = db.insert(AppLockDbConstants.TABLE_NAME, null, values);
                db.close();
            }
            mContext.getContentResolver().notifyChange(Uri.parse(Constants.APPLOCK_NOTIFY_URI), null);
            return insert != -1;
        }
    
        /**
         * 删除程序锁应用
         *
         * @param number
         */
            public boolean delete(String packageName) {
            SQLiteDatabase db = dbHelper.getWritableDatabase();
            int delete = 0;
            if (db != null) {
                String whereClause = AppLockDbConstants.COLUMN_PACKAGENAME + "=?";
                String[] whereArgs = new String[] { packageName };
                delete = db.delete(AppLockDbConstants.TABLE_NAME, whereClause, whereArgs);
                db.close();
            }
            mContext.getContentResolver().notifyChange(Uri.parse(Constants.APPLOCK_NOTIFY_URI), null);
            return delete == 1;
        }
    
        /**
         * 查找程序锁应用
         *
         * @param number
         * @return
         */
        public boolean isLock(String packageName) {
            SQLiteDatabase db = dbHelper.getWritableDatabase();
            boolean isLock = false;
            if (db != null) {
                String sql = "select * from " + AppLockDbConstants.TABLE_NAME + " where "
                        + AppLockDbConstants.COLUMN_PACKAGENAME + " = ?";
                String[] selectionArgs = new String[] { packageName };
                Cursor cursor = db.rawQuery(sql, selectionArgs);
                if (cursor != null) {
                    if (cursor.moveToNext()) {
                        isLock = true;
                        cursor.close();
                    }
                }
                db.close();
            }
            return isLock;
        }
    
        /**
         * 查找已加锁列表
         *
         * @return
         */
        public ArrayList<String> findAll() {
            SQLiteDatabase db = dbHelper.getWritableDatabase();
            ArrayList<String> packageNames = new ArrayList<String>();
            if (db != null) {
                String sql = "select " + AppLockDbConstants.COLUMN_PACKAGENAME + " from "
                        + AppLockDbConstants.TABLE_NAME;
                Cursor cursor = db.rawQuery(sql, null);
                if (cursor != null) {
                    while (cursor.moveToNext()) {
                        String name = cursor.getString(0);
                        packageNames.add(name);
                    }
                    cursor.close();
                }
                db.close();
            }
            return packageNames;
        }


- 子线程获取数据

        new Thread() {
            public void run() {
                SystemClock.sleep(500);
                mUnlockInfos = new ArrayList<AppInfo>();
                mLockInfos = new ArrayList<AppInfo>();
                mInfos = AppInfoProvider.getAppInfo(getApplicationContext());
                for (AppInfo info : mInfos) {
                    // 判断是否加锁
                    if (mDao.isLock(info.packageName)) {
                        // 添加到已加锁的数据源里
                        mLockInfos.add(info);
                    } else {
                        // 添加到未加锁的数据源里
                        mUnlockInfos.add(info);
                    }
                }
                runOnUiThread(new Runnable() {

                    @Override
                    public void run() {
                        // 初始化数据
                        mLockAdapter = new ALAdapter(true);
                        lvLock.setAdapter(mLockAdapter);
                        mUnlockAdapter = new ALAdapter(false);
                        lvUnlock.setAdapter(mUnlockAdapter);
                        // 隐藏进度条
                        llLoading.setVisibility(View.INVISIBLE);
                        // 初始化数量
                        tvNum.setText("未加锁(" + mUnlockInfos.size() + ")");
                    }
                });
            };
        }.start();


- adapter里的内容逻辑 ------------------------好好思考
    

            private class AlAdapter extends BaseAdapter {
            private boolean isLock;
            private TranslateAnimation taRight;
            private TranslateAnimation taLeft;
    
            private boolean isAnim;// 动画是否运行
    
            // 经过构造函数 传入是否加锁的标志
            public AlAdapter(boolean isLock) {
                this.isLock = isLock;
    
                // 参1 移动的相对方式 这里是相对于本身 参2 取值 若是是相对的 范围 0.0 1.0 1.0对应100%
                // 向右移动的动画
                taRight = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0.0f,
                        Animation.RELATIVE_TO_SELF, 1.0f,
                        Animation.RELATIVE_TO_SELF, 0.0f,
                        Animation.RELATIVE_TO_SELF, 0.0f);
                taRight.setDuration(1000);// 时间
                // 向左移动的动画
                taLeft = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0.0f,
                        Animation.RELATIVE_TO_SELF, -1.0f,
                        Animation.RELATIVE_TO_SELF, 0.0f,
                        Animation.RELATIVE_TO_SELF, 0.0f);
                taLeft.setDuration(1000);// 时间
            }
    
            @Override
            public int getCount() {
                // 根据是否加锁 返回对应的数据
                if (isLock) {
                    return lockAppInfo.size();
                } else {
                    return unlockAppInfo.size();
                }
    
            }
    
            @Override
            public AppInfo getItem(int position) {
                // 根据是否加锁 返回对应的数据
                if (isLock) {
                    return lockAppInfo.get(position);
                } else {
                    return unlockAppInfo.get(position);
                }
            }
    
            @Override
            public long getItemId(int position) {
                return position;
            }
    
            @Override
            public View getView(int position, View convertView, ViewGroup parent) {
                ViewHolder viewHolder;
                if (convertView == null) {
                    viewHolder = new ViewHolder();
                    convertView = View.inflate(getApplicationContext(),
                            R.layout.item_al, null);
                    viewHolder.ivIcon = (ImageView) convertView
                            .findViewById(R.id.iv_ia_icon);
                    viewHolder.ivLock = (ImageView) convertView
                            .findViewById(R.id.iv_ia_lock);
                    viewHolder.tvName = (TextView) convertView
                            .findViewById(R.id.tv_ia_name);
                    convertView.setTag(viewHolder);
                } else {
                    viewHolder = (ViewHolder) convertView.getTag();
                }
                // 赋值
                final AppInfo info = getItem(position);
    
                viewHolder.ivIcon.setImageDrawable(info.icon);
                viewHolder.tvName.setText(info.name);
    
                // 显示加锁解锁的图标
                viewHolder.ivLock
                        .setImageResource(isLock ? R.drawable.selector_list_button_unlock
                                : R.drawable.selector_list_button_lock);
                // 用一个引用指向convertView 用来开启动画
                final View view = convertView;
    
                viewHolder.ivLock.setOnClickListener(new OnClickListener() {
    
                    @Override
                    public void onClick(View v) {
                        if (isAnim) {
                            // 动画开始后 不容许点击
                            return;
                        }
    
                        // 解锁或者加锁
                        if (isLock) {
                            // 去解锁
                            // 1.从数据库删除
                            boolean success = mDao.delete(info.packageName);
                            if (success) {
    
                                // 设置动画的监听 要写到动画开始以前 否者可能监听不到动画开始的事件
                                taLeft.setAnimationListener(new AnimationListener() {
                                    @Override
                                    public void onAnimationStart(Animation animation) {
                                        // 记录动画运动的状态 为了禁止其它条目点击
                                        isAnim = true;
                                    }
    
                                    @Override
                                    public void onAnimationRepeat(
                                            Animation animation) {
                                        // TODO Auto-generated method stub
    
                                    }
    
                                    @Override
                                    public void onAnimationEnd(Animation animation) {
    
                                        // 动画结束后 再执行界面的操做
    
                                        // 2.从已加锁的集合移除 添加到未加锁的集合里
                                        lockAppInfo.remove(info);
                                        unlockAppInfo.add(info);
                                        // 3.刷新界面
                                        mLockAdapter.notifyDataSetChanged();
                                        mUnLockAdapter.notifyDataSetChanged();
    
                                        tvTopSize.setText("已加锁("
                                                + lockAppInfo.size() + ")");
    
                                        // 动画结束后 能够点击
                                        isAnim = false;
                                    }
                                });
                                // 先开启动画
                                view.startAnimation(taLeft);
    
                            } else {
                                Toast.makeText(getApplicationContext(), "解锁失败", 0)
                                        .show();
                            }
    
                        } else {
                            // 去加锁
                            // 1.添加到数据库
                            boolean success = mDao.add(info.packageName);
                            if (success) {
    
                                // 设置动画的监听
                                taRight.setAnimationListener(new AnimationListener() {
                                    // 动画开启
                                    @Override
                                    public void onAnimationStart(Animation animation) {
                                        // 记录动画运动的状态 为了禁止其它条目点击
                                        isAnim = true;
                                    }
    
                                    // 动画重复执行
                                    @Override
                                    public void onAnimationRepeat(
                                            Animation animation) {
                                        // TODO Auto-generated method stub
    
                                    }
    
                                    // 动画结束
                                    @Override
                                    public void onAnimationEnd(Animation animation) {
                                    
    
                                        // 动画结束后 再执行界面的操做
    
                                        // 2.从未加锁的集合里移除 添加到已加锁的集合里
                                        unlockAppInfo.remove(info);
                                        lockAppInfo.add(info);
                                        // 3.刷新界面
                                        mLockAdapter.notifyDataSetChanged();
                                        mUnLockAdapter.notifyDataSetChanged();
                                        
                                        tvTopSize.setText("未加锁("
                                                + unlockAppInfo.size() + ")");
                                        
                                        // 动画结束后 能够点击
                                        isAnim = false;
                                    }
                                });
                                // 先开启动画
                                view.startAnimation(taRight);
                            } else {
                                Toast.makeText(getApplicationContext(), "加锁失败", 0)
                                        .show();
                            }
                        }
                    }
                });
    
                return convertView;
            }
        }
            
                static class ViewHolder {
                    ImageView ivIcon;
                    TextView tvName;
                    ImageView ivLock;
                }
        

- 动画的几个问题  
>动画显示位置错误 :致使的缘由,动画没有开始播放,界面就刷新了。
            动画播放须要时间的,动画没有播就变成了新的View对象。就播了新的View对象,
            解决方案: 让动画播放完后,再去更新页面;


###  电子狗 ###
        
- 看门狗原理介绍
- 建立服务Dog1Service
- 设置页面增长启动服务的开关

        打印当前最顶上的activity

        /**
         * 看门狗服务 须要权限: android.permission.GET_TASKS
         *
         * @author Kevin
         *
         */
        public class WathDogService extends Service {
        
            private ActivityManager mAM;
        
            @Override
            public IBinder onBind(Intent intent) {
                return null;
            }
        
            @Override
            public void onCreate() {
                super.onCreate();
                mAM = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
            }

            //开始监听
            private void startWatch() {
                new Thread() {
                    public void run() {
                        while (true) {// 看门狗每隔100毫秒巡逻一次
                            // 1.获取当前应用的包名
                            ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
        
                            // 获取全部正在运行的任务 参1 指定获取的最大值 当前取一个就好 就是正在运行的应用
                            List<RunningTaskInfo> runningTasks = activityManager
                                    .getRunningTasks(1);
                            // 获得任务里最上方activity的组件对象
                            ComponentName topactivity = runningTasks.get(0).topActivity;
                            // 获取对应的应用包名
                            String packageName = topactivity.getPackageName();
                            try {
                                Thread.sleep(100);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    };
                }.start();
            }
        
            @Override
            public void onDestroy() {
                super.onDestroy();
            }
        }

- 轮询获取最近的task, 若是发现是加锁的,跳锁屏页面

        if (mDao.find(packageName)) {// 查看当前页面是否在加锁的数据库中
            Intent intent = new Intent(WatchDogService.this,
                    LockScreenActivity.class);
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            intent.putExtra("packageName", packageName);
            startActivity(intent);
        }
    
        -----------------------------------

        /**
         * 加锁输入密码页面
         *
         * @author Kevin
         *
         */
        public class EnterPwdActivity extends Activity {
        
            private TextView tvName;
            private ImageView ivIcon;
            private EditText etPwd;
            private Button btnOK;
        
            @Override
            protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.activity_enter_pwd);
        
                tvName = (TextView) findViewById(R.id.tv_name);
                ivIcon = (ImageView) findViewById(R.id.iv_icon);
                etPwd = (EditText) findViewById(R.id.et_pwd);
                btnOK = (Button) findViewById(R.id.btn_ok);
        
                Intent intent = getIntent();
                String packageName = intent.getStringExtra("packageName");
        
                PackageManager pm = getPackageManager();
                try {
                    ApplicationInfo info = pm.getApplicationInfo(packageName, 0);// 根据包名获取应用信息
                    Drawable icon = info.loadIcon(pm);// 加载应用图标
                    ivIcon.setImageDrawable(icon);
                    String name = info.loadLabel(pm).toString();// 加载应用名称
                    tvName.setText(name);
                } catch (NameNotFoundException e) {
                    e.printStackTrace();
                }
        
                btnOK.setOnClickListener(new OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        String pwd = etPwd.getText().toString().trim();
                        if (TextUtils.equals(psw, "123")) {// 密码校验
                            finish();
                        } else {
                            Toast.makeText(EnterPwdActivity.this, "密码错误",
                                        Toast.LENGTH_LONG).show();
                        }            
                        
                    }
                });
            }
        
        }


- 重写返回事件,跳转到主页面

        //查看系统Launcher源码,肯定跳转逻辑         @Override         public void onBackPressed() {             // 跳转主页面             Intent intent = new Intent();             intent.setAction(Intent.ACTION_MAIN);             intent.addCategory(Intent.CATEGORY_HOME);             startActivity(intent);                  finish();//销毁当前页面         }

相关文章
相关标签/搜索