## 短信備份 ##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();//銷燬當前頁面 }