1. Trang chủ
  2. » Công Nghệ Thông Tin

Android SDK (phần 11) ppsx

50 375 0

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 50
Dung lượng 1,72 MB

Nội dung

Using the Compass, Accelerometer, and Orientation Sensors ❘ 467 Sensor accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); sensorManager.registerListener(sensorEventListener, accelerometer, SensorManager.SENSOR_DELAY_FASTEST); Timer updateTimer = new Timer("gForceUpdate"); updateTimer.scheduleAtFixedRate(new TimerTask() { public void run() { updateGUI(); } }, 0, 100); } All code snippets in this example are part of the Chapter 14 G-Forceometer project, available for download at Wrox.com. Once you’re finished you’ll want to test this out. Ideally you can do that in an F16 while Maverick performs high-g maneuvers over the Atlantic. That’s been known to end badly, so failing that you can experiment with running or driving in the safety of your neighborhood. Given that keeping constant watch on your handset while driving, cycling, or flying is also likely to end poorly, you might consider some further enhancements before you take it out for a spin. Consider incorporating vibration or media player functionality to shake or beep with an intensity proportional to your current force, or simply log changes as they happen for later review. Determining Your Orientation The orientation Sensor is a combination of the magnetic field Sensors, which function as an electronic compass, and accelerometers, which determine the pitch and roll. If you’ve done a bit of trigonometry you’ve got the skills required to calculate the device orientation based on the accelerometer and magnetic field values along all three axes. If you enjoyed trig as much as I did you’ll be happy to learn that Android does these calculations for you. X heading Y pitch Z roll FIGURE 14-2 In fact, Android provides two alternatives for determining the device orientation. You can query the orientation Sensor directly or derive the orientation using the accelerometers and magnetic field Sensors. The latter option is slower, but offers the advan- tages of increased accuracy and the ability to modify the reference frame when determining your orientation. The following sections demonstrate both techniques. Using the standard reference frame, the device orientation is reported along three dimensions, as illustrated in Figure 14-2. As when using the accelerometers, the device is considered at rest faceup on a flat surface. ➤ x-axis (azimuth) The azimuth (also heading or yaw) is the direction the device is facing around the x-axis, where 0/360 degrees is north, 90 east, 180 south, and 270 west. 468 ❘ CHAPTER 14 SENSORS ➤ y-axis (pitch) Pitch represents the angle of the device around the y-axis. The tilt angle returned shows 0 when the device is flat on its back, -90 when it is standing upright (top of device pointing at the ceiling), 90 when it’s upside down, and 180/-180 when it’s facedown. ➤ z-axis (roll) The roll represents the device’s sideways tilt between -90 and 90 degrees on the z-axis. Zero is the device flat on its back, -90 is the screen facing left, and 90 is the screen facing right. Determining Orientation Using the Orientation Sensor The simplest way to monitor device orientation is by using a dedicated orientation Sensor. Create and register a Sensor Event Listener with the Sensor Manager, using the default orientation Sensor, as shown in Listing 14-3. LISTING 14-3: Determining orientation using the orientation Sensor SensorManager sm = (SensorManager)getSystemService(Context.SENSOR_SERVICE); int sensorType = Sensor.TYPE_ORIENTATION; sm.registerListener(myOrientationListener, sm.getDefaultSensor(sensorType), SensorManager.SENSOR_DELAY_NORMAL); When the device orientation changes, the onSensorChanged method in your SensorEventListener implementation is fired. The SensorEvent parameter includes a values float array that provides the device’s orientation along three axes. The first element of the values array is the azimuth (heading), the second pitch, and the third roll. final SensorEventListener myOrientationListener = new SensorEventListener() { public void onSensorChanged(SensorEvent sensorEvent) { if (sensorEvent.sensor.getType() == Sensor.TYPE_ORIENTATION) { float headingAngle = sensorEvent.values[0]; float pitchAngle = sensorEvent.values[1]; float rollAngle = sensorEvent.values[2]; // TODO Apply the orientation changes to your application. } } public void onAccuracyChanged(Sensor sensor, int accuracy) {} }; Calculating Orientation Using the Accelerometer and Magnetic Field Sensors The best approach for finding the device orientation is to calculate it from the accelerometer and mag- netic field Sensor results directly. This technique enables you to change the orientation reference frame to remap the x-, y-, and z-axes to suit the device orientation you expect during use. This approach uses both the accelerometer and magnetic field Sensors, so you need to create and register two Sensor Event Listeners. Within the onSensorChanged methods for each Sensor Event Listener, record the values array property received in two separate field variables, as shown in Listing 14-4. Using the Compass, Accelerometer, and Orientation Sensors ❘ 469 LISTING 14-4: Finding orientation using the accelerometer and magnetic field Sensors float[] accelerometerValues; float[] magneticFieldValues; final SensorEventListener myAccelerometerListener = new SensorEventListener() { public void onSensorChanged(SensorEvent sensorEvent) { if (sensorEvent.sensor.getType() == Sensor.TYPE_ACCELEROMETER) accelerometerValues = sensorEvent.values; } public void onAccuracyChanged(Sensor sensor, int accuracy) {} }; final SensorEventListener myMagneticFieldListener = new SensorEventListener() { public void onSensorChanged(SensorEvent sensorEvent) { if (sensorEvent.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) magneticFieldValues = sensorEvent.values; } public void onAccuracyChanged(Sensor sensor, int accuracy) {} }; Register both with the Sensor Manager, as shown in the following code extending Listing 14-4; this snippet uses the default hardware and UI update rate for both Sensors: SensorManager sm = (SensorManager)getSystemService(Context.SENSOR_SERVICE); Sensor aSensor = sm.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); Sensor mfSensor = sm.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD); sm.registerListener(myAccelerometerListener, aSensor, SensorManager.SENSOR_DELAY_UI); sm.registerListener(myMagneticFieldListener, mfSensor, SensorManager.SENSOR_DELAY_UI); To calculate the current orientation from these Sensor values you use the getRotationMatrix and getOrientation methods from the Sensor Manager, as follows. Note that getOrientation returns radians rather than degrees. float[] values = new float[3]; float[] R = new float[9]; SensorManager.getRotationMatrix(R, null, accelerometerValues, magneticFieldValues); SensorManager.getOrientation(R, values); // Convert from radians to degrees. values[0] = (float) Math.toDegrees(values[0]); values[1] = (float) Math.toDegrees(values[1]); values[2] = (float) Math.toDegrees(values[2]); 470 ❘ CHAPTER 14 SENSORS Remapping the Orientation Reference Frame To measure device orientation using a reference frame other than the default described earlier, use the remapCoordinateSystem method from the Sensor Manager. Earlier in this chapter the standard reference frame was described as the device being faceup on a flat surface. This method lets you remap the coordinate system used to calculate your orientation, for example by specifying the device to be at rest when mounted vertically. X heading Y roll Z pitch FIGURE 14-3 The remapCoordinateSystem method accepts four parameters: ➤ The initial rotation matrix, found using getRotationMatrix, as described earlier ➤ A variable used to store the output (transformed) rotation matrix ➤ The remapped x-axis ➤ The remapped y-axis Two final parameters are used to specify the new reference frame. The values used specify the new x- and y-axes relative to the default frame. The Sensor Manager provides a set of constants to let you specify the axis values: AXIS_X , AXIS_Y , AXIS_Z , AXIS_MINUS_X , AXIS_MINUS_Y ,and AXIS_MINUS_Z . Listing 14-5 shows how to remap the reference frame so that a device is at rest when mounted vertically — held in portrait mode with its screen facing the user — as shown in Figure 14-3. LISTING 14-5: Remapping the orientation reference frame SensorManager.getRotationMatrix(R, null, aValues, mValues); float[] outR = new float[9]; SensorManager.remapCoordinateSystem(R, SensorManager.AXIS_X, SensorManager.AXIS_Z, outR); SensorManager.getOrientation(outR, values); // Convert from radians to degrees. values[0] = (float) Math.toDegrees(values[0]); values[1] = (float) Math.toDegrees(values[1]); values[2] = (float) Math.toDegrees(values[2]); Creating a Compass and Artificial Horizon In Chapter 4 you created a simple CompassView to experiment with owner-drawn controls. In this example you’ll extend the functionality of the Compass View to display the device pitch and roll, before using it to display the device orientation. Using the Compass, Accelerometer, and Orientation Sensors ❘ 471 1. Open the Compass project you created in Chapter 4. You will be making changes to the CompassView as well as the Compass Activity used to display it. To ensure that the view and controller remain as decoupled as possible, the CompassView won’t be linked to the Sensors directly; instead it will be updated by the Activity. Start by adding field variables and get/set methods for pitch and roll to the CompassView . float pitch = 0; float roll = 0; public float getPitch() { return pitch; } public void setPitch(float pitch) { this.pitch = pitch; } public float getRoll() { return roll; } public void setRoll(float roll) { this.roll = roll; } 2. Update the onDraw method to include two circles that will be used to indicate the pitch and roll values. @Override protected void onDraw(Canvas canvas) { [ Existing onDraw method ] 2.1. Create a new circle that’s half filled and rotates in line with the sideways tilt (roll). RectF rollOval = new RectF((mMeasuredWidth/3)-mMeasuredWidth/7, (mMeasuredHeight/2)-mMeasuredWidth/7, (mMeasuredWidth/3)+mMeasuredWidth/7, (mMeasuredHeight/2)+mMeasuredWidth/7 ); markerPaint.setStyle(Paint.Style.STROKE); canvas.drawOval(rollOval, markerPaint); markerPaint.setStyle(Paint.Style.FILL); canvas.save(); canvas.rotate(roll, mMeasuredWidth/3, mMeasuredHeight/2); canvas.drawArc(rollOval, 0, 180, false, markerPaint); canvas.restore(); 2.2. Create a new circle that starts half filled and varies between full and empty based on the forward angle (pitch): RectF pitchOval = new RectF((2*mMeasuredWidth/3)-mMeasuredWidth/7, (mMeasuredHeight/2)-mMeasuredWidth/7, (2*mMeasuredWidth/3)+mMeasuredWidth/7, (mMeasuredHeight/2)+mMeasuredWidth/7 ); 472 ❘ CHAPTER 14 SENSORS markerPaint.setStyle(Paint.Style.STROKE); canvas.drawOval(pitchOval, markerPaint); markerPaint.setStyle(Paint.Style.FILL); canvas.drawArc(pitchOval, 0-pitch/2, 180+(pitch), false, markerPaint); markerPaint.setStyle(Paint.Style.STROKE); } FIGURE 14-4 . 3. That completes the changes to the CompassView . If you run the application now it should appear as shown in Figure 14-4. 4. Now update the Compass Activity. Use the Sen- sor Manager to listen for orientation changes using the magnetic field and accelerometer Sen- sors. Start by adding local field variables to store the last magnetic field and accelerometer val- ues, as well as references to the CompassView and SensorManager . float[] aValues = new float[3]; float[] mValues = new float[3]; CompassView compassView; SensorManager sensorManager; 5. Create a new updateOrientation method that uses new heading, pitch, and roll values to update the CompassView . private void updateOrientation(float[] values) { if (compassView!= null) { compassView.setBearing(values[0]); compassView.setPitch(values[1]); compassView.setRoll(-values[2]); compassView.invalidate(); } } 6. Update the onCreate method to get references to the CompassView and SensorManager ,and initialize the heading, pitch, and roll. @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); compassView = (CompassView)this.findViewById(R.id.compassView); sensorManager = (SensorManager)getSystemService(Context.SENSOR_SERVICE); updateOrientation(new float[] {0, 0, 0}); } Using the Compass, Accelerometer, and Orientation Sensors ❘ 473 7. Create a new calculateOrientation method to evaluate the device orientation using the last recorded accelerometer and magnetic field values. private float[] calculateOrientation() { float[] values = new float[3]; float[] R = new float[9]; SensorManager.getRotationMatrix(R, null, aValues, mValues); SensorManager.getOrientation(R, values); // Convert from Radians to Degrees. values[0] = (float) Math.toDegrees(values[0]); values[1] = (float) Math.toDegrees(values[1]); values[2] = (float) Math.toDegrees(values[2]); return values; } 8. Implement a SensorEventListener as a field variable. Within onSensorChanged it should check for the calling Sensor’s type and update the last accelerometer or magnetic field values as appropriate before making a call to updateOrientation using the calculateOrientation method. private final SensorEventListener sensorEventListener = new SensorEventListener() { public void onSensorChanged(SensorEvent event) { if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) aValues = event.values; if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) mValues = event.values; updateOrientation(calculateOrientation()); } public void onAccuracyChanged(Sensor sensor, int accuracy) {} }; 9. Now override onResume and onStop to register and unregister the SensorEventListener when the Activity becomes visible and hidden, respectively. @Override protected void onResume() { super.onResume(); Sensor accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); Sensor magField = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD); sensorManager.registerListener(sensorEventListener, accelerometer, SensorManager.SENSOR_DELAY_FASTEST); sensorManager.registerListener(sensorEventListener, 474 ❘ CHAPTER 14 SENSORS magField, SensorManager.SENSOR_DELAY_FASTEST); } @Override protected void onStop() { sensorManager.unregisterListener(sensorEventListener); super.onStop(); } If you run the application now you should see the three face dials update dynamically when the orientation of the device changes. 10. An artificial horizon is more useful if it’s mounted vertically. Modify the reference frame of the artificial horizon to match this orientation by updating calculateOrientation to remap the coordinate system. private float[] calculateOrientation() { float[] values = new float[3]; float[] R = new float[9]; float[] outR = new float[9]; SensorManager.getRotationMatrix(R, null, aValues, mValues); SensorManager.remapCoordinateSystem(R, SensorManager.AXIS_X, SensorManager.AXIS_Z, outR); SensorManager.getOrientation(outR, values); // Convert from Radians to Degrees. values[0] = (float) Math.toDegrees(values[0]); values[1] = (float) Math.toDegrees(values[1]); values[2] = (float) Math.toDegrees(values[2]); return values; } All code snippets in this example are part of the Chapter 14 Artificial Horizon project, available for download at Wrox.com. CONTROLLING DEVICE VIBRATION In Chapter 9 you learned how to create Notifications that can use vibration to enrich event feedback. In some circumstances you may want to vibrate the device independently of Notifications. Vibrating the device is an excellent way to provide haptic user feedback, and is particularly popular as a feedback mechanism for games. To control device vibration, your applications needs the VIBRATE permission. Add this to your applica- tion manifest using the following XML snippet: <uses-permission android:name="android.permission.VIBRATE"/> Summary ❘ 475 Device vibration is controlled through the Vibrator Service, accessible via the getSystemService method, as shown in Listing 14-6. LISTING 14-6: Controlling device vibration String vibratorService = Context.VIBRATOR_SERVICE; Vibrator vibrator = (Vibrator)getSystemService(vibratorService); Call vibrate to start device vibration; you can pass in either a vibration duration or a pattern of alter- nating vibration/pause sequences along with an optional index parameter that will repeat the pattern starting at the index specified. Both techniques are demonstrated in the following extension to List- ing 14-6: long[] pattern = {1000, 2000, 4000, 8000, 16000 }; vibrator.vibrate(pattern, 0); // Execute vibration pattern. vibrator.vibrate(1000); // Vibrate for 1 second. To cancel vibration call cancel ; exiting your application will automatically cancel any vibration it has initiated. SUMMARY In this chapter you learned how to use the Sensor Manager to let your application respond to the physical environment. You were introduced to the Sensors available on the Android platform and learned how to listen for Sensor Events using the Sensor Event Listener and how to interpret those results. Then you took a more detailed look at the accelerometer, orientation, and magnetic field detection hardware, using these Sensors to determine the device’s orientation and acceleration. In the process you created a g-forceometer and an artificial horizon. Youalsolearned: ➤ Which Sensors are available to Android applications ➤ How to remap the reference frame when determining a device’s orientation ➤ The composition and meaning of the Sensor Event values returned by each sensor ➤ How to use device vibration to provide physical feedback for application events In the final chapter, you’ll be introduced to some of the advanced Android features. You’ll learn more about security, how to use AIDL to facilitate interprocess communication, and using Wake Locks. You’ll be introduced to Android’s TTS library and learn about Android’s User Interface and graph- ics capabilities by exploring animations and advanced Canvas drawing techniques. Finally, you’ll be introduced to the SurfaceView and touch-screen input functionality. [...]... xmlns :android= "http://schemas .android. com/apk/res /android" android: shareInterpolator="true"> res/anim/popinlayout.xml 3.4 Create slide_top_out.xml 3.7 Create slide_right_in.xml 3.2 Create slide_bottom_out.xml ... android: toYDelta="-100%p" android: duration="700" /> 3.5 Create slide_left_in.xml Building Rich User Interfaces 3.6 Create slide_left_out.xml To display your animation,... android: fromXDelta="-100%p" android: toXDelta="0" android: duration="700" /> 3.8 Create slide_right_out.xml 4 Return to the ContentSlider Activity and get references to the Text View and each... android: toYScale="0.0" android: pivotX="50%" continues 492 ❘ CHAPTER 15 ADVANCED ANDROID DEVELOPMENT LISTING 15-13 (continued) android: pivotY="50%" android: startOffset="500" android: duration="500" /> As you can see, it’s generally both easier and more intuitive to create your animation sequences . new permission <permission android: name="com.paad.DETONATE_DEVICE" android: protectionLevel="dangerous" android: label="Self Destruct" android: description="@string/detonate_description"> </permission> Within. the Android documentation provides an excellent resource that describes the security features in depth at developer .android. com/guide/topics/security/security.html Linux Kernel Security Each Android. many of Android s native components have permission require- ments. The native permission strings used by native Android Activities and Services can be found as static constants in the android. Manifest.permission class. To

Ngày đăng: 05/07/2014, 15:20

TỪ KHÓA LIÊN QUAN

TÀI LIỆU CÙNG NGƯỜI DÙNG

TÀI LIỆU LIÊN QUAN