为了正常的体验网站,请在浏览器设置里面开启Javascript功能!

第14章 访问Android手机的硬件

2012-04-14 22页 pdf 1MB 20阅读

用户头像

is_815621

暂无简介

举报
第14章 访问Android手机的硬件 《Android/OPhone 开发完全讲义》样章 李宁 编著 http://nokiaguy.blogjava.net 内容简介 本书近 500 页,共 25 章,分为 5 篇,超过 200 个完整的例子、超过 2 万行代码。 第 1 篇:介绍了 Android 的相关内容,其中包括 Android 的基本概念、搭建 Android 开发环境、 Android SDK 中常用命令行工具的使用方法、在 PC 上安装 Android,并测试程序、Android 的学习资 源等,还会给出...
第14章 访问Android手机的硬件
《Android/OPhone 开发完全讲义》样章 李宁 编著 http://nokiaguy.blogjava.net 内容简介 本书近 500 页,共 25 章,分为 5 篇,超过 200 个完整的例子、超过 2 万行代码。 第 1 篇:介绍了 Android 的相关内容,其中包括 Android 的基本概念、搭建 Android 开发环境、 Android SDK 中常用命令行工具的使用方法、在 PC 上安装 Android,并测试程序、Android 的学习资 源等,还会给出一个简单的 Android 程序,使读者可以了解开发 Android 程序的基本过程。 第 2 篇:主要讲解了 Android 的用户接口,包括 View、定制组件、对话框、Toast 和 Notification、 各种菜单、布局;Android 中中的组件(android.widget 包中的组件);移动存储解决,包括 SharedPreferences、 PreferenceActivity、文件存储、XML 存储、Sqlite 数据库及其应用、ContentProvider 等;应用程序之间的通讯,包括跨进程调用 Activity、接收和发送广播;Android 服务详细解,包括 Service 的生命周期,系统服务、时间服务和 AIDL 服务;网络,包括从网络上获得数据装载 Gallery、 ListView 等组件。以及从 google 上获得图像,WebView 组件、访问 Http 资源以及 Webservice 等;多 媒体技术,包括图形的基本操作、旋转图像、透明度、扭曲和拉伸图像、路径,音频和视频等技术。 第 3 篇:2D 和 OpenGL ES 动画,国际化,Android 中的 14 种资源,访问 Android 手机的硬件, 包括通过 USB 驱动在手机上直接调试程序,录音,控制手机的摄像头、传感器(电子罗盘,计步器), GPS 和地图定位,wifi 等。App Widget、在桌面上添加快捷方式,实时文件夹(LiveFolder),NDK, 脚本语言(Python、perl 等),手势输入、TTS、蓝牙等。 第 4 篇:介绍了 OPhone 的基础知识,以及 OPhone 与 Android 的差异,OPhone 的 API 扩展,并 详细介绍了 JIL Widget 在多媒体,获得系统信息,控制硬件等方面的内容。 第 5 篇:给出了两个综合的例子:万年历,知道当前位置的 GTalk 机器人。 访问 Android 手机的硬件 第 25 章 2 25 C h ap te r 第 14 章 访问 Android 手机的硬件 现在手机已不仅仅是打电话的工具了,从早期的手机引入摄像头开始,各种类型的硬件逐渐在手机中 出现。例如传感器、GPS、WIFI、蓝牙等设备在手机中屡见不鲜。而作为开发人员的我们,不仅要理解和 使用这些硬件,还要学会用程序随心所欲地控制它们。如果你也和作者的想法一致,那么本章将会给你带 来意想不到的惊喜。 本章内容  在手机上测试、调试程序  录音  调用系统提供的拍照功能  实现自己的拍照功能  方向传感器和加速传感器  电子罗盘  计步器  Google 地图  GPS 定位  WIFI 14.1 在手机上测试硬件 虽然 Android 模拟器可以测试大多数应用程序,但却无法测试那些和硬件相关的程序,例如录音、拍 照(虽然拍照的部分功能能在模拟器上运行,但并不是真正使用摄像头进行拍摄)、重力感应、GPS、WIFI 访问 Android 手机的硬件 14 访问 Android 手机的硬件 第 25 章 3 25 C h ap te r 等。如果这些功能无法在模拟器上测试,将给开发工作带来非常大的困难。在发布 Android SDK 的同时发 布了一个 Android USB 驱动。将手机和电脑通过数据线相连后,并在计算机上安装这个 Android USB 驱动, 就可以将手机变成一个测试程序的模拟器,也就是说,在 Eclipse 中运行程序后,会直接在手机上运行, 而不是在计算机的模拟器中运行,这样就可以得到真实的运行效果。 14.1.1 安装 Android USB 驱动 Android USB 驱动只有 Windows 才需要安装。如果读者在 MAC OS X 或 Linux 上测试 Android 应用程 序,可以访问如下地址查看 Android USB 驱动的配置过程。本节只介绍 Windows 下的 Android USB 驱动的 安装过程。 http://developer.android.com/intl/zh-CN/guide/developing/device.html#setting-up 在作者写作本书时,Android USB 驱动的最新版本是 Revision 3。该版本支持 Windows XP 和 Windows Vista。如果读者下载并安装了最新版的 Android SDK(下载地址如下),会自动将 USB 驱动安装在电脑上。 http://developer.android.com/intl/zh-CN/sdk/index.html 在安装完 Android SDK 后,读者会在中看到一个 usb_driver 目录,该目录就 是 USB 驱动的安装目录。目录结构如图 14.1 所示。 图 14.1 USB 驱动安装目录的结构 在安装完 Android USB 驱动后,还要根据手机的不同型号安装随机带的驱动程序。例如,作者使用的 手机型号是 HTC Hero(G3),可以在 HTC 的官方网站上下载相应的驱动程序(HTC Sync)。成功安装驱 动程序后,读者会在设备管理的右侧中看到 Android USB Drivers 项,如图 14.2 所示。 图 14.2 Android USB Drivers 在安装 Android SDK 时如果安装失败,可以切换到 Settings 列项,并选中右侧界面下方的第 1 个复选项,如图 14.3 所示。 访问 Android 手机的硬件 第 25 章 4 25 C h ap te r 图 14.3 改成 http 下载 在安装完 Android USB 驱动后,需要进入手机的【设置】>【应用程序】>【开发】设备界面,选中【USB 调试】复选框,如图 14.4 所示。 14.1.2 在手机上测试程序 按 14.1.1 节介绍的成功安装 Android USB 驱动后,现在可以使用数据线连接手机和电脑了。如果手机 中有 SD 卡,会在【我的电脑】中多一个【可移动磁盘】选项,不过这个可移动磁盘是否可访问,我们都 不用管它。 现在可以用 Eclipse 运行程序了。如果这时未启动模拟器,程序会直接通过数据线传到手机上运行。 如果已启动了模拟器,在运行程序之前,Eclipse 会弹出对话框要求开发人员选择在模拟器或在手机上运行 程序,如图 14.5 所示。 图 14.4 选中【USB 调试】复选框(HTC Hero) 图 14.5 选择运行 Android 应用程序的设备 在如图 14.5 所示的界面中第 1 个设备是手机,第 2 个设备是模拟器。可以选择一个前面章节曾编写过 的例子来做一个测试。例如选择第 11 章的实例 73(旋转的星系)进行测试,在手机上的运行效果如图 14.6 所示。 也许很多读者会注意到图 14.6 也是一个类似于模拟器的屏幕截图。只是这个截图来自真实的手机屏幕。 从这一点可以看出,将手机变成可测试程序的模拟器后,可以和 PC 上的模拟器一样对手机屏幕进行截屏。 读者可以在 DDMS 透视图中通过【Devices】视图的【Screen Capture】按钮测试截取手机屏幕的功能。但 要注意,一定要选择【Devices】视图中的手机设备。 使用手机测试 Android 应用程序需要注意如下 2 点:  在【Run Configurations】对话框中不要选择运行目标(Target)的任何一个 AVD 设备,而且要将 运行模式设为 Automatic,这样在运行程序时才会弹出选择运行设备的对话框。如果选中任何一 个 AVD 设备(在 AVD 设备列表中并未列出手机设备),Eclipse 就会直接在选中的设备中运行程 访问 Android 手机的硬件 第 25 章 5 25 C h ap te r 序,而不会在手机上运行程序了。  如果在手机上已经安装了未使用 USB 驱动方式安装的程序(直接采用在手机上运行 apk 文件的 方式安装应用程序),而且 package与要运行的程序 package相同,应先在手机上卸载该应用程序, 然后通过 USB 驱动在手机上安装并测试程序。 14.1.3 在手机上调试程序 在手机上也可以调试应用程序。首先应在代码的相应位置设置断点,然后以 Debug 模式启动应用程序。 如果代码执行到断点处,会在手机屏幕上弹出一个对话框,如图 14.7 所示。读者并不需要关闭这个对话框, 几秒后该对话框会自动关闭。这时就可以像在模拟器中运行程序一样按步跟踪代码了。 图 14.6 旋转的星系(HTC Hero) 图 14.7 在手机上调试应用程序(HTC Hero) 14.2 录音 本节的例子代码所在的目录是 src\ch14\ch14_recorder 在模拟器中无法利用电脑的声卡录音,因此这个功能必须在真机上测试。录音功能需要使用 android.media.MediaRecorder 来完成。使用 MediaRecorder 录音需要通过如下 6 步完成: (1)设置音频来源(一般为麦克风)。 (2)设置音频输出格式。 (3)设置音频编码方式。 (4)设置输出音频的文件名。 (5)调用 MediaRecorder 类的 prepare 方法。 (6)调用 MediaRecorder 类的 start 方法开始录音。 实现录音功能的完整代码如下: MediaRecorder mediaRecorder = new MediaRecorder(); // 第 1 步:设置音频来源(MIC 表示麦克风) mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); // 第 2 步:设置音频输出格式(默认的输出格式) mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT); // 第 3 步:设置音频编码方式(默认的编码方式) mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT); // 创建一个临时的音频输出文件 audioFile = File.createTempFile("record_", ".amr"); // 第 4 步:指定音频输出文件 mediaRecorder.setOutputFile(audioFile.getAbsolutePath()); // 第 5 步:调用 prepare 方法 mediaRecorder.prepare(); 访问 Android 手机的硬件 第 25 章 6 25 C h ap te r // 第 6 步:调用 start 方法开始录音 mediaRecorder.start(); 上面的代码指定了一个临时的音频输出文件,这就意味着每次将生成不同的音频文件。文件名的格式 是 record_N.amr,其中 N 是整数。在录完音后,读者在 SD 卡的根目录会看到很多这样的文件(由录音的 次数多少决定 amr 文件的多少)。 停止录单可以使用 MediaRecorder 类的 stop 方法,代码如下: mediaRecorder.stop(); 在生成amr文件后,可以使用MediaPlayer来播放 amr文件。MediaPlayer类的使用方法请读者参阅10.2.1 节的内容。 14.3 控制手机摄像头(拍照) 现在几乎所有的手机都配有摄像头。而且随着摄像头的分辨率不断提高(有 200 万像素,有的可达到 500 万,甚至是 1000 万像素),用手机照相已成为很多用户最喜欢的方式。这主要是因为手机是唯一可以 随时携带的电子设备。而数码相机虽然在拍照功能上比同档次的拍照手机更强大,但毕竟数码相机不能总 是带在身边。除此之外,由于目前带摄像头的手机大多都是智能手机,除了拥有简单的拍照功能外,还可 以通过程序对拍照的过程和拍摄后的图像进行处理。这样的功能远比数码相机要强大得多。而随时随地写 微博也逐渐成为围脖(微博的斜音)们的时尚首选,而配上实时的照片将会为自己的微博吸引更多的粉丝, 那么实现这些功能非手机莫属。读到这里,也许很多读者迫不急待地想在自己的应用程序中添加拍照功能, 这些读者一定会对本节非常地感兴趣。 14.3.1 调用系统的拍照功能 本节的例子代码所在的工程目录是 src\ch14\ch14_systemcamera 读者可以先试试自己手机上的拍照功能。可能由于手机型号不同,拍照的方式和过程也可能不一样。 在 HTC Hero 手机上进行拍照会由系统自动对焦,在对焦的过程中,屏幕上会出现一个白色的对焦符号(类 似于中括号)。如果对焦成功,这个对焦符号就会变成绿色,如图 14.8 所示。 当对焦成功后,按手机下方的【呼吸灯】按钮进行拍照。在拍照后手机屏幕下方会出现两个按钮:【完 成】和【拍照】按钮。如果对照片满意,单击【完成】按钮结束拍照。如果对照片不满意,单击【拍照】 按钮继续拍照,上一次拍的照片将丢失。由于这两个按钮无法通过 DDMS 透视图截获,因此,只能截获所 拍的照片,如图 14.9 所示。当完成拍照后,可以对照片做进一步处理,例如本节的例子将照片显示在 ImageView 中,如图 14.10 所示。 图 14.8 对焦成功(HTC Hero) 图 14.9 拍照成功(HTC Hero) 图 14.10 在 ImageVie 中显示照片(HTC Hero) 从上面的拍照过程可以猜到,用于显示拍照过程影像的界面实际上也是一个 Activity。因此要调用系 访问 Android 手机的硬件 第 25 章 7 25 C h ap te r 统的拍照功能,就要用到 7.1.2 节介绍的调用其他应用程序的 Activity 的方式。与拍照功能对应的 Action 是 android.provider.MediaStore.ACTION_IMAGE_CAPTURE。用于拍照的 Activity 需要返回照片图像数据, 因此,需要使用 startActivityForResult 方法启动这个 Activity,代码如下: Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); startActivityForResult(intent, 1); 截获 Activity 返回的图像数据的事件方法是 onActivityResult,代码如下: protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == 1) { if (resultCode == Activity.RESULT_OK) { // 拍照 Activity 保存图像数据的 key 是 data,返回的数据类型是 Bitmap 对象 Bitmap cameraBitmap = (Bitmap) data.getExtras().get("data"); // 在 ImageView 组件中显示拍摄的照片 imageView.setImageBitmap(cameraBitmap); } } super.onActivityResult(requestCode, resultCode, data); } 在默认情况下,系统的拍照 Activity 将照片保存在 SD 卡的 DCIM\100MEDIA 目录中(不同型号的 手机可能保存的目录不同)。在拍照的过程中按手机下方的【menu】按钮会在屏幕的下方显示几个选项 菜单。单击【分辨率】菜单项,会弹出一个只有一个分辨率选项的对话框(在 HTC Hero 手机上的分别 率是 624×416,如图 14.11 所示。这个分辨率可能随着手机型号的不同而不同,但分辨率都很小)。这就 意味着所拍摄的照片分辨率不能大于 624*416。如果将照片保存成大于这个分辨率,照片就会失真。而手 机自带的拍照程序可以根据手机摄像头的最大分辨率设置多个照片分辨率,如图 14.12 所示。 图 14.11 拍照 Activity 时可设置的 图 14.12 拍照程序可设置的 照片分辨率(HTC Hero) 照片分辨率(HTC Hero) 根据官方文档的解释,在调用拍照 Activity 时通过 MediaStore.EXTRA_OUTPUT 指定照片保存的路径, 可以允许拍摄分辨率更大的照片。原文如下: The caller may pass an extra EXTRA_OUTPUT to control where this image will be written. If the EXTRA_OUTPUT is not present, then a small sized image is returned as a Bitmap object in the extra field. This is useful for applications that only need a small image. If the EXTRA_OUTPUT is present, then the full-sized image will be written to the Uri value of EXTRA_OUTPUT. 按着官方的解释,可以使用如下代码调用拍照 Activity: Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File("/sdcard/test.jpg"))); startActivityForResult(intent, 1); 但经作者测试,在调用拍照Activity时设置EXTRA_OUTPUT并不起任何作用(仅对Android SDK 1.5)。 访问 Android 手机的硬件 第 25 章 8 25 C h ap te r 这也许是 Android SDK 1.5 的一个 bug,或官方文档描述有误。如果读者非要拍摄更大分辨率的照片,可以 实现自己的拍照 Activity 来完成这个功能,这部分内容将在 14.3.2 节介绍。 虽然使用系统的拍照 Activity 无法拍摄更大分辨率的照片,但可以同时生成分辨率更小的照片。通 过 insertImage 方法可以同时在/sdcard/DCIM/.thumbnails 和/sdcard/DCIM/Camera 目录中分别生成分辨率 为 50×50 和 208×312 的图像(其他型号的手机也有可能是其他的分辨率)。调用 insertImage 方法的代码 如下: MediaStore.Images.Media.insertImage(getContentResolver(), cameraBitmap, null, null); 其中 cameraBitmap 是拍照 Activity 返回的 Bitmap 对象。 不仅可以调用系统的拍照 Activity,而且可以调用系统的摄像 Activity。摄像 Activity对应的 Action 是 MediaStore.ACTION_VIDEO_CAPTURE,调用方法与调用系统的拍照 Activity 相同。 14.3.2 实现自己的拍照 Activity 本节的例子代码所在的工程目录是 src\ch14\ch14_camera 拍照的核心类是 android.hardware.Camera,通过 Camera 类的静态方法 open 可以获得 Camera 对象,并 通过 Camera 类的 startPreview 方法开始拍照,最后通过 Camera 类的 takePicture 方法结束拍照,并在相应 的事件中处理照片数据。 上述的过程只是拍照过程的简化。在拍照之前,还需要做如下的准备工作。  指定用于显示拍照过程影像的容器,通常是 SurfaceHolder 对象。由于影像需要在 SurfaceView 对 象中显示,因此可以使用 SurfaceView 类的 getHolder 方法获得 SurfaceHolder 对象。  在拍照过程中涉及到一些状态的变化。这些状态包括开始拍照(对应 surfaceCreated 事件方法); 拍照状态变化(例如图像格式或方向,对应 surfaceChanged 事件方法);结束拍照(对应 surfaceDestroyed 事件方法)。这 3 个事件方法都是在 SurfaceHolder.Callback 接口中定义的,因此, 需要使用 SurfaceHolder 接口的 addCallback 方法指定 SurfaceHolder.Callback 对象,以便捕捉这 3 个事件。  拍完照后需要处理照片数据。处理这些数据的工作需要在 PictureCallback 接口的 onPictureTaken 方法中完成。当调用 Camera 类的 takePicture 方法后,onPictureTaken 事件方法被调用。  如果需要自动对焦,需要调用 Camera 类的 autoFocus 方法。该方法需要一个 AutoFocusCallback 类型的参数值。AutoFocusCallback 是一个接口,在该接口中定义了一个 onAutoFocus 方法,当摄 像头正在对焦或对焦成功都会调用该方法。 为了使拍照功能更容易使用,本节的例子将拍照功能封装在了 Preview 类中,代码如下: class Preview extends SurfaceView implements SurfaceHolder.Callback { private SurfaceHolder holder; private Camera camera; // 创建一个 PictureCallback 对象,并实现其中的 onPictureTaken 方法 private PictureCallback pictureCallback = new PictureCallback() { // 该方法用于处理拍摄后的照片数据 @Override public void onPictureTaken(byte[] data, Camera camera) { // data 参数值就是照片数据,将这些数据以 key-value 形式保存,以便其他调用该 Activity 的程序可 // 以获得照片数据 getIntent().putExtra("bytes", data); setResult(20, getIntent()); // 停止照片拍摄 camera.stopPreview(); 访问 Android 手机的硬件 第 25 章 9 25 C h ap te r camera = null; // 关闭当前的 Activity finish(); } }; // Preview 类的构造方法 public Preview(Context context) { super(context); // 获得 SurfaceHolder 对象 holder = getHolder(); // 指定用于捕捉拍照事件的 SurfaceHolder.Callback 对象 holder.addCallback(this); // 设置 SurfaceHolder 对象的类型 holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); } // 开始拍照时调用该方法 public void surfaceCreated(SurfaceHolder holder) { // 获得 Camera 对象 camera = Camera.open(); try { // 设置用于显示拍照影像的 SurfaceHolder 对象 camera.setPreviewDisplay(holder); } catch (IOException exception) { // 释放手机摄像头 camera.release(); camera = null; } } // 停止拍照时调用该方法 public void surfaceDestroyed(SurfaceHolder holder) { // 释放手机摄像头 camera.release(); } // 拍照状态变化时调用该方法 public void surfaceChanged(final SurfaceHolder holder, int format, int w, int h) { try { Camera.Parameters parameters = camera.getParameters(); // 设置照片格式 parameters.setPictureFormat(PixelFormat.JPEG); // 根据屏幕方向设置预览尺寸 if (getWindowManager().getDefaultDisplay().getOrientation() == 0) parameters.setPreviewSize(h, w); else parameters.setPreviewSize(w, h); // 设置拍摄照片的实际分辨率,本例中的分辨率是 1024×768 parameters.setPictureSize(1024, 768); // 设置保存的图像大小 camera.setParameters(parameters); // 开始拍照 camera.startPreview(); // 准备用于表示对焦状态的图像(类似图 14.8 所示的对焦符号) ivFocus.setImageResource(R.drawable.focus1); LayoutParams layoutParams = new LayoutParams( LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT); ivFocus.setScaleType(ScaleType.CENTER); 访问 Android 手机的硬件 第 25 章 10 25 C h ap te r addContentView(ivFocus, layoutParams); ivFocus.setVisibility(VISIBLE); // 自动对焦 camera.autoFocus(new AutoFocusCallback() { @Override public void onAutoFocus(boolean success, Camera camera) { if (success) { // success 为 true 表示对焦成功,改变对焦状态图像(一个绿色的 png 图像) ivFocus.setImageResource(R.drawable.focus2); } } }); } catch (Exception e) { } } // 停止拍照,并将拍摄的照片传入 PictureCallback 接口的 onPictureTaken 方法 public void takePicture() { if (camera != null) { camera.takePicture(null, null, pictureCallback); } } } 在编写 Preview 类时应注意如下 7 点:  由于 Preview 是 CameraPreview 的内嵌类(CameraPreview 就是自定义的拍照 Activity)。因此, 在 Preview 类中通过 putExtra 方法保存的数据会在调用 CameraPreview 的类中通过 onActivityResult 事件方法获得。  Camera 类的 takePicture 方法有 3 个参数,都是回调对象,但比较常用的是最后一个参数。当拍 完照后会调用该参数指定对象中的 onPictureTaken 方法,一般可以在该方法中对照片数据做进一 步处理。例如,在本例中使用 putExtra 方法以 key-value 对保存了照片数据。  当手机摄像头的状态变化时,例如手机由纵向变成横向,或分辨率发生变化后,很多参数需要重 新设置,这时系统就会调用 SurfaceHolder.Callback 接口的 surfaceChanged 方法。因此,可以在 该方法中对摄像头的参数进行设置,包括调用 startPreview 方法进行拍照。  根据手机的拍摄方向(纵向或横向),需要设置预览尺寸。surfaceChanged 方法的最后两个参数表 示摄像头预览时的实际尺寸。在使用 Camera.Parameters 类的 setPreviewSize 方法设置预览尺寸时, 如果是纵向拍摄,setPreviewSize 方法的第 1 个参数值是 h,第 2 个参数值是 w,如果是横向拍摄, 第 1 个参数值是 w,第 2 个参数值是 h。在设置时千万不要弄错了,否则当手机改变拍摄方向时 无法正常拍照。读者可以改变 Preview 类中的预览尺寸,看看会产生什么效果。  如果想设置照片的实际分辨率,需要使用 Camera.Parameters 类的 setPictureSize 方法进行设置。  本例中通过在 CameraActivity中添加 ImageView的方式在预览界面显示了一个表示对焦状态的图 像。这个图像文件有两个:focus1.png 和 focus2.png。其中 focus1.png 是白色的透明图像,表示 正在对焦。focus2.png 是绿色的透明图像,表示对焦成功。在开始拍照后,先显示 focus1.png, 当对焦成功后,系统会调用AutoFocusCallback接口的 onAutoFocus方法。在该方法中将 ImageView 中显示的图像变成 focus2.png,表示对焦成功,这时就可以结束拍照了。  在拍完照后需要调用 Camera 类的 release 方法释放手机摄像头,否则除非重启手机,否则其他的 应用程序无法再使用摄像头进行拍照。 访问 Android 手机的硬件 第 25 章 11 25 C h ap te r 本例通过触摸拍照预览界面结束拍照。因此,需要使用 Activity 的 onTouchEvent 事件方法来处理屏幕 触摸事件,代码如下: public boolean onTouchEvent(MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN) // 结束拍照 preview.takePicture(); return super.onTouchEvent(event); } 其中 preview 是 Preview 类的对象实例,在 CameraPreview 类的 onCreate 方法中创建了该对象。 在编写完 CameraPreview 类后,可以在其他的类中使用如下代码启动 CameraPreview,启动 CameraPreview 后会自动进行拍照: Intent intent = new Intent(this, CameraPreview.class); startActivityForResult(intent, 1); 在关闭 CameraPreview 后(可能是拍照成功,也可能是取消拍照),可以通过 onActivityResult 方法来 获得成功拍照后的照片数据,代码如下: protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == 1) { // 拍照成功后,响应码是 20 if (resultCode == 20) { Bitmap cameraBitmap; // 获得照片数据(byte 数组形式) byte[] bytes = data.getExtras().getByteArray("bytes"); // 将 byte 数组转换成 Bitmap 对象 cameraBitmap = BitmapFactory.decodeByteArray(bytes, 0,bytes.length); // 根据拍摄的方向旋转图像(纵向拍摄时需要将图像旋转 90 度) if (getWindowManager().getDefaultDisplay().getOrientation() == 0) { Matrix matrix = new Matrix(); matrix.setRotate(90); cameraBitmap = Bitmap.createBitmap(cameraBitmap, 0, 0, cameraBitmap.getWidth(), cameraBitmap.getHeight(),matrix, true); } // 将照片保存在 SD 卡的根目录(文件名是 camera.jpg) File myCaptureFile = new File("/sdcard/camera.jpg"); try { BufferedOutputStream bos = new BufferedOutputStream( new FileOutputStream(myCaptureFile)); cameraBitmap.compress(Bitmap.CompressFormat.JPEG, 100, bos); bos.flush(); bos.close(); imageView.setImageBitmap(cameraBitmap); } catch (Exception e) { } } } super.onActivityResult(requestCode, resultCode, data); } 在编写上面代码时应注意如下两点:  由于纵向拍摄时生成的照片是横向的,因此需要在处理照片时将其顺时针旋转 90 度。在 14.3.1 节介绍的系统拍照 Activity 已经将照片处理完了,因此,不需要对照片进行旋转。  由于直接使用 Camera 类进行拍照时,系统不会自动保存照片,因此,就需要在处理照片时自行 访问 Android 手机的硬件 第 25 章 12 25 C h ap te r 确定照片的存储位置,并保存照片。这种方法的优点是灵活,缺点是需要写更多的代码。至于是 选择系统提供的拍照功能,还是选择自己实现拍照功能,可根据具体的情况而定。如果对照片保 存的位置没什么要求,而且对照片的分辨率要求不高。可以使用系统提供的拍照功能,否则,就 要自己来实现拍照功能了。 虽然到现在为止拍照的功能已经完全实现了,但程序在手机或模拟器上仍然不能正常运行,原因是需 要在 AndroidManifest.xml 文件中设置拍照的权限许可(在调用系统提供的拍照功能时并不需要设置拍照权 限许可),代码如下: 本例的运行效果与 14.3.1 节的例子的运行效果类似,只是在拍照时需要触摸屏幕才能结束拍照。 14.4 传感器在手机中的应用 自从苹果公司在 2007 年发布第一代 iPhone 以来,以前看似和手机挨不着边的传感器也逐渐成为手机 硬件的重要组成部分。如果读者使用过 iPhone、HTC Dream、HTC Magic、HTC Hero 以及其他的 Android 手机,会发现通过将手机横向或纵向放置,屏幕会随着手机位置的不同而改变方向。这种功能就需要通过 重力传感器来实现,除了重力传感器,还有很多其他类型的传感器被应用到手机中,例如磁阻传感器就是 最重要的一种传感器。虽然手机可以通过 GPS 来判断方向,但在 GPS 信号不好或根本没有 GPS 信号的情 况下,GPS 就形同虚设。这时通过磁阻传感器就可以很容易判断方向(东、南、西、北)。有了磁阻传感 器,也使罗盘(俗称指向针)的电子化成为可能。 14.4.1 在应用程序中使用传感器 本节的例子代码所在的工程目录是 src\ch14\ch14_sensor 在 Android 应用程序中使用传感器要依赖于 android.hardware.SensorEventListener 接口。通过该接口可 以监听传感器的各种事件。SensorEventListener 接口的代码如下: package android.hardware; public interface SensorEventListener { public void onSensorChanged(SensorEvent event); public void onAccuracyChanged(Sensor sensor, int accuracy); } 在 SensorEventListener 接口中定义了两个方法:onSensorChanged 和 onAccuracyChanged。当传感器的 值发生变化时,例如磁阻传感器的方向改变时会调用 onSensorChanged 方法。当传感器的精度变化时会调 用 onAccuracyChanged 方法。 onSensorChanged 方法只有一个 SensorEvent 类型的参数 event,其中 SensorEvent 类有一个 values 变量 非常重要,该变量的类型是 float[]。但该变量最多只有 3 个元素,而且根据传感器的不同,values 变量中 元素所代表的含义也不同。 在解释 values 变量中元素的含义之前,先来介绍一下 Android 的坐标系统是如何定义 X、Y、Z 轴的。  X 轴的方向是沿着屏幕的水平方向从左向右。如果手机不是正方形的话,较短的边需要水平放置, 较长的边需要垂直放置。  Y 轴的方向是从屏幕的左下角开始沿着屏幕的垂直方向指向屏幕的顶端。  将手机平放在桌子上,Z 轴的方向是从手机里指向天空。 下面是 values 变量的元素在主要的传感器中所代表的含义。 1.方向传感器 在方向传感器中 values 变量的 3 个值都表示度数,它们的含义如下: 访问 Android 手机的硬件 第 25 章 13 25 C h ap te r  values[0]:该值表示方位,也就是手机绕着 Z 轴旋转的角度。0 表示北(North);90 表示东(East); 180 表示南(South);270 表示西(West)。如果 values[0]的值正好是这 4 个值,并且手机是水平 放置,表示手机的正前方就是这 4 个方向。可以利用这个特性来实现电子罗盘,实例 76 将详细 介绍电子罗盘的实现过程。  values[1]:该值表示倾斜度,或手机翘起的程度。当手机绕着 X 轴倾斜时该值发生变化。values[1] 的取值范围是-180≤values[1] ≤180。假设将手机屏幕朝上水平放在桌子上,这时如果桌子是完 全水平的,values[1]的值应该是 0(由于很少有桌子是绝对水平的,因此,该值很可能不为 0,但 一般都是-5 和 5 之间的某个值)。这时从手机顶部开始抬起,直到将手机沿 X 轴旋转 180 度(屏 幕向下水平放在桌面上)。在这个旋转过程中,values[1]会在 0 到-180 之间变化,也就是说,从 手机顶部抬起时,values[1]的值会逐渐变小,直到等于-180。如果从手机底部开始抬起,直到将 手机沿 X 轴旋转 180 度,这时 values[1]会在 0 到 180 之间变化。也就是 values[1]的值会逐渐增大, 直到等于 180。可以利用 values[1]和下面要介绍的 values[2]来测量桌子等物体的倾斜度。  values[2]:表示手机沿着 Y 轴的滚动角度。取值范围是-90≤values[2]≤90。假设
/
本文档为【第14章 访问Android手机的硬件】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。 本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。 网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。

历史搜索

    清空历史搜索