Android (X06HT Desire) カメラプレビューが横向きに表示されてしまう!の対応

カメラのプレビューが横向きに表示されてしまう!

X06HT Desre Android2.1 の時に、アプリでカメラを使用した Activity を作成していたのだが、普通に使うと何故か横向きにプレビューされてしまっていたので、何の気なしにか、なにかで調べてか忘れたが、以下の様なコードを書いて対応していた。

camera01

↑ こんな風にプレビューされるので、↓ こんな風に対応しておいたら、うまいこと動いていた。

  1. Camera.Parameters p = camera.getParameters();

  2. p.setRotation(90);

  3. camera.setParameters(p);

が、10月8日に、待ちわびた、Froyo化を行ったところ、元の横向きに戻ってしまい、Camera.Paramteres の値を変えても、書き方を変えても、うんともすんとも言わなくなってしまった。

不具合か~

と思ったが、どうも元々Androidのカメラとはそういうものらしい。

もはやケータイに必須のカメラをAndroidで制御しよう」によると、

そもそも、Android のカメラには、向きの概念が無くて、常にランドスケープモードで作動するようだ。

なんと。

なので、Activity のオリエンテーションモードを、ランドスケープにした上で、上記のようにRotation してあげれば、意図した方向に画面プレビューを表示出来ることが分かった。

・・・が、いくつか問題が。

メニューが横向きに出てきてしまう

camera02

こんな感じ。これは当然か~ でもこれじゃーメニューつかえねー

トーストが横向きに出てしまう。

これも使えない。ちなみに通知バーも横向きに出るので、フルスクリーンモードにして、通知バーも消す必要がある。

AndroidManifest.xml のアクティビティ要素にて、向きとフルスクリーン&タイトルバー無しを指定。

  1. <activity android:name="info.typea.shujiroid.core.CameraActivity"
  2. android:screenOrientation="landscape"
  3. android:theme="@android:style/Theme.NoTitleBar.Fullscreen"/>

あと、以下のパーミッションを指定する。

  1. <uses-permission android:name="android.permission.CAMERA"></uses-permission>
  2. <uses-feature android:name="android.hardware.camera"></uses-feature>
  3. <uses-feature android:name="android.hardware.camera.autofocus"></uses-feature>
  4. <uses-feature android:name="android.hardware.camera.flash"></uses-feature>

カメラのコントロールのための UI を自分で作らなきゃいけない!?

まぁ、そもそも インテントで、カメラを呼び出せばいいだけかもしれないが(呼び出せるよね?)乗りかかった船なので、何とか使える形に持って行きたい。

先ほどのサイトのサンプルをダウンロードすると、AR(!?)のサンプルというか、プレビュー上にDroid君が表示される例があったので、参考にさせてもらい、Activity に カメラプレビュー用の SurfaceView を乗っけて、その上に、カメラコントロール用の View を乗っけることで対応してみた。

  1. package info.typea.shujiroid.core;
  2.  
  3. import info.typea.shujiroid.free.R;
  4. import info.typea.shujiroid.free.ShujiActivity;
  5.  
  6. import java.io.IOException;
  7.  
  8. import android.app.Activity;
  9. import android.content.Context;
  10. import android.content.Intent;
  11. import android.content.SharedPreferences;
  12. import android.graphics.Bitmap;
  13. import android.graphics.BitmapFactory;
  14. import android.graphics.Canvas;
  15. import android.graphics.Color;
  16. import android.graphics.Paint;
  17. import android.graphics.Paint.Style;
  18. import android.hardware.Camera;
  19. import android.os.Bundle;
  20. import android.preference.PreferenceManager;
  21. import android.view.Menu;
  22. import android.view.MotionEvent;
  23. import android.view.SurfaceHolder;
  24. import android.view.SurfaceView;
  25. import android.view.View;
  26. import android.view.ViewGroup.LayoutParams;
  27. import android.widget.Toast;
  28.  
  29. /**
  30. * カメラ用画面
  31. *
  32. * @author piroto
  33. */
  34. public class CameraActivity extends Activity {
  35. public static final String KEY_CAMERA_DATA = "camera_data";
  36. public static final String KEY_PREF_FLASH_MODE = "flash_mode";
  37. public static final int MENU_SHUTTER = Menu.FIRST;
  38. private SurfaceView preview;
  39. private SurfaceHolder holder;
  40. CameraControlView cameraCtrl;
  41. @Override
  42. protected void onCreate(Bundle savedInstanceState) {
  43. super.onCreate(savedInstanceState);
  44. setContentView(R.layout.camera_main);
  45.  
  46. // カメラコントロール用ビュー
  47. cameraCtrl = new CameraControlView(this);
  48. addContentView(cameraCtrl, new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
  49. preview = (SurfaceView) findViewById(R.id.surview_preview);
  50. holder = preview.getHolder();
  51. holder.addCallback(cameraCtrl);
  52. holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
  53. }
  54. /**
  55. * カメラのコントロール用のビュー
  56. * @author piroto
  57. */
  58. class CameraControlView extends View implements SurfaceHolder.Callback,
  59. Camera.ShutterCallback,
  60. Camera.AutoFocusCallback,
  61. Camera.PictureCallback {
  62. SharedPreferences pref = null;
  63. private Camera camera;
  64. private boolean isInProcess;
  65. private float shutterX = 10f;
  66. private float shutterY = 10f;
  67. private float shutterR = 50f;
  68.  
  69. private String currentFlashMode = null;
  70. private float flashX = 20f;
  71. private float flashY = 10f;
  72. private float flashIconSize = 100f;
  73. /**
  74. * @param context
  75. */
  76. public CameraControlView(Context context) {
  77. super(context);
  78. setFocusable(true);
  79. pref = PreferenceManager.getDefaultSharedPreferences(getContext());
  80. currentFlashMode = pref.getString(KEY_PREF_FLASH_MODE, Camera.Parameters.FLASH_MODE_OFF);
  81. }
  82. /**
  83. * フラッシュモードに応じたアイコンを取得する
  84. * @param flashMode
  85. * @return
  86. */
  87. private Bitmap getFlashModeIcon(String flashMode) {
  88. int iconId = R.drawable.flash_off_icon;
  89. if (Camera.Parameters.FLASH_MODE_AUTO.equals(flashMode)) {
  90. iconId = R.drawable.flash_auto_icon;
  91. } else if (Camera.Parameters.FLASH_MODE_ON.equals(flashMode)) {
  92. iconId = R.drawable.flash_on_icon;
  93. }
  94. return BitmapFactory.decodeResource(getResources(), iconId);
  95. }
  96. /**
  97. * フラッシュモードを変更する
  98. * AUTO -> ON -> OFF
  99. */
  100. private void changeFlashMode() {
  101. if (Camera.Parameters.FLASH_MODE_AUTO.equals(currentFlashMode)) {
  102. currentFlashMode = Camera.Parameters.FLASH_MODE_ON;
  103. } else if (Camera.Parameters.FLASH_MODE_ON.equals(currentFlashMode)) {
  104. currentFlashMode = Camera.Parameters.FLASH_MODE_OFF;
  105. } else {
  106. currentFlashMode = Camera.Parameters.FLASH_MODE_AUTO;
  107. }
  108. // プリファレンスに設定を保存
  109. pref.edit().putString(KEY_PREF_FLASH_MODE, currentFlashMode).commit();
  110.  
  111. Camera.Parameters p = camera.getParameters();
  112. p.setFlashMode(currentFlashMode);
  113. camera.setParameters(p);
  114.  
  115. invalidate();
  116. return;
  117. }
  118. @Override
  119. protected void onDraw(Canvas canvas) {
  120. super.onDraw(canvas);
  121. int w = canvas.getWidth();
  122. int h = canvas.getHeight();
  123. // シャッターボタンを描画
  124. shutterX = w - (shutterR/2f+40f);
  125. shutterY = h / 2.0f;
  126. Paint paint = new Paint();
  127. paint.setAntiAlias(true);
  128. paint.setStrokeWidth(4);
  129. paint.setColor(Color.BLUE);
  130. paint.setStyle(Style.FILL);
  131. paint.setAlpha(92);
  132. canvas.drawCircle(shutterX, shutterY, shutterR, paint);
  133. paint.setStyle(Style.STROKE);
  134. canvas.drawCircle(shutterX, shutterY, shutterR, paint);
  135. // フラッシュモードアイコンを描画
  136. canvas.drawBitmap(getFlashModeIcon(currentFlashMode), flashX, flashY, paint);
  137. }
  138. /**
  139. * 写真を撮る
  140. */
  141. public void takePicture() {
  142. isInProcess = true;
  143. camera.takePicture(this, null, this);
  144. }
  145. @Override
  146. public boolean onTouchEvent(MotionEvent event) {
  147. switch(event.getAction()) {
  148. case MotionEvent.ACTION_DOWN:
  149. if (!isInProcess) {
  150. float x = event.getX();
  151. float y = event.getY();
  152. // シャッターが押されたかを判定
  153. float minX = shutterX - shutterR;
  154. float maxX = shutterX + shutterR;
  155. float minY = shutterY - shutterR;
  156. float maxY = shutterY + shutterR;
  157. if ( (minX <= x && x <= maxX) &&
  158. (minY <= y && y <= maxY) ) {
  159. takePicture();
  160. }
  161. // フラッシュアイコンが押されたかを判定
  162. minX = flashX;
  163. maxX = flashX + flashIconSize;
  164. minY = flashY;
  165. maxY = flashY + flashIconSize;
  166. if ( (minX <= x && x <= maxX) &&
  167. (minY <= y && y <= maxY) ) {
  168. changeFlashMode();
  169. }
  170. }
  171. break;
  172. default:
  173. if (!isInProcess) {
  174. camera.autoFocus(this);
  175. isInProcess = true;
  176. }
  177. break;
  178. }
  179. return true;
  180. }
  181. @Override
  182. public void onShutter() {
  183. }
  184.  
  185. @Override
  186. public void onAutoFocus(boolean success, Camera camera) {
  187. isInProcess = false;
  188. }
  189.  
  190. @Override
  191. public void onPictureTaken(byte[] data, Camera camera) {
  192. // 撮影した写真データを呼び出し元の Activity へ返す
  193. Intent intent = new Intent();
  194. intent.putExtra(KEY_CAMERA_DATA, data);
  195. setResult(ShujiActivity.REQUEST_CODE_CAMERA, intent);
  196. isInProcess = false;
  197. finish();
  198. }
  199. @Override
  200. public void surfaceCreated(SurfaceHolder holder) {
  201. try {
  202. camera = Camera.open();
  203. camera.setPreviewDisplay(holder);
  204. } catch (IOException e) {
  205. String msg = getString(R.string.msg_error_occured) + "\n"
  206. + e.getMessage();
  207. (Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_LONG)).show();
  208. }
  209. }
  210. @Override
  211. public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
  212. camera.stopPreview();
  213. // 擬似的にポートレートモードに
  214. Camera.Parameters p = camera.getParameters();
  215. p.setRotation(90);
  216. p.setFlashMode(currentFlashMode);
  217. camera.setParameters(p);
  218. camera.startPreview();
  219. }
  220.  
  221. @Override
  222. public void surfaceDestroyed(SurfaceHolder holder) {
  223. camera.stopPreview();
  224. camera.release();
  225. }
  226. }
  227. }

ちなみに、このアクティビティの呼び出しと、結果の受け取りは以下な感じ。

インテントを回答待ちで呼び出して、

  1. // インテントを起動
  2. startActivityForResult(new Intent(this, CameraActivity.class),
  3. REQUEST_CODE_CAMERA);

結果を byte 配列のまま受け取って、Bitmapに変換。

  1. // 結果を受け取ってBitmapに変換
  2. protected void onActivityResult(int requestCode, int resultCode, Intent data) {
  3.  
  4. switch (requestCode) {
  5. case REQUEST_CODE_CAMERA:
  6. Bundle bundle = data.getExtras();
  7. byte[] picdata = bundle.getByteArray(CameraActivity.KEY_CAMERA_DATA);
  8. Bitmap pic = BitmapFactory.decodeByteArray(picdata, 0, picdata.length);
  9. :

拙いながらも、まぁこれでそれなりに動くようにはなった。

しかしながら、Home キー長押しで出てくるタスクリストは横向き。

だけど、標準のカメラも同じなので、割り切るしかないな。

 

あと、他機種で全く検証出来ないのが難点だが、知人がIS03を購入するようだし、これから Android もちが増えていくことを期待。

こんな感じになります。・・・わかりにくいかな。

 

また一歩野望に近づいた!

Follow me!

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です