package com.example.cppinandroid;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
import org.opencv.core.Mat;
import java.io.File;
import static org.opencv.imgcodecs.Imgcodecs.CV_LOAD_IMAGE_GRAYSCALE;
import org.opencv.imgcodecs.Imgcodecs;
public class MainActivity extends AppCompatActivity
{
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView tv = findViewById( R.id.sample_text );
Mat image;
image = Imgcodecs.imread( "/home/<myName>/a.png", CV_LOAD_IMAGE_GRAYSCALE);
if ( image.size().height > 0 )
{
tv.setText( "No datfa in image!");
}
else
{
tv.setText( "xxff " + image.size().height);
}
}
}
I am NOT using any drawable or external media. Image is present in home folder and can be opened by a normal opencv c++ program by giving the exact same path.
Someone here told me that native C++ NDK will not be able to read Linux paths. Alright. Here it is all Java.
When I execute this, it always goes in else statement and shows the height as 0.0.
I have removed the extra code.
What is the way to read a normal png from home folder in this program on Linux?
All Android devices or emulators don't have access to storages outside like your Linux storage partition, they have access to their internal storage or sdcard. In the case of the emulator, their internal storage is emulated using a file with a certain format that cannot be easily read. In an emulator or a device that has Developer options enabled, one could use the adb command found within the Android SDK platform-tools folder to transfer files into it as such:
adb push file.jpg /sdcard/file.jpg
After that, you'll need to change the path of the file your using in the code to match and also enable permissions to READ_EXTERNAL_STORAGE (here external means external to the application your running, but still internal to the device).
Someone here told me that native C++ NDK will not be able to read
Linux paths. Alright. Here it is all Java.
Looking at your question and the answer, for start this is the same problem, trying to access a file that is not part of the device/emulator internal storage. However the answer isn't entirely true, the C/C++ code can access files and directories of the internal storage as long as permission is granted to the application. I would suggest you first try fixing the problem using Java and then switch back to the code you had in your other question but with the corrected path. With Java, you'll be using the Java wrapper for the OpenCV APIs, hence you'll need to call OpenCVLoader.initDebug() to load the wrapper lib. When using pure NDK, you'll only need to load the compiled lib (System.loadLibrary(<libname>) you created with the native C/C++ code.
When you use Imgcodecs.imread(...), it will read the path on your machine, which running your application.
So, if you run the Java Application, it will run on your JVM within your computer, that mean it read the path like ~/home/... on your computer and that path exist, so it can get somethings.
But, Android App will run on DVM within Android Device, that mean when you read ~/home/.., it will take that path on Android Device, but it wasn't exist on Android Devices. So you can't get anything.
The best practice, you should use Imgcodecs.imread(...) with the External Storage Path like some guys suggest you above.
Sometime, you maybe can use Imgcodecs.imread(...) on /mtn/..,path of SD Card, but it isn't correct completely.
see this example code, maybe help you, i tested this code and work for me, and i can get width and height of any image.
1) first you need import OpenCVLibrary to your project: see this Link - Link
2) then you need set READ_EXTERNAL_STORAGE permision to your application:
plz add this command on your AndroidManifest.xml:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
3) you need file picker for get specific file i use ru.bartwell:exfilepicker: Link
implementation 'ru.bartwell:exfilepicker:2.1'
4) and at the end you just add this simple code to your MainActivity:
private static final int READ_STORAGE_PERMISSION_REQUEST_CODE = 1;
private static final int EX_FILE_PICKER_RESULT = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initLoadOpenCV();
if (!checkPermissionForReadExtertalStorage()) {
requestPermissionForReadExtertalStorage();
}
}
private void initLoadOpenCV() {
boolean isDebug = OpenCVLoader.initDebug();
if (isDebug) {
Log.i("init Opencv", "init openCV success!!");
} else {
Log.e("init Opencv", "init openCV failure!!");
}
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == EX_FILE_PICKER_RESULT) {
ExFilePickerResult result = ExFilePickerResult.getFromIntent(data);
if (result != null && result.getCount() > 0) {
// Here is object contains selected files names and path
Log.i("folderLocation", result.getPath() + result.getNames().get(0));
Mat srcMat1 = Imgcodecs.imread(result.getPath() + result.getNames().get(0));
if (srcMat1.empty()) {
return;
}
int width = srcMat1.width();
int height = srcMat1.height();
int type = srcMat1.type();
Log.i("width", srcMat1.width() + "");
Log.i("height", srcMat1.height() + "");
Log.i("type", srcMat1.type() + "");
}
}
}
public boolean checkPermissionForReadExtertalStorage() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
int result = getApplicationContext().checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE);
return result == PackageManager.PERMISSION_GRANTED;
}
return false;
}
public void requestPermissionForReadExtertalStorage() {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
READ_STORAGE_PERMISSION_REQUEST_CODE);
}
#Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
switch (requestCode) {
case READ_STORAGE_PERMISSION_REQUEST_CODE:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Log.e("value", "Permission Granted, Now you can use local drive .");
ExFilePicker exFilePicker = new ExFilePicker();
exFilePicker.start(this, EX_FILE_PICKER_RESULT);
} else {
Log.e("value", "Permission Denied, You cannot use local drive .");
requestPermissionForReadExtertalStorage();
}
break;
}
}
The first problem mentioned in the comment below the question is that you must load the native library that implements the image loading. This can be done with the following code:
static {
// TODO: use OpenCVLoader.initAsync for a real application
if (!OpenCVLoader.initDebug()) {
Log.d(TAG, "Failed to initialize OpenCV.");
}
}
In a real application you would use the initAsync function such that the loading of the libraries does not block the main thread. In a simple example this does not matter.
Another problem is, that file IO on Android requires a permission if you want to access files in arbitrary directories. The permission must be declared in your manifest file. This can be done by adding the following two lines above the application tag in the manifest file.
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
These permissions must be requested at runtime. To check if the permission was granted already the following code can be used:
if (ContextCompat.checkSelfPermission(this,
android.Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
// do something with the permission
}
If the permission is not available, it can be requested as follows:
ActivityCompat.requestPermissions(this, new String[]{
android.Manifest.permission.WRITE_EXTERNAL_STORAGE}, RW_PERMISSION_REQUEST_CODE);
Note: we only request the write permission because they are grouped and if the user grants the write permission we automatically also obtain the read permission.
To handle the result the onRequestPermissionsResult callback in the activity class should be overwritten as seen in the full code example below. Because the permission system is quite complex take a look at the official documentation. For info on requesting permissions look here.
Finally to make the loading work the file path must be correct. The user-accessible memory locations depend on the phone manufacturer, therefore it is good to use the system methods provided by Android to find the correct path, for example getExternalStorageDirectory(). More information on the various storage locations can be found here.
Here the full code:
import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
import static android.os.Environment.getExternalStorageDirectory;
public class MainActivity extends AppCompatActivity {
private static String TAG = "MainActivity";
private static final int RW_PERMISSION_REQUEST_CODE = 123;
static {
// TODO: use OpenCVLoader.initAsync for a real application
if (!OpenCVLoader.initDebug()) {
Log.d(TAG, "Failed to initialize OpenCV.");
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (ContextCompat.checkSelfPermission(
this, WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
permissionDenied();
} else {
permissionGranted();
}
}
private void permissionDenied() {
if (ActivityCompat.shouldShowRequestPermissionRationale(this, WRITE_EXTERNAL_STORAGE)) {
new AlertDialog.Builder(this)
.setTitle("Read/Write permission required to read an image file.")
.setCancelable(false)
.setPositiveButton("Grant", (dialog, which) ->
ActivityCompat.requestPermissions(this, new String[]{
WRITE_EXTERNAL_STORAGE}, RW_PERMISSION_REQUEST_CODE))
.setNegativeButton("Deny", (dialog, which) -> {
Toast.makeText(this,
"App cannot work without permission.", Toast.LENGTH_LONG).show();
this.finish();
})
.create()
.show();
} else {
ActivityCompat.requestPermissions(
this, new String[]{WRITE_EXTERNAL_STORAGE}, RW_PERMISSION_REQUEST_CODE);
}
}
private void permissionGranted() {
String path = getExternalStorageDirectory().getAbsolutePath() + "/a.png";
Mat image = Imgcodecs.imread(path, Imgcodecs.IMREAD_GRAYSCALE);
if (image.empty()) {
Toast.makeText(this, "Failed image", Toast.LENGTH_LONG).show();
} else {
Size size = image.size();
Toast.makeText(this, "Loaded image " + size.height, Toast.LENGTH_LONG).show();
// the following code is only necessary to display the image in an ImageView
ImageView iv = findViewById(R.id.imageView);
Mat tmp = new Mat((int) size.height, (int) size.width, CvType.CV_8U, new Scalar(4));
try {
Imgproc.cvtColor(image, tmp, Imgproc.COLOR_GRAY2RGBA, 4);
Bitmap bmp = Bitmap.createBitmap(tmp.cols(), tmp.rows(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(tmp, bmp);
iv.setImageBitmap(bmp);
} catch (CvException e) {
Log.d(TAG, e.getMessage());
Toast.makeText(this, "Couldn't convert image.", Toast.LENGTH_LONG).show();
}
}
}
#Override
public void onRequestPermissionsResult(
int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
if (requestCode == RW_PERMISSION_REQUEST_CODE) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
permissionGranted();
} else {
permissionDenied();
}
} else {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
}
To make this code work add an ImageView with id imageView to your activity_main.xml layout file.
Before you read on further I would like to clarify a few things
From question it is not clear where the code is running? It seems that the user is running this android app on a virtual machine or emulator.
1.1 - From the question it seems that the file she wants to open is on the home directory of Linux machine and not in the emulator's storage or on an Android device - in this case Please note that android apps running on emulator can not access files from your computer.
---- so if you were trying to access file on your Linux pc from within android emulator or vm, please note that it is not possible. Instead copy and put the file in the android emulator or device on which your app will be running.
Please clarify question and let us know whether you have file on the emulator storage (or android device) or it is on your pc and code running on emulator.
If you have file on emulator or android device, please make sure you have right permissions declared in manifest and you have also requested user for permission to read storage before trying to read the image.
Update
Thank you for the response in comments.
How to put file on emulator?
To add a file to the emulated device, drag the file onto the emulator screen. The file is placed in the /sdcard/Download/ directory. You can view the file from Android Studio using the Device File Explorer, or find it from the device using the Downloads or Files app, depending on the device version
source https://developer.android.com/studio/run/emulator
For permissions related stuff you can refer easy to follow documentation on official website - https://developer.android.com/training/permissions/requesting
or check out this question - Android marshmallow request permission?
You can also check -- https://stackoverflow.com/a/30434631/9640177
Depreciation note
Please check https://stackoverflow.com/a/59812593/9640177
To avoid dealing with permissions and external directories, you can also transfer your file to your app's internal storage using android studio -- explore device storage.
Update 2
Refer this answer please - https://stackoverflow.com/a/5990806/9640177
If you want to access them in runtime and not push the files there you have to have a public IP on the internet in which you can access and expose the files on HTTP with something like Apache Tomcat or FTP and then access that from the emulator.
You can also access it locally without exposing it to the whole internet, by accessing from the Android emulator to the "localhost" IP. You'll have to search which IP this is.
So your use case necessitates accessing files from location on your pc, you can use something like tomcat to create a local http server.
Related
I know that there is too many solutions were given, but I can't get the exact solution. My problem is that I have picked one video from internal storage device and after picking video then I have converted to String and set the video to videoView but then also it shows that "Can't play this video" in videoView.
can anyone please help me to find out the solution :(
here is my code
File file = new File(Environment.getExternalStorageDirectory().getAbsolutePath()+"/Download/videos.mp4");
Log.d("video",""+file);
if (file.exists()) {
Uri uri = Uri.fromFile(file);
String video = String.valueOf(uri);
Log.d("video",""+uri);
videoView.setMediaController(new MediaController(this));
videoView.setVideoURI(Uri.parse(video));
videoView.requestFocus();
videoView.start();
}else {
Toast.makeText(this, "No video found", Toast.LENGTH_SHORT).show();
}
With scoped storage (required from API 30) you can't access files directly unless you request the MANAGE_EXTERNAL_STORAGE (on Google Play you need to request it to Google).
The new way is to use the file uri. You can try those ways:
Ask the user to select the file.
private final ActivityResultLauncher<String[]> openDoc =
registerForActivityResult(new ActivityResultContracts.OpenDocument(),
new ActivityResultCallback<Uri>() {
#Override
public void onActivityResult(Uri uri) {
// use uri
}
});
Call it with:
// Use the mimetype you want (optional). Like "text/plain"
openDoc.launch(new String[]{"text/plain"});
Read more here
Get the Media file uri with MediaStore
Read more here
You'll also need the READ_EXTERNAL_STORAGE permission if the file was not created by your app.
I am trying to upload an image selected from gallery to my Springboot server, but when my service try to post the image I get permission denied for the file path. I have added these permissions to my AndroidManifest:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<!-- permission below just in case, should not be needed I believe -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
I then ask for permission in real time to select the image, and then I want to place it in an inflated view where the user can provide more details about the image, then add it to a report which I will later post.
Since I got this permission trouble I also asked for permission again when I try to submit this Report object containing the images (Uri).
But still I get this error:
Caused by: java.io.FileNotFoundException: /storage/emulated/0/DCIM/Camera/IMG_20200206_120434.jpg (Permission denied)
Every hit I find on this error on google will point to someone who don't ask for this real-time permission, but I even do it once to much I believe.
This is some related snippets of my code:
else if (view.getId() == R.id.stubNewBreedingReportSelectImageButt) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[] {Manifest.permission.READ_EXTERNAL_STORAGE}, 1);
} else {
getPhotoFromPhone(); // this starts the intent to pick an image
}
}
}
else if (view.getId() == R.id.stubNewBreedingReportSubmitButt) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[] {Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE}, 2);
} else {
submitNewBreedingReport();
}
}
}
This is from my onClick(View view) method. The first one works since I am allowed to pick an image from the gallery. The second one should probably not need to check the permissions based on every example I have found of projects uploading images from android.
In my onActivityResult(int requestCode, int resultCode, Intent data) method I inflate this "add image details view". I also store the selected Uri as a private Uri selectedImg in the activity for future use. This all seems to work pretty much fine.
Then when I submit the image (in the submitNewReport() method) I use an ExecutorService (java class) to start a new async thread for the upload. In this Callable<> I get an instance of Springs RestTemplate and try to post the image, but when my restTemplate try to call and fetch the file from my Uri I get the permission denied.
This is the upload method in my apps ImageService:
public Gallery uploadPictureWithInfo(Uri uri, Map<String,Object> imgParams, Context context) {
if (uri.getPath() != null) {
File resourceFile = new File(getPathFromUri(uri,context));
//if (resourceFile.exists()) {
Gallery saved = null;
Map<String,Object> params = new HashMap<>();
params.put(PARAM_FILE, new FileSystemResource(resourceFile));
if (imgParams.get(PARAM_GALLERY_ID) != null || (long) imgParams.get(PARAM_GALLERY_ID) > (long) 0) {
params.put(PARAM_GALLERY_ID, imgParams.get(PARAM_GALLERY_ID));
if (imgParams.get(PARAM_DESCRIPTION) != null) {
params.put(PARAM_DESCRIPTION, imgParams.get(PARAM_DESCRIPTION));
}
if (imgParams.get(PARAM_PHOTOGRAPH) != null) {
params.put(PARAM_PHOTOGRAPH, imgParams.get(PARAM_PHOTOGRAPH));
}
if (imgParams.get(PARAM_USER_ID) != null && (long) imgParams.get(PARAM_USER_ID) > 0) {
params.put(PARAM_USER_ID, imgParams.get(PARAM_USER_ID));
}
HttpEntity requestEntity = new HttpEntity<>(params, AquaDbConfig.getImageHeaders());
ResponseEntity<Gallery> responseEntity =
restTemplate.exchange(AquaDbConfig.getApiUrl() + "/images/uploadImgWithInfo", HttpMethod.POST, requestEntity, Gallery.class);
if (responseEntity.hasBody()) {
saved = responseEntity.getBody();
}
return saved;
}
//}
}
return null;
}
public static String getPathFromUri(Uri uri, Context context) {
String[] filePath = { MediaStore.Images.Media.DATA };
Cursor c = context.getContentResolver().query(uri,filePath, null, null, null);
c.moveToFirst();
int columnIndex = c.getColumnIndex(filePath[0]);
String picturePath = c.getString(columnIndex);
c.close();
return picturePath;
}
I commented out the check for the file.isExist() to get past that test since it wont generate a stack trace otherwise.
So my question is HOW do I get to read the image file when I POST it to the server? I read a little about FileProvider class, but it seems to me that it is used to send files through Intents to new Activites or other Apps. It don't seem to me like it is intended for this because I never leave my Activity exept for picking the image in the gallery. The diffrent steps of creating this ReportedBreeding object is handeled by inflated ViewStubs and not new activites. Also the Uri I use don't refer to any directories I created for my app but rather the users image gallery (external storage).
I also tried to declare my ImageService as a Service in the android manifest, even though I'm not sure we talk about the same kind of service. I then added it this permission but it made no diffrence:
<service
android:name=".service.MyImageFactory"
android:permission="android.permission.READ_EXTERNAL_STORAGE">
</service>
If you know how to get the permission all the way to this RestTemplate POST method (which noone else seems to need in my reviewed examples) or how I can get around this problem, please share! I'm starting to get a little frustrated and stuck. The problem to me is Why do android require yet another permission check and how do I provide it or work around it in my uploadPictureWithInfo(..) method?
Try asking the permission for WRITE_EXTERNAL_STORAGE before getPhotoFromPhone()
For Android 10 this may be the permission issue, there are two solutions for that to handle for now. First method is to permission to manifest Application tag: android:requestLegacyExternalStorage="true"
The other one is to use openFileDescriptor
val parcelFileDescriptor = context.contentResolver.openFileDescriptor(fileUri, "r", null)
val inputStream = FileInputStream(parcelFileDescriptor.fileDescriptor)
fun ContentResolver.getFileName(fileUri: Uri): String {
var name = ""
val returnCursor = this.query(fileUri, null, null, null, null)
if (returnCursor != null) {
val nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)
returnCursor.moveToFirst()
name = returnCursor.getString(nameIndex)
returnCursor.close()
}
return name
}
val file = File(context.cacheDir, getFileName(context.contentResolver, fileUri))
val parcelFileDescriptor = context.contentResolver.openFileDescriptor(fileUri, "r", null)
parcelFileDescriptor?.let {
val inputStream = FileInputStream(parcelFileDescriptor.fileDescriptor)
val file = File(context.cacheDir, context.contentResolver.getFileName(fileUri))
val outputStream = FileOutputStream(file)
IOUtils.copy(inputStream, outputStream)
}
I am trying to build a parental control app. So now i want to disable or lock app (like Whatsapp, Facebook, etc). I have tried using PackageManager.setComponentEnabledSetting(). But it is throwing java.lang.SercurityException.
So how can I make a parental control app such that I can disable any app I want without root.
my code is
pm.setComponentEnabledSetting(new ComponentName(temp.activityInfo.packageName,
temp.activityInfo.name+".class"),
PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP);
my error was this
java.lang.SecurityException: Permission Denial: attempt to change component state from pid=11537, uid=10067, package uid=10029
You must add below permissions to manifest.
<uses-permission android:name="android.permission.WRITE_SETTINGS"/>
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS"/>
but , these permissions are for System apps and you can not use. :(
You can not write a app to lock or close another app.this is a policy in Google.
for lock a app you must check running apps repeatedly, if specific app is open,then show a activity over that.
while(!Thread.currentThread().isInterrupted())
{
String topActivity = getFrontApp();
if(topActivity.isEmpty())
{
threadSleep(500);
continue;
}
if(topActivity.equals("lockApp"))
{
showLockActivity();
}
threadSleep(500);
}
// for Api21+ need permission
public static String getFrontApp()
{
if (Build.VERSION.SDK_INT >= 21)
{
UsageStatsManager usageManager = SystemMaster.getUsageStatsManager();
long now = System.currentTimeMillis();
List<UsageStats> localList = usageManager.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, now - 900_000L, now);
String str = "";
if (localList != null)
{
SortedMap<Long,UsageStats> mySortedMap = new TreeMap<>();
for(UsageStats usageStats : localList)
mySortedMap.put(usageStats.getLastTimeUsed(), usageStats);
if(!mySortedMap.isEmpty())
str = mySortedMap.get(mySortedMap.lastKey()).getPackageName();
}
return str;
}
else
{
ActivityManager am = (ActivityManager) getApplication().getSystemService(Context.ACTIVITY_SERVICE);
return am.getRunningTasks(1).get(0).topActivity.getPackageName();
}
above code is very simple , for real app must write more.
I am attempting to integrate the Dropbox chooser drop-in api into my application. I am running into an abnormal issue. In my app when I launch the dbx chooser, anytime that I select a file the application fails with the following error code:
Sorry, an error has occurred. Please try again later.
Here is the portion of my code that implements the Dropbox API. This portion of the code is where the dropbox api is initially invoked.
public void StartDropboxApplication() {
// create the chooser
DbxChooser chooser = new DbxChooser(APP_KEY);
DbxChooser.ResultType result;
// determine which mode to be in // TODO REMOVE ALL BUT FILE CONTENT TODO SIMPLIFY by making this a setting
switch(( (RadioGroup) ParentActivity.findViewById(R.id.link_type)).getCheckedRadioButtonId() ) {
case R.id.link_type_content:
result = DbxChooser.ResultType.DIRECT_LINK;
break;
default:
throw new RuntimeException("Radio Group Related error.");
}
// launch the new activity
chooser.forResultType(result).launch(ParentActivity, 0);
}
Here is the position where the code should then pick it up although it never does.
protected void onActivityResult( int request, int result, Intent data ) {
Log.i(fileName, "result: " + result);
// check to see if the camera took a picture
if (request == 1) {
// check to see if the picture was successfully taken
if (result == Activity.RESULT_OK) {
onPicture();
} else {
Log.i(fileName, "Camera App cancelled.");
}
} else if (request == 0) {
if ( result == Activity.RESULT_OK ) {
onDropbox(data);
} else {
Log.i(fileName, "dropbox related issue.");
}
}
}
Thank you for any help or suggestions that you are able to provide.
I was able to solve my own issues and get this working. On the off chance that someone else has a similar problem I will detail the solution. The first issue was I was that my APP_KEY was incorrect.
The next issue was that I was attempting to read from a direct link instead of a content link. The direct link provides the application with a link to the file on the Dropbox server whereas the content link provides the application with a cached version of the file. If the file is not present on the device, the SDK downloads a copy for you.
I got this class:
import android.content.Context;
import android.media.MediaScannerConnection;
import android.net.Uri;
import android.util.Log;
public class MediaScannerWrapper implements
MediaScannerConnection.MediaScannerConnectionClient {
private MediaScannerConnection mConnection;
private String mPath;
private String mMimeType;
// filePath - where to scan;
// mime type of media to scan i.e. "image/jpeg".
// use "*/*" for any media
public MediaScannerWrapper(Context ctx, String filePath, String mime){
mPath = "/sdcard/DCIM/Camera";
mMimeType = "jpg";
mConnection = new MediaScannerConnection(ctx, this);
}
// do the scanning
public void scan() {
mConnection.connect();
}
// start the scan when scanner is ready
public void onMediaScannerConnected() {
mConnection.scanFile(mPath, mMimeType);
Log.w("MediaScannerWrapper", "media file scanned: " + mPath);
}
public void onScanCompleted(String path, Uri uri) {
// when scan is completes, update media file tags
}
}
How to use it in the other class?
I don't know how to properly use classes, I tried but nothing is working.
I do something wrong, but I don't know what, can someone help me with this.
The Story
Before Android 4.4, we could just send a broadcast to trigger the media scanner on any particular file, or folder or even on the root of the storage. But from 4.4 KitKat, this have been fixed by the Android Developers.
Why do I say fixed? The reason is simple. Sending a broadcast using MEDIA_MOUNTED on the root directory is very expensive. Running the Media Scanner is an expensive operation and the situation gets even worse when the user has got a lot of files in the storage and deep folder structures.
Before Android 4.4
Keep it straight and simple. If you are targeting your app before Android 4.4. But keep in mind not to use it on the root directory unless absolutely necessary.
sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://" + Environment.getExternalStorageDirectory())));
From Android 4.4
There are two ways for you.
i) The first one is very similar to the previous example, but may not work efficiently and is not recommended too.
sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse("file://" + Environment.getExternalStorageDirectory())));
ii) Now, let us move on to the most recommended and efficient solution to this problem.
Add the file paths of the files which have been updated, like this, in a String type ArrayList
ArrayList<String> toBeScanned = new ArrayList<String>();
toBeScanned.add(item.getFilePath());
Now you need to run scanFile() static method of the MediaScannerConnection class and pass the String array containing the list of all the files which have been updated and needs to be media scanned.
You can also put a listener to respond when the scanning has been finished for individual files.
String[] toBeScannedStr = new String[toBeScanned.size()];
toBeScannedStr = toBeScanned.toArray(toBeScannedStr);
MediaScannerConnection.scanFile(getActivity(), toBeScannedStr, null, new OnScanCompletedListener() {
#Override
public void onScanCompleted(String path, Uri uri) {
System.out.println("SCAN COMPLETED: " + path);
}
});
Hey I found out how to do it with a very simple code.
Just call this line of code:
sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://" + Environment.getExternalStorageDirectory())));
This should trigger mediascanner.
In Android, there is a content database which is used by the media scanner to keep track of all the media content present on the device.
When Android boots up, the mediascanner service is launched and runs through the entire external storage to find if there is any new media content if it finds one then,
It adds an entry of that media content into the content database
Each entry in the content database contains metadata of the media content like Name, date, file size, type of file, etc..
So when you make a modification to a media content, you will need to update the content database also.
If the content database is not update then other applications also will not be able to access that particular media content.
Running the media scanner just updates the content database
Instead of running the media scanner, you can update the content database yourself and it should resolve the problem.
Here is an explanation on how to insert, delete, update using the content resolver. (Search for the section "Inserting, Updating, and Deleting Data")
Edit:
There is a sample code in this answer. Check for the answer by Janusz.
File file = new File(absolutePath);
Uri uri = Uri.fromFile(file);
Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, uri);
sendBroadcast(intent);
private void galleryAddPic() {
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
File f = new File(mCurrentPhotoPath);
Uri contentUri = Uri.fromFile(f);
mediaScanIntent.setData(contentUri);
this.sendBroadcast(mediaScanIntent);
}
Reference: http://developer.android.com/training/camera/photobasics.html#TaskGallery
The Add the Photo to a Gallery Section
As #Aritra Roy's answer, i decide to make an experiment about this issue.
What i got here are:
Intent.ACTION_MEDIA_MOUNTED and Intent.ACTION_MEDIA_SCANNER_SCAN_FILE
can accept individual file path, so sendBroadcast(new
Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse(filePath)));
or sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED,
Uri.parse(filePath))); will be valid.
If you use individual file path with Intent.ACTION_MEDIA_MOUNTED on Kitkat or above, your application will still crash
If you use Intent.ACTION_MEDIA_SCANNER_SCAN_FILE or MediaScannerConnection on device lower than Kitkat, your application will not force close, but the method will just simply not working as you want.
From that experiment, i think the best method to handle is
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
MediaScannerConnection.scanFile(context, new String[]{imagePath}, null, new MediaScannerConnection.OnScanCompletedListener() {
public void onScanCompleted(String path, Uri uri) {
//something that you want to do
}
});
} else {
context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED,
Uri.parse("file://" + imagePath)));
}
Let me know if i missed something