转帖:http://book.csdn.net/bookfiles/1359/100135941745.shtml
8.2 系统服务
在Android系统中有很多内置的软件,例如,当手机接到来电时,会显示对方的电话号。也可以根据周围的环境将手机设置成震动或静音。如果想把这些功能加到自己的软件中应该怎么办呢?答案就是“系统服务”。在Android系统中提供了很多这种服务,通过这些服务,就可以像Android系统的内置软件一样随心所欲地控制Android系统了。本节将介绍几种常用的系统服务来帮助读者理解和使用这些技术。
8.2.1 获得系统服务
系统服务实际上可以看作是一个对象,通过Activity类的getSystemService方法可以获得指定的对象(系统服务)。getSystemService方法只有一个String类型的参数,表示系统服务的ID,这个ID在整个Android系统中是唯一的。例如,audio表示音频服务,window表示窗口服务,notification表示通知服务。
为了便于记忆和管理,Android SDK在android.content.Context类中定义了这些ID,例如,下面的代码是一些ID的定义。
public static final String AUDIO_SERVICE = "audio"; // 定义音频服务的ID
public static final String WINDOW_SERVICE = "window"; // 定义窗口服务的ID
public static final String NOTIFICATION_SERVICE = "notification"; // 定义通知服务的ID
下面的代码获得了剪贴板服务(android.text.ClipboardManager对象)。
// 获得ClipboardManager对象
android.text.ClipboardManager clipboardManager=
(android.text.ClipboardManager)getSystemService(Context.CLIPBOARD_SERVICE);
clipboardManager.setText("设置剪贴版中的内容");
在调用ClipboardManager.setText方法设置文本后,在Android系统中所有的文本输入框都可以从这个剪贴板对象中获得这段文本,读者不妨自己试一试!
窗口服务(WindowManager对象)是最常用的系统服务之一,通过这个服务,可以获得很多与窗口相关的信息,例如,窗口的长度和宽度,如下面的代码所示:
// 获得WindowManager对象
android.view.WindowManager windowManager = (android.view.WindowManager)
getSystemService(Context.WINDOW_SERVICE);
// 在窗口的标题栏输出当前窗口的宽度和高度,例如,320*480
setTitle(String.valueOf(windowManager.getDefaultDisplay().getWidth()) + "*"
+ String.valueOf(windowManager.getDefaultDisplay().getHeight()));
本节简单介绍了如何获得系统服务以及两个常用的系统服务的使用方法,在接下来的实例47和实例48中将给出两个完整的关于获得和使用系统服务的例子以供读者参考。
实例47:监听手机来电
工程目录:src/ch08/ch08_phonestate
当来电话时,手机会显示对方的电话号,当接听电话时,会显示当前的通话状态。在这期间存在两个状态:来电状态和接听状态。如果在应用程序中要监听这两个状态,并进行一些其他处理,就需要使用电话服务(TelephonyManager对象)。
本例通过TelephonyManager对象监听来电状态和接听状态,并在相应的状态显示一个Toast提示信息框。如果是来电状态,会显示对方的电话号,如果是通话状态,会显示“正在通话...”信息。下面先来看看来电和接听时的效果,如图8.5和图8.6所示。
图8.5 来电状态
图8.6 接听状态
要想获得TelephonyManager对象,需要使用Context.TELEPHONY_SERVICE常量,代码如下:
TelephonyManager tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
MyPhoneCallListener myPhoneCallListener = new MyPhoneCallListener();
// 设置电话状态监听器
tm.listen(myPhoneCallListener, PhoneStateListener.LISTEN_CALL_STATE);
其中MyPhoneCallListener类是一个电话状态监听器,该类是PhoneStateListener的子类,代码如下:
public class MyPhoneCallListener extends PhoneStateListener
{
@Override
public void onCallStateChanged(int state, String incomingNumber)
{
switch (state)
{
// 通话状态
case TelephonyManager.CALL_STATE_OFFHOOK:
Toast.makeText(Main.this, "正在通话...", Toast.LENGTH_SHORT).show();
break;
// 来电状态
case TelephonyManager.CALL_STATE_RINGING:
Toast.makeText(Main.this, incomingNumber,Toast.LENGTH_SHORT).show();
break;
}
super.onCallStateChanged(state, incomingNumber);
}
}
如果读者是在模拟器上测试本例,可以使用DDMS透视图的【Emulator Control】视图模拟打入电话。进入【Emulator Control】视图,会看到如图8.7所示的界面。在【Incoming number】文本框中输入一个电话号,选中【Voice】选项,单击【Call】按钮,这时模拟器就会接到来电。如果已经运行本例,在来电和接听状态就会显示如图8.5和图8.6所示的Toast提示信息。
图8.7 用【Emulator Control】视图模拟拨打电话
实例48:来电黑名单
工程目录:src/ch08/ch08_phoneblacklist
虽然手机为我们带来了方便,但有时实在不想接听某人的电话,但又不好直接挂断电话,怎么办呢?很简单,如果发现是某人来的电话,直接将手机设成静音,这样就可以不予理睬了。
本例与实例47类似,也就是说,仍然需要获得TelephonyManager对象,并监听手机的来电状态。为了可以将手机静音,还需要获得一个音频服务(AudioManager对象)。本例需要修改实例47中的手机接听状态方法onCallStateChanged中的代码,修改后的结果如下:
public class MyPhoneCallListener extends PhoneStateListener
{
@Override
public void onCallStateChanged(int state, String incomingNumber)
{
// 获得音频服务(AudioManager对象)
AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
switch (state)
{
case TelephonyManager.CALL_STATE_IDLE:
// 在手机空闲状态时,将手机音频设为正常状态
audioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
break;
case TelephonyManager.CALL_STATE_RINGING:
// 在来电状态时,判断打进来的是否为要静音的电话号,如果是,则静音
if ("12345678".equals(incomingNumber))
{
// 将电话静音
audioManager.setRingerMode(AudioManager.RINGER_MODE_SILENT);
}
break;
}
super.onCallStateChanged(state, incomingNumber);
}
}
在上面的代码中,只设置了“12345678”为静音电话号,读者可以采用实例47的方法使用“12345678”打入电话,再使用其他的电话号打入,看看模拟器是否会响铃。
8.2.2 在模拟器上模拟重力感应
众所周知,Android系统支持重力感应,通过这种技术,可以利用手机的移动、翻转来实现更为有趣的程序。但遗憾的是,在Android模拟器上是无法进行重力感应测试的。既然Android系统支持重力感应,但又在模拟器上无法测试,该怎么办呢?别着急,天无绝人之路,有一些第三方的工具可以帮助我们完成这个工作,本节将介绍一种在模拟器上模拟重力感应的工具(sensorsimulator)。这个工具分为服务端和客户端两部分。服务端是一个在PC上运行的Java Swing GUI程序,客户端是一个手机程序(apk文件),在运行时需要通过客户端程序连接到服务端程序上才可以在模拟器上模拟重力感应。
读者可以从下面的地址下载这个工具:
http://code.google.com/p/openintents/downloads/list
进入下载页面后,下载如图8.8所示的黑框中的zip文件。
图8.8 sensorsimulator下载页面
将zip文件解压后,运行bin目录中的sensorsimulator.jar文件,会显示如图8.9所示的界面。界面的左上角是一个模拟手机位置的三维图形,右上角可以通过滑杆来模拟手机的翻转、移动等操作。
图8.9 sensorsimulator主界面
下面来安装客户端程序,先启动Android模拟器,然后使用下面的命令安装bin目录中的SensorSimulatorSettings.apk文件。
adb install SensorSimulatorSettings.apk
如果安装成功,会在模拟器中看到如图8.10所示黑框中的图标。运行这个程序,会进入如图8.11所示的界面。在IP地址中输入如图8.9所示黑框中的IP(注意,每次启动服务端程序时这个IP可能不一样,应以每次启动服务端程序时的IP为准)。最后进入【Testing】页,单击【Connect】按钮,如果连接成功,会显示如图8.12所示的效果。
图8.10 安装客户端设置软件
图8.11 进行客户端设置
下面来测试一下SensorSimulator自带的一个demo,在这个demo中输出了通过模拟重力感应获得的数据。
这个demo就在samples目录中,该目录有一个SensorDemo子目录,是一个Eclipse工程目录。读者可以直接使用Eclipse导入这个目录,并运行程序,如果显示的结果如图8.13所示,说明成功使用SensorSimulator在Android模拟器上模拟了重力感应。
图8.12 测试连接状态
图8.13 测试重力感应demo
在实例49中将给出一个完整的例子来演示如何利用重力感应的功能来实现手机翻转静音的效果。
实例49:手机翻转静音
工程目录:src/ch08/ch08_phonereversal
与手机来电一样,手机翻转状态(重力感应)也由系统服务提供。重力感应服务(android.hardware.SensorManager对象)可以通过如下代码获得:
SensorManager sensorManager = (SensorManager)getSystemService(Context.SENSOR_SERVICE);
本例需要在模拟器上模拟重力感应,因此,在本例中使用SensorSimulator中的一个类(SensorManagerSimulator)来获得重力感应服务,这个类封装了SensorManager对象,并负责与服务端进行通信,监听重力感应事件也需要一个监听器,该监听器需要实现SensorListener接口,并通过该接口的onSensorChanged事件方法获得重力感应数据。本例完整的代码如下:
package net.blogjava.mobile;
import org.openintents.sensorsimulator.hardware.SensorManagerSimulator;
import android.app.Activity;
import android.content.Context;
import android.hardware.SensorListener;
import android.hardware.SensorManager;
import android.media.AudioManager;
import android.os.Bundle;
import android.widget.TextView;
public class Main extends Activity implements SensorListener
{
private TextView tvSensorState;
private SensorManagerSimulator sensorManager;
@Override
public void onAccuracyChanged(int sensor, int accuracy)
{
}
@Override
public void onSensorChanged(int sensor, float[] values)
{
switch (sensor)
{
case SensorManager.SENSOR_ORIENTATION:
// 获得声音服务
AudioManager audioManager = (AudioManager)
getSystemService(Context.AUDIO_SERVICE);
// 在这里规定翻转角度小于-120度时静音,values[2]表示翻转角度,也可以设置其他角度
if (values[2] < -120)
{
audioManager.setRingerMode(AudioManager.RINGER_MODE_SILENT);
}
else
{
audioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
}
tvSensorState.setText("角度:" + String.valueOf(values[2]));
break;
}
}
@Override
protected void onResume()
{
// 注册重力感应监听事件
sensorManager.registerListener(this, SensorManager.SENSOR_ORIENTATION);
super.onResume();
}
@Override
protected void onStop()
{
// 取消对重力感应的监听
sensorManager.unregisterListener(this);
super.onStop();
}
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// 通过SensorManagerSimulator对象获得重力感应服务
sensorManager = (SensorManagerSimulator) SensorManagerSimulator
.getSystemService(this, Context.SENSOR_SERVICE);
// 连接到服务端程序(必须执行下面的代码)
sensorManager.connectSimulator();
}
}
在上面的代码中使用了一个SensorManagerSimulator类,该类在SensorSimulator工具包带的sensorsimulator-lib.jar文件中,可以在lib目录中找到这个jar文件。在使用SensorManagerSimulator类之前,必须在相应的Eclipse工程中引用这个jar文件。
现在运行本例,并通过服务端主界面右侧的【Roll】滑动杆移动到指定的角度,例如,-74.0和-142.0,这时设置的角度会显示在屏幕上,如图8.14和图8.15所示。
图8.14 翻转角度大于-120度
图8.15 翻转角度小于-120度
读者可以在如图8.14和图8.15所示的翻转状态下拨入电话,会发现翻转角度在-74.0度时来电仍然会响铃,而翻转角度在-142.0度时就不再响铃了。
由于SensorSimulator目前不支持Android SDK 1.5及以上版本,因此,只能使用Android SDK 1.1中的SensorListener接口来监听重力感应事件。在Android SDK 1.5及以上版本并不建议继续使用这个接口,代替它的是android.hardware.SensorEventListener接口。 |