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();//銷燬當前頁面         }

相關文章
相關標籤/搜索