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