## 短信备份 ##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();//销毁当前页面 }