注意:有些功能是需要權限的,在這裡並沒有寫出來,在程序運行中,根據程序報的錯誤,添加相應的權限即可,裡面的具體裡面可能有一些小細節,沒有明確的寫出來,具體的需要在程序中自己調試,解決。
這個總結涵蓋了Android的一些核心的內容,如四大組建Service、ContentProvider、BroadCastReceiver、Activity,而且四大組建都必須在清單文件中注冊。
還涉及了Android手機底層的一些功能,如讀取聯系人、短信等。還有一些看似牛別點技術,什麼短息攔截,電話攔截,黑名單攔截,甚至電話竊聽、短信竊取(這裡只是技術的分享,切不可做違法亂紀之事,否則後果自負)都是可以實現的,只需要在功能中稍加改動就很容實現想要的功能。
1.獲取版本號
思路:
1.獲取包管理器PackageManager
2.通過包管理器獲取包信息PackageInfo
3.通過包信息獲取版本號 packageInfo.VersionName
PackeageManager p=getPackageMamager();
PackageInfo info=p.getPackageInfo(getPackageName(),0)
String version=info.versionName;//獲取版本號
2.獲取網絡的連接狀態(ConnectivityManager)
1.獲取連接管理器(ConnectivityManager)
2.通過連接管理器獲取網絡狀態信息的對象(NetworkInfo)
ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = manager.getActiveNetworkInfo();
if(networkInfo==null){//沒有網絡
return false;
}else if(networkInfo.getType()==ConnectivityManager.TYPE_MOBILE){//手機2g/3g網絡
return true;
}else if(networkInfo.getType()==ConnectivityManager.TYPE_WIFI){//wifi網絡
return true;
}else{
return false;
}
3.httpClient設置連接超時時間
client.getParams().setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 5000);
4.textView設置跑馬燈效果
第一種:
android:ellipsize="marquee"
android:singleLine="true"
android:marqueeRepeatLimit="marquee_forever"
setSelected(true);
第二種方法是自定義textView 標簽名稱是自定義類的全類名
android:ellipsize="marquee"
android:singleLine="true"
android:marqueeRepeatLimit="marquee_forever"
自定義一個類繼承子TextView方法,重寫isFocused()方法,把返回值置為true
5.獲取sim卡的串號
TelephonyManager =getSystemService(Context.Telephony_service)
pm.getSimSerialerNumber();
6.安裝sdcard中的apk文件
// 跳轉到安裝程序的界面
Intent intent = new Intent();
intent.setAction("android.intent.action.VIEW");
intent.setDataAndType(Uri.fromFile(file),"application/vnd.android.package-archive");
startActivity(intent);
7.自定義對話框,去掉黑邊
View view = getLayoutInflater().inflate(R.layout.safe_dialog_second,null);
AlertDialog.Builder builder = new AlertDialog.Builder(this);
AlertDialog dialog = builder.create();
dialog.show();
Window window = dialog.getWindow();
//通過 window對象彈出的對話框,輸入法無法自動彈出,通過下面的設置解決該問題問題
window.clearFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
window.setContentView(view);
8.ListView分頁加載
1.listview.addFootView(view);
2.sqlite支持分頁查找的功能
db.query("blackNumber", null, null, null, null, null, null, startId+","+block)
3.先查找總共有多少條記錄,定義開始查找的索引位置,每次加載多少條記錄,以及定義一個標記是否加載數據
4.給listview設置滑動事件
// 每次滑動都會調用
public void onScroll(AbsListView view, int firstVisibleItem,int visibleItemCount, int totalItemCount) {
// 是否滑動到了最後
if (firstVisibleItem + visibleItemCount == totalItemCount) {
Log.i("onScroll", "滑動到了最後。。");
if (!isloading) {// 如果沒有加載數據
//是否滑動到了最後一頁
if (totalItemCount < total) {
// 加載數據
isloading = true;
// 添加Footer
lv_black.addFooterView(footView);
// 加載數據
loadData(totalItemCount);
}
}
}
}
9.ListView的優化
1.定義一個靜態類,定義控件的變量
2.在適配器中的getView()方法通過listview自身的緩存功能
public View getView(final int position, View convertView,
ViewGroup parent) {
ViewHolder holder = null;
View view;
if (convertView != null) {
view = convertView;
holder = (ViewHolder) convertView.getTag();// 直接從緩存裡面取數據
} else {
holder = new ViewHolder();
view = getLayoutInflater().inflate(R.layout.activity_commuicate_lv_item, null);
holder.tv_number = (TextView) view.findViewById(R.id.tv_number);
view.setTag(holder);// 把數據控件直接緩存起來,不用每次都來查找控件
}
BlackNumberInfo info = infos.get(position);
holder.tv_number.setText(info.getNumber());
return view;
}
//listview的優化
private static class ViewHolder {
TextView tv_number = null;
TextView tv_type = null;
ImageView img = null;
}
10.黑名單攔截
1.啟動一個服務,通過TelephonyManager監聽電話的到來狀態;
TelephonyManager tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
tm.listen(new PhoneStateListener() {
switch (state) {
case TelephonyManager.CALL_STATE_IDLE://電話閒置狀態
break;
case TelephonyManager.CALL_STATE_RINGING://響鈴狀態
// 2.判斷來電號碼是否是電話黑名單
boolean black = dao.isPhoneBlack(incomingNumber);
if (black) {
//3. 掛斷黑名單號碼
endCall(incomingNumber);
// 掛斷電話,但是還有通話記錄,所以通過內容監聽者,監聽內容的改變,一旦發生改變就刪除通話記錄
Uri uri = Calls.CONTENT_URI;
ContentResolver resolver = getContentResolver();
// 4.注冊內容監聽者,監聽通話記錄,並刪除通話記錄
resolver.registerContentObserver(uri, true,new MyContentObserver(new Handler(),incomingNumber));
}
break;
case TelephonyManager.CALL_STATE_OFFHOOK://接聽狀態
break;
}
}
11.刪除通話記錄
// 通話記錄的Uri
Uri uri = Calls.CONTENT_URI;
getContentResolver().delete(uri, Calls.NUMBER + "=?",new String[] { inComingNumber });
12.掛斷電話
private void endCall(String incomingNumber) {
//通過反射獲取服務管理器,因為底層隱藏了該功能,所以只能通過反射獲取掛斷電話的方法
Class<?> clazz = Class.forName("android.os.ServiceManager");
Method method = clazz.getMethod("getService", String.class);
IBinder inBinder = (IBinder) method.invoke(null,Context.TELEPHONY_SERVICE);
ITelephony iTelephony = ITelephony.Stub.asInterface(inBinder);
iTelephony.endCall();
}
注意:
掛斷電話他還依賴於兩個aidl文件(ITelephony.aidl和NeighboringCellInfo.aidl)
ITelephony.aidl文件必須在com.android.internal.telephony該包下
NeighboringCellInfo.aidl文件必須在android.telephony包下
包名不能寫錯,因為這是系統規定好的關於進程間通信的文件,不能隨便亂改
13.獲取聯系人
public static List<ContactInfo> getContacts(ContentResolver cr) {
//1.首先查詢raw_contacts表中聯系人的id號
Cursor cursor = cr.query(Uri.parse("content://com.android.contacts/raw_contacts"),new String[] { "_id" }, null, null, null);
List<ContactInfo> Contacts = new ArrayList<ContactInfo>();
//2.遍歷所有所有聯系人的id
while (cursor.moveToNext()) {
int _id = cursor.getInt(0);
//3.根據聯系人的id,獲取聯系人的信息,data1代表聯系人的信息,mimtype是代表信息的類型,如電話,郵件,姓名等
Cursor contacts_cursor = cr.query(Uri.parse("content://com.android.contacts/raw_contacts/"+ _id + "/data"),new String[]{"data1","mimetype"},null,null,null);
ContactInfo info = new ContactInfo();
while (contacts_cursor.moveToNext()) {
String data = contacts_cursor.getString(0);
String mimetype = contacts_cursor.getString(1);
if ("vnd.android.cursor.item/name".equals(mimetype)) {// 姓名
info.setName(data);
} else if ("vnd.android.cursor.item/phone_v2".equals(mimetype)) {// 電話
info.setNumber(data);
}
}
Contacts.add(info);
}
return Contacts;
}
14.訂閱開機廣播,判斷sim卡是否變更
1.新建一個類繼承自BroadcastReceiver
2.注冊廣播,並訂閱開啟廣播 android.intent.action.BOOT_COMPLETED
3.在onReceiv()方法中取出手機sim的串口,在和首選項(sharedpreference)中的值進行配對
4.如果不對,就發送短信通知,手機有可能已經丟
15.攔截短信到來
1.新建一個類繼承自BroadcastReceiver
2.注冊廣播,並訂閱接收短信廣播 android.provider.Telephony.SMS_RECEIVED
3.在onReceive()方法中獲取短信內容
Object[] objects = (Object[]) intent.getExtras().get("pdus");
for (Object object : objects) {
byte[] sms = (byte[]) object;
SmsMessage message = SmsMessage.createFromPdu(sms);//創建一個短信對象
String msg_content = message.getDisplayMessageBody();// 獲取信息的內容
String number = message.getDisplayOriginatingAddress();// 獲取發送短信的號碼
//4.中斷廣播
abortBroadcast();
}
}
}
16.GPS手機定位
//獲取定位管理器
LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
//注冊地理發生改變事件監聽器
locationManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER, 0, 0,
new LocationListener() {
public void onStatusChanged(String provider,int status, Bundle extras) {}
public void onProviderEnabled(String provider) {}
public void onProviderDisabled(String provider) {}
public void onLocationChanged(Location location) {
double longitude = location.getLongitude();// 獲取經度值
double latitude = location.getLatitude();// 獲取緯度
}
});
17.遠程鎖屏
1.攔截短信,根據短信的指令判斷是否鎖屏
2.鎖屏
//安全設備管理器
DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
dpm.resetPassword("871405", 0);//設置鎖屏密碼
dpm.lockNow();// 鎖屏
3.遠程鎖屏需要管理員權限,所以要激活管理員權限
(1)首先要定義一個類繼承DeviceAdminReceiver類
public class MyAdmin extends DeviceAdminReceiver {}
(2)激活管理員
//設備安全管理器
DevicePolicyManager dpm = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
// 指定要激活的組件
ComponentName mDevice = new ComponentName(getApplicationContext(),MyAdmin.class);
//判斷該應用是否有管理員權限
if(!dpm.isAdminActive(mDeviceAdminSample)){
Intent intent = new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN);
// 意圖裡面攜帶的數據
intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN,mDevice);
intent.putExtra(DevicePolicyManager.EXTRA_ADD_EXPLANATION,"開啟後可以鎖定屏幕");
startActivityForResult(intent, 100);
}
(3)需要注冊廣播
<receiver
android:name="liu.li.meng.receiver.MyAdmin"
android:permission="android.permission.BIND_DEVICE_ADMIN" >
<meta-data
android:name="android.app.device_admin"
android:resource="@xml/device_admin_sample" />
<intent-filter>
<action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
</intent-filter>
</receiver>
(4)android:resource="@xml/device_admin_sample"依賴一個文件
<?xml version="1.0" encoding="utf-8"?>
<device-admin xmlns:android="http://schemas.android.com/apk/res/android">
<uses-policies>
<limit-password />
<watch-login />
<reset-password />重置密碼
<force-lock />鎖屏
<wipe-data />清理數據(恢復出廠設置)
</uses-policies>
</device-admin>
18.遠程清除數據(恢復出廠設置)
1.攔截短信,根據短信的指令判斷是否清理數據
2.恢復出廠設置(需要管理員權限)
//設備安全管理器
DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
dpm.wipeData(0);// 清除數據,恢復出廠設置
3.一樣需管理員權限,上面的操作都需要進行設置
19.播放報警音樂
1.攔截短信,根據指令播放播放報警音樂
2.播放報請音樂
MediaPlayer mediaPlayer = MediaPlayer.create(context,R.raw.shuai);
mediaPlayer.setLooping(true);// 循環播放
mediaPlayer.setVolume(1.0f, 1.0f);// 設置聲音最大,即使手機是靜音也是最大音量播放
mediaPlayer.start();
20獲取SDCard的可用內存,以及手機內置的可用內存
String sdcardPath = Environment.getExternalStorageDirectory().getAbsolutePath();
getAvailableMemory(sdcardPath);//獲取sdcard可用內存
String memoryPath = Environment.getDataDirectory().getAbsolutePath();
getAvailableMemory(memoryPath);//獲取手機可用內存
public String getAvailableMemory(String path) {
StatFs statFs = new StatFs(path);
// 獲取可用的內存塊
int blocks = statFs.getAvailableBlocks();
int size = statFs.getBlockSize();
// 計算可用的內存空間
int avaiableMemory = blocks * size;
String dataSize = Formatter.formatFileSize(this, avaiableMemory);//格式化數據
return dataSize;
}
21.獲取系統總共運行內存和可用運行內存
文件讀取文件管理器下/proc/meminfo文件;其中第一行就是總共的運行內存,第二行就是可用的運行內存
22.獲取安裝的所有應用
public static List<AppInfo> getInstallApp(Context context){
List<AppInfo> list=new ArrayList<AppInfo>();
PackageManager manager = context.getPackageManager();
List<PackageInfo> infos = manager.getInstalledPackages(0);//獲取所有安裝的應用信息的集合
for (PackageInfo info : infos) {
String versionName = info.versionName;//獲取程序的版本號
String packageName = info.packageName;//獲取應用程序的包名
ApplicationInfo appInfo = info.applicationInfo;//獲取應用程序的相關信息
Drawable iconDrawable = appInfo.loadIcon(manager);//獲取應用程序的圖標
int uid = appInfo.uid;//獲取應用的user id
String name = appInfo.loadLabel(manager).toString();//獲取應用程序的名字
int flags = appInfo.flags;//獲取應用的flags標識
boolean isUserApp = isUserApp(flags);//判斷是否是用戶應用還是系統應用
boolean isInstallSDCard = isInstallSDCard(flags);//判斷應用安裝的位置
AppInfo appInfos=new AppInfo(versionName, iconDrawable, name, uid, isInstallSDCard, isUserApp, packageName);
list.add(appInfos);
}
return list;
}
//判斷是否是系統應用,還是用戶應用
public static boolean isUserApp(int flags) {
if ((flags & ApplicationInfo.FLAG_SYSTEM) == 0) {//用戶安裝的應用
return true;
}else{//系統應用
return false;
}
}
// 判斷安裝的位置
public static boolean isInstallSDCard(int flags){
//安裝到了手機內存
if((flags& ApplicationInfo.FLAG_EXTERNAL_STORAGE)==0){
return false;
}else{//sd卡
return true;
}
}
23.ListView分欄顯示系統應用和用戶應用
1.首先應該是兩個集合,分別存放用戶的應用和系統的應用
2.在實現BaseAdapter類中的getCount()方法應該寫成,return userApp.size()+systemApp.size()+2;
這裡的加2是因為用來標識是系統應用欄目,還是用戶應用欄目
3.在getItem()方法中修改代碼如下:
public AppInfo getItem(int position) {
if(position==0){
return null;
}else if(position<=userApp.size()){
return userApp.get(position-1);//返回用於安裝的應用
}else if(position==userApp.size()+1){
return null;
}else{
return systemApp.get(position-(userApp.size()+2));//返回系統安裝的應用
}
}
4.getView()中的設置如下:
public View getView(int position, View convertView, ViewGroup parent) {
if (position == 0) {
TextView tv = null;
if(convertView != null && convertView instanceof TextView){
tv = (TextView) convertView;
}else{
tv = (TextView) getLayoutInflater().inflate(R.layout.list_separator, null);
}
tv.setText("用戶進程("+userApp.size()+")");
//用戶應用的欄目
return tv;
} else if (position == userApp.size() + 1) {
//系統應用的欄目
TextView tv = null;
if(convertView != null && convertView instanceof TextView){
tv = (TextView) convertView;
}else{
tv = (TextView) getLayoutInflater().inflate(R.layout.list_separator, null);
}
tv.setText("系統進程("+systemApp.size()+")");
return tv;
} else if(position<=userApp.size()){
ViewHolder holder = null;
View view = null;
if (convertView == null || convertView instanceof TextView) {
view = getLayoutInflater().inflate(R.layout.activity_app_manager_lv_item, null);
holder = new ViewHolder();
holder.app_icon = (ImageView) view.findViewById(R.id.app_icon);
......
view.setTag(holder);
} else {
view = convertView;
holder = (ViewHolder) view.getTag();
}
AppInfo appInfo = userApp.get(position-1);
holder.app_icon.setImageDrawable(appInfo.getIcon());
return view;
}
else{
ViewHolder holder = null;
View view = null;
if (convertView == null || convertView instanceof TextView) {
view = getLayoutInflater().inflate(R.layout.activity_app_manager_lv_item, null);
holder = new ViewHolder();
holder.app_icon = (ImageView) view.findViewById(R.id.app_icon);
holder.iv_app_lock = (ImageView) view.findViewById(R.id.iv_app_lock);
view.setTag(holder);
} else {
view = convertView;
holder = (ViewHolder) view.getTag();
}
AppInfo appInfo = systemApp.get(position-(userApp.size()+2));
holder.app_icon.setImageDrawable(appInfo.getIcon());
......
return view;
}
}
}
static class ViewHolder {
ImageView app_icon;
ImageView iv_app_lock;
TextView tv_app_name;
TextView tv_app_package_name;
TextView tv_app_version_name;
TextView tv_app_install_location;
TextView tv_app_uid;
}
24.卸載應用
Intent intent = new Intent();
intent.setAction("android.intent.action.DELETE");
intent.setData(Uri.parse("package:" + packageName));
startActivity(intent);
25.啟動應用
PackageManager pm=context.getPackageManager();
Intent intent = pm.getLaunchIntentForPackage(packageName);
if (intent == null) {
Toast.makeText(this, "該應用無法啟動", 0).show();
return;
}
startActivity(intent);
26.顯示應用詳情信息
Intent intent = new Intent();
intent.setAction("android.settings.APPLICATION_DETAILS_SETTINGS");
intent.setData(Uri.parse("package:" + packageName));
startActivity(intent);
27.激活新建短信頁面
Intent intent = new Intent();
intent.setAction(Intent.ACTION_SEND);
intent.setType("text/plain");
intent.putExtra(Intent.EXTRA_TEXT, "我發現了一個好玩的軟件,趕緊下載吧www.baidu.com");//短信內容
startActivity(intent);
28.PopupWindow
View v = getLayoutInflater().inflate(R.layout.app_manager_popup, null);
//新建popuwindow
PopupWindow pop = new PopupWindow(v, ViewGroup.LayoutParams.WRAP_CONTENT,ViewGroup.LayoutParams.WRAP_CONTENT);
// 設置pop獲得焦點
pop.setFocusable(true);
// 必須要設置背景資源,點擊別的區域,才會自動消失
pop.setBackgroundDrawable(new BitmapDrawable());
int[] location = new int[2];//定義一個數組存放view的位置
view.getLocationInWindow(location);//獲取view在窗口的位置
pop.showAtLocation(view, Gravity.LEFT | Gravity.TOP,location[0] + 50, location[1]);
// 定義動畫
AnimationSet set = new AnimationSet(false);// 動畫集合
AlphaAnimation alpha = new AlphaAnimation(0.3f, 1f);// 透明度改變動畫
alpha.setDuration(500);// 設置動畫的周期時間
ScaleAnimation scale = new ScaleAnimation(0f, 1f,// x軸
1f, 1f,// y軸
Animation.RELATIVE_TO_SELF, 0,// x點
Animation.RELATIVE_TO_SELF, 0.5f);// y點
scale.setDuration(500);
set.addAnimation(alpha);
set.addAnimation(scale);
v.startAnimation(set);
29.給程序加鎖或者解鎖
程序鎖的原理:就是在Android中有一個任務棧,獲取到任務棧的頂部的任務,就是剛才你打開的應用,根據這個原理
判斷一個應用是否在頂部,就可以判斷程序是否加鎖了
1.應該有一個開關開啟一個程序鎖的功能,並開啟一個程序鎖服務
2.在服務中實時的監測用戶要打開的應用是否加鎖,是一個非常耗時的操作,應該開啟一個線程;
並定義一個標志位使用while(flag)循環,在服務結束的時候就應該置為false
3.在應用列表中長按一個應用,進行加鎖或者解鎖的操作(程序鎖數據庫的增刪操作);
如果是解鎖操作,需要發送一個廣播,通知這個程序已經解鎖
4.在服務中OnCreate()方法獲取按住的應用,查詢應用鎖數據庫,是否是枷鎖狀態,如果是則解鎖(從數據庫刪除記錄),
如果不是就加鎖(往數據庫添加記錄)
5.當手機屏幕滅屏的時候,就讓線程休眠等待,手機亮屏就喚醒線程,這裡需要訂閱手機亮屏和滅屏的廣播接受者
核心代碼:
new Thread(new Runnable() {
public void run() {
while (flag) {
synchronized (AppLockService.class) {
if(isScreenOn){
ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
// 獲取正在運行的任務棧(最近打開的任務是在最前面)
List<RunningTaskInfo> tasks = manager.getRunningTasks(10);
// 最新的那個任務棧
RunningTaskInfo taskInfo = tasks.get(0);
// 最頂端的activity
ComponentName topActivity = taskInfo.topActivity;
final String packageName = topActivity.getPackageName();
if (!packageName.equals(tempApp)) {
if (isLockApp(packageName)) {
Intent intent = new Intent(getApplicationContext(),
AppLockEnterPasswordActivity.class);
intent.putExtra("packageName", packageName);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
}
}else{
try {
AppLockService.class.wait(500);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
}).start();
30.進程管理
1.獲取activityManager管理器ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
2.通過管理器獲取正在運行的進程集合manager.getRunningAppProcesses();
3.遍歷進程集合
public static List<TaskInfo> getRunningTask(Context context) {
List<TaskInfo> tasks = new ArrayList<TaskInfo>();
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
// 獲取所有運行的進程
List<RunningAppProcessInfo> runningAppProcesses = am.getRunningAppProcesses();
PackageManager pm = context.getPackageManager();
boolean flag=true;
for (RunningAppProcessInfo proInfo : runningAppProcesses) {
// 獲取應用的包名
String packageName = proInfo.processName;
TaskInfo taskInfo = new TaskInfo();
taskInfo.setPackageName(packageName);
ApplicationInfo applicationInfo=null;
try {
flag=true;
//當一個進程沒有應用信息時,就在下面的一句中,出現了異常所以捕捉異常
//所以這裡用了一個標記,來處理這些特殊的進程
applicationInfo = pm.getApplicationInfo(packageName, 0);
} catch (Exception e) {
flag=false;
}
if (!flag) {
taskInfo.setAppName(packageName);
taskInfo.setIcon(context.getResources().getDrawable(R.drawable.ic_launcher));
} else {
Drawable icon = applicationInfo.loadIcon(pm);
taskInfo.setIcon(icon);
String name = applicationInfo.loadLabel(pm).toString();
taskInfo.setAppName(name);
boolean isUserTask = filterApp(applicationInfo);
taskInfo.setUserTask(isUserTask);
}
// 獲取應用的占用內存空間
int pid = proInfo.pid;
int[] pids = new int[] { pid };
MemoryInfo[] processMemoryInfo = am.getProcessMemoryInfo(pids);
int memory = processMemoryInfo[0].getTotalPrivateDirty() * 1024;
String size = Formatter.formatFileSize(context, memory);// 格式化應用的內存
// 判斷是否是系統應用還是用戶應用
taskInfo.setMemory(size);
tasks.add(taskInfo);
}
return tasks;
}
//殺死進程
am.killBackgroundProcesses(taskInfo.getPackageName());
31.窗口小部件進行一鍵清理進程
//1.窗口小部件
AppWidgetManager widgetManager = AppWidgetManager.getInstance(getApplicationContext());
ComponentName provider = new ComponentName(getApplicationContext(),ProcessAppWidget.class);
RemoteViews views = new RemoteViews(getPackageName(),R.layout.example_appwidget);
widgetManager.updateAppWidget(provider, views);
ActivityManager activityManager=(ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
List<RunningAppProcessInfo> list = activityManager.getRunningAppProcesses();
views.setTextViewText(R.id.tv_running_task, "正在運行的軟件:"+list.size()+"個");
try {
views.setTextViewText(R.id.tv_avail_memory, "可用內存:"+getAvailMemory());
} catch (Exception e) {
e.printStackTrace();
}
//殺死進程
kills(list,activityManager);
//點擊一鍵清理按鈕,重新啟動服務,殺死所有正在運行的進程
Intent intented=new Intent(this,AppWidgetService.class);
PendingIntent pendingIntent=PendingIntent.getService(getApplicationContext(), 200, intented, 0);
views.setOnClickPendingIntent(R.id.btn_clear, pendingIntent);
//點擊手機衛士,啟動打開安全衛士的首頁
Intent intentStart=new Intent(this,MainActivity.class);
PendingIntent startMobile=PendingIntent.getActivity(getApplicationContext(), 200, intentStart, 0);
views.setOnClickPendingIntent(R.id.tv_mobilesafe, startMobile);
//更新視圖
widgetManager.updateAppWidget(provider, views);
//殺死進程
private void kills(List<RunningAppProcessInfo> list, ActivityManager activityManager) {
for (RunningAppProcessInfo info : list) {
String packageName = info.processName;
if(!packageName.equals(getPackageName())){
activityManager.killBackgroundProcesses(packageName);
}
}
}
//2.常見一個廣播繼承AppWidgetProvider
public class ProcessAppWidget extends AppWidgetProvider {
public void onEnabled(Context context) {
super.onEnabled(context);
//開啟窗口小部件服務
Intent service=new Intent(context, AppWidgetService.class);
context.startService(service);
}
public void onDisabled(Context context) {
super.onDisabled(context);//關閉窗口小部件服務
Intent service=new Intent(context, AppWidgetService.class);
context.stopService(service);
}
}
//3.注冊廣播
<receiver android:name="liu.li.meng.receiver.ProcessAppWidget" >
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/example_appwidget_info" />
</receiver>
//4.設置example_appwidget_info文件
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:minWidth="294dp"
android:minHeight="72dp"
android:initialLayout="@layout/example_appwidget">
</appwidget-provider>
32.流量統計(TrafficStats)
public static List<TrafficInfo> getTraffics(Context context){
List<TrafficInfo> traffics=new ArrayList<TrafficInfo>();
PackageManager pm = context.getPackageManager();
List<PackageInfo> installedPackages = pm.getInstalledPackages(0);
for (PackageInfo packageInfo : installedPackages) {
ApplicationInfo applicationInfo = packageInfo.applicationInfo;
String name = applicationInfo.loadLabel(pm).toString();//獲取應用的名字
Drawable icon = applicationInfo.loadIcon(pm);//獲取應用的圖標
int uid = applicationInfo.uid;//獲取應用的uid
long rx = TrafficStats.getUidRxBytes(uid);//獲取接受的數據流量
long tx = TrafficStats.getUidTxBytes(uid);//獲取發送的數據流量
long totalx=rx+tx;
TrafficInfo info=new TrafficInfo(rx, tx, name, totalx, icon);
traffics.add(info);
}
return traffics;
}
33.手機殺毒
使用金山的殺毒數據庫,殺毒原理:包名相同和簽名(經過MD5加密)也相同才認為是病毒
1.獲取應用的簽名信息
public String getSignatures(String packageName) throws Exception {
PackageInfo packageInfo = pm.getPackageInfo(packageName,PackageManager.GET_SIGNATURES);
Signature[] signatures = packageInfo.signatures;
String signature = signatures[0].toCharsString();
String result = Md5Utils.encode(signature);
return result;
}
2.查詢所有的病毒數據,進行掃描匹配;金山病毒數據庫,有兩個字段,md5(軟件簽名信息),name(應用的包名)
34.旋轉動畫
讓一個圖片不停的旋轉
animation = new RotateAnimation(0, 360,Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,0.5f);
// 動畫執行的周期
animation.setDuration(2000);
// 重復旋轉
animation.setRepeatCount(Integer.MAX_VALUE);
lv.startAnimation(animation);
35.自定義進度條
1.首先寫一個自定義進度條progress_style文件
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:id="@android:id/background">
<bitmap android:src="@drawable/security_progress_bg" />
</item>
<item android:id="@android:id/secondaryProgress">
<bitmap android:src="@drawable/security_progress" />
</item>
<item android:id="@android:id/progress">
<bitmap android:src="@drawable/security_progress" />
</item>
</layer-list>
2.然後在progressbar的屬性設置為android:progressDrawable="@drawable/progress_style"
36.移動改變控件的位置
1.找到控件
2.獲取到屏幕的寬高
Display display = getWindowManager().getDefaultDisplay();
//獲取屏幕的寬高
int screenwidth = display.getWidth();
int screenHeight = display.getHeight();
3.給控件設置觸摸事件
btn_location.setOnTouchListener(new OnTouchListener() {
int startx=0;
int starty=0;
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
startx=(int) event.getRawX();
starty=(int) event.getRawY();
break;
case MotionEvent.ACTION_MOVE:
//getRawx獲取的是相對於屏幕的坐標
int stopx=(int) event.getRawX();
int stopy=(int) event.getRawY();
//計算移動的距離
int distancex=stopx-startx;
int distancey=stopy-starty;
//計算控件相對於屏幕的位置變化
int left = btn_location.getLeft()+distancex;
int right = btn_location.getRight()+distancex;
int top = btn_location.getTop()+distancey;
int bottom = btn_location.getBottom()+distancey;
//在屏幕顯示區域改變位置,方式控件移除屏幕
if(left>=0 && right<=screenwidth && top>=0 && bottom<=screenHeight){
btn_location.layout(left, top, right, bottom);//更改控件的位置
}
//把這次的終點作為下次的起點
startx=stopx;
starty=stopy;
break;
case MotionEvent.ACTION_UP:
break;
}
return false;
}
});
37.三擊居中
btn_location.setOnClickListener(new OnClickListener() {
long[] mHits = new long[3];
public void onClick(View v) {System.arraycopy(mHits, 1, mHits, 0, mHits.length-1);
mHits[mHits.length-1] = SystemClock.uptimeMillis();
//三擊居中
if (mHits[0] >= (SystemClock.uptimeMillis()-500)) {
//獲取控件的寬高
int width = btn_location.getWidth();
int height = btn_location.getHeight();
int l = screenwidth/2 - width/2;
int t = screenHeight/2 - height/2;
int r = screenwidth/2 + width/2;
int b = screenHeight/2 + height/2;
//居中
btn_location.layout(l, t, r, b);
}
}
});
38.緩存清理
1.獲取所有具有緩存信息的應用
(1)public void getCacheApp(Context context) throws Exception {
PackageManager pm = context.getPackageManager();
List<PackageInfo> installedPackages = pm.getInstalledPackages(0);
size=installedPackages.size();
for (PackageInfo packageInfo : installedPackages) {
String packageName = packageInfo.packageName;
// 獲取緩存信息PackageManager中getPackageSizeInfo()隱藏了該方法,所以只能通過反射的手段得到
Class<?> clazz = Class.forName("android.content.pm.PackageManager");
Method method = clazz.getMethod("getPackageSizeInfo", new Class[] {String.class, IPackageStatsObserver.class });
// 調用方法,他會自動回調IPackageStatsObserver中的onGetStatsCompleted方法
method.invoke(pm, new Object[] { packageName, observer });
}
}
(2)//這是一個異步的方法
IPackageStatsObserver.Stub observer = new Stub() {
@Override
public void onGetStatsCompleted(PackageStats pStats, boolean succeeded) throws RemoteException {
i++;
long cacheSize=pStats.cacheSize;//緩存的大小
if(cacheSize>0){
try {
String packageName=pStats.packageName;//獲取應用的包名
ApplicationInfo applicationInfo = pm.getApplicationInfo(packageName, 0);
Drawable icon = applicationInfo.loadIcon(pm);//圖標
String name = applicationInfo.loadLabel(pm).toString();//應用的名字
String cache = Formatter.formatFileSize(context, cacheSize);
CacheInfo info=new CacheInfo(icon, name, cache, packageName);
caches.add(info);
} catch (Exception e) {
e.printStackTrace();
}
}
if(i==size){
//因為這是一個異步的方法,所以要用一個變量統計當內容加載完之後回調activity通知已經加載完畢 ,之後進行list的顯示
activity.cacheFinish(caches);
}
}
};
IPackageStatsObserver對象依賴於兩個個aidl文件,在android.content.pm包下的IPackageStatsObserver.aidl文件和PackageStats.aidl文件
2.一鍵清理緩存
在framwork中提供了該方法。但是在上層系統給隱藏了起來,所以只能通過反射才能獲取到該方法
public abstract void freeStorageAndNotify(long freeStorageSize, IPackageDataObserver observer);
PackageManager pm=getPackageManager();
Class<?> clazz = Class.forName("android.content.pm.PackageManager");
Method method = clazz.getMethod("freeStorageAndNotify", new Class[]{Long.TYPE,IPackageDataObserver.class});
//計算釋放的空間,這裡的參數是手機內存的大小(getMemory()或者getMemory()-1L)
Long freeSize=Long.valueOf(getMemory()-1L);
//清理緩存
method.invoke(pm, new Object[]{freeSize,obsever});
//清空集合
if(!(list == null || list.size() == 0)){
list.clear();
adapter.notifyDataSetChanged();
}
}
注意:單獨清理一個內存是實現不了的,因為系統不支持
39.短信的備份
原理:就是通過內容提供者讀取到所有的短信內容,之後通過把短信內容json格式的字符串寫入到一個文件中
1.讀取所有短信內容
public List<MessageInfo> getAllMessage(Context context){
List<MessageInfo> infos=new ArrayList<MessageInfo>();
ContentResolver re = context.getContentResolver();
Cursor cursor = re.query(Uri.parse("content://sms"), new String[]{"type","body","address","date"}, null, null, null);
while(cursor.moveToNext()){
int type = cursor.getInt(0);
String body = cursor.getString(1);
String address = cursor.getString(2);
long date = cursor.getLong(3);
MessageInfo info=new MessageInfo(address, date, body, type);
infos.add(info);
}
return infos;
}
2.通過Gson框架,把短信集合轉換成json字符串
Gson gson=new Gson();
String json = gson.toJson(infos);
3.把字符串寫入文件
FileOutputStream outputStream=new FileOutputStream(Environment.getExternalStorageDirectory()+"/msm.txt");
outputStream.write(json.getBytes());
outputStream.close();
40.短信的恢復
1.讀取備份短信文件
2.把json格式的數據封裝成對象
3.刪除所有短信內容,把數據添加到短信數據庫中
private void smsRestore(File file) {
try {
//1.讀取短息備份文件
FileInputStream inputStream=new FileInputStream(file);
int len=0;
byte[] buffer=new byte[1024];
ByteArrayOutputStream outputStream=new ByteArrayOutputStream();
while((len=inputStream.read(buffer))!=-1){
outputStream.write(buffer, 0, len);
}
String json = outputStream.toString();
//2.把字符串封裝到MessageInfo對象中
List<MessageInfo> infos = dao.changeStringToList(this, json);
ContentResolver re = getContentResolver();
//3.刪除所有短信內容
re.delete(Uri.parse("content://sms"), null, null);
//4.恢復短信內容
for (MessageInfo info : infos) {
ContentValues values=new ContentValues();
values.put("body", info.getBody());
values.put("date", info.getDate());
values.put("address", info.getAddress());
values.put("type", info.getType());
re.insert(Uri.parse("content://sms"), values);
}
Toast.makeText(this, "短信還原成功", 0).show();
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(this, "短信還原失敗", 0).show();
}
}
復制代碼
41.來去電歸屬地的顯示
1.應該通過一個開關,是否打開歸屬地顯示功能
2.如果開啟歸屬地顯示功能,就應該啟動一個服務,一直監聽電話的狀態
3.外撥電話歸屬地的顯示,需要獲取到外撥電話號碼,那就必須自己定義一個外撥電話廣播,獲取到電話號碼,之後查詢歸屬地數據庫顯示即可
4.來電歸屬地,通過TelephonyManager.listen(PhoneStateListener listen, PhoneStateListener.LISTEN_CALL_STATE)的一個方法監聽即可
5.歸屬地的顯示,需要通過windowManager對象添加到窗口上顯示,才可顯示出來,我們這裡通過Toast的方式添加到窗口中
//電話管理器
TelephonyManager telephonyManager = (TelephonyManager) getApplicationContext().getSystemService(Context.TELEPHONY_SERVICE);
//window管理器
WindowManagerw indowManager = (WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
//監聽來電電話的狀態
listener = new MyPhoneListener();
telephonyManager.listen(listener, PhoneStateListener.LISTEN_CALL_STATE);
//注冊外撥電話廣播接受者
receiver = new MyCallOutGoingReceiver();
IntentFilter filter=new IntentFilter();
filter.addAction(Intent.ACTION_NEW_OUTGOING_CALL);
registerReceiver(receiver, filter);
//外撥電話廣播
private class MyCallOutGoingReceiver extends BroadcastReceiver{
public void onReceive(Context context, Intent intent) {
String number = getResultData();//外撥電話號碼
showAddressWindow(number);
}
}
//來電狀態的一個監聽器
private class MyPhoneListener extends PhoneStateListener {
@Override
public void onCallStateChanged(int state, String incomingNumber) {
switch (state) {
case TelephonyManager.CALL_STATE_IDLE:// 閒置狀態
if(view!=null){
windowManager.removeView(view);
}
break;
case TelephonyManager.CALL_STATE_RINGING:// 響鈴狀態
showAddressWindow(incomingNumber);
break;
case TelephonyManager.CALL_STATE_OFFHOOK:// 接聽狀態
break;
}
}
}
//顯示歸屬地顯示視圖
private void showAddressWindow(String incomingNumber) {
final WindowManager.LayoutParams params = new LayoutParams();
params.height = WindowManager.LayoutParams.WRAP_CONTENT;
params.width = WindowManager.LayoutParams.WRAP_CONTENT;
params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
// | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE 不可觸摸
| WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
params.format = PixelFormat.TRANSLUCENT;
params.type = WindowManager.LayoutParams.TYPE_PRIORITY_PHONE;// 設置優先級和電話一樣
view = LayoutInflater.from(getApplicationContext()).inflate(R.layout.call_show_address, null);
TextView tv_address=(TextView) view.findViewById(R.id.btn_address);
//查詢電話號碼的歸屬地
String address = AddressDao.getAddress(getApplicationContext(), incomingNumber);
tv_address.setText(address);
view.setBackgroundResource(Id);
//添加window窗口
windowManager.addView(view, params);
//可以拖動歸屬地顯示的位置
view.setOnTouchListener(new OnTouchListener() {
int startx=0;
int starty=0;
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
startx=(int) event.getRawX();//getRawX()獲取到相對於屏幕的距離
starty=(int) event.getRawY();
break;
case MotionEvent.ACTION_MOVE:
int stopx=(int) event.getRawX();
int stopy=(int) event.getRawY();
int distancex=stopx-startx;//計算移動的距離
int distancey=stopy-starty;
params.x+=distancex;
params.y+=distancey;
windowManager.updateViewLayout(view, params);//更新視圖的位置
//把停止的點設置為新的起點
startx=stopx;
starty=stopy;
break;
case MotionEvent.ACTION_UP:
break;
}
return true;
}
});
}
@Override
public void onDestroy() {
// 取消電話的監聽
telephonyManager.listen(listener, PhoneStateListener.LISTEN_NONE);
unregisterReceiver(receiver);//取消外撥電話的廣播接受
super.onDestroy();
}