NFC DeadObjectException when onResume is called - java

I developed an application Android that detect NFC card then it open IsoDep connection with it to send APDU and get response. When application detect the NFC card it open a work session, I created a thread that every 500 ms check the isoDep connection, if connection was lost application close the work session (stop pooling , delete card data ...).
My application is device owner and is locked and it contain only one activity that start a webview to turn html code for user interfaces.
In The MainActivity, I stop the pooling in the onPause() before the super.onPause() and I restart it in the onResume() after the super.onResume().
Also I always call NfcAdapter.enableReaderMode() in onResume() and NfcAdapter.disableReaderMode in onPause().
//enable nfc dispatch
Bundle options = new Bundle();
options.putInt(NfcAdapter.EXTRA_READER_PRESENCE_CHECK_DELAY, 50);
NfcManager manager = (NfcManager) activity.
getApplicationContext().getSystemService(Context.NFC_SERVICE);
if(manager == null) {
return;
}
NfcAdapter nfcAdapter = manager.getDefaultAdapter();
if(nfcAdapter == null) {
return;
}
try {
nfcAdapter.enableReaderMode(activity,
new NfcAdapter.ReaderCallback() {
#Override
public void onTagDiscovered(final Tag tag) {
cardDetected(tag);
}
},
NfcAdapter.FLAG_READER_NFC_A | NfcAdapter.FLAG_READER_SKIP_NDEF_CHECK |
NfcAdapter.FLAG_READER_NO_PLATFORM_SOUNDS,
options);
} catch (Exception e) {
}
//disable nfc dispatch
NfcManager manager = (NfcManager)activity.getApplicationContext().getSystemService(Context.NFC_SERVICE);
if(manager == null) {
return;
}
NfcAdapter nfcAdapter = manager.getDefaultAdapter();
if(nfcAdapter == null) {
return;
}
try {
nfcAdapter.disableReaderMode(activity);
} catch (Exception e) {
}
I use Samsung Xcover4 Android 8 to test the application. And my problem is sometime when the onResume is called I see in the logcat a DeadObjectException :
E/NFC: NFC service dead - attempting to recover
android.os.DeadObjectException
at android.os.BinderProxy.transactNative(Native Method)
at android.os.BinderProxy.transact(Binder.java:777)
at android.nfc.INfcAdapter$Stub$Proxy.setAppCallback(INfcAdapter.java:1026)
at android.nfc.NfcActivityManager.requestNfcServiceCallback(NfcActivityMan ager.java:494)
at android.nfc.NfcActivityManager.onActivityResumed(NfcActivityManager.java:674)
at android.app.Application.dispatchActivityResumed(Application.java:240)
at android.app.Activity.onResume(Activity.java:1369)
at android.support.v4.app.FragmentActivity.onResume(FragmentActivity.java:514)
at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1363)
at android.app.Activity.performResume(Activity.java:7432)
at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3780)
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:3845)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1773)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:7000)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:441)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1408)
When it happen card is never detected and I have to restart NFC or application to be able to detect card.

Related

Android 9 background location tracking using foreground service

I am using an android fused location client for background location tracking which will run even if the app is cleared from the memory. I am using foreground service for this. It is running perfectly for most of the devices except the Samsung Galaxy devices with power saver modes. I have also added the permission for ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS on app runtime but still, the Samsung devices do not track perfectly. I am also using geofencing intent service along with a partial wake lock. This app is working fine on all other devices. Please check the code that I am using for background locations. This is not the full code.
Also when I enable location toasts then the distance is tracking perfectly even on Samsung. But when toasts are disabled then it only works for the first time in Samsung.
/**********LocationUpdatesService class********/
public class LocationUpdatesService extends Service {
#Override
public void onCreate() {
Log.i(TAG, "Service onCreate");
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
mLocationCallback = new LocationCallback() {
#Override
public void onLocationResult(LocationResult locationResult) {
super.onLocationResult(locationResult);
onNewLocation(locationResult.getLastLocation());
}
};
createLocationRequest();
if (checkPermissions()) {
getLastLocation();
}
powerManager = (PowerManager) getSystemService(POWER_SERVICE);
wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
"myapp::MyWakelockTag");
wakeLock.acquire();
}
public void requestLocationUpdates() {
Log.i(TAG, "Requesting location updates");
//Utils.setRequestingLocationUpdates(this, true);
startService(new Intent(getApplicationContext(), LocationUpdatesService.class));
try {
mFusedLocationClient.requestLocationUpdates(mLocationRequest,
mLocationCallback, Looper.myLooper());
} catch (SecurityException unlikely) {
//Utils.setRequestingLocationUpdates(this, false);
Log.e(TAG, "Lost location permission. Could not request updates. " + unlikely);
}
}
public void removeLocationUpdates() {
Log.i(TAG, "Removing location updates");
removeActivityUpdatesButtonHandler();
try {
mFusedLocationClient.removeLocationUpdates(mLocationCallback);
wakeLock.release();
stopForeground(true);
stopSelf();
} catch (SecurityException unlikely) {
//Utils.setRequestingLocationUpdates(this, true);
Log.e(TAG, "Lost location permission. Could not remove updates. " + unlikely);
}
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(TAG, "Service started");
boolean startedFromNotification = intent.getBooleanExtra(EXTRA_STARTED_FROM_NOTIFICATION,
false);
// We got here because the user decided to remove location updates from the notification.
if (startedFromNotification) {
//removeLocationUpdates();
//stopSelf();
}
startForeground(NOTIFICATION_ID, getNotification());
// Tells the system to not try to recreate the service after it has been killed.
return START_STICKY;
}
}
I am using this Bound service in my main activity.
The above is just a sample code for anyone's reference. Please let me know if anyone knows the solution. I am just having trouble in the case of Samsung devices with a power saver. Otherwise, my service is working fine and tracking the distance perfectly.

Need help figuring out why app crashes and stop video is called when I click to start it instead?

The code is supposed to work but when I click on my video button to stop recording I receive a "fatal exception" crash and it shows me that the line mMediaRecorder.stop(); doesn't work.
Here's my code:
private CameraDevice.StateCallback mCameraDeviceStateCallback = new CameraDevice.StateCallback() {
#Override
public void onOpened(#NonNull CameraDevice camera) { //camera device member return back to me
mCameraDevice = camera;
// Toast.makeText(getApplicationContext(), "Camera connection made!", Toast.LENGTH_SHORT).show();
// ^indicates camera is connected
if (mIsRecording){
try{
createVideoFileName();
}
catch(IOException e) {
e.printStackTrace();
}
startRecord();
mMediaRecorder.start();
}
else {
startPreview();
}
}
//makes this marshallow version compatible for Android because from Marshallow version and onwards we needed...
//...the permissions required.
private void checkWriteStoragePermission(){
// v check to support applications on devices older than Marshmallow version in Android
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.lollipop) { //support Marshallow or later versions
// v check to see if granted permission
if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) ==
PackageManager.PERMISSION_GRANTED) {
mIsRecording = true;
mRecordImageButton.setImageResource(R.drawable.btn_video_busy); //not recording
try {
createVideoFileName(); //was giving an unhandled exception java long error so needed try/catch here
} catch (IOException e) {
e.printStackTrace();
}
startRecord();
mMediaRecorder.start();
}/* else { //check if permission was granted and had been denied
if (shouldShowRequestPermissionRationale(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
Toast.makeText(this, "app needs to be able to save videos", Toast.LENGTH_SHORT).show();
}
requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_WRITE_EXTERNAL_STORAGE_PERMISSION_RESULT);
} */
}
else //if running older versions than Marshallow, not going to worry about it, so build "else" statement
{ // supporting old versions of Android
mIsRecording = true;
mRecordImageButton.setImageResource(R.drawable.btn_video_busy); //not recording
try{
createVideoFileName();
}
catch (IOException e){
e.printStackTrace();
}
startRecord();
mMediaRecorder.start();
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_camera);
createVideoFolder(); //creates the video folder when camera page loads
mMediaRecorder = new MediaRecorder();
mTextureView = (TextureView) findViewById(R.id.textureView);
mRecordImageButton = (ImageButton) findViewById(R.id.videoOnlineImageButton);
mRecordImageButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (mIsRecording) {
mIsRecording = false;
mRecordImageButton.setImageResource(R.drawable.btn_video_online);
mMediaRecorder.stop(); //<-- FATAL EXCEPTION CRASH
mMediaRecorder.reset();
startPreview(); //< this code says = once it's stops recording TextureView preview still continues
} else {
checkWriteStoragePermission();
}
}
});
}
private void createVideoFolder() {
File movieFile = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES);
mVideoFolder = new File(movieFile, "camera2VideoImage");
if(!mVideoFolder.exists()) {
mVideoFolder.mkdirs();
}
}
12-23 22:23:07.509 14045-14045/com.example.name.videoscrolltrial E/MediaRecorder: stop failed: -1007
12-23 22:23:07.510 14045-14045/com.example.name.videoscrolltrial D/AndroidRuntime: Shutting down VM
12-23 22:23:07.511 14045-14045/com.example.name.videoscrolltrial E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.name.videoscrolltrial, PID: 14045
java.lang.RuntimeException: stop failed.
at android.media.MediaRecorder._stop(Native Method)
at android.media.MediaRecorder.stop(MediaRecorder.java:1220)
at com.example.name.videoscrolltrial.Camera$3.onClick(Camera.java:192) //< causes the crash, this is mMediaRecorder.stop();
at android.view.View.performClick(View.java:6308)
at android.view.View$PerformClick.run(View.java:23969)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6823)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1563)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1451)
This code works for phones like Nexus 5X but for my Samsung Galaxy Note 8 it doesn't just gives a crash. I don't understand what I have to do to make the code compatible for ALL phones?
You can't stop the mediaRecorder without starting it first.

Get Bluetooth device information from the Android bluetooth device picker

I am developing an Android application which involves showing the user a list of nearby Bluetooth devices and connecting to the device selected by them. I'm trying to use the system bluetooth device picker as shown in these posts:
How to retrieve Bluetooth device info with Android Bluetooth device picker?
Android Bluetooth Device Picker Usage
The device picker does show, but I can't find out which device was selected in my code. The toast inside the onReceive does not show, which suggests that no broadcast is being received.
Another problem I faced is that if I try to start the device picker activity inside the onRequestPermissionsResult, the device picker does not show up at all, despite clicking 'allow' in the request permission dialog. The toast inside doesn't get displayed either.
Here's the code:
//Code inside Fragment
BroadcastReceiver mReceiver;
BluetoothAdapter bluetoothAdapter;
BluetoothSocket bsock;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
myView = inflater.inflate(R.layout.controller_mode_layout,container,false);
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
//Get location access permission.
if (bluetoothAdapter != null) {
if (bluetoothAdapter.isEnabled()) {
ActivityCompat.requestPermissions(getActivity(),new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, reqCode);
}
}
//Receiver to get the selected device information
mReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
context.unregisterReceiver(this);
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
Toast.makeText(context,"Device"+device.getAddress(), Toast.LENGTH_SHORT).show();
try {
bsock=device.createRfcommSocketToServiceRecord(UUID.fromString("00002415-0000-1000-8000-00805F9B34FB"));
bsock.connect();
//Send and receive data logic follows
} catch (IOException e) {
e.printStackTrace();
}
}
};
getActivity().registerReceiver(mReceiver, new IntentFilter("android.bluetooth.devicepicker.action.DEVICE_SELECTED"));
showDevicePicker();
return myView;
}
#Override
public void onRequestPermissionsResult (int requestCode, String[] permissions, int[] grantResults)
{
Toast.makeText(getActivity(),"Permission result", Toast.LENGTH_SHORT).show();
if((requestCode == reqCode) && (grantResults[0] == PackageManager.PERMISSION_GRANTED))
{
//Not working
// showDevicePicker();
}
}
public void showDevicePicker()
{
//Launch built in bluetooth device picker activity
startActivity( new Intent("android.bluetooth.devicepicker.action.LAUNCH")
.putExtra("android.bluetooth.devicepicker.extra.NEED_AUTH", false)
.putExtra("android.bluetooth.devicepicker.extra.FILTER_TYPE", 0)
.putExtra("android.bluetooth.devicepicker.extra.LAUNCH_PACKAGE","com.example.ankit2.controllerapp1")
.putExtra("android.bluetooth.devicepicker.extra.DEVICE_PICKER_LAUNCH_CLASS","com.example.ankit2.controllerapp1.Fragment1")
.setFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS));
}
Any help will be appreciated.
Note: I tested the code on a Lenovo K3 note running Marshmallow.
The problem was in the DEVICE_PICKER_LAUNCH_CLASS, which was specified as Fragment1. The launch class must be an activity, even if the broadcast receiver is inside a fragment. In this case, changing the launch class to ControllerActivity (which contains the fragment Fragment1) fixed the problem.

java.lang.IllegalArgumentException - dialog.dismiss

I am getting this error in my published application, only clients receive this error. I already tried several times to replicate the same mistake however unsuccessfully.
I also already tried to use the below code at all locations where there is a Dialog but also not solved.
if (dialog.isShowing ()) {
dialog.dismiss ();
}
The error report
java.lang.IllegalArgumentException: View=com.android.internal.policy.impl.PhoneWindow$DecorView{16faa139 V.E..... R.....I. 0,0-0,0} not attached to window manager
at android.view.WindowManagerGlobal.findViewLocked(WindowManagerGlobal.java:412)
at android.view.WindowManagerGlobal.removeView(WindowManagerGlobal.java:338)
at android.view.WindowManagerImpl.removeViewImmediate(WindowManagerImpl.java:122)
at android.app.Dialog.dismissDialog(Dialog.java:522)
at android.app.Dialog.dismiss(Dialog.java:504)
**at br.my.project.de.a(Unknown Source)
at br.my.project.de.onPostExecute(Unknown Source)**
at android.os.AsyncTask.finish(AsyncTask.java:636)
at android.os.AsyncTask.access$500(AsyncTask.java:177)
at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:653)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:145)
at android.app.ActivityThread.main(ActivityThread.java:6946)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1404)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1199)
I could see that you are trying to dismiss a ProgressDialog on the postExecute of an AsyncTask. This in itself is a good practice but is sometimes buggy, I kind of experienced this also before especially while you're showing the ProgressDialog and suddenly rotate the view.
A solution I've found to fix this is below:
You will need these function to handle the proper dismissal and avoid crashes.
private void dismissProgressDialog(ProgressDialog progressDialog) {
if (progressDialog != null) {
if (progressDialog.isShowing()) {
//get the Context object that was used to create the dialog
Context context = ((ContextWrapper) progressDialog.getContext()).getBaseContext();
// if the Context used here was an activity AND it hasn't been finished or destroyed
// then dismiss it
if (context instanceof Activity) {
// Api >=17
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
if (!((Activity) context).isFinishing() && !((Activity) context).isDestroyed()) {
dismissWithExceptionHandling(progressDialog);
}
} else {
// Api < 17. Unfortunately cannot check for isDestroyed()
if (!((Activity) context).isFinishing()) {
dismissWithExceptionHandling(progressDialog);
}
}
} else
// if the Context used wasn't an Activity, then dismiss it too
dismissWithExceptionHandling(progressDialog);
}
progressDialog = null;
}
}
public void dismissWithExceptionHandling(ProgressDialog dialog) {
try {
dialog.dismiss();
} catch (final IllegalArgumentException e) {
// Do nothing.
} catch (final Exception e) {
// Do nothing.
} finally {
dialog = null;
}
}
On your AsyncTask's onPostExecute implement the function.
#Override
protected void onPostExecute(Boolean b) {
// pass in the progressDialog as a parameter to the method
dismissProgressDialog(progressDialog);
}
fun Activity?.dismissDialog(dialog: Dialog?) {
if (isActivityActive()) {
dialog?.apply {
if (isShowing) dismiss()
}
}
}
fun Activity?.isActivityActive(): Boolean {
return null != this && !isFinishing && !isDestroyed
}
You are calling dismiss on a dialog that is currently not being shown anymore. As in: your Activity/Fragment is possibly already destroyed when you call dismiss.
Write this code in your activity's
onStop()
method.When anybody presses the home button and if dialog is opened than this error will come. Because on click of home button onPause() and onStop() method calls.Hope this helps.
if (dialog!=null && dialog.isShowing ()) {
dialog.dismiss ();
}

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