0
I’m having a problem using the SurfaceView
for a custom camera on Android, I can’t work the camera orientation with the SurfaceView
, no matter how I turn the Smartphone it always behaves strangely, in case I made two layouts for the two orientations, follows picture:
Before posting the code I wanted to know if the most correct way to work with Surfaceview is to leave your permanent guidance, being it Portrait or Landscape as in this manifest: android:screenOrientation="portrait"
or if I leave it free, in the example above it is with free guidance.
Excerpt from the code for guidance
public int onOrientationChanged() {
int orientation = this.getWindowManager().getDefaultDisplay().getOrientation();
android.hardware.Camera.CameraInfo info =
new android.hardware.Camera.CameraInfo();
android.hardware.Camera.getCameraInfo(0, info);
orientation = (orientation + 45) / 90 * 90;
int rotation = 0;
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
rotation = (info.orientation - orientation + 360) % 360;
} else { // back-facing camera
rotation = (info.orientation + orientation) % 360;
}
return rotation;
}
@Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
//Abre a câmera
try{
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
//int rotation = this.getWindowManager().getDefaultDisplay().getRotation();
camera = Camera.open();
Camera.Parameters parameters;
parameters = camera.getParameters();
parameters.setPreviewFrameRate(20);
parameters.setPictureSize(size.x,size.y);
int orientation = onOrientationChanged();
parameters.setRotation(orientation);
camera.setParameters(parameters);
//camera.setDisplayOrientation(mOrientation);
}catch (RuntimeException ex){
Log.e("ERRO",ex.getMessage());
Toast.makeText(this,"Ocorreu um erro com a câmera! ", Toast.LENGTH_SHORT);
}
try{
//O SurfaceView tem sido criado, agora comunica-se com a câmera para desenhar o Preview.
camera.setPreviewDisplay(surfaceHolder);
camera.startPreview();
}catch (Exception e){
Log.e("ERRO",e.getMessage());
}
}
Full Java code:
public class CameraApp extends FragmentActivity implements SurfaceHolder.Callback {
private Camera camera = null;
private int camId = 1;
@InjectView(R.id.surfaceView)
SurfaceView surfaceView;
@InjectView(R.id.btn_take_photo)
FloatingActionButton btn_take_photo;
SurfaceHolder surfaceHolder;
Camera.PictureCallback jpegCallback;
Camera.ShutterCallback shutterCallback;
private Context context = this;
private Evento evento;
private String dir;
private OrientationEventListener mOrientationEventListener;
private int mOrientation = -1;
private static final int ORIENTATION_PORTRAIT_NORMAL = 1;
private static final int ORIENTATION_PORTRAIT_INVERTED = 2;
private static final int ORIENTATION_LANDSCAPE_NORMAL = 3;
private static final int ORIENTATION_LANDSCAPE_INVERTED = 4;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.fragment_camera);
ButterKnife.inject(this);
evento = (Evento) getIntent().getSerializableExtra("item");
dir = (String) getIntent().getSerializableExtra("item2");
surfaceHolder = surfaceView.getHolder();
//Instalamos uma surfaceHolder.Callback então nós notificamos quando o underlying surface é criado e destroido.
surfaceHolder.addCallback(this);
//Confirguração precaria, ,as requer um android versão rioritaria 3.0
surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
btn_take_photo.setOnClickListener(new FloatingActionButton.OnClickListener() {
@Override
public void onClick(View view) {
cameraImage();
}
});
jpegCallback = new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] bytes, Camera camera) {
FileOutputStream outputStream = null;
File file_image = getDirc();
if(!file_image.exists() && !file_image.mkdirs()){
Toast.makeText(getApplicationContext(),"Não pode criar diretorio para salvar imagem", Toast.LENGTH_SHORT).show();
return;
}
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyymmddhhmmss");
String date = simpleDateFormat.format(new Date());
String photofile = dir.trim().replace(" ", "").toLowerCase() + "_" + evento.getNomeDoEvento().trim().replace(" ", "").toLowerCase() + "_" + date.trim().replace(" ", "") + ".jpeg";
String file_name = file_image.getAbsolutePath() + "/" + photofile;
File picFile = new File(file_name);
try{
outputStream = new FileOutputStream(picFile);
outputStream.write(bytes);
outputStream.close();
}catch (FileNotFoundException e) {
}catch (IOException ex){
}finally {
}
Toast.makeText(getApplicationContext(),file_name, Toast.LENGTH_SHORT).show();
refreshCamera();
refreshGallery(picFile);
}
};
}
public int onOrientationChanged() {
int orientation = this.getWindowManager().getDefaultDisplay().getOrientation();
android.hardware.Camera.CameraInfo info =
new android.hardware.Camera.CameraInfo();
android.hardware.Camera.getCameraInfo(0, info);
orientation = (orientation + 45) / 90 * 90;
int rotation = 0;
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
rotation = (info.orientation - orientation + 360) % 360;
} else { // back-facing camera
rotation = (info.orientation + orientation) % 360;
}
return rotation;
}
public void refreshCamera(){
if(surfaceHolder.getSurface() == null){
//Preview surface não existe
return;
}
//Para preview antes de fazer as mudanças
try{
camera.stopPreview();
}catch (Exception e){
}
//Coloca no preview tamanho e faz alguma mudança de tamanho, rotação ou reformata as mudanças aqui,
// inicia o preview com novas configurações.
try{
camera.setPreviewDisplay(surfaceHolder);
camera.startPreview();
}catch (Exception e){
}
}
public void refreshGallery(File file){
Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
intent.setData(Uri.fromFile(file));
sendBroadcast(intent);
}
private File getDirc(){
File dics = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "/Hashmidia/" + evento.getNomeDoEvento().trim().replace(" ", ""));
return new File(dics,dir.trim().replace(" ", ""));
}
public void cameraImage(){
//Tira a foto
camera.takePicture(null,null,jpegCallback);
}
@Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
//Abre a câmera
try{
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
//int rotation = this.getWindowManager().getDefaultDisplay().getRotation();
camera = Camera.open();
Camera.Parameters parameters;
parameters = camera.getParameters();
parameters.setPreviewFrameRate(20);
parameters.setPictureSize(size.x,size.y);
int orientation = onOrientationChanged();
parameters.setRotation(orientation);
camera.setParameters(parameters);
//camera.setDisplayOrientation(mOrientation);
}catch (RuntimeException ex){
Log.e("ERRO",ex.getMessage());
Toast.makeText(this,"Ocorreu um erro com a câmera! ", Toast.LENGTH_SHORT);
}
try{
//O SurfaceView tem sido criado, agora comunica-se com a câmera para desenhar o Preview.
camera.setPreviewDisplay(surfaceHolder);
camera.startPreview();
}catch (Exception e){
Log.e("ERRO",e.getMessage());
}
}
@Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {
refreshCamera();
}
@Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
//para preview w reinicia camera
camera.stopPreview();
camera.release();
camera = null;
}
private int pixels(float cm){
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
int width = size.x;
int height = size.y;
return width;
}
@Override
public void onBackPressed() {
//onBackPressed desabilitado
startActivity(new Intent(context, Gerenciador.class).putExtra("item",evento));
}
}
XML
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".activity.CameraApp">
<RelativeLayout
android:id="@+id/btn_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<SurfaceView
android:id="@+id/surfaceView"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
<RelativeLayout
android:id="@+id/layout_area2"
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_alignParentTop="true"
android:background="#000000FF">
<ImageView
android:id="@+id/image_flash"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:layout_margin="10dp"
android:src="@android:drawable/ic_lock_idle_low_battery"/>
</RelativeLayout>
<RelativeLayout
android:id="@+id/layout_area1"
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_alignParentBottom="true"
android:background="#000000FF">
<com.melnykov.fab.FloatingActionButton
android:id="@+id/btn_take_photo"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_centerInParent="true"
android:src="@drawable/fab_shadow"/>
<ImageView
android:id="@+id/image_galeria"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_margin="10dp"
android:src="@android:drawable/ic_menu_gallery"/>
<ImageView
android:id="@+id/image_moldura"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:layout_margin="10dp"
android:src="@android:drawable/ic_dialog_dialer"/>
</RelativeLayout>
</RelativeLayout>
</FrameLayout>
Leonardo speaks, blz? Man, let’s say 50% of the problem has been solved, it fits well when it gets in position PORTRAIT, but as I rotate the mobile the orientation gets messy again, I believe that if I seek to capture this movement and change to
camera.setDisplayOrientation(180);
can work, but I have a question, I leave the orientation free or should I "FREEZE THE ORIENTATION" in the manifest? Like this:<activity android:name=".activity.CameraApp" android:theme="@android:style/Theme.NoTitleBar" android:screenOrientation="portrait"/>
– Vinithius