Camera orientation change is too slow [duplicate] - android

I have a DrawerLayout which contains a FrameLayout and ListView in my app, I have to show the camera in the FrameLayout, I've done that fine (as following code) and the camera works correctly. The problem is when moving from portrait orientation to (right-Landscape orientation or left-landscape orientation), or vice versa, it take the mobile a long time to make changes, the problem does not appear when moving from right-Landscape orientation or left-landscape orientation or vice versa.
How could I make this operation as fast as I can?
public class ShowCamera extends SurfaceView implements SurfaceHolder.Callback{
//This ShowCamera class is a helpful class
private SurfaceHolder holdMe;
private Camera theCamera;
public ShowCamera(Context context,Camera camera) {
super(context);
theCamera = camera;
holdMe = getHolder();
holdMe.addCallback(this);
}
#Override
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
try {
theCamera.setPreviewDisplay(holder);
theCamera.startPreview();
synchronized (holder) {
}
} catch (Exception e) {}
}
#Override
public void surfaceDestroyed(SurfaceHolder arg0) {
holdMe.removeCallback(this);
theCamera.release();
}
}
Now the original class is:
public class MainActivity extends Activity {
private DrawerLayout mDrawerLayout;
private ListView mDrawerList;
String[] options = {"op1", "op2", "op3", "op4", "op5"}; //for the DrawerLayout
int[] icons = { 0,R.drawable.hospital,R.drawable.education,R.drawable.police,R.drawable.food}; //for the DrawerLayout
private Camera cameraObject;
private ShowCamera showCamera;
public static Camera getCamIfAvailable(){
Camera cam = null;
try { cam = Camera.open();}
catch (Exception e){}
return cam;
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
cameraObject = getCamIfAvailable();
new Thread(new Runnable()
{
int rotation = getWindowManager().getDefaultDisplay().getRotation();
#Override
public void run()
{
switch(rotation){
case 0: // portrait
cameraObject.setDisplayOrientation(90);
break;
case 1: // left Landscape
cameraObject.setDisplayOrientation(0);
break;
case 3: //right Landscape
cameraObject.setDisplayOrientation(180);
break;
}
}
}).start();
showCamera = new ShowCamera(this, cameraObject);
FrameLayout preview = (FrameLayout) findViewById(R.id.content_frame);
preview.addView(showCamera);
//.
//.
//.
//.
//. Here, code for Drawerlayout no problrm
//.
//.
//.
}
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
// Pass any configuration change to the drawer toggls
mDrawerToggle.onConfigurationChanged(newConfig);
// Checks the orientation of the screen
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
Toast.makeText(this, "landscape", Toast.LENGTH_SHORT).show();
} else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT){
Toast.makeText(this, "portrait", Toast.LENGTH_SHORT).show();
}
}
.
.
.
.
} // End of the class MainActivity
Also I have put in the manifest file the following as first answer mentioned here:
<activity android:name=".MyActivity"
android:configChanges="orientation|screenSize"
android:label="#string/app_name">
Any help will be appreciated.

Camera.open() is an heavy operation for the system. It is only triggered when a configuration change is happening, such as when you rotate your device from landscape to portrait and vice-versa.
When flipping the device (from portrait to reversed portrait, or from landscape to reversed landscape) this doesn't trigger a configuration change, only the screen rendering is flipped and therefore you don't call Camera.open() again.
So, you won't be able to make it faster (even though I recommend you to take a look at the systrace tool to see what's really happening when you rotate your screen).
But, I strongly encourage you to try calling the Camera.open() from a background Thread to avoid freezing the UI.

Related

Adapt camera view with Surfaceview dimension

I'm developing an application where I read some barcode. In a first step I had a big SurfaceView where I can see well the camera preview, but now I would set the dimensions of Surfaceview like the dimensions of barcode but I have bad camera visualization (it is too small). Can someone help me to stretch camera preview? Thanks
Here manage detector and surfaceview:
public class LettoreBarcode extends Fragment {
View view;
SurfaceView surfaceView;
Handler handler;
private BarcodeDetector detector;
private CameraSource cameraSource;
private TextView code;
SparseArray<Barcode> items;
private static Button btnBack;
String barcode = "" ;
SparseArray<Articoli> groups = new SparseArray<Articoli>();
Context _context = null;
ProductsAdapter.ViewHolder _ViewHolder = null;
public LettoreBarcode(){
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
view = inflater.inflate(R.layout.fragment_barcode_scanner, container, false);
surfaceView = (SurfaceView) view.findViewById(R.id.surfaceView);
detector = new BarcodeDetector.Builder(getActivity()).setBarcodeFormats(Barcode.ALL_FORMATS).build();
final Dialog d = new Dialog(getActivity());
btnBack = (Button) view.findViewById(R.id.btnBack);
handler = new Handler();
if(!detector.isOperational()){
Toast.makeText(getActivity(), "Detector non attivabile", Toast.LENGTH_LONG).show();
}
cameraSource = new CameraSource.Builder(getActivity(), detector).setAutoFocusEnabled(true).build();
surfaceView.getHolder().addCallback(new SurfaceHolder.Callback() {
#Override
public void surfaceCreated(SurfaceHolder holder) {
AttivaCamera();
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
});
detector.setProcessor(new Detector.Processor<Barcode>() {
#Override
public void release() {
}
#Override
public void receiveDetections(Detector.Detections<Barcode> detections) {
items = detections.getDetectedItems();
if (items.size() > 0){
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
if (items.valueAt(0) != null){
//do something
handler.postDelayed(new Runnable() {
#Override
public void run() {
DisattivaCamera();
}
},10); //1000
}else
{
d.setContentView(R.layout.dialog_barcode_assente);
d.setTitle("Scanner");
d.setCancelable(true);
d.show();
DisattivaCamera();
}
}
});
}
}
});
btnBack.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
getActivity().onBackPressed();
}
});
return view;
}
private void AttivaCamera()
{
try{
cameraSource.start(surfaceView.getHolder());
}catch(IOException e){
Toast.makeText(getActivity(), "Errore nell'avvio della fotocamera", Toast.LENGTH_LONG).show();
}
}
private void DisattivaCamera()
{
cameraSource.stop();
}
}
It is how I visualize camera with small surfaceview:
https://i.stack.imgur.com/TMunJ.png
I'm new in android development so I'm sorry if could be a lot of mistake in the code.
Sorry for my english also..
Thanks you guys!
In order to display only part of the camera input, i.e. to crop it on the screen, you need a surface view that has dimensions that fit the camera frame aspect ratio, and overlay it with some nontransparent views to leave only part of it visible. Don't put the SurfaeView inside scrolling layout:
So, instead of
<SurfaceView width: match_parent height: 400dp />
you need e.g. FrameLayout as explained here: Is it possible to crop camera preview?
This will not change the frame that arrives to the barcode detector. But this should not worry you; the detector will handle the uncropped image correctly.

Android NDK - handling orientation change

I'm creating a game with the Android NDK and OpenGLES (and not using NativeActivity / native_app_glue).
When the user rotates their phone, I don't want the whole activity to be destroyed and restarted, so I've added the necessary part to the manifest file:
android:configChanges="keyboardHidden|keyboard|orientation|screenSize"
and get an onConfigurationChanged() callback as expected. I also get a surfaceRedrawNeeded() callback, which is fine.
However, I would also expect to get a surfaceChanged() callback, but this never happens.
The java code looks like this:
public class MyActivity extends Activity
{
#Override
protected void onCreate(Bundle savedInstanceState)
{
surface = new MySurface();
getWindow().takeSurface(surface);
view = new MyView(this);
getWindow().setContentView(view);
... native setup
}
...
#Override
public void onConfigurationChanged(Configuration newConfig)
{
super.onConfigurationChanged(newConfig);
...
}
...
}
class MyView extends View
{
public MyView(Context context)
{
super(context);
}
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) { ... }
... other input stuff
}
class MySurface implements SurfaceHolder.Callback2
{
#Override
public void surfaceCreated(SurfaceHolder holder) { ... }
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { ... }
#Override
public void surfaceRedrawNeeded(SurfaceHolder holder) { ... }
#Override
public void surfaceDestroyed(SurfaceHolder holder) { ... }
...
}
Questions:
Should I be getting a surfaceChanged() callback in the surface when the orientation changes?
If not, I guess I have two options:
Rotate my camera and adjust the viewport width / height (not really something I want to keep track of).
Call ANativeWindow_setBuffersGeometry (would this actually give me a rotated display?) and / or eglCreateWindowSurface again? Would I then need to recreate my EGLContext (and reload all my OpenGL stuff... ick)?
So in general, what's the "correct" way of handling orientation changes with regard to the ANativeWindow, EGLSurface and EGLContext?

Different layout for "Landscape" and "Landscape-reverse" orientation

My problem:
For some requirements i need two different xml layouts for my activity:
One for Landscape mode.
And another one for Landscape-reverse mode (upside-down of Landscape).
Unfortunately Android doesn't allow creating a separate layout for landscape-reverse (like we can do for portrait and landscape with layout-land and layout-port).
AFAIK, the only way is to change the activity-xml from java code.
What i've tried:
1) Override onConfigurationChanged() method to detect orientation changes, but i can't figure out if it's Landscape or Landscape-reverse:
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
Log.d("TEST","Landscape");
}
}
( Whith android:configChanges="keyboardHidden|orientation|screenSize|layoutDirection" in my activity tag in manifest)
2) Use an OrientationEventListener with SENSOR_DELAY_NORMAL as suggested in this answer but the device orientation changes before entering my if blocks, so i get a delayed update of the view:
mOrientationEventListener = new OrientationEventListener(this, SensorManager.SENSOR_DELAY_NORMAL){
#Override
public void onOrientationChanged(int orientation) {
if (orientation==0){
Log.e("TEST", "orientation-Portrait = "+orientation);
} else if (orientation==90){
Log.e("TEST", "orientation-Landscape = "+orientation);
} else if(orientation==180){
Log.e("TEST", "orientation-Portrait-rev = "+orientation);
}else if (orientation==270){
Log.e("TEST", "orientation-Landscape-rev = "+orientation);
} else if (orientation==360){
Log.e("TEST", "orientation-Portrait= "+orientation);
}
}};
My question:
Is there a better solution to change activity-layout between "Landscape" and "Landscape-reverse" orientation?
Any suggestions are highly appreciated.
Are you trying as suggested here?. You may handle an event with a different types of configuration reverse and standart by using activity attribute sensorLandscape
EDITED: Try to use Display.getOrientation as described here http://android-developers.blogspot.in/2010/09/one-screen-turn-deserves-another.html
And do not forget to set configChanges flag on activity in manifest to handle changes manualy in onConfigurationChanges().
So it seems like only way to do this is to listen SensorManager as frequently as possible.
SensorManager sensorMan = (SensorManager)getSystemService(SENSOR_SERVICE);
Sensor sensor = sensorMan.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
sensorMan.registerListener(...)
in order to achive this goal, you need to implement a rotation listener,
you need also to know that android destroy objects and recreate them
to load your layouts, values... based on configuration qualifiers
STEP 01: create a Java interface [rotationCallbackFn]
public interface rotationCallbackFn {
void onRotationChanged(int lastRotation, int newRotation);
}
STEP 02: create a Java class [rotationListenerHelper]
import android.content.Context;
import android.hardware.SensorManager;
import android.view.OrientationEventListener;
import android.view.WindowManager;
public class rotationListenerHelper {
private int lastRotation;
private WindowManager windowManager;
private OrientationEventListener orientationEventListener;
private rotationCallbackFn callback;
public rotationListenerHelper() {
}
public void listen(Context context, rotationCallbackFn callback) {
// registering the listening only once.
stop();
context = context.getApplicationContext();
this.callback = callback;
this.windowManager = (WindowManager) context
.getSystemService(Context.WINDOW_SERVICE);
this.orientationEventListener = new OrientationEventListener(context, SensorManager.SENSOR_DELAY_NORMAL) {
#Override
public void onOrientationChanged(int orientation) {
WindowManager localWindowManager = windowManager;
rotationCallbackFn localCallback = rotationListenerHelper.this.callback;
if(windowManager != null && localCallback != null) {
int newRotation = localWindowManager.getDefaultDisplay().getRotation();
if (newRotation != lastRotation) {
localCallback.onRotationChanged(lastRotation, newRotation);
lastRotation = newRotation;
}
}
}
};
this.orientationEventListener.enable();
lastRotation = windowManager.getDefaultDisplay().getRotation();
}
public void stop() {
if(this.orientationEventListener != null) {
this.orientationEventListener.disable();
}
this.orientationEventListener = null;
this.windowManager = null;
this.callback = null;
}
}
STEP 03: add these statements to your mainActivity
// declaration
private rotationListenerHelper rotationListener = null;
private Context mContext;
//...
/* constructor ----------------------------------------------------------------*/
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mContext = this;
final int curOrientation = getWindowManager().getDefaultDisplay().getRotation();
switch (curOrientation) {
case 0:
//. SCREEN_ORIENTATION_PORTRAIT
setContentView(R.layout.your_layout_port);
break;
//----------------------------------------
case 2:
//. SCREEN_ORIENTATION_REVERSE_PORTRAIT
setContentView(R.layout.your_layout_port_rev);
break;
//----------------------------------------
case 1:
//. SCREEN_ORIENTATION_LANDSCAPE
setContentView(R.layout.your_layout_land);
break;
//----------------------------------------
case 3:
//. SCREEN_ORIENTATION_REVERSE_LANDSCAPE
setContentView(R.layout.your_layout_land_rev);
break;
//----------------------------------------
} /*endSwitch*/
rotationListener = new rotationListenerHelper();
rotationListener.listen(mContext, rotationCB);
//...
}
private rotationCallbackFn rotationCB = new rotationCallbackFn() {
#Override
public void onRotationChanged(int lastRotation, int newRotation) {
Log.d(TAG, "onRotationChanged: last " + (lastRotation) +" new " + (newRotation));
/**
* no need to recreate activity if screen rotate from portrait to landscape
* android do the job in order to reload resources
*/
if (
(lastRotation == 0 && newRotation == 2) ||
(lastRotation == 2 && newRotation == 0) ||
(lastRotation == 1 && newRotation == 3) ||
(lastRotation == 3 && newRotation == 1)
)
((Activity) mContext).recreate();
}
};
/* destructor -----------------------------------------------------------------*/
#Override
protected void onDestroy() {
rotationListener.stop();
rotationListener = null;
Log.i(TAG, "onDestroy: activity destroyed");
super.onDestroy();
}
FINAL STEP : ENJOY

Android camera: stopPreview vs releaseCamera

I am making an application where I have a camera inside of a viewPager. I am wondering what would best be suited to "pause" and "resume" the camera so it doesn't hog resources when it is pre-loaded. I have the feeling that stopPreview is better suited for this as it does not release the camera but keeps it however it doesn't display the camera which is the main reason it hogs resources.
Enter & exit application: startCamera() & releaseCamera()
Tab visible & not visible: startPreview() & stop Preview()
Would this be a good rule of thumb?
I had a similar situation. :
If I kept camera (in ViewPager) in on state, the swipe were clunky and OOM exceptions were frequent.
Two options came in my mind:
shift the entire instance in a different thread
OR
use stopPreview() and startPreview()
I went with the second one :
However, instead of doing this on Fragment lifecycle callbacks I gave a button on the fragment which toggled the preview. Reason being, if user is swiping very fast, you can still receive OOm exception since the preview calls will be queued, especially if there are very few fragments in the viewPager.
In essence Release camera onPause(), acquire camera in onResume() and give a groovy button in fragment which will toggle your Preview on the surface!
Hello Karl I had the same things need to implement in view pager. I have circular viewer in which one fragment has the camera fragment. I want to handle the camera preview in such a way so it should not consume the camera resource.
As you know android view pager default load two fragment in to the memory. We implemented the view pager change listener and call the fragment method to start and stop the preview. even also destroy the camera preview in on destroy method of fragment.
class ViewPagerChangeListener implements ViewPager.OnPageChangeListener {
int currentPosition = DEFAULT_FRAGMENT;
#Override
public void onPageScrollStateChanged(int state) {
TimberLogger.d(TAG, "onPageScrollStateChanged");
}
#Override
public void onPageScrolled(int index, float arg1, int arg2) {
TimberLogger.d(TAG, "onPageScrolled" + index);
}
#Override
public void onPageSelected(int position) {
mWatchPosition = position;
TimberLogger.d(TAG, "onPageSelected" + mWatchPosition);
int newPosition = 0;
if (position > 4) {
newPosition = position;
}
TimberLogger.d(TAG, "newPosition" + newPosition);
/**
* Listener knows the new position and can call the interface method
* on new Fragment with the help of PagerAdapter. We can here call
* onResumeFragment() for new fragment and onPauseFragment() on the
* current one.
*/
// new fragment onResume
loadedFragment(newPosition).onResumeFragment();
// current fragment onPuase called
loadedFragment(currentPosition).onPauseFragment();
currentPosition = newPosition;
TimberLogger.d(TAG, "currentPosition" + currentPosition);
}
}
See the two method onResumeFragment and onPuaseFragment this two are the custom function each view pager fragment implements. In view pager change event we call the pause of current fragment and onResume of the new fragment.
// new fragment onResume
loadedFragment(newPosition).onResumeFragment();
// current fragment onPuase called
loadedFragment(currentPosition).onPauseFragment();
You can write your camera start preview inside custom method onResumeFragment and stop preview in onPauseFragment and also make sure you should override the onDestory() method of your camera fragment for release the camera resources.
The best solution will be to startCamera() in onResume(), and release it in onPause(), so you can handle, that camera is not free in onResume().
In ViewPager you can startPreview(), when fragment with it is selected, and stopPreview() otherwise. Also u can startPreview() in onCreateView() and stopPreview() in onDestroyView() in fragment.
This takes care of most of the operations CameraPreview.java:
package com.example.fela;
import android.app.Activity;
import android.content.Context;
import android.graphics.PixelFormat;
import android.hardware.Camera;
import android.hardware.Camera.ErrorCallback;
import android.hardware.Camera.Parameters;
import android.hardware.Camera.Size;
import android.util.Log;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.WindowManager;
import java.util.List;
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private SurfaceHolder holder;
private Camera camera;
private int cameraId;
private Activity activity;
private CameraPreviewActivityInterface activityInterface;
public CameraPreview(Activity activity, int cameraId) {
super(activity);
try {
activityInterface = (CameraPreviewActivityInterface) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement ExampleFragmentCallbackInterface ");
}
this.activity = activity;
this.cameraId = cameraId;
holder = getHolder();
holder.addCallback(this);
// deprecated setting, but required on Android versions prior to 3.0
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
public void surfaceCreated(SurfaceHolder holder) {}
/**
* custom camera tweaks and startPreview()
*/
public void refreshCamera() {
if (holder.getSurface() == null || camera == null) {
// preview surface does not exist, camera not opened created yet
return;
}
Log.i(null, "CameraPreview refreshCamera()");
// stop preview before making changes
try {
camera.stopPreview();
} catch (Exception e) {
// ignore: tried to stop a non-existent preview
}
int rotation = ((WindowManager) activity.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getRotation();
int degrees = 0;
// specifically for back facing camera
switch (rotation) {
case Surface.ROTATION_0:
degrees = 90;
break;
case Surface.ROTATION_90:
degrees = 0;
break;
case Surface.ROTATION_180:
degrees = 270;
break;
case Surface.ROTATION_270:
degrees = 180;
break;
}
camera.setDisplayOrientation(degrees);
setCamera(camera);
try {
camera.setPreviewDisplay(holder);
camera.startPreview();
} catch (Exception e) {
// this error is fixed in the camera Error Callback (Error 100)
Log.d(VIEW_LOG_TAG, "Error starting camera preview: " + e.getMessage());
}
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
Log.i(null, "CameraPreview surfaceChanged()");
// if your preview can change or rotate, take care of those events here.
// make sure to stop the preview before resizing or reformatting it.
// do not start the camera if the tab isn't visible
if(activityInterface.getCurrentPage() == 1)
startCamera();
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {}
public Camera getCameraInstance() {
Camera camera = Camera.open();
// parameters for camera
Parameters params = camera.getParameters();
params.set("jpeg-quality", 100);
params.set("iso", "auto");
params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
params.setPictureFormat(PixelFormat.JPEG);
// set the image dimensions
List<Size> sizes = params.getSupportedPictureSizes();
int max = 0, width = 0, height = 0;
for(Size size : sizes) {
if(max < (size.width*size.height)) {
max = (size.width*size.height);
width = size.width;
height = size.height;
}
}
params.setPictureSize(width, height);
camera.setParameters(params);
// primarily used to fix Error 100
camera.setErrorCallback(new ErrorCallback() {
#Override
public void onError(int error, Camera camera) {
if(error == Camera.CAMERA_ERROR_SERVER_DIED) {
releaseCamera();
startCamera();
}
}
});
return camera;
}
/**
* intitialize a new camera
*/
protected void startCamera() {
if(getCamera() == null)
setCamera(getCameraInstance());
refreshCamera();
}
/**
* release camera so other applications can utilize the camera
*/
protected void releaseCamera() {
// if already null then the camera has already been released before
if (getCamera() != null) {
getCamera().release();
setCamera(null);
}
}
public Camera getCamera() {
return camera;
}
public void setCamera(Camera camera) {
this.camera = camera;
}
public void setCameraId(int cameraId) {
this.cameraId = cameraId;
}
/**
* get the current viewPager page
*/
public interface CameraPreviewActivityInterface {
public int getCurrentPage();
}
}
In my FragmentCamera.java file:
private CameraPreview cameraPreview;
// code...
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// code...
cameraPreview = new CameraPreview(getActivity(), cameraId);
previewLayout.addView(cameraPreview);
// code...
}
// code...
#Override
public void onPause() {
super.onPause();
cameraPreview.releaseCamera();
}
#Override
public void onResume() {
super.onResume();
cameraPreview.startCamera();
}
protected void fragmentVisible() {
onResume();
}
protected void fragmentNotVisible() {
onPause();
}
And the MainActivity.java file (implements CameraPreviewActivityInterface):
viewPager.setOnPageChangeListener(new OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageSelected(int position) {
currentPage = position;
if (currentPage == 1) {
fragmentCamera.fragmentVisible();
} else {
fragmentCamera.fragmentNotVisible();
}
}
#Override
public void onPageScrollStateChanged(int state) {
}
});
#Override
public int getCurrentPage() {
return currentPage;
}

Android move from Landscape to Portrait (or vice versa) when using camera is too slow?

I have a DrawerLayout which contains a FrameLayout and ListView in my app, I have to show the camera in the FrameLayout, I've done that fine (as following code) and the camera works correctly. The problem is when moving from portrait orientation to (right-Landscape orientation or left-landscape orientation), or vice versa, it take the mobile a long time to make changes, the problem does not appear when moving from right-Landscape orientation or left-landscape orientation or vice versa.
How could I make this operation as fast as I can?
public class ShowCamera extends SurfaceView implements SurfaceHolder.Callback{
//This ShowCamera class is a helpful class
private SurfaceHolder holdMe;
private Camera theCamera;
public ShowCamera(Context context,Camera camera) {
super(context);
theCamera = camera;
holdMe = getHolder();
holdMe.addCallback(this);
}
#Override
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
try {
theCamera.setPreviewDisplay(holder);
theCamera.startPreview();
synchronized (holder) {
}
} catch (Exception e) {}
}
#Override
public void surfaceDestroyed(SurfaceHolder arg0) {
holdMe.removeCallback(this);
theCamera.release();
}
}
Now the original class is:
public class MainActivity extends Activity {
private DrawerLayout mDrawerLayout;
private ListView mDrawerList;
String[] options = {"op1", "op2", "op3", "op4", "op5"}; //for the DrawerLayout
int[] icons = { 0,R.drawable.hospital,R.drawable.education,R.drawable.police,R.drawable.food}; //for the DrawerLayout
private Camera cameraObject;
private ShowCamera showCamera;
public static Camera getCamIfAvailable(){
Camera cam = null;
try { cam = Camera.open();}
catch (Exception e){}
return cam;
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
cameraObject = getCamIfAvailable();
new Thread(new Runnable()
{
int rotation = getWindowManager().getDefaultDisplay().getRotation();
#Override
public void run()
{
switch(rotation){
case 0: // portrait
cameraObject.setDisplayOrientation(90);
break;
case 1: // left Landscape
cameraObject.setDisplayOrientation(0);
break;
case 3: //right Landscape
cameraObject.setDisplayOrientation(180);
break;
}
}
}).start();
showCamera = new ShowCamera(this, cameraObject);
FrameLayout preview = (FrameLayout) findViewById(R.id.content_frame);
preview.addView(showCamera);
//.
//.
//.
//.
//. Here, code for Drawerlayout no problrm
//.
//.
//.
}
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
// Pass any configuration change to the drawer toggls
mDrawerToggle.onConfigurationChanged(newConfig);
// Checks the orientation of the screen
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
Toast.makeText(this, "landscape", Toast.LENGTH_SHORT).show();
} else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT){
Toast.makeText(this, "portrait", Toast.LENGTH_SHORT).show();
}
}
.
.
.
.
} // End of the class MainActivity
Also I have put in the manifest file the following as first answer mentioned here:
<activity android:name=".MyActivity"
android:configChanges="orientation|screenSize"
android:label="#string/app_name">
Any help will be appreciated.
Camera.open() is an heavy operation for the system. It is only triggered when a configuration change is happening, such as when you rotate your device from landscape to portrait and vice-versa.
When flipping the device (from portrait to reversed portrait, or from landscape to reversed landscape) this doesn't trigger a configuration change, only the screen rendering is flipped and therefore you don't call Camera.open() again.
So, you won't be able to make it faster (even though I recommend you to take a look at the systrace tool to see what's really happening when you rotate your screen).
But, I strongly encourage you to try calling the Camera.open() from a background Thread to avoid freezing the UI.

Categories

Resources