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 もちが増えていくことを期待。
こんな感じになります。・・・わかりにくいかな。
また一歩野望に近づいた!