I'm adapting an app so it will work on the KindleFire, which doesn't have a camera.
I don't have any Android devices that lack a camera, so I don't know if the following code actually will return false for the Kindle. I'm using reflection because my app has already been released with Donut compatibility, and Donut doesn't have PackageManager.hasSystemFeature().
I'm assuming Donut devices all have cameras--hasn't caused me trouble yet.
public static boolean isCameraAvailable(Context context){
PackageManager pm = context.getPackageManager();
return tryHasSystemFeature(pm,"android.hardware.camera");
}
private static Method packageManager_hasSystemFeature;
static {
initCompatibility();
};
private static void initCompatibility() {
try {
packageManager_hasSystemFeature = PackageManager.class.getMethod(
"hasSystemFeature", new Class[] { String.class } );
} catch (NoSuchMethodException nsme) {
//leave the Method null
}
}
static private boolean tryHasSystemFeature(PackageManager pm,String feature){
if (packageManager_hasSystemFeature != null) {
try {
final Boolean hasIt = (Boolean) packageManager_hasSystemFeature.invoke(pm,feature);
return hasIt.booleanValue();
} catch (Exception e) {
e.printStackTrace();
} finally {
}
}
return true;
}
Actually it's recommended to add this line in your manifest file, if you want to be sure the device has a camera:
<uses-feature android:name="android.hardware.camera" />
Market will prevent a device without a camera from downloading your application.
Related
I am using Android to turn on my S Voice application in Android. As previous work, I will use the follows code to turn on it
String SVOICE_PACKAGE_NAME = "com.vlingo.midas";
String SVOICE_LISTEN_ACTION = "com.sec.action.SVOICE";
Intent intent = new Intent();
intent.setPackage(SVOICE_PACKAGE_NAME);
intent.setAction(SVOICE_LISTEN_ACTION);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
try {
getApplication().startActivity(intent);
} catch (final ActivityNotFoundException e) {
e.printStackTrace();
} catch (final Exception e) {
e.printStackTrace();
}
The above code worked well in Galaxy S4 with Android 5.0. However, the issue comes from first and second lines in Galaxy S7 with Android 6.0. In Galaxy S7 with Android 6.0, the first and second lines have to modify as
SVOICE_PACKAGE_NAME = "com.samsung.voiceserviceplatform";
SVOICE_LISTEN_ACTION = "com.sec.action.SVOICE";
And also the application name S Voice with changing from "S Voice" to "S Voice App". That changing gives me a difficult work. Hence, I want to determine the S Voice App in my phone before deciding calls these function. Currently, I do not know the changing is from Android version or the device. Could you have any idea to adapt the issue in various phones: S4 and S7?
Whenever opening applications, there could be package or application name differences. Here is a standard utility method to check:
/**
* Check if the user has a package installed
*
* #param ctx the application context
* #param packageName the application package name
* #return true if the package is installed
*/
public static boolean isPackageInstalled(#NonNull final Context ctx, #NonNull final String packageName) {
if (DEBUG) {
MyLog.i(CLS_NAME, "isPackageInstalled");
}
try {
ctx.getApplicationContext().getPackageManager().getApplicationInfo(packageName, 0);
return true;
} catch (final PackageManager.NameNotFoundException e) {
if (DEBUG) {
MyLog.w(CLS_NAME, "isPackageInstalled: NameNotFoundException");
}
} catch (final NullPointerException e) {
if (DEBUG) {
MyLog.w(CLS_NAME, "isPackageInstalled: NullPointerException");
}
} catch (final Exception e) {
if (DEBUG) {
MyLog.w(CLS_NAME, "isPackageInstalled: Exception");
}
}
return false;
}
You'll need to remove my custom logging.
I have a problem regarding the camera in the most recent Marshmallow build, more specifically the flashlight.
On any pre-Marshmallow version all I need to do to turn the flash on/off was the following:
private void turnFlashOn(final Camera camera, int flashLightDurationMs) {
if (!isFlashOn()) {
final List<String> supportedFlashModes = camera.getParameters().getSupportedFlashModes();
if (supportedFlashModes != null && supportedFlashModes.contains(Camera.Parameters.FLASH_MODE_TORCH)) {
mParams.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
camera.setParameters(mParams);
}
}
}
and
private void turnFlashOff(Camera camera) {
if (camera != null) {
final List<String> supportedFlashModes = camera.getParameters().getSupportedFlashModes();
if (supportedFlashModes != null && supportedFlashModes.contains(Camera.Parameters.FLASH_MODE_OFF)) {
mParams.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
camera.setParameters(mParams);
}
}
}
Unfortunately, Marshmallow devices began to crash in the wild. Somehow camera.getParameters() and camera.setParameters() began to fail with messages such as:
RuntimeException: getParameters failed (empty parameters)
RuntimeException: setParameters failed
I tried starting and stopping the preview before getting the parameters, which no longer throws errors. However the preview is not resumed when I call camera.startPreview().
I fear releasing the camera and reopening it is out of the question as this takes some seconds and would produce a bad experience.
Any suggestions on how to turn the flashlight on/off in Marshmallow reliably?
Google has introduced torchmode in OS 6 (Android M).
if your purpose is only to turn on/off the flash, below code can help you with that:
private static void handleActionTurnOnFlashLight(Context context){
try{
CameraManager manager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
String[] list = manager.getCameraIdList();
manager.setTorchMode(list[0], true);
}
catch (CameraAccessException cae){
Log.e(TAG, cae.getMessage());
cae.printStackTrace();
}
}
private static void handleActionTurnOffFlashLight(Context context){
try{
CameraManager manager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
manager.setTorchMode(manager.getCameraIdList()[0], false);
}
catch (CameraAccessException cae){
Log.e(TAG, cae.getMessage());
cae.printStackTrace();
}
}
All you have to do is: Get cameraid's list out of which camera ID zero(0) is your primary camera for which you want to turn flash on/off. Simply pass the cameraID to setTochMode API with boolean value for turning it on or off.
Do note that this piece of code will work only with OS 6, so you need to check for device OS and based upon that you need to select which API's to call for pre-marshmallow devices.
Kindly mark this as solution if it solves your problem.
As Saurabh7474 has responded, to check the version of Android and use setTorchMode API it's very correct.
Although you can also use params.setFlashMode (...) in marshmallow using
mCamera.setPreviewTexture (new SurfaceTexture (100))
after Camera.open (...) and before calling mCamera.startPreview();
try {
Log.i(TAG, "getCamera");
int requestedCameraId = getIdForRequestedCamera(mFacing);
if (requestedCameraId == -1) {
throw new RuntimeException("Could not find requested camera.");
}
mCamera = Camera.open(requestedCameraId);
mCamera.setPreviewTexture(new SurfaceTexture(DUMMY_TEXTURE_NAME));
params = mCamera.getParameters();
} catch (RuntimeException e) {
Log.e("Failed to Open. Error:", e.getMessage());
} catch (IOException e) {
Log.e("Failed to Open. can't setPreviewTexture:", e.getMessage());
}
then when you want, you can use
mParams.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
camera.setParameters(mParams);
My answer is based on CameraSource examples of Vision API that uses params.setFlashMode (...) and works in Api 23 and above.
If you decide to inspect CameraSource, the key method that has solved the same problem is "start ()", in the line 312 ...
https://github.com/googlesamples/android-vision/blob/master/visionSamples/barcode-reader/app/src/main/java/com/google/android/gms/samples/vision/barcodereader/ui/camera/CameraSource.java
The reason you can find here
https://stackoverflow.com/a/33333046/4114846
Update your app to check for permissions at runtime. You have to have android.permission.CAMERA granted. Including it in the manifest of your app is not going to grant it to you on Marshmallow. You'll need to detect whether or not it has been granted and request it.
Building off of Saurabh7474's answer, you can toggle Marshmallow's torchMode by registering a torchCallback:
final CameraManager mCameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
CameraManager.TorchCallback torchCallback = new CameraManager.TorchCallback() {
#Override
public void onTorchModeUnavailable(String cameraId) {
super.onTorchModeUnavailable(cameraId);
}
#Override
public void onTorchModeChanged(String cameraId, boolean enabled) {
super.onTorchModeChanged(cameraId, enabled);
boolean currentTorchState = enabled;
try {
mCameraManager.setTorchMode(cameraId, !currentTorchState);
} catch (CameraAccessException e){}
}
};
mCameraManager.registerTorchCallback(torchCallback, null);//fires onTorchModeChanged upon register
mCameraManager.unregisterTorchCallback(torchCallback);
I'm trying to reimplement Redlaser barcode Scanner using Google play services. And face to the problem with flashlight. Android hardware.Camera object can't be using in common with CameraSource from gms.vision.
Is there any opportunity to working with flashlight and Google barcode scanner?
Not sure I fully get what you're asking but my approach to this was to use the already created mCamerSource Object and setFlashMode() from there, this worked for me as I used a button to toggle the flash.
In your onCreate add this or in createCameraSource method just like in the samples ->
mCameraSource = builder
.setFlashMode(useFlash ? Camera.Parameters.FLASH_MODE_TORCH : null)
.build();
Then Make a method to toggle the flash, hope this helps.
private void ToggleFlash()
{
fab_flash.startAnimation(spin_it);
if(currentDrawalbe == FLASH_DEFAULT_STATE)
{
fab_flash.setImageResource(FLASH_TOGGLE_STATE);
currentDrawalbe = FLASH_TOGGLE_STATE;
mCameraSource.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
}
else
{
fab_flash.setImageResource(FLASH_DEFAULT_STATE);
currentDrawalbe = FLASH_DEFAULT_STATE;
mCameraSource.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
}
}
The currentDrawable is just an image for the flash light icon, so basically if the image is a turned on flash light executes else clause otherwise if clause
The issue was that the camera API does not support opening the camera multiple times. Turning on the flashlight and starting CameraSource both require separate calls to open the camera. If you try to do both, the one that is requested last will fail.
The good news is that we recently open sourced the CameraSource implementation. This new version includes an option for turning on the flashlight, which should fix this issue. See here:
https://github.com/googlesamples/android-vision/blob/master/visionSamples/barcode-reader/app/src/main/java/com/google/android/gms/samples/vision/barcodereader/ui/camera/CameraSource.java
Currently I'm using this code to find camera object:
private boolean findCameraObject(){
if(mCameraSource == null) {
return false;
}
Field[] declaredFields = null;
try {
declaredFields = CameraSource.class.getDeclaredFields();
} catch (Exception ex) {
ex.printStackTrace();
}
if(declaredFields == null) {
return false;
}
for (Field field : declaredFields) {
if (field.getType() == Camera.class) {
field.setAccessible(true);
try {
Camera camera = (Camera) field.get(this.mCameraSource);
if (camera != null) {
Camera.Parameters params = camera.getParameters();
params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
camera.setParameters(params);
setCamera(camera);
return true;
}
return false;
} catch (IllegalAccessException e) {
e.printStackTrace();
}
break;
}
}
return false;
}
I am using this code and it is working successfully
Replace : cameraSource.start(surfaceView.getHolder()); OR cameraSource.start(); TO setFlash ();
BY
import java.lang.reflect.Field;
import android.hardware.Camera;
Don't Forgot AndroidManifest:
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<permission android:name="android.permission.FLASHLIGHT"
android:permissionGroup="android.permission-group.HARDWARE_CONTROLS"
android:protectionLevel="normal"/>
Then ADD this methods
public static Camera getCamera(CameraSource cameraSource) {
Field[] declaredFields = CameraSource.class.getDeclaredFields();
for (Field field : declaredFields) {
if (field.getType() == Camera.class) {
field.setAccessible(true);
try {
Camera camera = (Camera) field.get(cameraSource);
if (camera != null) {
return camera;
}
return null;
} catch (IllegalAccessException e) {
e.printStackTrace();
}
break;
}
}
return null;
}
public void setFlash () throws IOException {
getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH);
cameraSource.start(surfaceView.getHolder());
Camera _cam = getCamera (cameraSource);
if (_cam != null) {
Camera.Parameters _pareMeters = _cam.getParameters();
_pareMeters.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
_cam.setParameters(_pareMeters);
_cam.startPreview();
}
}
Add permossion on AndroidManifest file
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<permission android:name="android.permission.FLASHLIGHT"
android:permissionGroup="android.permission-group.HARDWARE_CONTROLS"
android:protectionLevel="normal"/>
Turn on torch on Android, using Kotlin.
cameraProvider.bindToLifecycle((LifecycleOwner)this,
cameraSelector, imageAnalysis, preview);
Get Camera for cameraProvider..
camera = cameraProvider!!.bindToLifecycle(
(this as LifecycleOwner),
cameraSelector!!, Preview
)
to turn on/off the FlashLight
private fun navigateflash(isFlash : Boolean) {
try {
if(camera!= null && camera!!.cameraInfo.hasFlashUnit()){
if(isFlash){
camera!!.cameraControl.enableTorch(false); // or false
isFlashOn = false
}else{
camera!!.getCameraControl().enableTorch(true); // or false
isFlashOn = true
}
}
} catch (e: Exception) {
e.printStackTrace()
}
}
I'm try send DTMF codes in icoming CALL. For this i'n try use Java reflection:
public void initialize(){
ClassLoader classLoader = Dtmf.class.getClassLoader();
final Class<?> classCallManager = classLoader.loadClass("com.android.internal.telephony.CallManager");
Method methodGetInstance = classCallManager.getDeclaredMethod("getInstance");
objectCallManager = methodGetInstance.invoke(null);
methodGetState = classCallManager.getDeclaredMethod(SEND_DTMF, char.class);
}
public boolean sendDtmf(char ch) {
boolean result = false;
if ( methodGetState != null) {
try {
Object res = methodGetState.invoke(objectCallManager,
new Object[]{Character.valueOf(ch)});
if (res instanceof Boolean) {
result = ((Boolean) res).booleanValue();
}
} catch (IllegalArgumentException e) {
} catch (IllegalAccessException e) {
} catch (InvocationTargetException e) {
}
}
return result;
}
Link for source code of class CallManager : Call Manager source code
But i'm always get "false" in method sendDtmf(). In debug, code is go into next:
Object res = methodGetState.invoke(objectCallManager,
new Object[]{Character.valueOf(ch)});
What wrong?
The method is likely throwing an InvocationTargetException if your application isn't signed with the platform certificate as conventional apps cannot execute these methods (and will not be granted the required platform permissions to do so).
In short: the method is returning false because you're catching (and ignoring) the exception.
There's an open issue (#1428) on the Android issue tracker for sending DTMF tones as it presently isn't possible.
I have used reflection to mount/unmount external storage.it is working below 4.4 Api.
code is below
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.storage.IMountService;
private static final String MOUNT_POINT = "/mnt/ext_usb" or "/mnt/sdcard/" ...
private IMountService mMountService = null;
private synchronized IMountService getMountService() {
if (mMountService == null) {
IBinder service = ServiceManager.getService("mount");
if (service != null) {
mMountService = IMountService.Stub.asInterface(service);
} else {
Log.e(TAG, "Can't get mount service");
}
}
return mMountService;
}
private void mount() {
IMountService mountService = getMountService();
try {
if (mountService != null) {
mountService.mountVolume(MOUNT_POINT);
} else {
//
}
} catch (RemoteException ex) {
// Not much can be done
}
}
private void unmount() {
StorageManager sm = (StorageManager) getSystemService(Context.STORAGE_SERVICE);
String state = sm.getVolumeState(MOUNT_POINT);
if (!Environment.MEDIA_MOUNTED.equals(state) &&
!Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
//
return;
}
IMountService mountService = getMountService();
try {
if (mountService != null) {
mountService.unmountVolume(MOUNT_POINT, true, false);
} else {
Log.e(TAG, "Mount service is null, can't unmount");
}
} catch (RemoteException ex) {
// Not much can be done
}
}
Any workaround to get it working.As it throws Security Exception.android.permission.mount_unmount_filesystems requires.I have decleared this in manifest.I have google about this issue i found that the permission have system|signature protection level.Thanks in advance.
In order to use something with signature | system permissions your package has to be signed by the platform's signing key. Unless you're creating your own custom ROM or have a rooted device, you won't be able to do this.
If your app is a regular 3rd party app (released in the Play store) then you should only use the public APIs and not depend on reflection. Only the public Android APIs are considered stable and exposed. Others are hidden because they are only intended to be used by the internals of the system.