Android (X06HT Desire) カメラプレビューが横向きに表示されてしまう!の対応
カメラのプレビューが横向きに表示されてしまう!
X06HT Desre Android2.1 の時に、アプリでカメラを使用した Activity を作成していたのだが、普通に使うと何故か横向きにプレビューされてしまっていたので、何の気なしにか、なにかで調べてか忘れたが、以下の様なコードを書いて対応していた。
↑ こんな風にプレビューされるので、↓ こんな風に対応しておいたら、うまいこと動いていた。
Camera.Parameters p = camera.getParameters(); p.setRotation(90); camera.setParameters(p);
が、10月8日に、待ちわびた、Froyo化を行ったところ、元の横向きに戻ってしまい、Camera.Paramteres の値を変えても、書き方を変えても、うんともすんとも言わなくなってしまった。
不具合か~
と思ったが、どうも元々Androidのカメラとはそういうものらしい。
「もはやケータイに必須のカメラをAndroidで制御しよう」によると、
そもそも、Android のカメラには、向きの概念が無くて、常にランドスケープモードで作動するようだ。
なんと。
なので、Activity のオリエンテーションモードを、ランドスケープにした上で、上記のようにRotation してあげれば、意図した方向に画面プレビューを表示出来ることが分かった。
・・・が、いくつか問題が。
メニューが横向きに出てきてしまう
こんな感じ。これは当然か~ でもこれじゃーメニューつかえねー
トーストが横向きに出てしまう。
これも使えない。ちなみに通知バーも横向きに出るので、フルスクリーンモードにして、通知バーも消す必要がある。
AndroidManifest.xml のアクティビティ要素にて、向きとフルスクリーン&タイトルバー無しを指定。
<activity android:name="info.typea.shujiroid.core.CameraActivity" android:screenOrientation="landscape" android:theme="@android:style/Theme.NoTitleBar.Fullscreen"/>
あと、以下のパーミッションを指定する。
<uses-permission android:name="android.permission.CAMERA"></uses-permission> <uses-feature android:name="android.hardware.camera"></uses-feature> <uses-feature android:name="android.hardware.camera.autofocus"></uses-feature> <uses-feature android:name="android.hardware.camera.flash"></uses-feature>
カメラのコントロールのための UI を自分で作らなきゃいけない!?
まぁ、そもそも インテントで、カメラを呼び出せばいいだけかもしれないが(呼び出せるよね?)乗りかかった船なので、何とか使える形に持って行きたい。
先ほどのサイトのサンプルをダウンロードすると、AR(!?)のサンプルというか、プレビュー上にDroid君が表示される例があったので、参考にさせてもらい、Activity に カメラプレビュー用の SurfaceView を乗っけて、その上に、カメラコントロール用の View を乗っけることで対応してみた。
package info.typea.shujiroid.core; import info.typea.shujiroid.free.R; import info.typea.shujiroid.free.ShujiActivity; import java.io.IOException; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Paint.Style; import android.hardware.Camera; import android.os.Bundle; import android.preference.PreferenceManager; import android.view.Menu; import android.view.MotionEvent; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.View; import android.view.ViewGroup.LayoutParams; import android.widget.Toast; /** * カメラ用画面 * * @author piroto */ public class CameraActivity extends Activity { public static final String KEY_CAMERA_DATA = "camera_data"; public static final String KEY_PREF_FLASH_MODE = "flash_mode"; public static final int MENU_SHUTTER = Menu.FIRST; private SurfaceView preview; private SurfaceHolder holder; CameraControlView cameraCtrl; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.camera_main); // カメラコントロール用ビュー cameraCtrl = new CameraControlView(this); addContentView(cameraCtrl, new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT)); preview = (SurfaceView) findViewById(R.id.surview_preview); holder = preview.getHolder(); holder.addCallback(cameraCtrl); holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); } /** * カメラのコントロール用のビュー * @author piroto */ class CameraControlView extends View implements SurfaceHolder.Callback, Camera.ShutterCallback, Camera.AutoFocusCallback, Camera.PictureCallback { SharedPreferences pref = null; private Camera camera; private boolean isInProcess; private float shutterX = 10f; private float shutterY = 10f; private float shutterR = 50f; private String currentFlashMode = null; private float flashX = 20f; private float flashY = 10f; private float flashIconSize = 100f; /** * @param context */ public CameraControlView(Context context) { super(context); setFocusable(true); pref = PreferenceManager.getDefaultSharedPreferences(getContext()); currentFlashMode = pref.getString(KEY_PREF_FLASH_MODE, Camera.Parameters.FLASH_MODE_OFF); } /** * フラッシュモードに応じたアイコンを取得する * @param flashMode * @return */ private Bitmap getFlashModeIcon(String flashMode) { int iconId = R.drawable.flash_off_icon; if (Camera.Parameters.FLASH_MODE_AUTO.equals(flashMode)) { iconId = R.drawable.flash_auto_icon; } else if (Camera.Parameters.FLASH_MODE_ON.equals(flashMode)) { iconId = R.drawable.flash_on_icon; } return BitmapFactory.decodeResource(getResources(), iconId); } /** * フラッシュモードを変更する * AUTO -> ON -> OFF */ private void changeFlashMode() { if (Camera.Parameters.FLASH_MODE_AUTO.equals(currentFlashMode)) { currentFlashMode = Camera.Parameters.FLASH_MODE_ON; } else if (Camera.Parameters.FLASH_MODE_ON.equals(currentFlashMode)) { currentFlashMode = Camera.Parameters.FLASH_MODE_OFF; } else { currentFlashMode = Camera.Parameters.FLASH_MODE_AUTO; } // プリファレンスに設定を保存 pref.edit().putString(KEY_PREF_FLASH_MODE, currentFlashMode).commit(); Camera.Parameters p = camera.getParameters(); p.setFlashMode(currentFlashMode); camera.setParameters(p); invalidate(); return; } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); int w = canvas.getWidth(); int h = canvas.getHeight(); // シャッターボタンを描画 shutterX = w - (shutterR/2f+40f); shutterY = h / 2.0f; Paint paint = new Paint(); paint.setAntiAlias(true); paint.setStrokeWidth(4); paint.setColor(Color.BLUE); paint.setStyle(Style.FILL); paint.setAlpha(92); canvas.drawCircle(shutterX, shutterY, shutterR, paint); paint.setStyle(Style.STROKE); canvas.drawCircle(shutterX, shutterY, shutterR, paint); // フラッシュモードアイコンを描画 canvas.drawBitmap(getFlashModeIcon(currentFlashMode), flashX, flashY, paint); } /** * 写真を撮る */ public void takePicture() { isInProcess = true; camera.takePicture(this, null, this); } @Override public boolean onTouchEvent(MotionEvent event) { switch(event.getAction()) { case MotionEvent.ACTION_DOWN: if (!isInProcess) { float x = event.getX(); float y = event.getY(); // シャッターが押されたかを判定 float minX = shutterX - shutterR; float maxX = shutterX + shutterR; float minY = shutterY - shutterR; float maxY = shutterY + shutterR; if ( (minX <= x && x <= maxX) && (minY <= y && y <= maxY) ) { takePicture(); } // フラッシュアイコンが押されたかを判定 minX = flashX; maxX = flashX + flashIconSize; minY = flashY; maxY = flashY + flashIconSize; if ( (minX <= x && x <= maxX) && (minY <= y && y <= maxY) ) { changeFlashMode(); } } break; default: if (!isInProcess) { camera.autoFocus(this); isInProcess = true; } break; } return true; } @Override public void onShutter() { } @Override public void onAutoFocus(boolean success, Camera camera) { isInProcess = false; } @Override public void onPictureTaken(byte[] data, Camera camera) { // 撮影した写真データを呼び出し元の Activity へ返す Intent intent = new Intent(); intent.putExtra(KEY_CAMERA_DATA, data); setResult(ShujiActivity.REQUEST_CODE_CAMERA, intent); isInProcess = false; finish(); } @Override public void surfaceCreated(SurfaceHolder holder) { try { camera = Camera.open(); camera.setPreviewDisplay(holder); } catch (IOException e) { String msg = getString(R.string.msg_error_occured) + "\n" + e.getMessage(); (Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_LONG)).show(); } } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { camera.stopPreview(); // 擬似的にポートレートモードに Camera.Parameters p = camera.getParameters(); p.setRotation(90); p.setFlashMode(currentFlashMode); camera.setParameters(p); camera.startPreview(); } @Override public void surfaceDestroyed(SurfaceHolder holder) { camera.stopPreview(); camera.release(); } } }
ちなみに、このアクティビティの呼び出しと、結果の受け取りは以下な感じ。
インテントを回答待ちで呼び出して、
// インテントを起動 startActivityForResult(new Intent(this, CameraActivity.class), REQUEST_CODE_CAMERA);
結果を byte 配列のまま受け取って、Bitmapに変換。
// 結果を受け取ってBitmapに変換 protected void onActivityResult(int requestCode, int resultCode, Intent data) { switch (requestCode) { case REQUEST_CODE_CAMERA: Bundle bundle = data.getExtras(); byte[] picdata = bundle.getByteArray(CameraActivity.KEY_CAMERA_DATA); Bitmap pic = BitmapFactory.decodeByteArray(picdata, 0, picdata.length); :
拙いながらも、まぁこれでそれなりに動くようにはなった。
しかしながら、Home キー長押しで出てくるタスクリストは横向き。
だけど、標準のカメラも同じなので、割り切るしかないな。
あと、他機種で全く検証出来ないのが難点だが、知人がIS03を購入するようだし、これから Android もちが増えていくことを期待。
こんな感じになります。・・・わかりにくいかな。
また一歩野望に近づいた!