注意:有些功能是須要權限的,在這裏並無寫出來,在程序運行中,根據程序報的錯誤,添加相應的權限便可,裏面的具體裏面可能有一些小細節,沒有明確的寫出來,具體的須要在程序中本身調試,解決。
這個總結涵蓋了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(); }