Android: Check whether camera supports auto-focus? - android

For the Android API version 2.1 and higher, we can use context:
getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_AUTOFOCUS)
But before version 2.1, how can we perform the same operation? Is there anything like this that does not involve invoking Camera.open and then getParameters?

List<String> supportedFocusModes = camera.getParameters().getSupportedFocusModes();
boolean hasAutoFocus = supportedFocusModes != null && supportedFocusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)

i'm guessing: Do not use the unknown constant.
getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_AUTOFOCUS)
Should be:
getPackageManager().hasSystemFeature("android.hardware.camera.autofocus")
It was a short sight of the developers to use constants here. It solves the problem of knowing if a device, running an API that knows about a feature has a feature. but fails on the case you just mentioned... they really make supporting multiple api levels difficult.
Updated: just tested it myself... PackageManager.hasSystemFeature() only showed up at API level 5. I was trying to add that check to my code that can very well support API level 3 (1.5) but which could benefit from camera's auto focus...seems like i have to choose support 1.5 or be able to use auto focus... or move my backward compatibility to level 5... or implement this http://www.java.net/forum/topic/java-tools/java-development-tools/wwyt-conditional-compilation-pre-process ...yeah, right.
they really make it difficult to support multiple versions. So sorry 1.5 and 1.6 and 2.0 users. since my device is on 2.2 that will be my bottom line.

private void getSuppourtedFocusedModes(Camera camera)
{
final Camera.Parameters parameters = camera.getParameters();
List<String> supportedFocusModes = parameters.getSupportedFocusModes();
LogUtils.infoMsg("supportedFocusModes " + supportedFocusModes);
for (String mode : supportedFocusModes) {
LogUtils.infoMsg("supportedFocusModes " + mode);
}
}

CameraManager cameraManager = (android.hardware.camera2.CameraManager) getSystemService(CAMERA_SERVICE);
int[] afModes = cameraManager.getCameraCharacteristics("0").get(CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES);
if (afModes.length <= 1)
{Log.d(TAG, "Camera doesn't have autofocus");}
else
{Log.d(TAG, "Camera has autofocus");}
Log.d(TAG, "CONTROL_AF_AVAILABLE_MODES:");
for (int position : afModes) {
switch (afModes[position]) {
case 0:
Log.d(TAG, "CONTROL_AF_MODE_OFF (0)");
break;
case 1:
Log.d(TAG, "CONTROL_AF_MODE_AUTO (1)");
break;
case 2:
Log.d(TAG, "CONTROL_AF_MODE_MACRO (2)");
break;
case 3:
Log.d(TAG, "CONTROL_AF_MODE_CONTINUOUS_VIDEO (3)");
break;
case 4:
Log.d(TAG, "CONTROL_AF_MODE_CONTINUOUS_PICTURE (4)");
break;
case 5:
Log.d(TAG, "CONTROL_AF_MODE_EDOF (5)");
break;
default:
Log.d(TAG, String.valueOf(afModes[position]));
}
}

There are a number of methods of the Camera.Parameters class added in API Level 5 (I believe that maps to Android 2.0) that will return a list of supported features. Call getSupportedFocusModes on the Camera.Parameters object retrieved from camera.getParameters()
http://developer.android.com/reference/android/hardware/Camera.Parameters.html

Related

Unity XR.Settings.LoadDeviceByName() not loading device

I have tried to use XRSettings.LoadDeviceByName() but it never work. I have already check if the parameter device name is same as the current device name but nothing changes. Also, I have added the None in the sdk list
The XRSettings.loadedDeviceName is cardboard when initiating.
IEnumerator testThis() {
if (string.Compare(XRSettings.loadedDeviceName, "", true) != 0) {
XRSettings.LoadDeviceByName("none");
some_text.text = XRSettings.loadedDeviceName;
yield return new WaitForSeconds(1);
XRSettings.enabled = true;
some_text.text = "Device name " + XRSettings.loadedDeviceName;
}
}
IEnumerator temp() {
some_text.text = "Device name " + XRSettings.loadedDeviceName;
yield return new WaitForSeconds(10);
StartCoroutine(testThis());
}
No matter how I detect, the device name is still cardboard.
https://docs.unity3d.com/ScriptReference/XR.XRSettings.LoadDeviceByName.html
What I have done:
Make None as one of the Virtual Reality SDKs
Use XR-Plugin Management
2.1 Disable Virtual Reality Supported
2.2 Convert camera to XR-Rig
2.3 Use the code about turning VR off in XR-Plugin Management
2.4 Remarks: all the procedure in step 2 is work in iOS build but fail in android build.
2.5 https://docs.unity3d.com/Packages/com.unity.xr.management#4.0/manual/index.html
Tried XRSettings.LoadDeviceByName("none"); XRSettings.LoadDeviceByName(""); XRSettings.LoadDeviceByName("None");
Make sure that ''none'' is first in your VR SDK's, Then Cardboard.
I see a problem with your compare, there is no value
if (string.Compare(XRSettings.loadedDeviceName, "", true) != 0) {
If I understand correctly what you want to do, this code down here will receive a device name and will trigger the LoadDevice couroutine with this name.
public void VerifyDeviceName(string newDeviceName)
{
if (newDeviceName == "none")
{
Debug.Log("Will load none device");
StartCoroutine(LoadDevice(newDeviceName));
}
if (newDeviceName == "cardboard")
{
Debug.Log("Will load cardboard device");
StartCoroutine(LoadDevice(newDeviceName));
}
else
{
Debug.Log("Can't find device with name " + newDeviceName);
}
}
IEnumerator LoadDevice(string newDeviceName)
{
XRSettings.LoadDeviceByName(newDeviceName);
yield return new WaitForSeconds(10);
XRSettings.enabled = true;
Debug.Log("Loaded " + newDeviceName);
}
Note; This will obviously not work in editor you wil get a message saying you cannot trigger on/off vr in editor mode.
I just got through this by brute forcing it. The secret is not to Load device by name. If your trying to load "none" you should just initialize and deinitialize your XR loader.
Disable "Initialize XR on Startup" in Project Settings -> XR Plugin Management
In the code use these two methods
IEnumerator StartXR(){
yield return XRGeneralSettings.Instance.Manager.InitializeLoader();
if(XRGeneralSettings.Instance.Manager.activeLoader == null){
Debug.Log("initialization FAILED");
}
else{
XRGeneralSettings.Instance.Manager.activeLoader.Start();
}
}
void StopXR(){
XRGeneralSettings.Instance.Manager.activeLoader.Stop();
XRGeneralSettings.Instance.Manager.activeLoader.Deinitialize();
}
(Sorry I am terrable at code snippits! I'm new to answering)
Then call these as you need them. It should turn on and turn off XR in your project

Scan QRcode with inverted colors using Vision API

After struggling a few hours on making my app detect this QRCode:
I realized that the problem was the in the QRCode appearance. After inverting the colors, the detection was working perfectly..
Is there a way to make Vision API detect the first QRCode? I tried to enable all symbologies but it did not work. I guess it is possible because the app QR Code Reader detects it.
I improved googles example app "barcode-reader" to detect both inverted colored barcodes and regular ones.
here is a link to googles example app:
https://github.com/googlesamples/android-vision/tree/master/visionSamples/barcode-reader
I did so by editing "CameraSource" class,
package: "com.google.android.gms.samples.vision.barcodereader.ui.camera".
I added a parameter: private boolean isInverted = false;
and changed function void setNextFrame(byte[] data, Camera camera):
void setNextFrame(byte[] data, Camera camera) {
synchronized (mLock) {
if (mPendingFrameData != null) {
camera.addCallbackBuffer(mPendingFrameData.array());
mPendingFrameData = null;
}
if (!mBytesToByteBuffer.containsKey(data)) {
Log.d(TAG,
"Skipping frame. Could not find ByteBuffer associated with the image " +
"data from the camera.");
return;
}
mPendingTimeMillis = SystemClock.elapsedRealtime() - mStartTimeMillis;
mPendingFrameId++;
if (!isInverted){
for (int y = 0; y < data.length; y++) {
data[y] = (byte) ~data[y];
}
isInverted = true;
} else {
isInverted = false;
}
mPendingFrameData = mBytesToByteBuffer.get(data);
// Notify the processor thread if it is waiting on the next frame (see below).
mLock.notifyAll();
}
}
I think this is still an open issue, please see link for details. One workaround for this as stated by a developer:
Right, the barcode API generally doesn't support color-inverted codes. There's no parameter or option to control this at the moment. Though some APIs support them, I don't believe it's a common feature.
For a workaround, you could preprocess the colors in the bitmap before passing them to the barcode API (perhaps inverting colors on alternate frames).
Hope this helps.

Removing a usb camera from my Android device does not refresh the list

I have this function that I call every 5 seconds:
#NonNull
private ArrayList<LmiVideoCapturerDeviceInfo> getNumberOfCameras() {
ArrayList<LmiVideoCapturerDeviceInfo> newDevices= new ArrayList<>();
int numberOfCameras = Camera.getNumberOfCameras();
Log.i("Refresh devices"," lookForDevicesChangesRunnable refresh devices size is!!!!!!!!!!!!!!!!!!!!!!!!!!!: " + numberOfCameras);
for (int i = 0; i < numberOfCameras; i++) {
Camera.CameraInfo info = new Camera.CameraInfo();
Camera.getCameraInfo(i, info);
Log.i("Refresh devices", "camera ids are: " + info.toString());
String facing = "BACK";
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
facing = "FRONT";
}
newDevices.add(new LmiVideoCapturerDeviceInfo("Camera " + i, Integer.toString(i), "Camera" + i, facing));
}
return newDevices;
}
Now I for example at the beginning have 0 cameras, I add a camera in the usb plug, and it will update, and this will return 1, and it will refresh my list.
BUT If I have 1 camera connected, and I remove it, this function will still return 1, for a long time, even though the camera is not there anymore, and if I try to open it, in the app nothing happens, just get the last frame (from when I removed it). Why isn't my list being updated sooner?
PS: the tv box set I'm using is Android 4.4.2 , so I cannot use Camera2 API, hence why I'm using the CameraAPI
There's no built-in support for webcams in Android, so the manufacturer of your device must have added it.
Unfortunately, since there's no built-in support, it's fairly easy for there to be scenarios that don't work correctly. You're likely hitting one of those. You can try to report the problem to the manufacturer, but whether that'll get the issue resolved anytime soon is hard to say.

Android: PackageManager.getSystemAvailableFeatures() is not working as expected on Nexus9

I am trying to get all the available system features on my Nexus9 device using PackageManager.getSystemAvailableFeatures().
From Android 5.0 Lollipop, Google introduced new camera APIs (camera2). I think Nexus9 is using Camera2 APIs.
When I am running this API on Nexus9 device it is not listing camera2 APIs features like:
android.hardware.camera.level.full
android.hardware.camera.capability.manual_post_processing
android.hardware.camera.capability.manual_sensor
android.hardware.camera.capability.raw
I am using below code to get all the available features:
public final static boolean isFeatureAvailable(Context context, String feature) {
final PackageManager packageManager = context.getPackageManager();
final FeatureInfo[] featuresList = packageManager.getSystemAvailableFeatures();
for (FeatureInfo f : featuresList) {
if (f.name != null && f.name.equals(feature)) {
return true;
}
}
return false;
}
Questions:
Is Nexus9 using & having camera2 API features?
If answer is yes for above question, then Why it is not listing these system level features? I am doing something wrong?
Thanks for your comments in advance!
Is Nexus9 using & having camera2 API features?
Yes. All Android Lollipop devices and newer have the camera2 APIs.
If answer is yes for above question, then Why it is not listing these system level features?
Supported APIs are usually not included in the system features list. Most system features are related to things that can vary from device to device and are usually related to hardware features (e.g. sensors, bluetooth, NFC, etc) or system-wide software support (e.g. backup, device management, multi-user, etc). There's a list of all supported capabilities here.
I am doing something wrong?
According to the docs, the recommended way to check if the camera2 APIs exist is by requesting the camera service via:
CameraManager cameraManager = (CameraManager) getSystemService("camera");
Basically this method returns null if the camera2 APIs aren't available, either because the version of Android is too old (sdkVersion < 21) or because they've been removed from the system (e.g. via a custom ROM).
Finally I was able to get answers to my questions.
Is Nexus9 using & having camera2 API features?
Ans: Yes Nexus9 is having and using Camera2 APIs. It has LIMITED supported hardware level and has capabilities: BACKWARD_COMPATIBLE and MANUAL_SENSOR
If answer is yes for above question, then Why it is not listing these system level features? I am doing something wrong?
Ans: Because using above code I am listing features not capabilities. To list down the capabilities I used below code:
Activity activity = getActivity();
CameraManager manager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);
try {
for (String cameraId : manager.getCameraIdList()) {
CameraCharacteristics characteristics
= manager.getCameraCharacteristics(cameraId);
if (characteristics.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL) == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_FULL) {
Log.d("Camera2 SUPPORTED_HARDWARE_LEVEL: ", "FULL");
} else if (characteristics.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL) == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY) {
Log.d("Camera2 SUPPORTED_HARDWARE_LEVEL: ", "LEGACY");
} else if(characteristics.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL) == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED) {
Log.d("Camera2 SUPPORTED_HARDWARE_LEVEL: ", "LIMITED");
}
StringBuilder stringBuilder = new StringBuilder();
for (int i=0; i<characteristics.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES).length; i++) {
if(characteristics.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES)[i] ==CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE) {
stringBuilder.append("BACKWARD_COMPATIBLE" + " ");
} else if (characteristics.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES)[i] ==CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING) {
stringBuilder.append("MANUAL_POST_PROCESSING" + " ");
} else if(characteristics.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES)[i] ==CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR) {
stringBuilder.append("MANUAL_SENSOR" + " ");
} else if (characteristics.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES)[i] ==CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_RAW) {
stringBuilder.append("RAW" + " ");
}
}
Log.d("Camera2: ", stringBuilder.toString());

Retrieving Android API version programmatically

Is there any way to get the API version that the phone is currently running?
As described in the Android documentation, the SDK level (integer) the phone is running is available in:
android.os.Build.VERSION.SDK_INT
The class corresponding to this int is in the android.os.Build.VERSION_CODES class.
Code example:
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP){
// Do something for lollipop and above versions
} else{
// do something for phones running an SDK before lollipop
}
Edit: This SDK_INT is available since Donut (android 1.6 / API4) so make sure your application is not retro-compatible with Cupcake (android 1.5 / API3) when you use it or your application will crash (thanks to Programmer Bruce for the precision).
Corresponding android documentation is here and here
Very easy:
String manufacturer = Build.MANUFACTURER;
String model = Build.MODEL;
int version = Build.VERSION.SDK_INT;
String versionRelease = Build.VERSION.RELEASE;
Log.e("MyActivity", "manufacturer " + manufacturer
+ " \n model " + model
+ " \n version " + version
+ " \n versionRelease " + versionRelease
);
Output:
E/MyActivity: manufacturer ManufacturerX
model SM-T310
version 19
versionRelease 4.4.2
Build.VERSION.RELEASE;
That will give you the actual numbers of your version; aka 2.3.3 or 2.2.
The problem with using Build.VERSION.SDK_INT is if you have a rooted phone or custom rom, you could have a non standard OS (aka my android is running 2.3.5) and that will return a null when using Build.VERSION.SDK_INT so Build.VERSION.RELEASE will work no matter using standard Android version or not !
To use it, you could just do this;
String androidOS = Build.VERSION.RELEASE;
try this:
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.GINGERBREAD) {
// only for gingerbread and newer versions
}
Taking into account all said, here is the code I use for detecting if device has Froyo or newer Android OS (2.2+):
public static boolean froyoOrNewer() {
// SDK_INT is introduced in 1.6 (API Level 4) so code referencing that would fail
// Also we can't use SDK_INT since some modified ROMs play around with this value, RELEASE is most versatile variable
if (android.os.Build.VERSION.RELEASE.startsWith("1.") ||
android.os.Build.VERSION.RELEASE.startsWith("2.0") ||
android.os.Build.VERSION.RELEASE.startsWith("2.1"))
return false;
return true;
}
Obviously, you can modify that if condition to take into account 1.0 & 1.5 versions of Android in case you need generic checker. You will probably end up with something like this:
// returns true if current Android OS on device is >= verCode
public static boolean androidMinimum(int verCode) {
if (android.os.Build.VERSION.RELEASE.startsWith("1.0"))
return verCode == 1;
else if (android.os.Build.VERSION.RELEASE.startsWith("1.1")) {
return verCode <= 2;
} else if (android.os.Build.VERSION.RELEASE.startsWith("1.5")) {
return verCode <= 3;
} else {
return android.os.Build.VERSION.SDK_INT >= verCode;
}
}
Let me know if code is not working for you.
android.os.Build.VERSION.SDK should give you the value of the API Level. You can easily find the mapping from api level to android version in the android documentation. I believe, 8 is for 2.2, 7 for 2.1, and so on.
SDK.INT is supported for Android 1.6 and up
SDK is supported for all versions
So I do:
String sdk_version_number = android.os.Build.VERSION.SDK;
Credits to: CommonsWare over this answer
Got it. Its using the getApplicationInfo() method of the Context class.
I generally prefer to add these codes in a function to get the Android version:
int whichAndroidVersion;
whichAndroidVersion= Build.VERSION.SDK_INT;
textView.setText("" + whichAndroidVersion); //If you don't use "" then app crashes.
For example, that code above will set the text into my textView as "29" now.
i prefer have the version as number to be handeled more easyway than i wrote this:
public static float getAPIVerison() {
Float f = null;
try {
StringBuilder strBuild = new StringBuilder();
strBuild.append(android.os.Build.VERSION.RELEASE.substring(0, 2));
f = new Float(strBuild.toString());
} catch (NumberFormatException e) {
Log.e("", "error retriving api version" + e.getMessage());
}
return f.floatValue();
}
I improved code i used
public static float getAPIVerison() {
float f=1f;
try {
StringBuilder strBuild = new StringBuilder();
strBuild.append(android.os.Build.VERSION.RELEASE.substring(0, 2));
f= Float.valueOf(strBuild.toString());
} catch (NumberFormatException e) {
Log.e("myApp", "error retriving api version" + e.getMessage());
}
return f;
}
Like this:
String versionRelease = BuildConfig.VERSION_NAME;
versionRelease :- 2.1.17
Please make sure your import package is correct ( import package your_application_package_name, otherwise it will not work properly).

Categories

Resources