ARCore - How to detect single horizontal plane only - java

I am working with ARCore in one of my project. There, I need to detect a plane and place some objects(Anchors) on it.
In my onResume function, I created a AR session and able to detect only horizontal planes using Session configuration.
#Override
protected void onResume() {
super.onResume();
if (arSceneView == null) {
return;
}
if (arSceneView.getSession() == null) {
// If the session wasn't created yet, don't resume rendering.
// This can happen if ARCore needs to be updated or permissions are not granted yet.
try {
session = DemoUtils.createArSession(this, installRequested);
mArConfig = session.getConfig();
mArConfig.setPlaneFindingMode(Config.PlaneFindingMode.HORIZONTAL);
mArConfig.setUpdateMode(Config.UpdateMode.LATEST_CAMERA_IMAGE);
session.configure(mArConfig);
if (session == null) {
installRequested = DemoUtils.hasCameraPermission(this);
return;
} else {
arSceneView.setupSession(session);
}
} catch (UnavailableException e) {
DemoUtils.handleSessionException(this, e);
}
}
try {
arSceneView.resume();
} catch (CameraNotAvailableException ex) {
DemoUtils.displayError(this, "Unable to get camera", ex);
finish();
return;
}
if (arSceneView.getSession() != null) {
try {
session.resume();
} catch (CameraNotAvailableException e) {
e.printStackTrace();
}
}
}
Here I get many horizontal planes. My requirement is to get only one horizontal plane which is detected first.
So, I tried to Disable plane finding mode in setOnUpdateListener as following,
arSceneView.getScene().setOnUpdateListener(frameTime -> {
if (loadingMessageSnackbar == null){
return;
}
Frame frame = arSceneView.getArFrame();
if (frame == null){
return;
}
if (frame.getCamera().getTrackingState() != TrackingState.TRACKING){
return;
}
for (Plane plane : frame.getUpdatedTrackables(Plane.class)){
if (plane.getTrackingState() == TrackingState.TRACKING){
Config c =arSceneView.getSession().getConfig();
c.setPlaneFindingMode(Config.PlaneFindingMode.DISABLED);
arSceneView.getSession().configure(c);
}
}
});
Here, once the plane is detected it is getting hide.
Can anyone suggest any method to get the first detected horizontal plane and place objects in that plane only??
Thanks in advance...!!

Config config = arFragment.getArSceneView().getSession().getConfig();
config.setPlaneFindingMode(Config.PlaneFindingMode.DISABLED);
arFragment.getArSceneView().getSession().configure(config);

Related

Why not update UI elemnts in Android

In my application i should used socket.io and i want when receive my event update UI elements!
I write below codes and i receive my events show me logs, but not update any UI!
I want when receive event, check this winner is user or not and then update my UI.
In logCat show me my logs but not update any UI elements!
My codes:
public void onsocketFinishRecieve(final JSONObject ob) {
try {
((BaseActivity) context).runOnUiThread(() -> {
try {
cancelTimer();
final FinishResponse finishResponse = new Gson().fromJson(ob.toString(), FinishResponse.class);
if (finishResponse.getRes().getWinnerName().equals("not user") || finishResponse.getRes().getWinnerName().equals("not winner")) {
winnerNameWhenFinished = "Not winner";
} else {
winnerNameWhenFinished = finishResponse.getRes().getWinnerName();
}
if (detail.getId() != null) {
if (detail.getId() == finishResponse.getRes().getId()) {
//Set new winner layouts
//Register in auction
if (Constants.profileResponse != null) {
if (Constants.profileResponse.getRes() != null) {
if (Constants.profileResponse.getRes().getUser() != null) {
//Winner
if (Constants.profileResponse.getRes().getUser().getId().equals(finishResponse.getRes().getUserId())) {
Log.e("FinishedSocket", "1");
detailPage_bottomWinnerRateTxt.setVisibility(View.GONE);
detailPage_bottomWinnerBuyTxt.setText("Show basket");
detailPage_bottomWinnerBuyTxt.setOnClickListener(v -> {
Intent intent = new Intent(context, MainActivity.class);
intent.putExtra("OPEN_CART_IN_MAIN", "true");
startActivity(intent);
});
} else {
Log.e("FinishedSocket", "2");
//Loser
detailPage_bottomWinnerBuyTxt.setText("Awesome offers");
}
}
}
}
}
}
} catch (Exception e) {
Log.e("DetailResErr", e.getMessage());
}
});
} catch (Exception e) {
Log.e("DetailResErr", e.getMessage());
}
}
Logcat message :
2020-03-08 13:37:37.399 E/FinishedSocket: 2
In logcat show me above message , why not run this line : detailPage_bottomWinnerBuyTxt.setText("Awesome offers"); ??
How can i fix it?
try to run this on Mainthread like this.
someActivity.runOnUiThread(new Runnable() {
#Override
public void run() {
//Your code to run in GUI thread here
detailPage_bottomWinnerBuyTxt.setText("Awesome offers");
}
});
Sockets work on IOThread while other side UI Work on separate Thread called UI thread. So, update the UI element on UI Thread.
Use Annotation :
#UiThread
public abstract void setText(#NonNull String text) { ... }
For know about more annotation, Check the following blog:
https://medium.com/#gurwindersingh_37022/android-annotations-30b4a2850d0

How to Disable All Automatics in Android Camera2 API

I'm trying to disable auto-exposure, auto-focus, and auto-white-balance in Google's Camera2Basic sample. Here's my code:
private void disableAutomatics() {
try {
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_MODE, CaptureRequest.CONTROL_MODE_OFF);
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_VIDEO_STABILIZATION_MODE, CaptureRequest.CONTROL_VIDEO_STABILIZATION_MODE_OFF);
mPreviewRequestBuilder.set(CaptureRequest.LENS_OPTICAL_STABILIZATION_MODE, CaptureRequest.LENS_OPTICAL_STABILIZATION_MODE_OFF);
mPreviewRequestBuilder.set(CaptureRequest.LENS_FOCUS_DISTANCE, .2f);
mPreviewRequestBuilder.set(CaptureRequest.SENSOR_EXPOSURE_TIME, 1000000L);
mPreviewRequest = mPreviewRequestBuilder.build();
// Set new repeating request with our changed one
mCaptureSession.setRepeatingRequest(mPreviewRequest, mCaptureCallback, mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
The problem is I don't know where to place the method in Camera2BasicFragment.java.
Any help would be greatly appreciated.
There are two places where you may want to do those settings:
If you want to do it before the preview starts, the better place would be inside of the overridden method onConfigured within the createCameraPreviewSession() void (line 696 in the Camera2BasicFragment file provided in the Google's Camera2Basic sample:
private void createCameraPreviewSession() {
try {
SurfaceTexture texture = mTextureView.getSurfaceTexture();
assert texture != null;
// We configure the size of default buffer to be the size of camera preview we want.
texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
// This is the output Surface we need to start preview.
Surface surface = new Surface(texture);
// We set up a CaptureRequest.Builder with the output Surface.
mPreviewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
mPreviewRequestBuilder.addTarget(surface);
// Here, we create a CameraCaptureSession for camera preview.
mCameraDevice.createCaptureSession(Arrays.asList(surface, mImageReader.getSurface()),
new CameraCaptureSession.StateCallback() {
#Override
public void onConfigured(#NonNull CameraCaptureSession cameraCaptureSession) {
// The camera is already closed
if (null == mCameraDevice) {
return;
}
// When the session is ready, we start displaying the preview.
mCaptureSession = cameraCaptureSession;
try {
//Place here your custom camera settings
// Start displaying the camera preview.
mPreviewRequest = mPreviewRequestBuilder.build();
mCaptureSession.setRepeatingRequest(mPreviewRequest,
mCaptureCallback, mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
#Override
public void onConfigureFailed(#NonNull CameraCaptureSession cameraCaptureSession) {
showToast("Failed");
}
}, null
);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
If you want to do the settings after the preview has started and in runtime just call your disableAutomatics() from the UI or anywhere else and it should work fine.
Note that you don't have to close the older CaptureSession by calling its CaptureSession.close() method as explained in an answer to this other question because the new replaces the older one.
On another hand, I am not sure about setting the exposure time value manually as you did in your question:
mPreviewRequestBuilder.set(CaptureRequest.SENSOR_EXPOSURE_TIME, 1000000L);
because you may get unexpected results varying on different devices. What I know is that doing so is usually discouraged and it's preferred instead to let the camera adjust by its own and then call AE (auto-exposure) lock:
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_LOCK, true);
You can check the CONTROL_AE_LOCK reference here.
But if your code needs a fixed exposure time then it should work.

Run-time Exception Fail to connect to camera Service in Some Devices

I am using Barcode Scanner in my app. In some mobile it is giving the run-time exception Fail to connect to camera.
Here is the code I am using for Camera
/**
* Opens the camera and applies the user settings.
*
* #throws RuntimeException if the method fails
*/
#SuppressLint("InlinedApi")
private Camera createCamera() {
int requestedCameraId = getIdForRequestedCamera(mFacing);
if (requestedCameraId == -1) {
throw new RuntimeException("Could not find requested camera.");
}
Camera camera = Camera.open(requestedCameraId);
SizePair sizePair = selectSizePair(camera, mRequestedPreviewWidth, mRequestedPreviewHeight);
if (sizePair == null) {
throw new RuntimeException("Could not find suitable preview size.");
}
Size pictureSize = sizePair.pictureSize();
mPreviewSize = sizePair.previewSize();
int[] previewFpsRange = selectPreviewFpsRange(camera, mRequestedFps);
if (previewFpsRange == null) {
throw new RuntimeException("Could not find suitable preview frames per second range.");
}
Camera.Parameters parameters = camera.getParameters();
if (pictureSize != null) {
parameters.setPictureSize(pictureSize.getWidth(), pictureSize.getHeight());
}
parameters.setPreviewSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
parameters.setPreviewFpsRange(
previewFpsRange[Camera.Parameters.PREVIEW_FPS_MIN_INDEX],
previewFpsRange[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]);
parameters.setPreviewFormat(ImageFormat.NV21);
setRotation(camera, parameters, requestedCameraId);
if (mFocusMode != null) {
if (parameters.getSupportedFocusModes().contains(
mFocusMode)) {
parameters.setFocusMode(mFocusMode);
} else {
Log.i(TAG, "Camera focus mode: " + mFocusMode + " is not supported on this device.");
}
}
// setting mFocusMode to the one set in the params
mFocusMode = parameters.getFocusMode();
if (mFlashMode != null) {
if (parameters.getSupportedFlashModes() != null) {
if (parameters.getSupportedFlashModes().contains(
mFlashMode)) {
parameters.setFlashMode(mFlashMode);
} else {
Log.i(TAG, "Camera flash mode: " + mFlashMode + " is not supported on this device.");
}
}
}
// setting mFlashMode to the one set in the params
mFlashMode = parameters.getFlashMode();
camera.setParameters(parameters);
// Four frame buffers are needed for working with the camera:
//
// one for the frame that is currently being executed upon in doing detection
// one for the next pending frame to process immediately upon completing detection
// two for the frames that the camera uses to populate future preview images
camera.setPreviewCallbackWithBuffer(new CameraPreviewCallback());
camera.addCallbackBuffer(createPreviewBuffer(mPreviewSize));
camera.addCallbackBuffer(createPreviewBuffer(mPreviewSize));
camera.addCallbackBuffer(createPreviewBuffer(mPreviewSize));
camera.addCallbackBuffer(createPreviewBuffer(mPreviewSize));
return camera;
}
* Stops the camera.
*/
#Override
protected void onPause() {
super.onPause();
if (mPreview != null) {
mPreview.stop();
}
}
/**
* Releases the resources associated with the camera source, the associated detectors, and the
* rest of the processing pipeline.
*/
#Override
protected void onDestroy() {
super.onDestroy();
if (mPreview != null) {
mPreview.release();
}
}
/**
* Restarts the camera.
*/
#Override
protected void onResume() {
super.onResume();
startCameraSource();
}
The run time exception I am getting is
java.lang.RuntimeException: Fail to connect to camera service
at android.hardware.Camera.<init>(Camera.java:532)
at android.hardware.Camera.open(Camera.java:360)
Any help Regarding this issue because in some devices it is working but in some it is not working I am not able to get the issue.
Always check if the camera is available or not before accesing it.
private Camera mCamera;
/**
* Opens the camera and applies the user settings.
*
* #throws RuntimeException if the method fails
*/
#SuppressLint("InlinedApi")
private Camera createCamera() {
int requestedCameraId = getIdForRequestedCamera(mFacing);
if (requestedCameraId == -1) {
throw new RuntimeException("Could not find requested camera.");
}
if (mCamera != null){
mCamera.release();
mCamera = null;
}
mCamera= Camera.open(requestedCameraId);
if(camera == null){
Toast.makeText(mContext, "Camera service is not available currently.", Toast.LENGTH_LONG.show())
}
//....
}
}
And relsease the camera before onDestroy().
/**
* Releases the resources associated with the camera source, the associated detectors, and the
* rest of the processing pipeline.
*/
#Override
protected void onDestroy() {
super.onDestroy();
if (mPreview != null) {
mPreview.release();
mCamera.release();
mCamera = null;
}

How to launch specific activity from GooglePlayGames invitation

I'm trying to create a new android application that is comprised of multiple mini-games. The launcher activity extends BaseGameActivity and has a sign-in button and a ListView containing all the possible games that can be played.
Inside of a mini-game activity (also extends BaseGameActivity), how can I get it to create a notification which will launch a specific Activity? Currently, when I call invitePlayersToGame, the invitation that gets sent is for the full application (Mini-Games) and not the individual game (specific dice game).
public void invitePlayersToGame(View pView) {
Intent intent = Games.RealTimeMultiplayer.getSelectOpponentsIntent(getApiClient(), 1, 1);
intent.putExtra("gameName", "Patman Yahtzee");
startActivityForResult(intent, RC_SELECT_PLAYERS);
}
Is there a way to get the notification to generate with a specific message? Is there a way to get notification to open directly to the mini-game activity without going to the main launcher activity first?
Any help is appreciated. Thanks!
You can send sendReliableMessage for method handshaking.
First enter a room (quickgame or send invite).
public void openInvitationIntent() {
// launch the player selection screen
// minimum: 1 other player; maximum: 1 other players
Intent intent = Games.RealTimeMultiplayer.getSelectOpponentsIntent(mGoogleApiClient, 1, 1);
startActivityForResult(intent, RC_SELECT_PLAYERS);
}
onConnected:
#Override
public void onConnected(Bundle connectionHint) {
// QuickGame
if (mGameMode == 1) {
Log.d(TAG, "onConnected() called. Sign in successful!");
Log.d(TAG, "Sign-in succeeded.");
startQuickGame();
// register listener so we are notified if we receive an invitation to play
// while we are in the game
if (connectionHint != null) {
Log.d(TAG, "onConnected: connection hint provided. Checking for invite.");
Invitation inv = connectionHint.getParcelable(Multiplayer.EXTRA_INVITATION);
if (inv != null && inv.getInvitationId() != null) {
// retrieve and cache the invitation ID
Log.d(TAG, "onConnected: connection hint has a room invite!");
acceptInviteToRoom(inv.getInvitationId());
return;
}
}
}
// Send request
else if (mGameMode == 0) {
// request code for the "select players" UI
// can be any number as long as it's unique
invitationInbox();
}
// request accepted
else {
mIncomingInvitationId = getIntent().getExtras().getString(AppConstants.RC_INVITATION_ID);
RoomConfig.Builder roomConfigBuilder = makeBasicRoomConfigBuilder();
roomConfigBuilder.setInvitationIdToAccept(mIncomingInvitationId);
Games.RealTimeMultiplayer.join(mGoogleApiClient, roomConfigBuilder.build());
// prevent screen from sleeping during handshake
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
}
After this, you can send model class (includes what you need).
private void broadcastMessage(ModelGameRecievedMessage broadcastedMessage, boolean isFinal) {
try {
if ( mParticipants != null && broadcastedMessage != null) {
byte[] bytes = Utils.serialize(broadcastedMessage);
// Send to every other participant.
for (Participant p : mParticipants) {
if (p.getParticipantId().equals(mMyId)) {
continue;
}
if (p.getStatus() != Participant.STATUS_JOINED) {
continue;
}
if (mRoomId != null) {
if (isFinal) {
// final score notification must be sent via reliable broadcastedMessage
Games.RealTimeMultiplayer.sendReliableMessage(mGoogleApiClient, null, bytes,
mRoomId, p.getParticipantId());
} else {
// it's an interim score notification, so we can use unreliable
Games.RealTimeMultiplayer.sendUnreliableMessage(mGoogleApiClient, bytes,
mRoomId, p.getParticipantId());
}
}
}
Logy.l("broadcastedMessage.getMessageTypeId(); " + broadcastedMessage.getMessageTypeId());
Logy.l("broadcastedMessage.getMessage(); " + broadcastedMessage.getMessage());
}
} catch (IOException e) {
e.printStackTrace();
}
}
finally you can reach the data on other devices:
#Override
public void onRealTimeMessageReceived(RealTimeMessage rtm) {
byte[] bufy = rtm.getMessageData();
ModelGameRecievedMessage recievedMessage = null;
try {
recievedMessage = (ModelGameRecievedMessage) Utils.deserialize(bufy);
Logy.l("recievedMessage.getMessageTypeId(); " + recievedMessage.getMessageTypeId());
Logy.l("recievedMessage.getMessage(); " + recievedMessage.getMessage());
} catch (Exception e) {
Logy.e("Exception onRealTimeMessageReceived deserialize: " + e);
}
switch (recievedMessage.getMessageTypeId()) {
case AppConstants.RC_MULTI_START_TIMEMILIS_MULTIPLAYER:
....

Enabling Camera Flash While Recording Video

I need a way to control the camera flash on an Android device while it is recording video. I'm making a strobe light app, and taking videos with a flashing strobe light would result in the ability to record objects that are moving at high speeds, like a fan blade.
The flash can only be enabled by starting a video preview and setting FLASH_MODE_TORCH in the camera's parameters. That would look like this:
Camera c = Camera.open();
Camera.Parameters p = c.getParameters();
p.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
c.setParameters(p);
c.startPreview();
Once the preview has started, I can flip that parameter back and forth to turn the light on and off. This works well until I try to record a video. The trouble is that in order to give the camera to the MediaRecorder, I first have to unlock it.
MediaRecorder m = new MediaRecorder();
c.unlock(); // the killer
m.setCamera(c);
After that unlock, I can no longer change the camera parameters and therefore have no way to change the flash state.
I do not know if it is actually possible to do this since I'm not the best at java-hacking, but here is what I do know:
Camera.unlock() is a native method, so I can't really see the mechanism behind the way it locks me out
Camera.Parameter has a HashMap that contains all of its parameters
Camera.setParameters(Parameters) takes the HashMap, converts it to a string, and passes it to a native method
I can eliminate all the parameters but TORCH-MODE from the HashMap and the Camera will still accept it
So, I can still access the Camera, but it won't listen to anything I tell it. (Which is kind of the purpose of Camera.unlock())
Edit:
After examining the native code, I can see that in CameraService.cpp my calls to Camera.setParameters(Parameters) get rejected because my Process ID does not match the Process ID the camera service has on record. So it would appear that that is my hurdle.
Edit2:
It would appear that the MediaPlayerService is the primary service that takes control of the camera when a video is recording. I do not know if it is possible, but if I could somehow start that service in my own process, I should be able to skip the Camera.unlock() call.
Edit3:
One last option would be if I could somehow get a pointer to the CameraHardwareInterface. From the looks of it, this is a device specific interface and probably does not include the PID checks. The main problem with this though is that the only place that I can find a pointer to it is in CameraService, and CameraService isn't talking.
Edit4: (several months later)
At this point, I don't think it is possible to do what I originally wanted. I don't want to delete the question on the off chance that someone does answer it, but I'm not actively seeking an answer. (Though, receiving a valid answer would be awesome.)
I encountered a similar issue. The user should be able to change the flash mode during recording to meet their needs depending on the light situation. After some investigative research i came to the following solution:
I assume, that you've already set up a proper SurfaceView and a SurfaceHolder with its necessary callbacks. The first thing i did was providing this code (not declared variables are globals):
public void surfaceCreated(SurfaceHolder holder) {
try {
camera = Camera.open();
parameters = camera.getParameters();
parameters.setFlashMode(Parameters.FLASH_MODE_OFF);
camera.setParameters(parameters);
camera.setPreviewDisplay(holder);
camera.startPreview();
recorder = new MediaRecorder();
} catch (IOException e) {
e.printStackTrace();
}
}
My next step was initializing and preparing the recorder:
private void initialize() {
camera.unlock();
recorder.setCamera(camera);
recorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
recorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
recorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
recorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
recorder.setVideoFrameRate(20);
recorder.setOutputFile(filePath);
try {
recorder.prepare();
} catch (IllegalStateException e) {
e.printStackTrace();
finish();
} catch (IOException e) {
e.printStackTrace();
finish();
}
}
It's important to note, that camera.unlock() has to be called BEFORE the whole initialization process of the media recorder. That said also be aware of the proper order of each set property, otherwise you'll get an IllegalStateException when calling prepare() or start(). When it comes to recording, i do this. This will usually be triggered by a view element:
public void record(View view) {
if (recording) {
recorder.stop();
//TODO: do stuff....
recording = false;
} else {
recording = true;
initialize();
recorder.start();
}
}
So now, i finally can record properly. But what's with that flash? Last but not least, here comes the magic behind the scenes:
public void flash(View view) {
if(!recording) {
camera.lock();
}
parameters.setFlashMode(parameters.getFlashMode().equals(Parameters.FLASH_MODE_TORCH) ? Parameters.FLASH_MODE_OFF : Parameters.FLASH_MODE_TORCH);
camera.setParameters(parameters);
if(!recording) {
camera.unlock();
}
}
Everytime i call that method via an onClick action i can change the flash mode, even during recording. Just take care of properly locking the camera. Once the lock is aquired by the media recorder during recording, you don't have to lock/unlock the camera again. It doesn't even work. This was tested on a Samsung Galaxy S3 with Android-Version 4.1.2. Hope this approach helps.
After preparing media recorder, use camera.lock(), and then set whatever parameters you want to set to camera.
But before starting recording you need to call camera.unlock(), and after you stop media recorder you need to call camera.lock() to start preview.
Enjoy!!!
Try this.. hopefully it will work.. :)
private static Torch torch;
public Torch() {
super();
torch = this;
}
public static Torch getTorch() {
return torch;
}
private void getCamera() {
if (mCamera == null) {
try {
mCamera = Camera.open();
} catch (RuntimeException e) {
Log.e(TAG, "Camera.open() failed: " + e.getMessage());
}
}
}
public void toggleLight(View view) {
toggleLight();
}
private void toggleLight() {
if (lightOn) {
turnLightOff();
} else {
turnLightOn();
}
}
private void turnLightOn() {
if (!eulaAgreed) {
return;
}
if (mCamera == null) {
Toast.makeText(this, "Camera not found", Toast.LENGTH_LONG);
button.setBackgroundColor(COLOR_WHITE);
return;
}
lightOn = true;
Parameters parameters = mCamera.getParameters();
if (parameters == null) {
button.setBackgroundColor(COLOR_WHITE);
return;
}
List<String> flashModes = parameters.getSupportedFlashModes();
if (flashModes == null) {
button.setBackgroundColor(COLOR_WHITE);
return;
}
String flashMode = parameters.getFlashMode();
Log.i(TAG, "Flash mode: " + flashMode);
Log.i(TAG, "Flash modes: " + flashModes);
if (!Parameters.FLASH_MODE_TORCH.equals(flashMode)) {
if (flashModes.contains(Parameters.FLASH_MODE_TORCH)) {
parameters.setFlashMode(Parameters.FLASH_MODE_TORCH);
mCamera.setParameters(parameters);
button.setBackgroundColor(COLOR_LIGHT);
startWakeLock();
} else {
Toast.makeText(this, "Flash mode (torch) not supported",
Toast.LENGTH_LONG);
button.setBackgroundColor(COLOR_WHITE);
Log.e(TAG, "FLASH_MODE_TORCH not supported");
}
}
}
private void turnLightOff() {
if (lightOn) {
button.setBackgroundColor(COLOR_DARK);
lightOn = false;
if (mCamera == null) {
return;
}
Parameters parameters = mCamera.getParameters();
if (parameters == null) {
return;
}
List<String> flashModes = parameters.getSupportedFlashModes();
String flashMode = parameters.getFlashMode();
if (flashModes == null) {
return;
}
Log.i(TAG, "Flash mode: " + flashMode);
Log.i(TAG, "Flash modes: " + flashModes);
if (!Parameters.FLASH_MODE_OFF.equals(flashMode)) {
if (flashModes.contains(Parameters.FLASH_MODE_OFF)) {
parameters.setFlashMode(Parameters.FLASH_MODE_OFF);
mCamera.setParameters(parameters);
stopWakeLock();
} else {
Log.e(TAG, "FLASH_MODE_OFF not supported");
}
}
}
}
private void startPreview() {
if (!previewOn && mCamera != null) {
mCamera.startPreview();
previewOn = true;
}
}
private void stopPreview() {
if (previewOn && mCamera != null) {
mCamera.stopPreview();
previewOn = false;
}
}
private void startWakeLock() {
if (wakeLock == null) {
Log.d(TAG, "wakeLock is null, getting a new WakeLock");
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
Log.d(TAG, "PowerManager acquired");
wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKE_LOCK_TAG);
Log.d(TAG, "WakeLock set");
}
wakeLock.acquire();
Log.d(TAG, "WakeLock acquired");
}
private void stopWakeLock() {
if (wakeLock != null) {
wakeLock.release();
Log.d(TAG, "WakeLock released");
}
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (Eula.show(this)) {
eulaAgreed = true;
}
setContentView(R.layout.main);
button = findViewById(R.id.button);
surfaceView = (SurfaceView) this.findViewById(R.id.surfaceview);
surfaceHolder = surfaceView.getHolder();
surfaceHolder.addCallback(this);
surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
disablePhoneSleep();
Log.i(TAG, "onCreate");
}
To access the device camera, you must declare the CAMERA permission in your Android Manifest. Also be sure to include the <uses-feature> manifest element to declare camera features used by your application. For example, if you use the camera and auto-focus feature, your Manifest should include the following:
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
A sample that checks for torch support might look something like this:
//Create camera and parameter objects
private Camera mCamera;
private Camera.Parameters mParameters;
private boolean mbTorchEnabled = false;
//... later in a click handler or other location, assuming that the mCamera object has already been instantiated with Camera.open()
mParameters = mCamera.getParameters();
//Get supported flash modes
List flashModes = mParameters.getSupportedFlashModes ();
//Make sure that torch mode is supported
//EDIT - wrong and dangerous to check for torch support this way
//if(flashModes != null && flashModes.contains("torch")){
if(flashModes != null && flashModes.contains(Camera.Parameters.FLASH_MODE_TORCH)){
if(mbTorchEnabled){
//Set the flash parameter to off
mParameters.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
}
else{
//Set the flash parameter to use the torch
mParameters.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
}
//Commit the camera parameters
mCamera.setParameters(mParameters);
mbTorchEnabled = !mbTorchEnabled;
}
To turn the torch on, you simply set the camera parameter Camera.Parameters.FLASH_MODE_TORCH
Camera mCamera;
Camera.Parameters mParameters;
//Get a reference to the camera/parameters
mCamera = Camera.open();
mParameters = mCamera.getParameters();
//Set the torch parameter
mParameters.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
//Comit camera parameters
mCamera.setParameters(mParameters);
To turn the torch off, set Camera.Parameters.FLASH_MODE_OFF

Categories

Resources