Can I get and edit the list of files, downloaded with DownloadProvider?
What do I mean? We have an application called Downloads in Android that displays all the downloads made with DownloadProvider. The records it displays are stored in a database somewhere in /data and are not strongly connected with real files. E.g. if I delete a record in Downloads, the file is deleted too, but not vice versa.
So, I want to delete the file in filesystem and delete the record in Downloads application about this file.
Currently I have tried using something like:
DownloadManager dm = (DownloadManager)getSystemService(DOWNLOAD_SERVICE);
DownloadManager.Query query = new DownloadManager.Query();
query.setFilterByStatus(DownloadManager.STATUS_PAUSED|
DownloadManager.STATUS_PENDING|
DownloadManager.STATUS_RUNNING|
DownloadManager.STATUS_SUCCESSFUL);
Cursor cur = dm.query(query);
and I don't see any ID's in query which I could pass to the DownloadManager.remove(long...IDs). Can I do what I want with Android API or the only way to achieve this is to edit the database itself?
Try call
mDownloadManager.remove(long... ids)
Related
Is there a way in Firebase Storage to generate a download url pointing to nothing, in order to upload a file to that url later? something like that (in Kotlin):
fun generateItemPhotoUrl(id: String) =
storageRef.child("$Id/${generateUniqueName()}.${COMPRESS_FORMAT.name}").downloadUrl
This code returns a failed task...
I want this so my upload process can look like so:
// Case: old photo is null but new one is not - upload new photo to a new uri
generateItemPhotoUrl(itemId).continueWithTask { generateTask ->
if (generateTask.isSuccessful) {
val destUrl = generateTask.result.toString()
// Uploading may take time, so first update document to hold a uri, so consecutive
// calls will result in updating instead of uploading a new file
updateItemPhoto(itemId, destUrl).continueWithTask { updateTask ->
if (updateTask.isSuccessful)
uploadFileToDest(destUrl, newImage).continueWithTask { uploadTask ->
if (!uploadTask.isSuccessful) updateItemPhoto(itemId, null)
}
}
}
}
As explained in code, I need this to prevent the case of updating the item's photo twice in a row too fast for the first one to finish it's upload. I end up with 2 files - one of them is not referenced from anywhere. If I could do something like this, the second upload will go to my "update" case (instead of the "new photo" case presented here) - where the file will be switched correctly.
Is there a way in Firebase Storage to generate a download URL pointing to nothing, in order to upload a file to that URL later?
No, this is not possible. You cannot generate a Storage URL in advance and upload the file sometime later. You get the download URL only when the file is successfully uploaded on the Firebase servers. This is because the URL that comes from the UploadTask contains a token that is generated on the server, and it's apart of the URL. To get the entire download URL of an uploaded file, please see my answer from the following post:
How to get the download url from Firebase Storage?
The process of uploading the file is asynchronous, meaning that any code that needs that URL, needs to be inside the" onSuccess()" method, or be called from there. So there is no need to upload the file twice.
I am trying to copy a database file from the assets folder to the device /data/data folder for reference by the app. This copy process keeps failing.
I have used a copyDatabase() method found in the answers to similar problems on stackoverflow. These methods use an InputStream variable set by context().getAssets().open(databaseName); however, in my case, this assignment fails to populate a database. A subsequent method that queries the db throws an exception, since the database has no table 'main' as expected.
This is my copyDatabase() method:
String DATABASE_NAME = "birdsDBase3.db"
private void copyDatabase(String DATABASE_PATH){
Log.i(TAG, "now in copyDatabase()");
try {
Log.i(TAG, "trying to copy database.");
InputStream assetDB = context.getAssets().open(DATABASE_NAME);
Log.i(TAG, assetDB.toString());
OutputStream appDataBase = new FileOutputStream(DATABASE_PATH, false);
byte[] buffer = new byte[1024];
int length;
while ((length = assetDB.read(buffer)) > 0){
appDataBase.write(buffer, 0, length);
}
appDataBase.flush();
appDataBase.close();
assetDB.close();
} catch(IOException e){
e.printStackTrace();
}
}
}
Error from log: "SQLiteLog: (1) no such table: category"
I want the database to copy over to the device so that another method can send a query for distinct tuples in one column. Instead, this method fails due to the absence of a 'main' table in the database. I know that the query is well formed because I have run it within the SQLite Browser and got the expected result, and the method has been checked in a different thread on stackoverflow.
Assuming that the issue is simple that the database hasn't been correctly saved (not a rare occurrence so check and double check that the file copied into the assets folder is populated accordingly) then the likely issue is as per :-
Since the advent of Android 9 many of the older methods of copying the database from the assets folder now fail. This due to using the getWritableDatabase method to create the databases folder into which the database is copied.
That is when an App is installed the folders data/data/package are created for the App's data. SQlite databases are be default stored in /data/data/package/databases, the copy will fail with a NOENT if the databases folder doesn't exist.
Using the SQLiteOpenHelper's getWritableDatabase will create the databases folder when it creates the database, whihc is typically the same name/file as the database to be copied from the assets folder and the final database name.
Before Android 9 the default logging used was journal mode. This mode uses a file named the same as the database name but suffixed with -journal. The file contains transactions and can be used to roll back the transaction from the actual database.
With Android 9 Write-Ahead Logging (WAL) is used be default. This writes the actual transaction to a file -wal, (which is effectively part of the database and looked at first) and when a checkpoint occurs the database file is updated and the -wal file cleared.
The -wal file is therefore instrinsic, if it exists it MUST belong to the database for which it was created.
So what happens is that getWritableDatabase creates a database, and some transactions, such as creating the android_metadata table are written to the -wal file. The database is copied from the assets file overwriting the newly created database but the -wal and the -shm files (a shared memory file used by WAL) remain. When the database is opened the error results in an unusable database, due to the -wal and -shm files not belonging to the copied database, and the SDK/API creates a usable new database and hence no tables that existed in the asset file that was copied.
The solutions can be :-
Disable WAL by calling the SQLiteDatabase's disableWriteAheadLogging method before the database has been used.
If using a subclass of SQLiteOpenHelper, generally by overriding the onConfigure method of the SQLiteOpenHelper.
Not recommended as the benefits of WAL are lost.
Using a different database name to create the databases folder (never known that to be done).
Awkward, never tried and thus not considered.
Deleting or renaming the -wal and -shm files before the copied database is opened.
The best option so far but...
Create the databases folder using standard/basic File handling i.e. by using the_databases_parent_file.mkdirs();
The best and recommended option as
it does not have the overheads of opening the database file
doing the checks
creating the android_metadata table
creating and writing the -wal and -shm files
overwriting the intermediate database file
deleting the -wal and -shm files
affords the advantages of WAL
An example that uses this technique when checking for the existence of the database file is :-
private boolean checkDataBase(Context context, String databaseName) {
/**
* Does not open the database instead checks to see if the file exists
* also creates the databases directory if it does not exists
* (the real reason why the database is opened, which appears to result in issues)
*/
File db = new File(context.getDatabasePath(databaseName).getPath()); //Get the file name of the database
Log.d("DBPATH","DB Path is " + db.getPath()); //TODO remove for Live App
if (db.exists()) return true; // If it exists then return doing nothing
// Get the parent (directory in which the database file would be)
File dbdir = db.getParentFile();
// If the directory does not exits then make the directory (and higher level directories)
if (!dbdir.exists()) {
db.getParentFile().mkdirs();
dbdir.mkdirs();
}
return false;
}
To implemnt the above your would use the above to check the database and do away with the getWritableDatabase that is called between checking the database and calling the copyDatbase method.
You need to implement
SqliteAssetHelper
Search over the web and try it.
How should I notify images Content Provider, that I just saved a file in Pictures directory? I expect e.g. Gallery-like apps to be able to see my new file.
Uri uri = Uri.fromFile(file);
getContext().getContentResolver().notifyChange(uri, null);
which I found somewhere (Vogella?) does not seem to work. Or is it a wrong approach from the start?
The image notification is done after the image is inserted into media database. This is usually done by the android system media scanner when it finds the image.
You can write your own code to insert the image into the media database and then call getContext().getContentResolver().notifyChange(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, null); to notify that some image has changed without beeing specific exatly which image.
If you modified an image that is already in the media database you have to translate the file uri into a content: uri. getContext().getContentResolver().notifyChange(imageContentUri, null); .
If you are implementing for android-4.4 or later You can ask the media scanner to (re)analyse your file. For details see How to trigger MediaScan on Nexus 7? . in pre android-4.4 this might not work as expected (i.e. on my android-4.2 it starts a complete rescan)
With the ID of an item stored on box, you can download it if it's a file, or download its contents if it's a folder. Either way it seems you need to know what sort of thing you're downloading in order to access it, doing either BoxFile file = new BoxFile(api, id); or BoxFolder folder = new BoxFolder(api, id); before handling the actual download.
I was hoping to be able to do something like
BoxItem boxItem = new BoxItem(api, id);
if (boxItem instanceof BoxFile) {
// download file
} else if (boxItem instanceof BoxFolder) {
// download all files in folder
}
sort of like the example in the docs of downloading a folder's contents. However, in that case the ID is that of a specific folder, whereas my ID is for either a folder or a file in the root folder, and I don't want to loop through all of the root folder's contents. And, anyway, BoxItem cannot be instantiated.
How can I tell ahead of time whether I'm downloading a file or a folder, with just the item's ID? If not, is there a way to download the item anyway?
I don't believe the API supports downloading an entire folder (and therefore the SDK doesn't either). The closest you can get is downloading all of the folder's files. That's why BoxFile has a download() method, but BoxFolder and BoxItem don't.
As for checking whether or not an ID corresponds to a file or folder - there isn't a way to tell without trying to make an API request. For example, you could try doing new BoxFile(api, id).getInfo() and seeing if it returns a 404.
I am using JGit for my project where i have to maintain the files uploaded by the users.
If the file already existing then it would create a new version of the same and associate the customer with his commited/uploaded set of files.
It works file locally i.e each file one uploads , commit it to repository i.e. on server machine and adds the same recored in the DB , to associate the customer and its respective file versioning lists i.e. commitIds.
But after few iterations of upload files (each upload may consists around 200 files) , JGit able to commit the files and generate the commitIds properly but not able to retreive the content of the files when showing the user back his commmitted files.
Unfortunately log does not show any errors while retreiving the files.
Hence i am lost ....and struggling to understand stand what is wrong here.
My questions are:
Does the JGIT have enough scalability ? i.e. fetch time would be fast enough as it grows?
what to do if i retrieve the files properly.
Below is the piece of code which i am using
FileUtils.copyFile(aFile,destFile);
AddCommand add = git.add();
add.addFilepattern(".").call();
CommitCommand commit = git.commit();
commit.setAuthor(user.getFirstName(), user.getUserId());
commit.setMessage("comments" ).call();
ObjectId lastCommitId = git.getRepository().resolve(org.eclipse.jgit.lib.Constants.HEAD);
Above destFile is GIT repository and aFile is the file name
Using the lastCommitId i am trying to retrive the content of the file but me getting the:
MissingObjectException: Missing unknown 0000000000000000000000000000000000000000
Code used to retreive the file is:
ObjectId lastCommitId = repo.resolve(lastCommitId);
RevTree tree = commit.getTree();
TreeWalk treeWalk = new TreeWalk(repo);
treeWalk.addTree(tree);
treeWalk.setRecursive(true);
treeWalk.setFilter(PathFilter.create("actial_File_Name")); //this is actual file name i used
boolean next = treeWalk.next();
if (next)
{
ObjectId objectId = treeWalk.getObjectId(0);
log.logError(" objectId :" + objectId );
try{
ObjectLoader loader = repo.open(objectId);
OutputStream out = new FileOutputStream(targetFile); ///targetFile is the actual file name i wanted to retreive the content i.e orginal name
loader.copyTo(out);
}
}
The 'missing unknown 0000' seems to suggest that one of your references is missing, and the null is being returned for the objectId. You should check to see if the objectId.equals(ObjectId.zeroId()) when you do the lookup.
You might also want to check to see if the repository needs garbage collection (either with JGit or a standalone Git client) - by default JGit doesn't do automatic garbage collection.
Note also that a commit doesn't get inserted into the database until you call the call() method and you get a commit back again. Maybe that's why you can't find it in your code?