So my problem is that I want to get file path from content uri, I had googled but I didn't get any of the solutions, please help me out of this problem.
here is my code what I have tried
Intent getPdf = getIntent();
String action = getPdf.getAction();
String type = getPdf.getType();
Log.d("sdsfgsdfsdf",""+type);
if (Intent.ACTION_SEND.equals(action) ||Intent.ACTION_VIEW.equals(action) || type != null){
if (type.startsWith("application/pdf")){
viewPdf(getPdf,action);
}
}
private void viewPdf(Intent getPdf, String action) {
Uri uri = Uri.parse(getPdf.getData().toString());
if (uri != null) {
File file = new File(String.valueOf(uri.getPath()));
name = file.getName();
path = String.valueOf(uri);
Log.d("sdsfgsdfsdf",""+name);
}else {
// Toast.makeText(this, ""+ uri.toString(), Toast.LENGTH_SHORT).show();
}
}
This is the output
content://com.android.externalstorage.documents/document/primary%3AWhatsApp%2FMedia%2FWhatsApp%20Documents%2FAJAX_And_PHP_Building_Responsive_Web_Applications-(2006).pdf
but I want to get file:// path instead of content uri
It is unclear where you got that uri that content scheme from.
You should have started with that
Further it makes no sense trying to get a path for it as mostly you will not have read access then.
Further you did not tell why you want a path
Use the uri! Use the content scheme.
You can use PickiT library for get path from URI.
Sample code for how to use it.
PickiT pickiT = new PickiT(this, new PickiTCallbacks() {
#Override
public void PickiTonUriReturned() {
}
#Override
public void PickiTonStartListener() {
}
#Override
public void PickiTonProgressUpdate(int progress) {
}
#Override
public void PickiTonCompleteListener(String filePath, boolean wasDriveFile, boolean wasUnknownProvider, boolean wasSuccessful, String Reason) {
if (wasSuccessful) {
// Use file path
}
}
#Override
public void PickiTonMultipleCompleteListener(ArrayList<String> paths, boolean wasSuccessful, String Reason) {
}
}, this);
pickiT.getPath(uri, Build.VERSION.SDK_INT);
Related
I have implemented a function to download aws s3 files using the following code:
public void credentialsProvider()
{
CognitoCachingCredentialsProvider credentialsProvider = new CognitoCachingCredentialsProvider(
getApplicationContext(), "us-east-2:xxxxxx-xxxxx-xxxxx-xxxx-xxxxxxx", Regions.US_EAST_2
);
setAmazonS3Client(credentialsProvider);
System.out.println("setAmazonS3Client done");
}
public void setAmazonS3Client( CognitoCachingCredentialsProvider credentialsProvider)
{
s3 = new AmazonS3Client(credentialsProvider);
s3.setRegion(Region.getRegion(Regions.US_EAST_2));
}
public void setTransferUtility()
{
transferUtility = new TransferUtility(s3, getApplicationContext());
System.out.println("setTransferUtility done");
}
public void setFileDownload()
{
final String path = this.getFilesDir().getAbsolutePath();
File myFile = new File(path);
TransferObserver transferObserver = transferUtility.download("sample-bucket-001", "images-4.jpeg", myFile);
transferObserverListener(transferObserver);
}
public void transferObserverListener(TransferObserver transferObserver)
{
transferObserver.setTransferListener(new TransferListener() {
#Override
public void onStateChanged(int id, TransferState state) {
System.out.println("onStateChanged: "+ state);
if(state == TransferState.FAILED || state == TransferState.WAITING_FOR_NETWORK){
}
}
#Override
public void onProgressChanged(int id, long bytesCurrent, long bytesTotal) {
int percentage = (int)(bytesCurrent/bytesTotal * 100);
System.out.println("percentage: "+ percentage);
}
#Override
public void onError(int id, Exception ex) {
System.out.println("Error faced: "+ ex.toString());
}
});
}
As I try to execute the following code I get the following error:
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.xxxxxx.xxxxxxxx/com.xxxxxx.xxxxxxxx.Activity}: java.lang.IllegalArgumentException: Invalid file: /data/user/0/com.xxxxxx.xxxxxxxx/files/
I cannot save the file on external storage as I prefer to have them hidden and protected, and deleted in case the app got deleted. I used to use the path to save files on it, that are directly loaded from the internet and no problem there.
Kindly advise on the matter.
The file path supplied to TransferUtility needs to include a file name, e.g.:
final String path = this.getFilesDir().getAbsolutePath() + "images-4.jpeg";
I have finally found the solution to the question asked, which simple using a path that is totally new, unused previously, so it can create the folder that where it will store the downloaded picture or file.
final String path = this.getFilesDir().getAbsolutePath()+"/zip";
I wish Amazon's feedback could be a bit more specific than just 'invalid file'.
I am trying to get the download Url based on the condition that the image path for the storage reference is null or not.
I tried to put the whole code inside the if else statement instead of just assigning the value to download_uri inside the condition which resolves the error. I am not able to understand why this approach works and another one doesn't.
mSaveButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
final String name=mProfileName.getText().toString();
if(!TextUtils.isEmpty(name) && mainImageUri!=null){
mProgressBar.setVisibility(View.VISIBLE);
if(isChanged){
//The task of storing the data goes through uploading the image as well.
user_id = mUser.getUid();
final StorageReference image_path= mStorageReference.child("profile_photo").child(user_id+".jpg");
image_path.putFile(mainImageUri).addOnCompleteListener(new OnCompleteListener<UploadTask.TaskSnapshot>() {
#Override
public void onComplete(#NonNull Task<UploadTask.TaskSnapshot> task) {
if(task.isSuccessful()){
storeFireStore(image_path,name);
}else{
String error = task.getException().getMessage();
Toast.makeText(SetUpActivity.this,"Image Error: "+error,Toast.LENGTH_SHORT).show();
}
mProgressBar.setVisibility(View.INVISIBLE);
}
});
}else{
//The task of storing the data does not go through uploading the image.
storeFireStore(null,name);
mProgressBar.setVisibility(View.INVISIBLE);
}
}
}
});
}
private void storeFireStore(StorageReference image_path, final String name) {
final Uri[] download_uri = new Uri[1];
if(image_path!=null){
image_path.getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() {
#Override
public void onSuccess(Uri uri) {
download_uri[0] =uri;
Log.d(TAG,"Download Url obtained");
}
});
} else{
download_uri[0] =mainImageUri;
Log.d(TAG,"Download Url obtained in else");
}
Map<String,String> userMap=new HashMap<>();
userMap.put("image", download_uri[0].toString());//line 202 this is
where the error occurs.userMap.put("name",name);
I expect to get the downLoad_uri but it provides a null value
image_path.getDownloadUrl().addOnSuccessListener() is asynchronous and returns immediately, before the results of the operation are complete. Your code goes on to access the download_uri array which is initialized with null values. You can only expect the array to have a populated value after the callback completes.
I don't know why you are doing unnecessary work to get download URL of image if you can do it by just simple on line of code.
Just use below code to upload image in firebase storage.
image_path.putFile(mainImageUri).addOnCompleteListener(new OnCompleteListener<UploadTask.TaskSnapshot>() {
#Override
public void onComplete(#NonNull Task<UploadTask.TaskSnapshot> task) {
if(task.isSuccessful()){
// HERE YOU CAN DIRECTLY GET DOWNLOAD URL OF UPLOADED IMAGE USING TASK RESULT.
String downloadUrl = String.valueOf(taskSnapshot.getDownloadUrl());
storeFireStore(downloadUrl,name);
} else {
String error = task.getException().getMessage();
Toast.makeText(SetUpActivity.this,"Image Error: "+error,Toast.LENGTH_SHORT).show();
}
mProgressBar.setVisibility(View.INVISIBLE);
}
});
And make change in storeFireStore method like below,
private void storeFireStore(String image_path, final String name) {
Map<String, String> userMap = new HashMap<>();
userMap.put("image", image_path != null ? image_path : "");//line 202 this is where the error occurs.
userMap.put("name", name);
}
I need download multiple files in one time (About 100 files)
It does not matter whether the download is synchronized
And the important thing is that all files be downloaded.
My code for getting urls and file names:
for (int i = 0; i < AssetData.size(); i++){
String item = AssetData.get(i).toString();
String name[] = item.split("/");
String Url = setting.Main_Domain+"/"+item;// Url for downloading
String fname =name[name.length-1] ;// File name like: test.txt
File file2 = new File(getFilesDir(),item.replace(fname,"")); // Parent File like: data/user/0/com.test.app/data/
if(!file2.exists()){file2.mkdir();}
}
The size of the files is small and all together is about 3 megabytes.
You can implement your code with using this library. You can download multiple files concurrent or you can start next download after one is completed.
https://github.com/MindorksOpenSource/PRDownloader
This is how your code will look
int downloadId = PRDownloader.download(url, dirPath, fileName)
.build()
.setOnStartOrResumeListener(new OnStartOrResumeListener() {
#Override
public void onStartOrResume() {
}
})
.setOnPauseListener(new OnPauseListener() {
#Override
public void onPause() {
}
})
.setOnCancelListener(new OnCancelListener() {
#Override
public void onCancel() {
}
})
.setOnProgressListener(new OnProgressListener() {
#Override
public void onProgress(Progress progress) {
}
})
.start(new OnDownloadListener() {
#Override
public void onDownloadComplete() {
}
#Override
public void onError(Error error) {
}
});
Isn't this simple. :)
This seems to me ion is a pretty elegant solution for you. It's easy to use and has many futures like connection pooling and reuse via HTTP Connection...
I created an app. Within this app, you have objects which contains 2 strings (name and age) and a bitmap (avatar). Everything is saved to a sqlite database.
Now I want these objects to be accessible on my smart watch. So I want to achieve that you can go to start, start the application and scroll to the left and right to see these objects.
This means I have to retrieve the objects from the phone and get them at the watch.
I am currently wondering if I did everything right, or that I should do stuff differently. Whenever you start the application on your watch, I am sending a request to the phone that I want the objects.
private void sendMessage() {
if(mGoogleApiClient.isConnected()) {
new Thread( new Runnable() {
#Override
public void run() {
NodeApi.GetConnectedNodesResult nodes = Wearable.NodeApi.getConnectedNodes( mGoogleApiClient ).await();
for(Node node : nodes.getNodes()) {
Wearable.MessageApi.sendMessage(mGoogleApiClient, node.getId(), REQUEST_PET_RETRIEVAL_PATH, null).await();
}
}
}).start();
}
}
On the phone, I am receiving this message and sending a message back with an object.
public void onMessageReceived(MessageEvent messageEvent) {
super.onMessageReceived(messageEvent);
if (messageEvent.getPath().equals(REQUEST_PET_RETRIEVAL_PATH)) {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(new GoogleApiClient.ConnectionCallbacks() {
#Override
public void onConnected(Bundle connectionHint) {
final PutDataMapRequest putRequest = PutDataMapRequest.create("/send-pets");
final DataMap map = putRequest.getDataMap();
File imgFile = new File(obj.getAvatar());
Bitmap avatar;
if(imgFile.exists()) {
avatar = BitmapFactory.decodeFile(imgFile.getAbsolutePath());
} else {
avatar = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
}
Asset asset = createAssetFromBitmap(avatar);
map.putAsset("avatar", asset);
map.putString("name", obj.getName());
map.putString("age", obj.getDateOfBirth());
Wearable.DataApi.putDataItem(mGoogleApiClient, putRequest.asPutDataRequest());
}
#Override
public void onConnectionSuspended(int cause) {
}
})
.addOnConnectionFailedListener(new GoogleApiClient.OnConnectionFailedListener() {
#Override
public void onConnectionFailed(ConnectionResult result) {
}
})
.addApi(Wearable.API)
.build();
mGoogleApiClient.connect();
}
On the watch, I am then retrieving the object.
public void onDataChanged(DataEventBuffer dataEvents) {
final List<DataEvent> events = FreezableUtils.freezeIterable(dataEvents);
for(DataEvent event : events) {
final Uri uri = event.getDataItem().getUri();
final String path = uri!=null ? uri.getPath() : null;
if("/send-pets".equals(path)) {
final DataMap map = DataMapItem.fromDataItem(event.getDataItem()).getDataMap();
String name = map.getString("name");
String age = map.getString("age");
Asset avatar = map.getAsset("avatar");
Bitmap bitmap = loadBitmapFromAsset(avatar);
}
}
}
Now I am stuck with 2 questions:
1) Is this the way to go or should I solve it differently?
2) Is it possible to sent multiple objects at once or do I just have to put a loop around the part in the "onConnected" method and sent each object separatly?
Yes, this approach is good and correct one.
Yes it is possible to send multiple but you should be aware that they are not "send" they are more something like shared or synchronized between phone and Wear, and can be modified in any further point in time (however I would recommend to save them to SharedPreferences on Wear to be able to access them in offline mode.
So Message API sends objects (fast, and simple), and DataItem API is more complex but is used for bigger data and to share things between watch and phone.
My ContentObserver for observing the history in the browser is not being called. I don't understand why it isn't. I'm not doing anything different or bizarre, I'm following the API specs exactly, but to no avail! Below is my code:
In my service:
public class MonitorService extends Service {
//some global variables declared here
private ContentObserver historyObserver, searchObserver, chromeObserver;
public void onCreate() {
super.onCreate();
isRunning = false;
this.preferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
//this.historyObserver = new HistoryObserver();
this.historyObserver = new HistoryObserver(new Handler());
this.searchObserver = new HistoryObserver(new Handler());
this.chromeObserver = new HistoryObserver(new Handler());
getApplicationContext().getContentResolver().registerContentObserver(Uri.parse("content://com.android.chrome.browser/history"), false, this.chromeObserver);
getApplicationContext().getContentResolver().registerContentObserver(android.provider.Browser.BOOKMARKS_URI, false, this.historyObserver);
getApplicationContext().getContentResolver().registerContentObserver(android.provider.Browser.SEARCHES_URI, false, this.searchObserver);
}
//Other required methods in class
}//end of class
Then in my HistoryObserver Class we have:
public class HistoryObserver extends ContentObserver {
public final String TAG = "HistoryObserver";
public HistoryObserver(Handler handler) {
super(handler);
Log.d(TAG, "Creating new HistoryObserver");
}
public HistoryObserver() {
super(null);
Log.d(TAG, "Creating a new HistoryObserver without a Handler");
}
#Override
public boolean deliverSelfNotifications() {
Log.d(TAG, "delivering self notifications");
return true;
}
#Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
Log.d(TAG, "onChange without uri: " + selfChange);
//onChange(selfChange, null);
}
public void onChange(boolean selfChange, Uri uri) {
super.onChange(selfChange, uri);
Log.d(TAG, "onChange: " + selfChange + "\t " + uri.toString());
}
}
Like I said there is nothing special or unique about this implementation. Yet, when I go go to a new website or search for something in Chrome, the onChange method is never fired.
I figured out the problem. The /history content provider isn't an observable. The observables come through the /bookmark uri. Once I discovered that, things got working very quickly and very well.