I am beginner in android developing and I am trying to make a camera app. The camera app is opening but camera hardware is not detecting this is the code of main activity code. Now what am I missing to added to detect camera hardware please describe it and help me to solve it
public class CamTestActivity extends Activity {
private static final String TAG = "CamTestActivity";
Preview preview;
Button buttonClick;
Camera camera;
Activity act;
Context ctx;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ctx = this;
act = this;
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.main);
preview = new Preview(this, (SurfaceView)findViewById(R.id.surfaceView));
preview.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
((FrameLayout) findViewById(R.id.layout)).addView(preview);
preview.setKeepScreenOn(true);
preview.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
camera.takePicture(shutterCallback, rawCallback, jpegCallback);
}
});
Toast.makeText(ctx, getString(R.string.take_photo_help), Toast.LENGTH_LONG).show();
buttonClick = (Button) findViewById(R.id.btnCapture);
buttonClick.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
try {
preview.mCamera.takePicture(shutterCallback, rawCallback, jpegCallback);
camera.takePicture(shutterCallback, rawCallback, jpegCallback);
}catch (Exception e)
{
Toast.makeText(ctx, getString(R.string.camera_not_found), Toast.LENGTH_LONG).show();
}
}
});
buttonClick.setOnLongClickListener(new OnLongClickListener(){
#Override
public boolean onLongClick(View arg0) {
camera.autoFocus(new Camera.AutoFocusCallback(){
#Override
public void onAutoFocus(boolean arg0, Camera arg1) {
//camera.takePicture(shutterCallback, rawCallback, jpegCallback);
}
});
return true;
}
});
}
#Override
protected void onResume() {
super.onResume();
int numCams = Camera.getNumberOfCameras();
if(numCams > 0){
try{
camera = Camera.open(1);
camera.startPreview();
preview.setCamera(camera);
} catch (RuntimeException ex){
Toast.makeText(ctx, getString(R.string.camera_not_found), Toast.LENGTH_LONG).show();
}
}
}
#Override
protected void onPause() {
if(camera != null) {
camera.stopPreview();
preview.setCamera(null);
camera.release();
camera = null;
}
super.onPause();
}
private void resetCam() {
camera.startPreview();
preview.setCamera(camera);
}
private void refreshGallery(File file) {
Intent mediaScanIntent = new Intent( Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
mediaScanIntent.setData(Uri.fromFile(file));
sendBroadcast(mediaScanIntent);
}
ShutterCallback shutterCallback = new ShutterCallback() {
public void onShutter() {
// Log.d(TAG, "onShutter'd");
}
};
PictureCallback rawCallback = new PictureCallback() {
public void onPictureTaken(byte[] data, Camera camera) {
// Log.d(TAG, "onPictureTaken - raw");
}
};
PictureCallback jpegCallback = new PictureCallback() {
public void onPictureTaken(byte[] data, Camera camera) {
new SaveImageTask().execute(data);
resetCam();
Log.d(TAG, "onPictureTaken - jpeg");
}
};
private class SaveImageTask extends AsyncTask<byte[], Void, Void> {
#Override
protected Void doInBackground(byte[]... data) {
FileOutputStream outStream = null;
// Write to SD Card
try {
File sdCard = Environment.getExternalStorageDirectory();
File dir = new File (sdCard.getAbsolutePath() + "/camtest");
dir.mkdirs();
String fileName = String.format("%d.jpg", System.currentTimeMillis());
File outFile = new File(dir, fileName);
outStream = new FileOutputStream(outFile);
outStream.write(data[0]);
outStream.flush();
outStream.close();
Log.d(TAG, "onPictureTaken - wrote bytes: " + data.length + " to " + outFile.getAbsolutePath());
refreshGallery(outFile);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
}
return null;
}
}
}
this is the manifest code
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.niit.cameraapp">
<uses-sdk android:minSdkVersion="9" />
<uses-feature android:name="android.hardware.camera" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.hardware.camera.autofocus" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name" >
<activity
android:label="#string/app_name"
android:name=".CamTestActivity"
android:screenOrientation="portrait" >
<intent-filter >
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
this is the logcat error
04-26 12:20:13.694 9167-9167/com.example.niit.cameraapp I/zygote64: Late-enabling -Xcheck:jni
04-26 12:20:13.969 9167-9167/com.example.niit.cameraapp I/InstantRun: starting instant run server: is main process
04-26 12:20:14.142 9167-9167/com.example.niit.cameraapp W/.niit.cameraapp: type=1400 audit(0.0:84362): avc: denied { read } for name="u:object_r:camera_prop:s0" dev="tmpfs" ino=6271 scontext=u:r:untrusted_app:s0:c512,c768 tcontext=u:object_r:camera_prop:s0 tclass=file permissive=0
04-26 12:20:14.149 9167-9167/com.example.niit.cameraapp E/libc: Access denied finding property "camera.hal1.packagelist"
04-26 12:20:14.152 9167-9167/com.example.niit.cameraapp W/CameraBase: An error occurred while connecting to camera 1: Status(-8): '1: validateClientPermissionsLocked:920: Caller "com.example.niit.cameraapp" (PID 10190, UID 9167) cannot open camera "1" without camera permission'
04-26 12:20:14.181 9167-9330/com.example.niit.cameraapp D/OpenGLRenderer: HWUI GL Pipeline
04-26 12:20:14.233 9167-9330/com.example.niit.cameraapp I/Adreno: QUALCOMM build : 7f08991, I8a9bdcf8d3
04-26 12:20:14.236 9167-9330/com.example.niit.cameraapp I/vndksupport: sphal namespace is not configured for this process. Loading /vendor/lib64/hw/gralloc.msm8953.so from the current namespace instead.
04-26 12:20:14.232 9167-9167/com.example.niit.cameraapp W/RenderThread: type=1400 audit(0.0:84363): avc: denied { search } for name="proc" dev="debugfs" ino=5174 scontext=u:r:untrusted_app:s0:c512,c768 tcontext=u:object_r:qti_debugfs:s0 tclass=dir permissive=0
04-26 12:20:14.244 9167-9330/com.example.niit.cameraapp I/Adreno: PFP: 0x005ff087, ME: 0x005ff063
04-26 12:20:14.249 9167-9330/com.example.niit.cameraapp I/OpenGLRenderer: Initialized EGL, version 1.4
04-26 12:20:14.249 9167-9330/com.example.niit.cameraapp D/OpenGLRenderer: Swap behavior 2
04-26 12:20:14.309 9167-9330/com.example.niit.cameraapp I/vndksupport: sphal namespace is not configured for this process. Loading /vendor/lib64/hw/gralloc.msm8953.so from the current namespace instead.
04-26 12:20:17.316 9167-9202/com.example.niit.cameraapp I/zygote64: Debugger is no longer active
screenshot of the deployed app
The issue is most likely that, while you have asked for the Camera permission in the manifest, you also need to ask at runtime. The reason is that in older versions of Android (I think < Android 6.0), you only needed to declare permissions in the manifest. However, now the user can turn permissions on and off after the app has been installed. So now you are supposed to check during runtime whether you have permission for the feature you require. If you don't have it, then you should ask the user to enable it.
You can find code for this online. But first we need to verify that that is indeed the problem. The simplest way of doing that is by going to your Android Settings app. Then in there, there should be an Apps options. Find your app and click on it. In there, there should be a section with the Permissions. If the camera permission is not checked there, then check it and rerun your app.
If this fixes your issue, then you need to find code to ask the user to grant you the permission after the app opens. One such way of doing this is simply on the splash screen, as demonstrated here.
I assume you are running the app on a device with Android 6 or higher. So, you should additionally check for the runtime permissions to use the camera:
https://developer.android.com/training/permissions/requesting
If you don't add this permission check, Android will block the access to the camera hardware. It will also block hardware detection, because it requires also the camera permission. So, everytime you make a call on camera it will fail with a permission denied exception, which is logged in you logcat:
04-26 12:20:14.152 9167-9167/com.example.niit.cameraapp W/CameraBase: An error occurred while connecting to camera 1: Status(-8): '1: validateClientPermissionsLocked:920: Caller "com.example.niit.cameraapp" (PID 10190, UID 9167) cannot open camera "1" without camera permission'
Additionally, it seems you are using the deprecated camera api instead of the camera2 api:
https://developer.android.com/reference/android/hardware/camera2/package-summary
Related
I am creating an Unity app which will be controlling Numato GPIO USB powered controller through smartphone USB connection. Since I have to connect the controller to phone I have no debug log so I have no idea what is going on. Thus, I include plugin code and a custom manifest which I use in Unity.
I get questioned by the App if I want to grant permission to control the device (Shows right device name etc) and after I grant the permission app crashes immediately.
Is there a way to check what causes the error? Or maybe I don't see something obvious here.
public class PluginInstance extends Activity {
private static Activity unityActivity;
private static Context unityContext;
public Gpio laser1;
public static void receiveUnityActivity(Activity tActivity) {
unityActivity = tActivity;
}
public static void receiveUnityContext(Context tContext) { unityContext = tContext; }
//Debugging purposes
public void Toast(String msg) {
Toast.makeText(unityActivity, msg, Toast.LENGTH_SHORT).show();
}
//Action Usb Permission
public static final String ACTION_USB_PERMISSION = "com.unity3d.player.UnityPlayerActivity.USB_PERMISSION";
public DevicesManager mDevicesManager;
//USB permission
public final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (ACTION_USB_PERMISSION.equals(action)) {
synchronized (this) {
UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
if (device != null) {
Bundle deviceIndexBundle = intent.getExtras();
if (deviceIndexBundle == null) {
return;
}
int deviceIndex = deviceIndexBundle.getInt(AppConstant.EXTRA_DEVICE_INDEX);
Toast.makeText(unityActivity, "Usb permission granted", Toast.LENGTH_SHORT).show();
}
} else {
Toast.makeText(unityActivity, "Usb permission declined", Toast.LENGTH_SHORT).show();
}
unregisterReceiver(mUsbReceiver);
}
}
}
};
public void InstantiateManager() {
mDevicesManager = DevicesManager.getInstance();
}
public void GetGpios() {
NumatoUSBDevice numatoUSBDevice = mDevicesManager.getDevices().get(0);
Gpio lazer1 = numatoUSBDevice.mGpios.get(1);
}
public void GpioOn() {
laser1.setCurrentOutputState(true);
laser1.setState(true);
}
public void GpioOff() {
laser1.setCurrentOutputState(false);
laser1.setState(false);
}
public void EnumerateDevices() {
UsbManager manager = (UsbManager) unityActivity.getSystemService(Context.USB_SERVICE);
int index = 0;
ArrayList<UsbDevice> cdcAcmDevices = CdcAcmDriver.ListDevices(manager);
mDevicesManager.clearDevices();
ArrayList<Integer> supportedDevices = NumatoUSBDevice.GetSupportedProductIds();
if(!cdcAcmDevices.isEmpty()){
for (UsbDevice cdcAcmDevice : cdcAcmDevices){
int vendorId = cdcAcmDevice.getVendorId();
if(vendorId == NumatoUSBDevice.VID_NUMATOLAB && supportedDevices.contains(cdcAcmDevice.getProductId())){
mDevicesManager.addDevice(new NumatoUSBDevice(index, cdcAcmDevice, manager));
index++;
}
}
}
}
public void MakeConnection() {
NumatoUSBDevice numatoUSBDevice = mDevicesManager.getDevices().get(0);
UsbManager manager = (UsbManager) unityActivity.getSystemService(Context.USB_SERVICE);
//TODO unityContext in mPermissionIntent
PendingIntent mPermissionIntent = PendingIntent.getBroadcast(unityContext, 0,
new Intent(ACTION_USB_PERMISSION).putExtra(AppConstant.EXTRA_DEVICE_INDEX, 0), 0);
IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
unityActivity.registerReceiver(mUsbReceiver, filter);
manager.requestPermission(numatoUSBDevice.getDevice(), mPermissionIntent);
}
}
And the manifest file:
<?xml version="1.0" encoding="utf-8"?>
<!-- GENERATED BY UNITY. REMOVE THIS COMMENT TO PREVENT OVERWRITING WHEN EXPORTING AGAIN-->
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.unity3d.player"
xmlns:tools="http://schemas.android.com/tools">
<application>
<activity android:name="com.unity3d.player.UnityPlayerActivity"
android:theme="#style/UnityThemeSelector">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"/>
</intent-filter>
<meta-data
android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
android:resource="#xml/device_filter"/>
</activity>
</application>
</manifest>
Edit: I managed to access debug log through wifi and this is what I get:
FATAL EXCEPTION: main
Process: com.jonquil.A2NumatoController, PID: 16837
java.lang.RuntimeException: Error receiving broadcast Intent { act=com.unity3d.player.UnityPlayerActivity.USB_PERMISSION flg=0x10 (has extras) } in com.jonquil.unityplugin.PluginInstance$1#7d45921
at android.app.LoadedApk$ReceiverDispatcher$Args.lambda$getRunnable$0$LoadedApk$ReceiverDispatcher$Args(LoadedApk.java:1689)
at android.app.LoadedApk$ReceiverDispatcher$Args$$ExternalSyntheticLambda0.run(Unknown Source:2)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loopOnce(Looper.java:201)
at android.os.Looper.loop(Looper.java:288)
at android.app.ActivityThread.main(ActivityThread.java:7838)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.content.Context.unregisterReceiver(android.content.BroadcastReceiver)' on a null object reference
at android.content.ContextWrapper.unregisterReceiver(ContextWrapper.java:769)
at com.jonquil.unityplugin.PluginInstance$1.onReceive(PluginInstance.java:63)
at android.app.LoadedApk$ReceiverDispatcher$Args.lambda$getRunnable$0$LoadedApk$ReceiverDispatcher$Args(LoadedApk.java:1679)
... 9 more
This looks like there is a problem with broadcast receiver since error is caused by invoking method on a null object reference.
I have the following in my manifest
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<uses-permission android:name="android.permission.CAMERA" />
however I receive this error
An error occurred while connecting to camera 0: Status(-8, EX_SERVICE_SPECIFIC): '1: validateClientPermissionsLocked:1165: Caller ... (PID 10153, UID 6049) cannot open camera "0" without camera permission'
I am attempting to get a camera working using this code
public static Camera getCameraInstance(){
Camera c = null;
try {
c = Camera.open();
} catch (Exception e) {
Log.e("getCameraInstance", "exception", e);
}
return c; // returns null if camera is unavailable
}
How do I get this camera working?
Need to enable permissions at runtime. The above error is outputted when the 0 indexed camera does not have permissions. Adding permissions to the manifest is not what enables it on the phone... the below code will.
public static void checkCameraPermissions(Context context){
if (ContextCompat.checkSelfPermission(context, Manifest.permission.CAMERA)
!= PackageManager.PERMISSION_GRANTED)
{
// Permission is not granted
Log.d("checkCameraPermissions", "No Camera Permissions");
ActivityCompat.requestPermissions((Activity) context,
new String[] { Manifest.permission.CAMERA },
100);
}
}
I was trying to download an image from a server and save it in the external memory, but in Android 11 it gives me an error when I try to create the file.
I have granted permission to access the external storage.
i searched a bit on the internet and they suggested me to put this code in the manifest, but it didn't work for android 11
android:requestLegacyExternalStorage="true"
manifest
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:requestLegacyExternalStorage="true"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/Theme.TestDwonloadImgApp"
android:usesCleartextTraffic="true">
<activity android:name=".MainActivity2">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".MainActivity">
</activity>
</application>
MainActivity
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ImageView img = findViewById(R.id.img);
ImmagineInterface ii = RetrofitManager.retrofit.create(ImmagineInterface.class);
Call<ResponseBody> call = ii.downloadFile("/immaginimusei/arte-scienza.jpg");
call.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
if (response.code() == 200) {
boolean result = writeResponseBody(response.body(), "/immaginimusei/arte-scienza.jpg");
if(result) {
Bitmap bitmap = BitmapFactory.decodeFile(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).toString() + "/ArtHunter/immaginimusei/arte-scienza.jpg");
img.setImageBitmap(bitmap);
}
}
}
#Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Bitmap bitmap = BitmapFactory.decodeFile(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).toString() + "/ArtHunter/immaginimusei/arte-scienza.jpg");
img.setImageBitmap(bitmap);
}
});
}
}
writeResponseBody
public static boolean writeResponseBody(ResponseBody body, String dir1) {
try {
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)) {
// todo change the file location/name according to your needs
String path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).toString() + "/ArtHunter";
String path1 = path + dir1;
File f = new File(path1);
String path2 = f.getPath();
String nome = f.getName();
path2 = path2.replaceAll("/" + nome, "");
File directory = new File(path2);
if (!directory.exists())
directory.mkdirs();
File img = new File(path2, nome);
if (img.exists())
return true;
img.createNewFile();
InputStream inputStream = null;
FileOutputStream outputStream = null;
try {
byte[] fileReader = new byte[4096];
inputStream = body.byteStream();
outputStream = new FileOutputStream(img); //error here!
while (true) {
int read = inputStream.read(fileReader);
if (read == -1) {
break;
}
outputStream.write(fileReader, 0, read);
}
outputStream.flush();
return true;
} catch (IOException e) {
e.printStackTrace();
return false;
} finally {
if (inputStream != null) {
inputStream.close();
}
if (outputStream != null) {
outputStream.close();
}
}
}
return false;
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
error
/System.err: java.io.FileNotFoundException: /storage/emulated/0/Download/ArtHunter/immaginimusei/arte-scienza.jpg: open failed: EEXIST (File exists)
W/System.err: at libcore.io.IoBridge.open(IoBridge.java:492)
at java.io.FileOutputStream.<init>(FileOutputStream.java:236)
at java.io.FileOutputStream.<init>(FileOutputStream.java:186)
at com.theapplegeek.testdwonloadimgapp.MainActivity.writeResponseBody(MainActivity.java:93)
at com.theapplegeek.testdwonloadimgapp.MainActivity$1.onResponse(MainActivity.java:47)
at retrofit2.DefaultCallAdapterFactory$ExecutorCallbackCall$1.lambda$onResponse$0$DefaultCallAdapterFactory$ExecutorCallbackCall$1(DefaultCallAdapterFactory.java:89)
at retrofit2.-$$Lambda$DefaultCallAdapterFactory$ExecutorCallbackCall$1$hVGjmafRi6VitDIrPNdoFizVAdk.run(Unknown Source:6)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:245)
at android.app.ActivityThread.main(ActivityThread.java:8004)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:631)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:978)
Caused by: android.system.ErrnoException: open failed: EEXIST (File exists)
at libcore.io.Linux.open(Native Method)
at libcore.io.ForwardingOs.open(ForwardingOs.java:166)
at libcore.io.BlockGuardOs.open(BlockGuardOs.java:254)
W/System.err: at libcore.io.ForwardingOs.open(ForwardingOs.java:166)
at android.app.ActivityThread$AndroidOs.open(ActivityThread.java:7865)
at libcore.io.IoBridge.open(IoBridge.java:478)
... 13 more
In Android 11 android:requestLegacyExternalStorage="true" will simply be ignored, since it was an ad-hoc solution for Android < 11 to not break old apps.
Now, you must use
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
Also you could just use SAF to avoid all this 'permissions' hassle. This is what Google recommends for apps that do not need to manage most internal storage data. Refer to:
https://developer.android.com/guide/topics/providers/document-provider
However, if you don't want to break you app and lose all your hard work, consider
if(Environment.isExternalStorageManager())
{
internal = new File("/sdcard");
internalContents = internal.listFiles();
}
else
{
Intent permissionIntent = new Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION);
startActivity(permissionIntent);
}
This will bring up a settings page where you will be able to give storage access to your app. If the app already has permission, then you will be able to access the directory. Place this at the very beginning of onCreate() method after setting layout resource.
It's best not to do this for any future apps you build.
Go to your mobile setting -> apps -> select your app -> permissions -> storage -> select Allow managment of all files
It works for me.
Android has become too complex when it comes to creating folders.
If you want to avoid so many problems and not use things like android:requestLegacyExternalStorage="true" and adding many permissions like MANAGE_EXTERNAL_STORAGE, READ_EXTERNAL_STORAGE, WRITE_EXTERNAL_STORAGE which can be a nightmare, even when it comes to publishing your app to the marketplace.
In addition to that, from Android version 30 onwards, you ca NOT extend android:requestLegacyExternalStorage="true". So you will have problems again.
What is recommended is to start to save your recordings inside applications dedicated folder, because in the future Android will no longer let you create folders anymore, even with legacy methods. You can use standard directories in which to place any file like DIRECTORY_MUSIC, DIRECTORY_PICTURES, etc.
For instance, I created my own method for saving audio recording in Android 33 and it works perfectly. I don't need to add anything to my Manifest.
override fun startRecording(): Boolean {
try {
val recordingStoragePath = "${app.getExternalFilesDir(Environment.DIRECTORY_MUSIC)}"
recordingFilePath = "$recordingStoragePath/${fileRecordingUtils.generateFileName()}"
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC)
mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP)
// Audio Quality Normal
mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB)
mediaRecorder.setAudioSamplingRate(8000)
// Set path
mediaRecorder.setOutputFile(recordingFilePath)
mediaRecorder.prepare()
mediaRecorder.start()
Toast.makeText(app, "Recording Started", Toast.LENGTH_SHORT).show()
} catch (e: IOException) {
Toast.makeText(app, "Recording Failed. Problem accessing storage.", Toast.LENGTH_SHORT).show()
mediaRecorder.reset()
return false
} catch (e: Exception) {
mediaRecorder.reset()
return false
}
return true
}
The following code throws a runtime exception when trying to start a camera with deprecated Camera API for android:
E/MediaRecorder: start failed: -19
E/AndroidRuntime: FATAL EXCEPTION: IntentService[RecordIntentService]
Process: com.example.songtry2, PID: 15956
java.lang.RuntimeException: start failed.
at android.media.MediaRecorder._start(Native Method)
at android.media.MediaRecorder.start(MediaRecorder.java:1348)
at com.example.songtry2.RecordIntentService.prepareVideoRecorder(RecordIntentService.java:259)
at com.example.songtry2.RecordIntentService.handleActionRecord(RecordIntentService.java:149)
at com.example.songtry2.RecordIntentService.onHandleIntent(RecordIntentService.java:119)
at android.app.IntentService$ServiceHandler.handleMessage(IntentService.java:76)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:214)
at android.os.HandlerThread.run(HandlerThread.java:65)
D/ViewRootImpl#1099d2e[MainActivity]: dispatchDetachedFromWindow
I/Process: Sending signal. PID: 15956 SIG: 9
Disconnected from the target VM, address: 'localhost:8603', transport: 'socket'
I really tried using the new camera2 API, but had no luck with it...
The service I am trying to create should open the camera in a service and record video in the background until the camera should be closed.
Manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.songtry2">
<uses-permission android:name="android.permission.RECORD_AUDIO"></uses-permission>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
<uses-permission android:name="android.permission.CAMERA"/>
<uses-feature android:name="android.hardware.camera.front" android:required="false" />
<uses-feature android:name="android.hardware.camera" android:required="false" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<service
android:name=".RecordIntentService"
android:exported="false">
</service>
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
The code which the MainActivity uses in order to open the camera:
package com.example.songtry2;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import android.Manifest;
import android.app.IntentService;
import android.app.Service;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
0);
} else {
Toast.makeText(this, "wow storage", Toast.LENGTH_SHORT).show();
Log.d("camera","camera");
}
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.RECORD_AUDIO},
0);
} else {
Toast.makeText(this, "Camera on! Cool!!!", Toast.LENGTH_SHORT).show();
Log.d("camera","camera");
}
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA},
0);
}
RecordIntentService.startActionRecord(this);
}
}
'getCameraInstance' function used in order to search for a front-facing camera and open it for use:
public static Camera getCameraInstance(){
int cameraCount = 0;
Camera cam = null;
Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
cameraCount = Camera.getNumberOfCameras();
for (int camIdx = 0; camIdx < cameraCount; camIdx++) {
Camera.getCameraInfo(camIdx, cameraInfo);
if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
try {
cam = Camera.open(camIdx);
} catch (RuntimeException e) {
Log.e(TAG, "Camera failed to open: " + e.getLocalizedMessage());
}
}
}
return cam;
}
The function which uses the camera in the Recording Service code:
private boolean prepareVideoRecorder(){
mCamera = getCameraInstance();
recorder = new MediaRecorder();
recorder.reset();
//recorder.setCamera(Camera.Face);
// Step 1: Unlock and set camera to MediaRecorder
mCamera.unlock();
recorder.setCamera(mCamera);
// Step 2: Set sources
recorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
recorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
// Step 3: Set a CamcorderProfile (requires API Level 8 or higher)
//recorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH));
CamcorderProfile profile = CamcorderProfile.get(Camera.CameraInfo.CAMERA_FACING_FRONT,CamcorderProfile.QUALITY_LOW);
recorder.setProfile(profile);
// Step 4: Set output file
recorder.setOutputFile(getOutputMediaFile(MEDIA_TYPE_VIDEO).toString());
// Step 6: Prepare configured MediaRecorder
try {
recorder.prepare();
recorder.start();
} catch (IllegalStateException e) {
Log.d(TAG, "IllegalStateException preparing MediaRecorder: " + e.getMessage());
System.out.println("ERROR" + e.getMessage());
releaseMediaRecorder();
return false;
} catch (IOException e) {
Log.d(TAG, "IOException preparing MediaRecorder: " + e.getMessage());
releaseMediaRecorder();
return false;
}
return true;
}
private void releaseCamera(){
if (mCamera != null){
mCamera.release(); // release the camera for other applications
mCamera = null;
}
}
I have an android app where I take a photo from camera and then I would like to convert it to the base64 format but I have an error after accepting the taken photo. It seems like I don't have access to the external storage and I think this leads to a null bitmap. THE PERMISSIONS IN THE ANDROID_MANIFEST HAVE BEEN DECLARED. How can I resolve the permission problem and what may lead to a null bitmap?
here is my code:
public class MainActivity extends AppCompatActivity {
private Button takePhotoButton;
private String encoded_string, image_name;
private Bitmap bitmap;
private File file;
private Uri file_uri;
private String getRealPathFromURI(Uri contentUri) {
String[] proj = { MediaStore.Images.Media.DATA };
CursorLoader loader = new CursorLoader(this, contentUri, proj, null, null, null);
Cursor cursor = loader.loadInBackground();
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
String result = cursor.getString(column_index);
cursor.close();
return result;
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
takePhotoButton = (Button) findViewById(R.id.take_photo);
takePhotoButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent i = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
getFileUri();
i.putExtra(MediaStore.EXTRA_OUTPUT, file_uri);
startActivityForResult(i, 10);
}
});
}
private void getFileUri() {
image_name= "test123.jpg";
file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) + File.separator + image_name);
file_uri = Uri.fromFile(file);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if(requestCode == 10 && resultCode == RESULT_OK){
new Encode_image().execute();
}
}
private class Encode_image extends AsyncTask<Void, Void, Void>{
#Override
protected Void doInBackground(Void... params) {
BitmapFactory.Options options = new BitmapFactory.Options();
int scale = 8;
options.inSampleSize = scale;
options.inJustDecodeBounds = false;
bitmap = BitmapFactory.decodeFile(file_uri.getPath(), options);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 50, stream);
//convert stream to byte array
byte[] array = stream.toByteArray();
encoded_string = Base64.encodeToString(array, 0);
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
makeRequest();
}
}
private void makeRequest() {
RequestQueue requestQueue = Volley.newRequestQueue(this);
StringRequest request = new StringRequest(Request.Method.POST, "http://192.168.1.102/AndroidFileUpload/connection.php",
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
}
}) {
#Override
protected Map<String, String> getParams() throws AuthFailureError {
HashMap<String, String> map = new HashMap<>();
map.put("encoded_string", encoded_string);
map.put("image_name", image_name);
return map;
}
};
requestQueue.add(request);
}
}
I get the error in the line
bitmap.compress(Bitmap.CompressFormat.JPEG, 50, stream)
because the bitmap is null.
The crash after running the app returned this errors/messages:
E/BitmapFactory: Unable to decode stream: java.io.FileNotFoundException: /storage/emulated/0/Pictures/test123.jpg: open failed: EACCES (Permission denied)
E/AndroidRuntime: FATAL EXCEPTION: AsyncTask #1
Process: com.example.andrei.sendphotos, PID: 17972
java.lang.RuntimeException: An error occurred while executing doInBackground()
at android.os.AsyncTask$3.done(AsyncTask.java:309)
at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:354)
at java.util.concurrent.FutureTask.setException(FutureTask.java:223)
at java.util.concurrent.FutureTask.run(FutureTask.java:242)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:234)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
at java.lang.Thread.run(Thread.java:818)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'boolean android.graphics.Bitmap.compress(android.graphics.Bitmap$CompressFormat, int, java.io.OutputStream)' on a null object reference
at com.example.andrei.sendphotos.MainActivity$Encode_image.doInBackground(MainActivity.java:115)
at com.example.andrei.sendphotos.MainActivity$Encode_image.doInBackground(MainActivity.java:92)
at android.os.AsyncTask$2.call(AsyncTask.java:295)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:234)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
at java.lang.Thread.run(Thread.java:818)
E/Surface: getSlotFromBufferLocked: unknown buffer: 0xa23ae0e0
Android Manifest xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.andrei.sendphotos">
<uses-permission android:name="android.permission.INTERNET" />
<uses-feature android:name="android.hardware.camera" android:required="true" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
You need to implement run-time permissions for Android 6.X. Refer the official documentation here: Requesting Runtime Permissions
There are public helper classes available like one of my own here: PermissionHelper.java
Or you could simply downgrade your target SDK version to 22 and all the dependencies too, which I wouldn't recommend.
One of the major changes in Android 6.X was the enforced run-time permission model. Google had to keep backward compatibility for the applications already in the market (which don't check and ask for permissions on run-time).
So they made it work like - if the application targets SDK version 22, all the permissions will be granted to the application on installation. But if an application targets SDK 23, it will not be granted permissions by default, rather the application should check for permissions before performing any task that needs dangerous permissions and ask the user for it if not already granted before continuing the same.