本篇博文主要介绍的是Android中的Java服务。
这部分服务大部分都有一个Manager类,其实就是一个RPC调用,用户通过调用xxxManager的方法,实际上被Binder给迁移到system_server进程中对应的xxxManagerService中对应的方法,并将结果再通过binder带回。
常用的有如下几个:
PowerManagerService –> PowerManager
| Tables | Are |
|---|---|
| PowerManagerService –> PowerManager | Android 的电源管理 |
| ActivityManagerService->ActivityManager | 整个Android framework框架中最为核心的一个服务,管理整个框架中任务、进程管理, Intent解析等的核心实现。虽然名为Activity的Manager Service,但它管辖的范围,不只是Activity,还有其他三大组件,和它们所在的进程。也就是说用户应用程序的生命管理,都是由他负责的。 |
| TelephonyRegistry->TelephonyManager | 电话注册、管理服务模块,可以获取电话的链接状态、信号强度等等 |
| PackageManagerService -> PackageManager | 包括对软件包的解包,验证,安装以及升级等等,对于我们现在不能安装.so文件的问题,应该先从这块着手分析原因。 |
| AccountManagerService -> AccountManager | 提供账户、密码和authtoken管理设备上的账户 |
| ContentService -> ContentResolver | 内容服务,主要是数据库等提供解决方法的服务。 |
| BatteryService | 监控电池充电及状态的服务,当状态改变时,会广播Intent |
| WindowManagerService -> WindowManager -> PhoneWindowManager | 和ActivityManagerService高度粘合窗口管理,这里最核心的就是输入事件的分发和管理。 |
| AlarmManagerService -> AlarmManager | 闹钟服务程序 |
| BluetoothService -> BluetoothDevice | 蓝牙的后台管理和服务程序 |
| ClipboardService -> ClipboardManager | 和其他系统的clipBoard服务类似,提供复制黏贴功过。 |
| InputMethodManagerService -> InputMethodManager | 输入法的管理服务程序,包括何时使能输入法,切换输入法等等。 |
| NetStatService | 手机网络服务 |
| ConnectivityService -> ConnectivityManager | 网络连接状态服务,可供其他应用查询,当网络状态变化时,也可广播改变。 |
| NotificationManagerService -> NotificationManager | 负责管理和通知后台事件的发生等,这个和statusbar胶黏在一起,一般会在statusbar上添加响应图标。用户可以通过这知道系统后台发生了什么 |
| WallpaperManagerService -> WallpaperManager | 管理桌面背景的服务,深度定制化桌面系统 |
| AppWidgetService -> AppWidgetManager | Android可以让用户写的程序以widget的方式放在桌面上,这就是这套管理和服务的接口 |
| AudioService -> AudioManager | AudioFlinger的上层管理封装,主要是音量、音效、声道及铃声等的管理 |
TelephonyManager telephonyManager = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
Uri uri=Uri.parse("tel:"+电话号码);
Intent intent=new Intent(Intent.ACTION_DIAL,uri);
startActivity(intent);
public class MainActivity extends AppCompatActivity {
private TextView tv_phone1;
private TextView tv_phone2;
private TextView tv_phone3;
private TextView tv_phone4;
private TextView tv_phone5;
private TextView tv_phone6;
private TextView tv_phone7;
private TextView tv_phone8;
private TextView tv_phone9;
private TelephonyManager tManager;
private String[] phoneType = {"未知","2G","3G","4G"};
private String[] simState = {"状态未知","无SIM卡","被PIN加锁","被PUK加锁",
"被NetWork PIN加锁","已准备好"};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//①获得系统提供的TelphonyManager对象的实例
tManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
bindViews();
}
private void bindViews() {
tv_phone1 = (TextView) findViewById(R.id.tv_phone1);
tv_phone2 = (TextView) findViewById(R.id.tv_phone2);
tv_phone3 = (TextView) findViewById(R.id.tv_phone3);
tv_phone4 = (TextView) findViewById(R.id.tv_phone4);
tv_phone5 = (TextView) findViewById(R.id.tv_phone5);
tv_phone6 = (TextView) findViewById(R.id.tv_phone6);
tv_phone7 = (TextView) findViewById(R.id.tv_phone7);
tv_phone8 = (TextView) findViewById(R.id.tv_phone8);
tv_phone9 = (TextView) findViewById(R.id.tv_phone9);
tv_phone1.setText("设备编号:" + tManager.getDeviceId());
tv_phone2.setText("软件版本:" + (tManager.getDeviceSoftwareVersion()!= null?
tManager.getDeviceSoftwareVersion():"未知"));
tv_phone3.setText("运营商代号:" + tManager.getNetworkOperator());
tv_phone4.setText("运营商名称:" + tManager.getNetworkOperatorName());
tv_phone5.setText("网络类型:" + phoneType[tManager.getPhoneType()]);
tv_phone6.setText("设备当前位置:" + (tManager.getCellLocation() != null ? tManager
.getCellLocation().toString() : "未知位置"));
tv_phone7.setText("SIM卡的国别:" + tManager.getSimCountryIso());
tv_phone8.setText("SIM卡序列号:" + tManager.getSimSerialNumber());
tv_phone9.setText("SIM卡状态:" + simState[tManager.getSimState()]);
}
}
访问以上API,记得清单文件添加权限
<!-- 添加访问手机位置的权限 -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<!-- 添加访问手机状态的权限 -->
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
网络信号强度的单位是dBm(毫瓦分贝),一般用负数表示,正常手机信号变化范围是从-110dBm (差)到-50dBm(好)之间,如果你比-50dBm还小的话,说明你就站在基站的附近。
另外2G,3G,4G获得信号强度的方式都是重写PhoneStateListener的onSignalStrengthsChanged() 方法,当信号强度发生改变的时候就会触发这个事件,我们可以在这个事件里获取信号强度!
手机获取信号强度代码示例:
dBm =-113+2*asu这是一个固定公式,asu(独立信号单元)
public class MainActivity extends AppCompatActivity {
private TextView tv_rssi;
private MyPhoneStateListener mpsListener;
private TelephonyManager tManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tManager = ((TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE));
tv_rssi = (TextView) findViewById(R.id.tv_rssi);
mpsListener = new MyPhoneStateListener();
tManager.listen(mpsListener,290);
}
private class MyPhoneStateListener extends PhoneStateListener {
private int asu = 0,lastSignal = 0;
@Override
public void onSignalStrengthsChanged(SignalStrength signalStrength) {
asu = signalStrength.getGsmSignalStrength();
lastSignal = -113 + 2 * asu;
tv_rssi.setText("当前手机的信号强度:" + lastSignal + " dBm" );
super.onSignalStrengthsChanged(signalStrength);
}
}
}
getEvdoDbm():电信3G
getCdmaDbm():联通3G
getLteDbm():4G
详见本人另外一篇博客来去电拦截
详见本人另外一篇博客AIDL与来去电自动挂断
不建议使用 android.telephony.gsm.SmsManager这个类
This class was deprecated in API level 4.
Replaced by android.telephony.SmsManager that supports both GSM and CDMA.
建议使用 android.telephony.SmsManager
这样发短信,app安装的时候就可以少写一条发短信的权限
核心代码
public void SendSMSTo(String phoneNumber,String message){
//判断输入的phoneNumber是否为合法电话号码
if(PhoneNumberUtils.isGlobalPhoneNumber(phoneNumber)){
//Uri.parse("smsto") 这里是转换为指定Uri,固定写法
Intent intent = new Intent(Intent.ACTION_SENDTO, Uri.parse("smsto:"+phoneNumber));
intent.putExtra("sms_body", message);
startActivity(intent);
}
}
这个就需要发短信的权限啦
uses-permission android:name="android.permission.SEND_SMS"/>
我们直接调用SmsManager为我们提供的短信接口发送短信:
sendTextMessage(destinationAddress, scAddress, text, sentIntent, deliverIntent);
参数依次是:
核心代码
public void sendSMS(String phoneNumber,String message){
//获取短信管理器
android.telephony.SmsManager smsManager = android.telephony.SmsManager.getDefault();
//拆分短信内容(手机短信长度限制),貌似长度限制为140个字符,就是
//只能发送70个汉字,多了要拆分成多条短信发送
//第四五个参数,如果没有需要监听发送状态与接收状态的话可以写null
List<String> divideContents = smsManager.divideMessage(message);
for (String text : divideContents) {
smsManager.sendTextMessage(phoneNumber, null, text, sentPI, deliverPI);
}
}
可能你还需要监听短信是否发送成功,或者收信人是否接收到信息,就把下面的加上吧:
//处理返回的发送状态
String SENT_SMS_ACTION = "SENT_SMS_ACTION";
Intent sentIntent = new Intent(SENT_SMS_ACTION);
PendingIntent sentPI = PendingIntent.getBroadcast(context, 0, sentIntent, 0);
//注册发送信息的广播接收者
context.registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context _context, Intent _intent) {
switch (getResultCode()) {
case Activity.RESULT_OK:
Toast.makeText(context, "短信发送成功", Toast.LENGTH_SHORT).show();
break;
case SmsManager.RESULT_ERROR_GENERIC_FAILURE: //普通错误
break;
case SmsManager.RESULT_ERROR_RADIO_OFF: //无线广播被明确地关闭
break;
case SmsManager.RESULT_ERROR_NULL_PDU: //没有提供pdu
break;
case SmsManager.RESULT_ERROR_NO_SERVICE: //服务当前不可用
break;
}
}
}, new IntentFilter(SENT_SMS_ACTION));
//处理返回的接收状态
String DELIVERED_SMS_ACTION = "DELIVERED_SMS_ACTION";
//创建接收返回的接收状态的Intent
Intent deliverIntent = new Intent(DELIVERED_SMS_ACTION);
PendingIntent deliverPI = PendingIntent.getBroadcast(context, 0,deliverIntent, 0);
context.registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context _context, Intent _intent) {
Toast.makeText(context,"收信人已经成功接收", Toast.LENGTH_SHORT).show();
}
}, new IntentFilter(DELIVERED_SMS_ACTION));
AudioManager audiomanage = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE);
简单的示例:使用Mediaplayer播放音乐,通过AudioManager调节音量大小与静音!
对了,先在res下创建一个raw的文件夹,往里面丢一个MP3资源文件!
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/LinearLayout1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:id="@+id/btn_start"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="播放" />
<Button
android:id="@+id/btn_stop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:enabled="false"
android:text="停止" />
<Button
android:id="@+id/btn_higher"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="调高音量" />
<Button
android:id="@+id/btn_lower"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="调低音量" />
<Button
android:id="@+id/btn_quite"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="静音" />
</LinearLayout>
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private Button btn_start;
private Button btn_stop;
private Button btn_higher;
private Button btn_lower;
private Button btn_quite;
private MediaPlayer mePlayer;
private AudioManager aManager;
//定义一个标志用来标示是否点击了静音按钮
private int flag = 1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//获得系统的音频对象
aManager = (AudioManager) getSystemService(Service.AUDIO_SERVICE);
//初始化mediaplayer对象,这里播放的是raw文件中的mp3资源
mePlayer = MediaPlayer.create(MainActivity.this, R.raw.countingstars);
//设置循环播放:
mePlayer.setLooping(true);
bindViews();
}
private void bindViews() {
btn_start = (Button) findViewById(R.id.btn_start);
btn_stop = (Button) findViewById(R.id.btn_stop);
btn_higher = (Button) findViewById(R.id.btn_higher);
btn_lower = (Button) findViewById(R.id.btn_lower);
btn_quite = (Button) findViewById(R.id.btn_quite);
btn_start.setOnClickListener(this);
btn_stop.setOnClickListener(this);
btn_higher.setOnClickListener(this);
btn_lower.setOnClickListener(this);
btn_quite.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_start:
btn_stop.setEnabled(true);
mePlayer.start();
btn_start.setEnabled(false);
break;
case R.id.btn_stop:
btn_start.setEnabled(true);
mePlayer.pause();
btn_stop.setEnabled(false);
break;
case R.id.btn_higher:
// 指定调节音乐的音频,增大音量,而且显示音量图形示意
aManager.adjustStreamVolume(AudioManager.STREAM_MUSIC,
AudioManager.ADJUST_RAISE, AudioManager.FLAG_SHOW_UI);
break;
case R.id.btn_lower:
// 指定调节音乐的音频,降低音量,只有声音,不显示图形条
aManager.adjustStreamVolume(AudioManager.STREAM_MUSIC,
AudioManager.ADJUST_LOWER, AudioManager.FLAG_PLAY_SOUND);
break;
case R.id.btn_quite:
// 指定调节音乐的音频,根据isChecked确定是否需要静音
flag *= -1;
if (flag == -1) {
aManager.setStreamMute(AudioManager.STREAM_MUSIC, true); //API 23过期- -
// aManager.adjustStreamVolume(AudioManager.STREAM_MUSIC, AudioManager.ADJUST_MUTE,
// AudioManager.FLAG_SHOW_UI); //23以后的版本用这个
btn_quite.setText("取消静音");
} else {
aManager.setStreamMute(AudioManager.STREAM_MUSIC, false);//API 23过期- -
// aManager.adjustStreamVolume(AudioManager.STREAM_MUSIC, AudioManager.ADJUST_UNMUTE,
// AudioManager.FLAG_SHOW_UI); //23以后的版本用这个
aManager.setMicrophoneMute(false);
btn_quite.setText("静音");
}
break;
}
}
}
设置静音的方法setStreamMute()在API 23版本过期, 可以使用另一个方法adjustStreamVolume(int, int, int),然后第三个属性设置:
ADJUST_MUTE 或 ADJUST_UNMUTE!
对了,还有:
如果adjustStreamVolume()的第三个参数你设置了振动(Vibrator), 需要在AndroidManifest.xml中添加这个权限!
<uses-permission android:name=”android.permission.VIBRATE”/>
Vibrator vb = (Vibrator)getSystemService(Service.VIBRATOR_SERVICE);
<uses-permission android:name="android.permission.VIBRATE"/>对于Vibrator用的最广泛的莫过于所谓的手机按摩器类的app
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:id="@+id/btn_hasVibrator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="判断是否有振动器" />
<Button
android:id="@+id/btn_short"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="短振动" />
<Button
android:id="@+id/btn_long"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="长振动" />
<Button
android:id="@+id/btn_rhythm"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="节奏振动" />
<Button
android:id="@+id/btn_cancle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="取消振动" />
</LinearLayout>
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private Button btn_hasVibrator;
private Button btn_short;
private Button btn_long;
private Button btn_rhythm;
private Button btn_cancle;
private Vibrator myVibrator;
private Context mContext;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//获得系统的Vibrator实例:
myVibrator = (Vibrator) getSystemService(Service.VIBRATOR_SERVICE);
mContext = MainActivity.this;
bindViews();
}
private void bindViews() {
btn_hasVibrator = (Button) findViewById(R.id.btn_hasVibrator);
btn_short = (Button) findViewById(R.id.btn_short);
btn_long = (Button) findViewById(R.id.btn_long);
btn_rhythm = (Button) findViewById(R.id.btn_rhythm);
btn_cancle = (Button) findViewById(R.id.btn_cancle);
btn_hasVibrator.setOnClickListener(this);
btn_short.setOnClickListener(this);
btn_long.setOnClickListener(this);
btn_rhythm.setOnClickListener(this);
btn_cancle.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_hasVibrator:
Toast.makeText(mContext, myVibrator.hasVibrator() ? "当前设备有振动器" : "当前设备无振动器",
Toast.LENGTH_SHORT).show();
break;
case R.id.btn_short:
myVibrator.cancel();
myVibrator.vibrate(new long[]{100, 200, 100, 200}, 0);
Toast.makeText(mContext, "短振动", Toast.LENGTH_SHORT).show();
break;
case R.id.btn_long:
myVibrator.cancel();
myVibrator.vibrate(new long[]{100, 100, 100, 1000}, 0);
Toast.makeText(mContext, "长振动", Toast.LENGTH_SHORT).show();
break;
case R.id.btn_rhythm:
myVibrator.cancel();
myVibrator.vibrate(new long[]{500, 100, 500, 100, 500, 100}, 0);
Toast.makeText(mContext, "节奏振动", Toast.LENGTH_SHORT).show();
break;
case R.id.btn_cancle:
myVibrator.cancel();
Toast.makeText(mContext, "取消振动", Toast.LENGTH_SHORT).show();
}
}
}
清单文件权限
<uses-permission android:name="android.permission.VIBRATE"/>
关键参数说明:
要说的是,此例子只在Android 4.4以下的系统可行,5.0以上并不可行,后续如果有5.0 以上AlarmManager的解决方案,到时再补上!另外,这里用set方法可能有点不准,如果要 更精确的话可以使用setExtra()方法来设置AlarmManager!
首先一个简单的布局文件:activity_main.xml,另外在res创建一个raw文件夹,把音频文件丢进去! 另外创建一个只有外层布局的activity_clock.xml作为闹钟响时Activity的布局!
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/LinearLayout1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:id="@+id/btn_set"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="设置闹钟" />
<Button
android:id="@+id/btn_cancel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="关闭闹钟"
android:visibility="gone" />
</LinearLayout>
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
private Button btn_set;
private Button btn_cancel;
private AlarmManager alarmManager;
private PendingIntent pi;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bindViews();
}
private void bindViews() {
btn_set = (Button) findViewById(R.id.btn_set);
btn_cancel = (Button) findViewById(R.id.btn_cancel);
alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
Intent intent = new Intent(MainActivity.this, ClockActivity.class);
pi = PendingIntent.getActivity(MainActivity.this, 0, intent, 0);
btn_set.setOnClickListener(this);
btn_cancel.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.btn_set:
Calendar currentTime = Calendar.getInstance();
new TimePickerDialog(MainActivity.this, 0,
new TimePickerDialog.OnTimeSetListener() {
@Override
public void onTimeSet(TimePicker view,
int hourOfDay, int minute) {
//设置当前时间
Calendar c = Calendar.getInstance();
c.setTimeInMillis(System.currentTimeMillis());
// 根据用户选择的时间来设置Calendar对象
c.set(Calendar.HOUR, hourOfDay);
c.set(Calendar.MINUTE, minute);
// ②设置AlarmManager在Calendar对应的时间启动Activity
alarmManager.set(AlarmManager.RTC_WAKEUP, c.getTimeInMillis(), pi);
Log.e("HEHE",c.getTimeInMillis()+""); //这里的时间是一个unix时间戳
// 提示闹钟设置完毕:
Toast.makeText(MainActivity.this, "闹钟设置完毕~"+ c.getTimeInMillis(),
Toast.LENGTH_SHORT).show();
}
}, currentTime.get(Calendar.HOUR_OF_DAY), currentTime
.get(Calendar.MINUTE), false).show();
btn_cancel.setVisibility(View.VISIBLE);
break;
case R.id.btn_cancel:
alarmManager.cancel(pi);
btn_cancel.setVisibility(View.GONE);
Toast.makeText(MainActivity.this, "闹钟已取消", Toast.LENGTH_SHORT)
.show();
break;
}
}
}
闹铃页面的ClockActivity.java
public class ClockActivity extends AppCompatActivity {
private MediaPlayer mediaPlayer;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_clock);
mediaPlayer = mediaPlayer.create(this,R.raw.pig);
mediaPlayer.start();
//创建一个闹钟提醒的对话框,点击确定关闭铃声与页面
new AlertDialog.Builder(ClockActivity.this).setTitle("闹钟").setMessage("小猪小猪快起床~")
.setPositiveButton("关闭闹铃", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
mediaPlayer.stop();
ClockActivity.this.finish();
}
}).show();
}
}
核心流程
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE); 获得系统提供的AlarmManager服务的对象Intent intent = new Intent(MainActivity.this, ClockActivity.class);PendingIntent pi = =PendingIntent.getActivity(MainActivity.this, 0, intent, 0);alarmManager.set(AlarmManager.RTC_WAKEUP,c.getTimeInMillis(), pi);另外假如出现闹铃无效的话,你可以从这些方面入手:
1.系统版本或者手机,5.0以上基本没戏,小米,自行百度吧~ 2.ClockActivity有注册没?
3.假如你用的是alarmManager发送广播,广播再激活Activity的话,则需要为Intent设置一个flag: i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
4. PendingIntent,要写成getActivity启动闹铃页面
原文:http://blog.csdn.net/yangshangwei/article/details/50990256