Turning on/off flash with Android camera2 API not working - android

I'm creating an Android app with a custom camera and I'm switching to the new camera2 API. I have a button allowing to turn ON and OFF the flash when the back camera is on (without stopping the camera, like any classic camera app).
When I tap the flash icon, nothing happens and this is what the logcat returns:
D/ViewRootImpl: ViewPostImeInputStage processPointer 0
D/ViewRootImpl: ViewPostImeInputStage processPointer 1
I don't know why it's not working. Here is the code:
I have a RecordVideoActivity using a RecordVideoFragment. Here is the fragment's XML part that contains the flash button code:
<ImageButton
android:id="#+id/button_flash"
android:src="#drawable/ic_flash_off"
android:layout_alignParentLeft="true"
style="#style/actions_icons_camera"
android:onClick="actionFlash"/>
And the Java code:
ImageButton flashButton;
private boolean hasFlash;
private boolean isFlashOn = false;
With in the onViewCreated:
#Override
public void onViewCreated(final View view, Bundle savedInstanceState) {
...
[some code]
...
// Flash on/off button
flashButton = (ImageButton) view.findViewById(R.id.button_flash);
// Listener for Flash on/off button
flashButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
actionFlash();
}
});
And here is the actionFlash() function definition:
private void actionFlash() {
/* First check if device is supporting flashlight or not */
hasFlash = getActivity().getApplicationContext().getPackageManager()
.hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH);
if (!hasFlash) {
// device doesn't support flash
// Show alert message and close the application
AlertDialog alert = new AlertDialog.Builder(this.getActivity())
.create();
alert.setMessage("Sorry, your device doesn't support flash light!");
alert.setButton(DialogInterface.BUTTON_POSITIVE, "OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
alert.show();
return;
}
else { // the device support flash
CameraManager mCameraManager = (CameraManager) getActivity().getSystemService(Context.CAMERA_SERVICE);
try {
String mCameraId = mCameraManager.getCameraIdList()[0];
if (mCameraId.equals("1")) { // currently on back camera
if (!isFlashOn) { // if flash light was OFF
// Turn ON flash light
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
mCameraManager.setTorchMode(mCameraId, true);
}
} catch (Exception e) {
e.printStackTrace();
}
// Change isFlashOn boolean value
isFlashOn = true;
// Change button icon
flashButton.setImageResource(R.drawable.ic_flash_off);
} else { // if flash light was ON
// Turn OFF flash light
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
mCameraManager.setTorchMode(mCameraId, false);
}
} catch (Exception e) {
e.printStackTrace();
}
// Change isFlashOn boolean value
isFlashOn = false;
// Change button icon
flashButton.setImageResource(R.drawable.ic_flash_on);
}
}
} catch (CameraAccessException e) {
Toast.makeText(getActivity(), "Cannot access the camera.", Toast.LENGTH_SHORT).show();
getActivity().finish();
}
}
}
Any idea what could be wrong?
(I already looked at this question but it doesn't address my problem)
Thank you very much for your help. This is driving me crazy.

Create these variables:
public static final String CAMERA_FRONT = "1";
public static final String CAMERA_BACK = "0";
private String cameraId = CAMERA_BACK;
private boolean isFlashSupported;
private boolean isTorchOn;
then add these methods:
public void switchFlash() {
try {
if (cameraId.equals(CAMERA_BACK)) {
if (isFlashSupported) {
if (isTorchOn) {
mPreviewBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF);
mPreviewSession.setRepeatingRequest(mPreviewBuilder.build(), null, null);
flashButton.setImageResource(R.drawable.ic_flash_off);
isTorchOn = false;
} else {
mPreviewBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_TORCH);
mPreviewSession.setRepeatingRequest(mPreviewBuilder.build(), null, null);
flashButton.setImageResource(R.drawable.ic_flash_on);
isTorchOn = true;
}
}
}
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
public void setupFlashButton() {
if (cameraId.equals(CAMERA_BACK) && isFlashSupported) {
flashButton.setVisibility(View.VISIBLE);
if (isTorchOn) {
flashButton.setImageResource(R.drawable.ic_flash_off);
} else {
flashButton.setImageResource(R.drawable.ic_flash_on);
}
} else {
flashButton.setVisibility(View.GONE);
}
}
after this line add this code:
Boolean available = characteristics.get(CameraCharacteristics.FLASH_INFO_AVAILABLE);
isFlashSupported = available == null ? false : available;
setupFlashButton();
at the end call switchFlash() in your desired click listener.
et voilĂ !
PS. This might be helpful - front/back camera switcher

I see for cameraX, ImageCapture.flashMode only has effect during we build with initial configuration, ImageCapture.Builder() etc.
But if you want to enable/disable flash dynamically, you will have to use the following.
camera?.cameraControl?.enableTorch(enableFlash)
If you are wondering what camera is? Captured it from documentation.
// A variable number of use-cases can be passed here -
// camera provides access to CameraControl & CameraInfo
camera = cameraProvider.bindToLifecycle(
this, cameraSelector, preview, imageCapture
)

The answer by #MrOnyszko is correct, but it needs to be updated to
isTorchAvailable = camChars.get(CameraCharacteristics.FLASH_INFO_AVAILABLE).booleanValue();
CameraManager camManager = (CameraManager).context.getSystemService(Context.CAMERA_SERVICE);
try {
String cameraId cameraId = camManager.getCameraIdList()[0];
CameraCharacteristics camChars = camManager.getCameraCharacteristics(cameraId);
boolean isTorchAvailable = camChars.get(CameraCharacteristics.FLASH_INFO_AVAILABLE).booleanValue();
if(isTorchAvailable) {
camManager.setTorchMode(cameraId, true); //Turn ON
camManager.setTorchMode(cameraId, false);
}
} catch (CameraAccessException e) {
e.printStackTrace();
}

The problem with your code is "mCameraManager.setTorchMode(mCameraId, true);"
This call requires API 23+. Hence, You can not call this native method from APIs lower than API 23.
What you could do is use Depricated Camera API. It works for all devices and will keep on working for quite sometime in near future.
Here is what you could do, add this code using if-else statements. If device is API23+, use Camera2 otherwise use Camera. That's what I do.
Add hardware.Camera in your imports
import android.hardware.Camera;
Initialize variables
Camera camera;
Camera.Parameters params;
Now, Get the Camera and turn on the flash
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
mCameraManager.setTorchMode(CameraId, true);
}
else {
camera = Camera.open();
params = camera.getParameters();
params.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
camera.setParameters(params);
camera.startPreview();
}
catch (Exception e)
{
e.printStackTrace();
}
And you are good to go.

The logic that you are using is not backward compatible, and I have also verified that it does not work even on some of the 23+ devices, its better to use the camera manager api (supported 21+ onwards)
mPreviewBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF);
Refer the accepted answer for details

Related

Android CameraX - Get camera info (view angle, preview image size)

I'm trying to switch from old Android camera API to new CameraX API. I'm using preview mode for an Augmented Reality App and I need to get some info like angle of view and size on my camera used by the Preview.
This is my code so far:
PreviewConfig config = new PreviewConfig.Builder()
.setLensFacing(CameraX.LensFacing.BACK)
.setTargetResolution(new Size(dsiWidth, dsiHeight))
.build();
Preview preview = new Preview(config);
preview.setOnPreviewOutputUpdateListener(new Preview.OnPreviewOutputUpdateListener() {
#Override
public void onUpdated(Preview.PreviewOutput output) {
tvCameraView.setSurfaceTexture(output.getSurfaceTexture());
}
});
CameraX.bindToLifecycle(this, preview);
This works so far. But how do I get information on the camera used by the Preview? Thanks a lot in advance!
When you use the "androidx.camera:camera-camera2:1.0.0-alpha02" dependency you can have a look at the class Camera2CameraFactory. There you can see how the front and back facing camera is determined.
#Override
public Set<String> getAvailableCameraIds() throws CameraInfoUnavailableException {
List<String> camerasList = null;
try {
camerasList = Arrays.asList(mCameraManager.getCameraIdList());
} catch (CameraAccessException e) {
throw new CameraInfoUnavailableException(
"Unable to retrieve list of cameras on device.", e);
}
// Use a LinkedHashSet to preserve order
return new LinkedHashSet<>(camerasList);
}
#Nullable
#Override
public String cameraIdForLensFacing(LensFacing lensFacing)
throws CameraInfoUnavailableException {
Set<String> cameraIds = getAvailableCameraIds();
// Convert to from CameraX enum to Camera2 CameraMetadata
Integer lensFacingInteger = -1;
switch (lensFacing) {
case BACK:
lensFacingInteger = CameraMetadata.LENS_FACING_BACK;
break;
case FRONT:
lensFacingInteger = CameraMetadata.LENS_FACING_FRONT;
break;
}
for (String cameraId : cameraIds) {
CameraCharacteristics characteristics = null;
try {
characteristics = mCameraManager.getCameraCharacteristics(cameraId);
} catch (CameraAccessException e) {
throw new CameraInfoUnavailableException(
"Unable to retrieve info for camera with id " + cameraId + ".", e);
}
Integer cameraLensFacing = characteristics.get(CameraCharacteristics.LENS_FACING);
if (cameraLensFacing == null) {
continue;
}
if (cameraLensFacing.equals(lensFacingInteger)) {
return cameraId;
}
}
return null;
}
It boils down to picking the first camera that matches the orientation from the camera service. I would assume that they will expand those apis in the future camerax release.

Android Camera 2: ImageReader's Images Have no Stride Values

I've been trying to route the images from the camera to an ImageReader so that I can manipulate the images directly using the Camera2 API. When I have the capture session stream to a SurfaceView, the stream works just fine. When I then set the capture session stream to my ImageReader, I notice that the images are somehow invalid.
In my ImageReader's OnImageAvailable callback function, I pull the next available Image and try to read it. This is where I have the problem. The Image isn't null and the planes are there, but the planes' buffers are null at first. When I try to grab the buffers, they are suddenly not null, but trying to read from them crashes the app without a stack trace. Further, the pixel and row strides in the planes are set to 0. The width and height of the image are properly set, though.
Therefore, I think that I'm not setting my ImageReader up correctly. The question is then what am I not doing correctly?
Code:
public class CompatibleCamera {
private static final int CAMERA2_API_LEVEL = 23;
public static final int FORMAT_RAW = ImageFormat.RAW_SENSOR;
public static final int FORMAT_JPEG = ImageFormat.JPEG;
private static final int MAX_IMAGES = 2;
// Interface for the user to use. User supplies the function to manipulate the image
public interface ImageTransform
{
void doTransform(Image image);
}
//***********Camera 2 API Members***********
// The camera2 API CameraManager. Used to access the camera device
private CameraManager mCamera2Manager;
// The information used by the device to reference the camera. Not a camera object itself
private CameraDevice mCamera2Device;
private String mCamera2DeviceID = "";
// The class that allows us to get the camera's image
private ImageReader mImageReader;
// This listener is where we have the programmer deal with the image. Just edit the interface
private ImageReader.OnImageAvailableListener mListener;
// This is the thread for the handler. It keeps it off the UI thread so we don't block the GUI
private HandlerThread mCameraCaptureHandlerThread;
// This runs in the background and handles the camera feed, activating the OnImageAvailableListener
private Handler mCameraCaptureHandler;
private HandlerThread mImageAvailableHandlerThread;
// This runs in the background and handles the camera feed, activating the OnImageAvailableListener
private Handler mImageAvailableHandler;
// This object is the camera feed, essentially. We store it so we can properly close it later
private CameraCaptureSession cameraCaptureSession;
// DEBUG
private boolean TEST_SURFACE_VIEW = false;
private Surface dbSurface;
// Mutex lock. Locks and unlocks when the ImageReader is pulling and processing an image
private Semaphore imageReaderLock = new Semaphore(1);
//***********Common Members***********
// The context of the activity holding this object
private Context mContext;
// Our ImageTransform implementation to alter the image as it comes in
private ImageTransform mTransform;
private int iImageFormat= FORMAT_RAW;
//==========Methods==========
public CompatibleCamera(Context context, ImageTransform transform, int imageFormat)
{
mContext = context;
mTransform = transform;
mListener = new ImageReader.OnImageAvailableListener() {
#Override
public void onImageAvailable(ImageReader imageReader) {
try {
imageReaderLock.acquire();
Image image = imageReader.acquireNextImage();
//<--------------Problem With Image is Here-------------->
mTransform.doTransform(image);
image.close();
imageReaderLock.release();
}
catch(InterruptedException ex)
{
ex.printStackTrace();
}
}
};
}
private boolean camera2GetManager()
{
//----First, get the CameraManager and a Camera Device----
mCamera2Manager = (CameraManager) mContext.getSystemService(Context.CAMERA_SERVICE);
if (mCamera2Manager == null) {
System.out.println(" DEBUG: Manager is null");
return false;
}
else {
System.out.println(" DEBUG: Camera Manager obtained");
try {
String[] cameraIDs = mCamera2Manager.getCameraIdList();
for (String cameraID : cameraIDs) {
CameraCharacteristics cameraCharacteristics = mCamera2Manager.getCameraCharacteristics(cameraID);
if (cameraCharacteristics.get(CameraCharacteristics.LENS_FACING) ==
CameraCharacteristics.LENS_FACING_BACK) {
mCamera2DeviceID = cameraID;
break;
}
}
if (mCamera2DeviceID.equals("")) {
System.out.println("No back camera, exiting");
return false;
}
System.out.println(" DEBUG: Camera Device obtained");
// Open the Camera Device
} catch (Exception ex) {
ex.printStackTrace();
return false;
}
return camera2OpenCamera();
}
}
private boolean camera2SetupImageReader()
{
// Get the largest image size available
CameraCharacteristics cameraCharacteristics;
try {
cameraCharacteristics= mCamera2Manager.getCameraCharacteristics(mCamera2DeviceID);
} catch(Exception e) {
e.printStackTrace();
return false;
}
StreamConfigurationMap map = cameraCharacteristics.get(
CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
Size largestSize = Collections.max(
Arrays.asList(map.getOutputSizes(iImageFormat)),
new CompareSizesByArea());
// Set up the handler
mCameraCaptureHandlerThread = new HandlerThread("cameraCaptureHandlerThread");
mCameraCaptureHandlerThread.start();
mCameraCaptureHandler = new Handler(mCameraCaptureHandlerThread.getLooper());
mImageAvailableHandlerThread = new HandlerThread("imageReaderHandlerThread");
mImageAvailableHandlerThread.start();
mImageAvailableHandler = new Handler(mImageAvailableHandlerThread.getLooper());
mImageReader = ImageReader.newInstance( largestSize.getWidth(),
largestSize.getHeight(),
iImageFormat,
MAX_IMAGES);
mImageReader.setOnImageAvailableListener(mListener, mImageAvailableHandler);
// This callback is used to asynchronously set up the capture session on our end
final CameraCaptureSession.StateCallback captureStateCallback = new CameraCaptureSession.StateCallback() {
// When configured, set the target surface
#Override
public void onConfigured(#NonNull CameraCaptureSession session) {
try
{
CaptureRequest.Builder requestBuilder = session.getDevice().createCaptureRequest(CameraDevice.TEMPLATE_RECORD);
if (TEST_SURFACE_VIEW)
requestBuilder.addTarget(dbSurface);
else
requestBuilder.addTarget(mImageReader.getSurface());
//set to null - image data will be produced but will not receive metadata
session.setRepeatingRequest(requestBuilder.build(), null, mCameraCaptureHandler);
cameraCaptureSession = session;
}
catch (Exception ex)
{
ex.printStackTrace();
}
}
#Override
public void onConfigureFailed(#NonNull CameraCaptureSession cameraCaptureSession) {
System.out.println("Failed to configure the capture session :(");
}
};
ArrayList<Surface> surfaces = new ArrayList<>();
if (TEST_SURFACE_VIEW)
surfaces.add(dbSurface);
else
surfaces.add(mImageReader.getSurface());
try
{
mCamera2Device.createCaptureSession(surfaces, captureStateCallback, mCameraCaptureHandler);
}
catch(Exception ex)
{
ex.printStackTrace();
}
return true;
}
}
RAW_SENSOR is a special beast of formats.
General raw camera sensor image format, usually representing a single-channel Bayer-mosaic image. Each pixel color sample is stored with 16 bits of precision.
The layout of the color mosaic, the maximum and minimum encoding values of the raw pixel data, the color space of the image, and all other needed information to interpret a raw sensor image must be queried from the android.hardware.camera2.CameraDevice which produced the image.
You should not attempt to use its stride info directly, as if it were a YUV frame.

How to turn off Flash light of Camera with use Night scene, when take a picture in Android?

Problem: When i set scene mode to SCENE_MODE_NIGHT, flash cannot be set to Off when i call takePicture() method.
Pseudo:
Camera mCamera = Camera.open(Camera.CameraInfo.CAMERA_FACING_BACK)
Camera.Parameters params = camera.getParameters();
//AUTO-FOCUS
List<String> focus = params.getSupportedFocusModes();
if (focus != null && focus.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO)
params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
//AUTO NIGHT SCENE
List<String> scene = params.getSupportedSceneModes();
if (scene != null && scene.contains(Camera.Parameters.SCENE_MODE_NIGHT)){
params.setSceneMode(Camera.Parameters.SCENE_MODE_NIGHT);
}
//FLASH
List<String> flash = params.getSupportedFlashModes();
if(flash != null && flash.contains(Camera.Parameters.FLASH_MODE_OFF)) {
params.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
}
mCamera.setParameters(params);
mPreview = new CameraPreview(this, mCamera, params); //surfaceView (CameraPreview extends SurfaceView implements SurfaceHolder.Callback)
Call take a picture:
if(params.isVideoSnapshotSupported()){//Some device not supported this mode
mCamera.takePicture(null, null, new Camera.PictureCallback(){
...
}
Permissions:
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.FLASHLIGHT" /> <!--somewhere i find this strange permission, but still not working-->
Logcat shows correctly: params.getFlashMode(): off, but flash is fired.
Logcat (Nexus 5) shows: I/mm-jpeg-intf: process_sensor_data: Flash value 1 flash mode 4 flash state 3 after call mCamera.takePicture.
When i comment line: params.setSceneMode(Camera.Parameters.SCENE_MODE_NIGHT); (or change to Camera.Parameters.SCENE_MODE_AUTO) flash is not fired.
Logcat (Nexus 5) shows: I/mm-jpeg-intf: process_sensor_data: Flash value 0 flash mode 0 flash state 2 after call mCamera.takePicture.
Goal: Use these parameters: SCENE_MODE_NIGHT, FLASH_MODE_OFF together.
Use: Android Camera 1 API. Back camera.
Ocurrence: Android 6,7, maybe Android 5 too.
Tested:
Nexus 5: NOT OK.
Huawei Honor 4C: OK
Probably it's Nexus 5 "bug" because i tried Open Camera application from Google Play, set scene to night, disable flash, but flash is still active while take a picture.
use the below code on onClick of flash on and flash off Button
/**
* Action to be performed when image is capture is clicked
*/
private OnClickListener OnFlashClick = new OnClickListener()
{
#Override
public void onClick(View v)
{
if(btn_cameraFlashOn.isSelected())
{
btn_cameraFlashOn.setSelected(false);
mCamUtils.setFlashParams(Parameters.FLASH_MODE_OFF);
}
else
{
btn_cameraFlashOn.setSelected(true);
mCamUtils.setFlashParams(Parameters.FLASH_MODE_TORCH);
}
}
};
private OnClickListener OffFlashClick = new OnClickListener()
{
#Override
public void onClick(View v)
{
mCamUtils.toggleFlashSettings();
}
};
private String mFlashSetting = null;
/**
* Set the flash mode for camera
*/
public void toggleFlashSettings()
{
if (null == mCamera)
{
return;
}
Camera.Parameters params = mCamera.getParameters();
List<String> flashModes = params.getSupportedFlashModes();
if (flashModes == null)
{
mCallback.enableFlashButton(false);
return;
}
else
{
mCallback.enableFlashButton(true);
}
// Log.d(LOGTAG, " mFlashSetting mode = " + mFlashSetting);
if ((Camera.Parameters.FLASH_MODE_AUTO.equals(mFlashSetting))
&& (flashModes.contains(Camera.Parameters.FLASH_MODE_ON)))
{
setFlashParams(Camera.Parameters.FLASH_MODE_ON);
} else if ((Camera.Parameters.FLASH_MODE_ON.equals(mFlashSetting))
&& (flashModes.contains(Camera.Parameters.FLASH_MODE_OFF)))
{
setFlashParams(Camera.Parameters.FLASH_MODE_OFF);
}
else if (flashModes.contains(Camera.Parameters.FLASH_MODE_AUTO))
{
setFlashParams(Camera.Parameters.FLASH_MODE_AUTO);
}
}
/**
* Returns the current flash setting of the device
*
* #return
*/
public String getFlashMode()
{
if (null == mCamera)
{
return null;
}
mFlashSetting = mCamera.getParameters().getFlashMode();
return mFlashSetting;
}
/**
* Sets the flash mode of the camera. this is a internal method only
*
* #return
*/
public void setFlashParams(String flash)
{
if (null == mCamera)
{
return;
}
Camera.Parameters params = mCamera.getParameters();
List<String> flashModes = params.getSupportedFlashModes();
if (flashModes == null)
{
mCallback.enableFlashButton(false);
return;
}
else
{
mCallback.enableFlashButton(true);
}
if (flashModes.contains(flash))
{
mFlashSetting = flash;
params.setFlashMode(flash);
mCallback.flashSet(flash);
mCamera.setParameters(params);
// Log.d(LOGTAG, " new flash mode = " + flash);
}
else
{
// Log.e(LOGTAG, " INVALID FLASH MODE");
}
}

How to turn on/off wifi hotspot programmatically in Android 8.0 (Oreo)

I know how to turn on/off wifi hot spot using reflection in android using below method.
private static boolean changeWifiHotspotState(Context context,boolean enable) {
try {
WifiManager manager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
Method method = manager.getClass().getDeclaredMethod("setWifiApEnabled", WifiConfiguration.class,
Boolean.TYPE);
method.setAccessible(true);
WifiConfiguration configuration = enable ? getWifiApConfiguration(manager) : null;
boolean isSuccess = (Boolean) method.invoke(manager, configuration, enable);
return isSuccess;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
But the above method is not working Android 8.0(Oreo).
When I execute above method in Android 8.0, I am getting below statement in logcat.
com.gck.dummy W/WifiManager: com.gck.dummy attempted call to setWifiApEnabled: enabled = true
Is there any other way to on/off hotspot on android 8.0
I thought the LocalOnlyHotspot route was the way to, but as #edsappfactory.com said in the comments - it only gives closed network, no internet access.
In Oreo hot-spotting/tethering moved to ConnectionManager, and its annotated #SystemApi, so (nominally) inaccessible.
As part of something else I was doing, I made an app and put it on github here. It uses reflection to get at the function and DexMaker to generate a subclass of ConnectionManager.OnStartTetheringCallback (which is also inaccessible).
Think it all works okay - bit rough around the edges, so please feel free to make better!
Relevant bits of code are in:
MyOreoWifiManager and;
CallbackMaker
I lost patience trying to get my DexMaker-generated callback to fire the MyOnStartTetheringCallback so all that code is in disarray and commented out.
Finally I got the solution.
Android 8.0, they provided public api to turn on/off hotspot. WifiManager
Below is the code to turn on hotspot
private WifiManager.LocalOnlyHotspotReservation mReservation;
#RequiresApi(api = Build.VERSION_CODES.O)
private void turnOnHotspot() {
WifiManager manager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
manager.startLocalOnlyHotspot(new WifiManager.LocalOnlyHotspotCallback() {
#Override
public void onStarted(WifiManager.LocalOnlyHotspotReservation reservation) {
super.onStarted(reservation);
Log.d(TAG, "Wifi Hotspot is on now");
mReservation = reservation;
}
#Override
public void onStopped() {
super.onStopped();
Log.d(TAG, "onStopped: ");
}
#Override
public void onFailed(int reason) {
super.onFailed(reason);
Log.d(TAG, "onFailed: ");
}
}, new Handler());
}
private void turnOffHotspot() {
if (mReservation != null) {
mReservation.close();
}
}
onStarted(WifiManager.LocalOnlyHotspotReservation reservation) method will be called if hotspot is turned on.. Using WifiManager.LocalOnlyHotspotReservation reference you call close() method to turn off hotspot.
Note:
To turn on hotspot, the Location(GPS) should be enabled in the device. Otherwise, it will throw SecurityException
As per Jon suggestion, I got another way to enable WifiHotSpot in Android Oreo and above.
public boolean enableTetheringNew(MyTetheringCallback callback) {
File outputDir = mContext.getCodeCacheDir();
try {
proxy = ProxyBuilder.forClass(classOnStartTetheringCallback())
.dexCache(outputDir).handler(new InvocationHandler() {
#Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
switch (method.getName()) {
case "onTetheringStarted":
callback.onTetheringStarted();
break;
case "onTetheringFailed":
callback.onTetheringFailed();
break;
default:
ProxyBuilder.callSuper(proxy, method, args);
}
return null;
}
}).build();
} catch (IOException e) {
e.printStackTrace();
}
ConnectivityManager manager = (ConnectivityManager) mContext.getApplicationContext().getSystemService(ConnectivityManager.class);
Method method = null;
try {
method = manager.getClass().getDeclaredMethod("startTethering", int.class, boolean.class, classOnStartTetheringCallback(), Handler.class);
if (method == null) {
Log.e(TAG, "startTetheringMethod is null");
} else {
method.invoke(manager, TETHERING_WIFI, false, proxy, null);
}
return true;
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return false;
}
private Class classOnStartTetheringCallback() {
try {
return Class.forName("android.net.ConnectivityManager$OnStartTetheringCallback");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}

How does one retrieve the cameraID and use setTorchMode?

So Android M recently came out and it now has a built in cameralight function called setTorchMode. I was curious as to how this worked as the parameters are (String cameraID, Boolean true/false). The Boolean obviously dictates whether the light is on or off, but how do you get the cameraID? I know there's a method called getCameraIDList, but that returns an array of IDs, not just one. How do you know which one in that list to use?
You should use CameraManager "getCameraIdList" function which will retrieve you a list of strings where each represent an active camera.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
mCameraManager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
try {
for (String camID : mCameraManager.getCameraIdList()) {
CameraCharacteristics cameraCharacteristics = mCameraManager.getCameraCharacteristics(camID);
int lensFacing = cameraCharacteristics.get(CameraCharacteristics.LENS_FACING);
if (lensFacing == CameraCharacteristics.LENS_FACING_FRONT && cameraCharacteristics.get(CameraCharacteristics.FLASH_INFO_AVAILABLE)) {
mCameraId = camID;
break;
} else if (lensFacing == CameraCharacteristics.LENS_FACING_BACK && cameraCharacteristics.get(CameraCharacteristics.FLASH_INFO_AVAILABLE)) {
mCameraId = camID;
}
}
if (mCameraId != null) {
mCameraManager.setTorchMode(mCameraId, true);
}
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
mCameraId will turn on front camera flash if available or else back camera flash if available. If no flash is available then mCameraId will be null and setTorchMode will not be called.

Categories

Resources