How to update insert delete to Contentprovider with nosql - android

I am not using sql db. a single key contains all my data as list of object.
(key:list)
How would I remove or insert or update the files and object holding paths of those files and also effect on content provider so that third party apps should know the changes and also dir, key-value storage and content provider all should synced .
Hawk storage storing the list of all Objects so I cannot access any specific object directly. For adding new object I have to store all objects in a list and add new object to list then put the list into Hawk with same key so it will replace the exisitng list.
I am using a key-value pair storage called Hawk which holds list of objects.
Objects has paths of stored files
files are stored in app specific storagei.e. CacheDir.
Content provider adds uri each time I create new Object
ContentProvider:
#Override
public boolean onCreate() {
Hawk.init(getContext()).build();
final String authority = RNWhatsAppStickersModule.getContentProviderAuthority(getContext());
if (!authority.startsWith(Objects.requireNonNull(getContext()).getPackageName())) {
throw new IllegalStateException("your authority (" + authority + ") for the content provider should start with your package name: " + getContext().getPackageName());
}
Log.d("ReactNative","authority "+authority);
//the call to get the metadata for the sticker packs.
MATCHER.addURI(authority, METADATA, METADATA_CODE);
//the call to get the metadata for single sticker pack. * represent the identifier
MATCHER.addURI(authority, METADATA + "/*", METADATA_CODE_FOR_SINGLE_PACK);
//gets the list of stickers for a sticker pack, * respresent the identifier.
MATCHER.addURI(authority, STICKERS + "/*", STICKERS_CODE);
for (StickerPack stickerPack : getStickerPackList()) {
MATCHER.addURI(authority, STICKERS_ASSET + "/" + stickerPack.identifier + "/" + stickerPack.trayImageFile, STICKER_PACK_TRAY_ICON_CODE);
for (Sticker sticker : stickerPack.getStickers()) {
MATCHER.addURI(authority, STICKERS_ASSET + "/" + stickerPack.identifier + "/" + sticker.imageFileName, STICKERS_ASSET_CODE);
}
}
return true;
}
#Override
public Cursor query(#NonNull Uri uri, #Nullable String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
final int code = MATCHER.match(uri);
if (code == METADATA_CODE) {
Log.d("ReactNative","METADATA_CODE "+String.valueOf(code));
return getPackForAllStickerPacks(uri);
} else if (code == METADATA_CODE_FOR_SINGLE_PACK) {
Log.d("ReactNative","METADATA_CODE_FOR_SINGLE_PACK "+String.valueOf(code));
return getCursorForSingleStickerPack(uri);
} else if (code == STICKERS_CODE) {
Log.d("ReactNative","STICKERS_CODE "+String.valueOf(code));
return getStickersForAStickerPack(uri);
} else {
throw new IllegalArgumentException("Unknown URI: " + uri);
}
}
#Nullable
#Override
public AssetFileDescriptor openAssetFile(#NonNull Uri uri, #NonNull String mode) {
final int matchCode = MATCHER.match(uri);
// if (matchCode == STICKERS_ASSET_CODE || matchCode == STICKER_PACK_TRAY_ICON_CODE) {
return getImageAsset(uri);
// return null;
}
#Override
public String getType(#NonNull Uri uri) {
final int matchCode = MATCHER.match(uri);
switch (matchCode) {
case METADATA_CODE:
return "vnd.android.cursor.dir/vnd." + RNWhatsAppStickersModule.getContentProviderAuthority(getContext()) + "." + METADATA;
case METADATA_CODE_FOR_SINGLE_PACK:
return "vnd.android.cursor.item/vnd." + RNWhatsAppStickersModule.getContentProviderAuthority(getContext()) + "." + METADATA;
case STICKERS_CODE:
return "vnd.android.cursor.dir/vnd." + RNWhatsAppStickersModule.getContentProviderAuthority(getContext()) + "." + STICKERS;
case STICKERS_ASSET_CODE:
return "image/webp";
case STICKER_PACK_TRAY_ICON_CODE:
return "image/png";
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
}
private synchronized void readContentFile(#NonNull Context context) {
// try (InputStream contentsInputStream = context.getAssets().open(CONTENT_FILE_NAME)) {
// stickerPackList = ContentFileParser.parseStickerPacks(contentsInputStream);
// } catch (IOException | IllegalStateException e) {
// throw new RuntimeException(CONTENT_FILE_NAME + " file has some issues: " + e.getMessage(), e);
// }
Log.d("ReactNative","readContentFile ");
if (Hawk.get("sticker_packs", new ArrayList<StickerPack>()) != null) {
stickerPackList.addAll(Hawk.get("sticker_packs", new ArrayList<StickerPack>()));
}
}
public List<StickerPack> getStickerPackList() {
// if (stickerPackList == null) {
// readContentFile(Objects.requireNonNull(getContext()));
// }
// return stickerPackList;
/*
* if (stickerPackList == null) {
* readContentFile(Objects.requireNonNull(getContext())); }
*/
Log.d("ReactNative","getStickerPackList ");
return (List) Hawk.get("sticker_packs", new ArrayList<StickerPack>());
}
private Cursor getPackForAllStickerPacks(#NonNull Uri uri) {
return getStickerPackInfo(uri, getStickerPackList());
}
private Cursor getCursorForSingleStickerPack(#NonNull Uri uri) {
final String identifier = uri.getLastPathSegment();
for (StickerPack stickerPack : getStickerPackList()) {
if (identifier.equals(stickerPack.identifier)) {
return getStickerPackInfo(uri, Collections.singletonList(stickerPack));
}
}
return getStickerPackInfo(uri, new ArrayList<StickerPack>());
}
#NonNull
private Cursor getStickerPackInfo(#NonNull Uri uri, #NonNull List<StickerPack> stickerPackList) {
MatrixCursor cursor = new MatrixCursor(
new String[]{
STICKER_PACK_IDENTIFIER_IN_QUERY,
STICKER_PACK_NAME_IN_QUERY,
STICKER_PACK_PUBLISHER_IN_QUERY,
STICKER_PACK_ICON_IN_QUERY,
ANDROID_APP_DOWNLOAD_LINK_IN_QUERY,
IOS_APP_DOWNLOAD_LINK_IN_QUERY,
PUBLISHER_EMAIL,
PUBLISHER_WEBSITE,
PRIVACY_POLICY_WEBSITE,
LICENSE_AGREENMENT_WEBSITE,
IMAGE_DATA_VERSION, // #3373
AVOID_CACHE, // #3373
ANIMATED_STICKER_PACK, // #3373
});
int i = 1;
for (StickerPack stickerPack : stickerPackList) {
Log.d("ReactNative","builder.add "+String.valueOf(i));
i++;
MatrixCursor.RowBuilder builder = cursor.newRow();
builder.add(stickerPack.identifier);
builder.add(stickerPack.name);
builder.add(stickerPack.publisher);
builder.add(stickerPack.trayImageFile);
builder.add(stickerPack.androidPlayStoreLink);
builder.add(stickerPack.iosAppStoreLink);
builder.add(stickerPack.publisherEmail);
builder.add(stickerPack.publisherWebsite);
builder.add(stickerPack.privacyPolicyWebsite);
builder.add(stickerPack.licenseAgreementWebsite);
builder.add(stickerPack.imageDataVersion); // #373
builder.add(stickerPack.avoidCache ? 1 : 0); // #373
builder.add(stickerPack.animatedStickerPack ? 1 : 0); // #373
}
cursor.setNotificationUri(Objects.requireNonNull(getContext()).getContentResolver(), uri);
return cursor;
}
#NonNull
private Cursor getStickersForAStickerPack(#NonNull Uri uri) {
final String identifier = uri.getLastPathSegment();
MatrixCursor cursor = new MatrixCursor(new String[]{STICKER_FILE_NAME_IN_QUERY, STICKER_FILE_EMOJI_IN_QUERY});
for (StickerPack stickerPack : getStickerPackList()) {
if (identifier.equals(stickerPack.identifier)) {
for (Sticker sticker : stickerPack.getStickers()) {
cursor.addRow(new Object[]{sticker.imageFileName, TextUtils.join(",", sticker.emojis)});
}
}
}
cursor.setNotificationUri(Objects.requireNonNull(getContext()).getContentResolver(), uri);
return cursor;
}
private AssetFileDescriptor getImageAsset(Uri uri) throws IllegalArgumentException {
Log.d("ReactNative","getImageAsset "+uri.toString());
AssetManager am = Objects.requireNonNull(getContext()).getAssets();
final List<String> pathSegments = uri.getPathSegments();
if (pathSegments.size() != 3) {
throw new IllegalArgumentException("path segments should be 3, uri is: " + uri);
}
String fileName = pathSegments.get(pathSegments.size() - 1);
final String identifier = pathSegments.get(pathSegments.size() - 2);
if (TextUtils.isEmpty(identifier)) {
throw new IllegalArgumentException("identifier is empty, uri: " + uri);
}
if (TextUtils.isEmpty(fileName)) {
throw new IllegalArgumentException("file name is empty, uri: " + uri);
}
//making sure the file that is trying to be fetched is in the list of stickers.
for (StickerPack stickerPack : getStickerPackList()) {
android.util.Log.d("ReactNative","stickerPack.identifier "+stickerPack.identifier);
if (identifier.equals(stickerPack.identifier)) {
if (fileName.equals(stickerPack.trayImageFile)) {
return fetchFile(uri, am, fileName, identifier, true);
} else {
for (Sticker sticker : stickerPack.getStickers()) {
if (fileName.equals(sticker.imageFileName)) {
return fetchFile(uri, am, fileName, identifier, false);
}
}
}
}
}
return null;
}
private AssetFileDescriptor fetchFile(#NonNull Uri uri, #NonNull AssetManager am, #NonNull String fileName, #NonNull String identifier, Boolean isTrayFile) {
Log.d("ReactNative","fetchFile "+fileName);
try {
File file;
file = new File(getContext().getFilesDir() + "/" + "stickers_asset" + "/" + identifier + "/", fileName);
if (!file.exists()) {
Log.d("ReactNative", "StickerPack dir not found");
// Log.d("fetFile", "StickerPack dir not found");
}
return new AssetFileDescriptor(ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY), 0L, -1L);
} catch (IOException e) {
Log.e(Objects.requireNonNull(getContext()).getPackageName(),
"IOException when getting asset file, uri:" + uri, e);
Log.d("ReactNative","IOException when getting asset file, uri:" + uri);
try {
return am.openFd("1" + "/" + "namaskar.webp");
} catch (IOException err) {
Log.e(Objects.requireNonNull(getContext()).getPackageName(), "IOException when getting asset file, uri:" + uri, err);
return null;
}
}
}
#Override
public int delete(#NonNull Uri uri, #Nullable String selection, String[] selectionArgs) {
throw new UnsupportedOperationException("Not supported");
}
#Override
public Uri insert(#NonNull Uri uri, ContentValues values) {
throw new UnsupportedOperationException("Not supported");
}
#Override
public int update(#NonNull Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
throw new UnsupportedOperationException("Not supported");
}
Adding new object to Hawk Storage:
...
// first extract all stored objects by Hawk.get("sticker_packs")
List<StickerPack> temp = Hawk.get("sticker_packs");
temp.add(newStickerPack);
Hawk.put("sticker_packs", temp);
// I am new to content provider . I understood how to do CRUD with content provider +sqlite. But here only uri are being added
...
I want to update the content provider and also want to make sure that Hawk storage and physical files should be updated as well. I am worried that if I change content uri then It wont hawk storage and real files path will be different.

Related

Can't create file with deleted file name at android 10

I want to keep a log text file for each day in the download folder. I want to store day based text files in my own Log folder(MyApp Log folder) in the Download folder.
When I delete the My App Log folder, I can't create this folder in the same location with the same name. Likewise, when the text file I created is deleted, I can't create a file with the same text file name. resolver.insert(downloadUri, contentValues); always returns null.
Even though I get a null result when I query whether there is a file belonging to that path, I can't create the same file.
The function where I created the file:
public static void createFile(){
String contentType = "text/log";
Date cDate = new Date(System.currentTimeMillis());
String today = new SimpleDateFormat("yyyy_MM_dd").format(cDate);
long seconds = TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis());
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
ContentValues contentValues = new ContentValues();
contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, today + ".txt");//2021_10_13.txt
contentValues.put(MediaStore.MediaColumns.MIME_TYPE, contentType);//text/log
contentValues.put(MediaStore.MediaColumns.DATE_ADDED, seconds);//System.currentTimeMillis
contentValues.put(MediaStore.MediaColumns.DATE_MODIFIED, seconds);//System.currentTimeMillis
contentValues.put(MediaStore.MediaColumns.IS_PENDING, 1);
contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS + File.separator + "MyApp Log");//Download/MyApp Log
ContentResolver resolver = getContext().getContentResolver();
outputUri = resolver.insert(getDownloadUri(), contentValues);
if (outputUri == null)
throw new IOException("Failed to create new MediaStore record.");
try (final OutputStream stream = resolver.openOutputStream(outputUri)) {
if (stream == null)
return;
} finally {
ContentValues updateValues = new ContentValues();
updateValues.put(MediaStore.MediaColumns.IS_PENDING, 0);
resolver.update(outputUri, updateValues, null, null);
}
}
public static #NonNull
Uri getDownloadUri() {
if (Build.VERSION.SDK_INT < 29) {
return getLegacyUri(Environment.DIRECTORY_DOWNLOADS);
} else {
return MediaStore.Downloads.EXTERNAL_CONTENT_URI;
}
}
The function I am querying if the file exists:
public static Uri getExternalContentUriFromFile(Uri externalUri, String filePath) {
if (externalUri == null)
return null;
try (Cursor cursor = getContentResolver().query(externalUri, new String[]{MediaStore.MediaColumns._ID},
MediaStore.MediaColumns.DATA + "=? ", new String[]{filePath}, null)) {
if (cursor != null && cursor.moveToFirst()) {
int id = cursor.getInt(cursor.getColumnIndex(MediaStore.MediaColumns._ID));
return Uri.withAppendedPath(externalUri, "" + id);
}
return null;
}
}
I found a solution myself:
int fileNo = 0;
Uri uri = saveToUri(fileName, contentType, seconds, relativePath);
if (uri == null) {
while (fileNo < 4 && uri == null) {
fileNo++;
fileName = AttachmentUtil.removeExtensionForName(fileName) + "(" + fileNo + ")" + extension;
uri = saveToUri(fileName, contentType, seconds, storageName + File.separator + myDirName, storageUri);
}
}
#Will V :
public static String removeExtensionForName(String fileName) {
int i = fileName.lastIndexOf('.');
if (i > 0) {
return fileName.substring(0, i);
}
return fileName;
}
And I got my code in above question into saveToUri function.

How to get URI from filename which is saved in the external Storage using Scoped Storage in android 10 and above?

Before SDK 29 this is the correct way to find the Uri but now it won't work anymore for sdk greater than 28. Let's assume I save the BITMAP using scoped-storage like:
#RequiresApi(api = Build.VERSION_CODES.Q)
#NonNull
private Uri saveBitmap(#NonNull final Context context, #NonNull final Bitmap bitmap,
#NonNull final Bitmap.CompressFormat format, #NonNull final String mimeType,
#NonNull final String displayName, #Nullable final String subFolder) throws IOException {
String relativeLocation = Environment.DIRECTORY_PICTURES;
if (!TextUtils.isEmpty(subFolder)) {
relativeLocation += File.separator + subFolder;
}
final ContentValues contentValues = new ContentValues();
contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, displayName);
contentValues.put(MediaStore.MediaColumns.MIME_TYPE, mimeType);
contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, relativeLocation);
final ContentResolver resolver = context.getContentResolver();
OutputStream stream = null;
Uri uri = null;
try {
final Uri contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
uri = resolver.insert(contentUri, contentValues);
if (uri == null) {
throw new IOException("Failed to create new MediaStore record.");
}
stream = resolver.openOutputStream(uri);
if (stream == null) {
throw new IOException("Failed to get output stream.");
}
if (!bitmap.compress(format, 95, stream)) {
throw new IOException("Failed to save bitmap.");
}
return uri;
} catch (IOException e) {
if (uri != null) {
// Don't leave an orphan entry in the MediaStore
resolver.delete(uri, null, null);
}
throw e;
} finally {
if (stream != null) {
stream.close();
}
}
}
This code works for SDK <= 28. But, How to get URI using fileName which is saved in the external storage for SDK version 29 and above?
private String getFilePathUri(String enteredFileName) {
String file_uri_string = Environment.getExternalStorageDirectory() + "/"
+ AppConstants.APP_FOLDER + "/" + enteredFileName + ".jpg";
AppUtils.showLog(TAG, file_uri_string + "");
return file_uri_string;
}
Android 10 and above: Here the uri gives the file_id based you the given displayName.
/**
* Returns the Uri which can be used to delete/work with images in the photo gallery.
* #param displayName Path to IMAGE on SD card
* #return Uri in the format of... content://media/external/images/media/[NUMBER]
*/
private Uri getUriFromPath(String displayName) {
long photoId;
Uri photoUri = MediaStore.Images.Media.getContentUri("external");
String[] projection = {MediaStore.Images.ImageColumns._ID};
// TODO This will break if we have no matching item in the MediaStore.
Cursor cursor = getContentResolver().query(photoUri, projection, MediaStore.Images.ImageColumns.DISPLAY_NAME + " LIKE ?", new String[] { displayName }, null);
assert cursor != null;
cursor.moveToFirst();
int columnIndex = cursor.getColumnIndex(projection[0]);
photoId = cursor.getLong(columnIndex);
cursor.close();
return Uri.parse(photoUri.toString() + "/" + photoId);
}

Whatsapp stickers showing error while adding to whatsapp

I am working on whatsapp stickers. I have tried this demo https://github.com/viztushar/stickers-internet .Also with the same data i am able add stickers in demo but not working in my code.
Content provide class :
public class StickerContentProvider extends ContentProvider {
/**
* Do not change the strings listed below, as these are used by WhatsApp. And changing these will break the interface between sticker app and WhatsApp.
*/
public static final String STICKER_PACK_IDENTIFIER_IN_QUERY = "sticker_pack_identifier";
public static final String STICKER_PACK_NAME_IN_QUERY = "sticker_pack_name";
public static final String STICKER_PACK_PUBLISHER_IN_QUERY = "sticker_pack_publisher";
public static final String STICKER_PACK_ICON_IN_QUERY = "sticker_pack_icon";
public static final String ANDROID_APP_DOWNLOAD_LINK_IN_QUERY = "android_play_store_link";
public static final String IOS_APP_DOWNLOAD_LINK_IN_QUERY = "ios_app_download_link";
public static final String PUBLISHER_EMAIL = "sticker_pack_publisher_email";
public static final String PUBLISHER_WEBSITE = "sticker_pack_publisher_website";
public static final String PRIVACY_POLICY_WEBSITE = "sticker_pack_privacy_policy_website";
public static final String LICENSE_AGREENMENT_WEBSITE = "sticker_pack_license_agreement_website";
public static final String STICKER_FILE_NAME_IN_QUERY = "sticker_file_name";
public static final String STICKER_FILE_EMOJI_IN_QUERY = "sticker_emoji";
public static final String CONTENT_FILE_NAME = "contents.json";
public static final String CONTENT_SCHEME = "content";
private static final String TAG = StickerContentProvider.class.getSimpleName();
public static Uri AUTHORITY_URI = new Uri.Builder().scheme(StickerContentProvider.CONTENT_SCHEME).authority(BuildConfig.CONTENT_PROVIDER_AUTHORITY).appendPath(StickerContentProvider.METADATA).build();
/**
* Do not change the values in the UriMatcher because otherwise, WhatsApp will not be able to fetch the stickers from the ContentProvider.
*/
private static final UriMatcher MATCHER = new UriMatcher(UriMatcher.NO_MATCH);
static final String METADATA = "metadata";
private static final int METADATA_CODE = 1;
private static final int METADATA_CODE_FOR_SINGLE_PACK = 2;
static final String STICKERS = "stickers";
private static final int STICKERS_CODE = 3;
static final String STICKERS_ASSET = "stickers_asset";
private static final int STICKERS_ASSET_CODE = 4;
private static final int STICKER_PACK_TRAY_ICON_CODE = 5;
private List<StickerPack> stickerPackList = new ArrayList<>();
#Override
public boolean onCreate() {
Hawk.init(getContext()).build();
final String authority = BuildConfig.CONTENT_PROVIDER_AUTHORITY;
if (!authority.startsWith(Objects.requireNonNull(getContext()).getPackageName())) {
throw new IllegalStateException("your authority (" + authority + ") for the content provider should start with your package name: " + getContext().getPackageName());
}
//the call to get the metadata for the sticker packs.
MATCHER.addURI(authority, METADATA, METADATA_CODE);
//the call to get the metadata for single sticker pack. * represent the identifier
MATCHER.addURI(authority, METADATA + "/*", METADATA_CODE_FOR_SINGLE_PACK);
//gets the list of stickers for a sticker pack, * respresent the identifier.
MATCHER.addURI(authority, STICKERS + "/*", STICKERS_CODE);
for (StickerPack stickerPack : getStickerPackList()) {
Log.e(TAG, "onCreate: " + stickerPack.identifier);
MATCHER.addURI(authority, STICKERS_ASSET + "/" + stickerPack.identifier + "/" + stickerPack.tray_image_file, STICKER_PACK_TRAY_ICON_CODE);
if (stickerPack.getStickers() != null) {
for (Sticker sticker : stickerPack.getStickers()) {
MATCHER.addURI(authority, STICKERS_ASSET + "/" + stickerPack.identifier + "/" + sticker.image_file, STICKERS_ASSET_CODE);
}
}
}
return true;
}
#Override
public Cursor query(#NonNull Uri uri, #Nullable String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
final int code = MATCHER.match(uri);
Log.d(TAG, "query: " + code + uri);
if (code == METADATA_CODE) {
return getPackForAllStickerPacks(uri);
} else if (code == METADATA_CODE_FOR_SINGLE_PACK) {
return getCursorForSingleStickerPack(uri);
} else if (code == STICKERS_CODE) {
return getStickersForAStickerPack(uri);
} else {
throw new IllegalArgumentException("Unknown URI: " + uri);
}
}
#Nullable
#Override
public AssetFileDescriptor openAssetFile(#NonNull Uri uri, #NonNull String mode) throws FileNotFoundException {
MATCHER.match(uri);
final int matchCode = MATCHER.match(uri);
final List<String> pathSegments = uri.getPathSegments();
Log.d(TAG, "openFile: " + matchCode + uri + "\n" + uri.getAuthority()
+ "\n" + pathSegments.get(pathSegments.size() - 3) + "/"
+ "\n" + pathSegments.get(pathSegments.size() - 2) + "/"
+ "\n" + pathSegments.get(pathSegments.size() - 1));
return getImageAsset(uri);
}
private AssetFileDescriptor getImageAsset(Uri uri) throws IllegalArgumentException {
AssetManager am = Objects.requireNonNull(getContext()).getAssets();
final List<String> pathSegments = uri.getPathSegments();
if (pathSegments.size() != 3) {
throw new IllegalArgumentException("path segments should be 3, uri is: " + uri);
}
String fileName = pathSegments.get(pathSegments.size() - 1);
final String identifier = pathSegments.get(pathSegments.size() - 2);
if (TextUtils.isEmpty(identifier)) {
throw new IllegalArgumentException("identifier is empty, uri: " + uri);
}
if (TextUtils.isEmpty(fileName)) {
throw new IllegalArgumentException("file name is empty, uri: " + uri);
}
//making sure the file that is trying to be fetched is in the list of stickers.
for (StickerPack stickerPack : getStickerPackList()) {
if (identifier.equals(stickerPack.identifier)) {
if (fileName.equals(stickerPack.tray_image_file)) {
return fetchFile(uri, am, fileName, identifier);
} else {
for (Sticker sticker : stickerPack.getStickers()) {
if (fileName.equals(sticker.image_file)) {
return fetchFile(uri, am, fileName, identifier);
}
}
}
}
}
return null;
}
private AssetFileDescriptor fetchFile(#NonNull Uri uri, #NonNull AssetManager am, #NonNull String fileName, #NonNull String identifier) {
try {
File file;
if(fileName.endsWith(".png")){
file = new File(getContext().getFilesDir()+ "/" + "stickers_asset" + "/" + identifier + "/try/", fileName);
} else {
file = new File(getContext().getFilesDir()+ "/" + "stickers_asset" + "/" + identifier + "/", fileName);
}
if (!file.exists()) {
Log.d("fetFile", "StickerPack dir not found");
}
Log.d("fetchFile", "StickerPack " + file.getPath());
return new AssetFileDescriptor(ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY), 0L, -1L);
} catch (IOException e) {
Log.e(Objects.requireNonNull(getContext()).getPackageName(), "IOException when getting asset file, uri:" + uri, e);
return null;
}
}
#Override
public String getType(#NonNull Uri uri) {
final int matchCode = MATCHER.match(uri);
switch (matchCode) {
case METADATA_CODE:
return "vnd.android.cursor.dir/vnd." + BuildConfig.CONTENT_PROVIDER_AUTHORITY + "." + METADATA;
case METADATA_CODE_FOR_SINGLE_PACK:
return "vnd.android.cursor.item/vnd." + BuildConfig.CONTENT_PROVIDER_AUTHORITY + "." + METADATA;
case STICKERS_CODE:
return "vnd.android.cursor.dir/vnd." + BuildConfig.CONTENT_PROVIDER_AUTHORITY + "." + STICKERS;
case STICKERS_ASSET_CODE:
return "image/webp";
case STICKER_PACK_TRAY_ICON_CODE:
return "image/png";
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
}
private synchronized void readContentFile(#NonNull Context context) {
if (Hawk.get("sticker_pack", new ArrayList<StickerPack>()) != null) {
stickerPackList.addAll(Hawk.get("sticker_pack", new ArrayList<StickerPack>()));
}
}
public List<StickerPack> getStickerPackList() {
/* if (stickerPackList == null) {
readContentFile(Objects.requireNonNull(getContext()));
}*/
return (List)Hawk.get("sticker_packs",new ArrayList<StickerPack>());
}
private Cursor getPackForAllStickerPacks(#NonNull Uri uri) {
return getStickerPackInfo(uri, getStickerPackList());
}
private Cursor getCursorForSingleStickerPack(#NonNull Uri uri) {
final String identifier = uri.getLastPathSegment();
for (StickerPack stickerPack : getStickerPackList()) {
if (identifier.equals(stickerPack.identifier)) {
return getStickerPackInfo(uri, Collections.singletonList(stickerPack));
}
}
return getStickerPackInfo(uri, new ArrayList<StickerPack>());
}
#NonNull
private Cursor getStickerPackInfo(#NonNull Uri uri, #NonNull List<StickerPack> stickerPackList) {
MatrixCursor cursor = new MatrixCursor(
new String[]{
STICKER_PACK_IDENTIFIER_IN_QUERY,
STICKER_PACK_NAME_IN_QUERY,
STICKER_PACK_PUBLISHER_IN_QUERY,
STICKER_PACK_ICON_IN_QUERY,
ANDROID_APP_DOWNLOAD_LINK_IN_QUERY,
IOS_APP_DOWNLOAD_LINK_IN_QUERY,
PUBLISHER_EMAIL,
PUBLISHER_WEBSITE,
PRIVACY_POLICY_WEBSITE,
LICENSE_AGREENMENT_WEBSITE
});
for (StickerPack stickerPack : stickerPackList) {
MatrixCursor.RowBuilder builder = cursor.newRow();
builder.add(stickerPack.identifier);
builder.add(stickerPack.name);
builder.add(stickerPack.publisher);
builder.add(stickerPack.tray_image_file);
builder.add(stickerPack.androidPlayStoreLink);
builder.add(stickerPack.iosAppStoreLink);
builder.add(stickerPack.publisher_email);
builder.add(stickerPack.publisher_website);
builder.add(stickerPack.privacy_policy_website);
builder.add(stickerPack.license_agreement_website);
}
Log.d(TAG, "getStickerPackInfo: " + stickerPackList.size());
cursor.setNotificationUri(Objects.requireNonNull(getContext()).getContentResolver(), uri);
return cursor;
}
#NonNull
private Cursor getStickersForAStickerPack(#NonNull Uri uri) {
final String identifier = uri.getLastPathSegment();
MatrixCursor cursor = new MatrixCursor(new String[]{STICKER_FILE_NAME_IN_QUERY, STICKER_FILE_EMOJI_IN_QUERY});
for (StickerPack stickerPack : getStickerPackList()) {
if (identifier.equals(stickerPack.identifier)) {
for (Sticker sticker : stickerPack.getStickers()) {
cursor.addRow(new Object[]{sticker.image_file, TextUtils.join(",", sticker.emojis)});
}
}
}
cursor.setNotificationUri(Objects.requireNonNull(getContext()).getContentResolver(), uri);
return cursor;
}
#Override
public int delete(#NonNull Uri uri, #Nullable String selection, String[] selectionArgs) {
throw new UnsupportedOperationException("Not supported");
}
#Override
public Uri insert(#NonNull Uri uri, ContentValues values) {
throw new UnsupportedOperationException("Not supported");
}
#Override
public int update(#NonNull Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
throw new UnsupportedOperationException("Not supported");
}
}
Please let me know if any other code require.
Error trace :
IOException when getting asset file, uri:content://com.mercatus.shoppers.stag.provider.StickerContentProvider/stickers_asset/1/69DEA9206D7A4EDF8D8E6439B41BBBB4.ashx
java.io.FileNotFoundException: open failed: ENOENT (No such file or directory)
at android.os.ParcelFileDescriptor.openInternal(ParcelFileDescriptor.java:313)
at android.os.ParcelFileDescriptor.open(ParcelFileDescriptor.java:211)
at com.mall.provider.StickerContentProvider.fetchFile(StickerContentProvider.java:187)
at com.mall.provider.StickerContentProvider.getImageAsset(StickerContentProvider.java:162)
at com.mall.provider.StickerContentProvider.openAssetFile(StickerContentProvider.java:140)
at android.content.ContentProvider.openTypedAssetFile(ContentProvider.java:1746)
at android.content.ContentProvider.openTypedAssetFile(ContentProvider.java:1812)
at android.content.ContentProvider$Transport.openTypedAssetFile(ContentProvider.java:425)
at android.content.ContentProviderNative.onTransact(ContentProviderNative.java:302)
at android.os.Binder.execTransact(Binder.java:739)
Error :
File location :

How to retrieve multiple audio files from android internal/External storage to a listview in another activity?

I am new to android programming and i am trying to get my hands dirty by building an app. I am try to retrieve multiple audio files(mp3) from internal or external storage and displaying each song in a listview in another activity. Then from there i want to be able to manipulate each song in the list. I am not interested in playing the song immediately. I am only able the get only one song title in another activity. I am confused right now and i dont know what to do or how to go about it. Any help or pointers would be very appreciated.
Here is my work so far. Its very basic.
public class MainActivity extends AppCompatActivity {
private static final int READ_REQUEST_CODE = 42;
private static final String TAG = "DATA";
Button btnOpenFileExplorer, btnViewTones, btnExit;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnOpenFileExplorer = findViewById(R.id.btnOpenFileExplorer);
btnViewTones = findViewById(R.id.btnViewSongs);
btnExit = findViewById(R.id.btnExit);
btnOpenFileExplorer.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("audio/*");
startActivityForResult(intent, READ_REQUEST_CODE);
}
});
}
#Override
protected void onActivityResult(int requestCode, int resultCode, #Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == READ_REQUEST_CODE && resultCode == Activity.RESULT_OK) {
Uri uri = null;
if (data != null) {
uri = data.getData();
Log.i(TAG, "Uri: " + uri.toString());
Cursor cursor = getContentResolver().query(uri, null, null, null, null);
try {
if (cursor != null && cursor.moveToFirst()) {
String displayName = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
Log.i(TAG, "Display Name: " + displayName);
Intent intent = new Intent(MainActivity.this, SongListActivity.class);
intent.putExtra("Song", displayName);
startActivity(intent);
Toast.makeText(this, "Display Name: " + displayName, Toast.LENGTH_SHORT).show();
}
} catch (Exception e) {
e.printStackTrace();
}
finally {
cursor.close();
}
}
}
}
}
I used this code retrieving songs from a custom location
by use this code Context.getContentResolver().query(uri, null, selection, filter, sortOrder)
/**
* Read the songs present in external storage
*
* #param context
* #return
* selection == "your audio selection criteria"
* filter= "your custom audio location (internal/external) "
* sortOrder="your audio list order "
*/
public static ArrayList<MediaItem> listOfSongs(Context context) {
// File file = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/" + .......path.... + "/");
// if (!file.exists()) {
//file.mkdir();
// }
Uri uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
String loc = Environment.getExternalStorageDirectory().getAbsolutePath() + "/" + "......" + "/";
// Filter only mp3s, only those marked by the MediaStore to be music and longer than 1 minute
String selection = MediaStore.Audio.Media.IS_MUSIC + " != 0"
+ " AND " + MediaStore.Audio.Media.DATA + " LIKE ? AND " +
MediaStore.Audio.Media.DATA + " NOT LIKE ?";
// + " AND " + MediaStore.Audio.Media.MIME_TYPE + "= 'audio/mpeg'";
// + " AND " + MediaStore.Audio.Media.DURATION + " > 60000";
String sortOrder = MediaStore.Audio.AudioColumns.TITLE
+ " COLLATE LOCALIZED ASC";
String test = MediaStore.Audio.Media.DATA + " LIKE ? AND " +
MediaStore.Audio.Media.DATA + " NOT LIKE ?";
// String[] test1 = new String[]{loc + "%", loc + "%/%"};
String[] filter = new String[]{loc + "%", loc + "%/%"};
Log.d(TAG, "Songs: loc " + loc);
Cursor c = context.getContentResolver().query(uri, null, selection, filter, sortOrder);
ArrayList<MediaItem> listOfSongs = new ArrayList<MediaItem>();
try {
// c.moveToFirst();
while (c.moveToNext()) {
MediaItem songData = new MediaItem();
String title = c.getString(c.getColumnIndex(MediaStore.Audio.Media.TITLE));
String artist = c.getString(c.getColumnIndex(MediaStore.Audio.Media.ARTIST));
String album = c.getString(c.getColumnIndex(MediaStore.Audio.Media.ALBUM));
long duration = c.getLong(c.getColumnIndex(MediaStore.Audio.Media.DURATION));
String data = c.getString(c.getColumnIndex(MediaStore.Audio.Media.DATA));
long albumId = c.getLong(c.getColumnIndex(MediaStore.Audio.Media.ALBUM_ID));
String composer = c.getString(c.getColumnIndex(MediaStore.Audio.Media.COMPOSER));
songData.setTitle(title);
songData.setAlbum(album);
songData.setArtist(artist);
songData.setDuration(duration);
songData.setPath(data);
songData.setAlbumId(albumId);
songData.setComposer(composer);
listOfSongs.add(songData);
}
c.close();
} catch (Exception e) {
Log.d(TAG, "listOfSongs() " + e.getMessage());
}
Log.d(TAG, "listOfSongs: size :" + listOfSongs.size());
return listOfSongs;
}
MediaItem.java
public class MediaItem {
String title;
String artist;
String album;
String path;
long duration;
long albumId;
String composer;
#Override
public String toString() {
return title;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getArtist() {
return artist;
}
public void setArtist(String artist) {
this.artist = artist;
}
public String getAlbum() {
return album;
}
public void setAlbum(String album) {
this.album = album;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
public long getDuration() {
return duration;
}
public void setDuration(long duration) {
this.duration = duration;
}
public long getAlbumId() {
return albumId;
}
public void setAlbumId(long albumId) {
this.albumId = albumId;
}
public String getComposer() {
return composer;
}
public void setComposer(String composer) {
this.composer = composer;
}
}

Getting filename from uri

How can I get the name of a file from a uri returned in OnActivityResult,
I tried using this bit of code
Uri uri = data.getData();
String fileName = uri.getLastPathSegment();
but it just returns something like this images:3565. The file that is picked is not only of image type it can be a video, or document file, etc.... I realized that the uri returned from kitkat is different than previous versions as well, I would be interested in a method that works for pre kitkat as well.
This is the code I'm using to get informations from a Uri :
public static class FileMetaData
{
public String displayName;
public long size;
public String mimeType;
public String path;
#Override
public String toString()
{
return "name : " + displayName + " ; size : " + size + " ; path : " + path + " ; mime : " + mimeType;
}
}
public static FileMetaData getFileMetaData(Context context, Uri uri)
{
FileMetaData fileMetaData = new FileMetaData();
if ("file".equalsIgnoreCase(uri.getScheme()))
{
File file = new File(uri.getPath());
fileMetaData.displayName = file.getName();
fileMetaData.size = file.length();
fileMetaData.path = file.getPath();
return fileMetaData;
}
else
{
ContentResolver contentResolver = context.getContentResolver();
Cursor cursor = contentResolver.query(uri, null, null, null, null);
fileMetaData.mimeType = contentResolver.getType(uri);
try
{
if (cursor != null && cursor.moveToFirst())
{
int sizeIndex = cursor.getColumnIndex(OpenableColumns.SIZE);
fileMetaData.displayName = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
if (!cursor.isNull(sizeIndex))
fileMetaData.size = cursor.getLong(sizeIndex);
else
fileMetaData.size = -1;
try
{
fileMetaData.path = cursor.getString(cursor.getColumnIndexOrThrow("_data"));
}
catch (Exception e)
{
// DO NOTHING, _data does not exist
}
return fileMetaData;
}
}
catch (Exception e)
{
Log.e(Log.TAG_CODE, e);
}
finally
{
if (cursor != null)
cursor.close();
}
return null;
}
}
Maybe this is too trivial, but in my case it worked:
DocumentFile.fromSingleUri(context, uri).getName();
(simplified, without null pointer checks). Similar with other metadata.
I think the most straightforward and easy way to retrieve information from an URI is using DocumentFile. Just create a new DocumentFile using context and your URI.
DocumentFile file = DocumentFile.fromSingleUri(context, uri);
Then you can retrieve various information from it.
String fileName = file.getName();
long fileSize = file.length();
String mimeType = file.getType(); //get the mime type
Note that file.getName() will return file name with extension (e.g. video.mp4)
For kotlin just use the name atttribute from the File class:
val fileName = File(uri.path).name
According to Android Documentation
/*
* Get the file's content URI from the incoming Intent,
* then query the server app to get the file's display name
* and size.
*/
returnIntent.data?.let { returnUri ->
contentResolver.query(returnUri, null, null, null, null)
}?.use { cursor ->
/*
* Get the column indexes of the data in the Cursor,
* move to the first row in the Cursor, get the data,
* and display it.
*/
val nameIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)
val sizeIndex = cursor.getColumnIndex(OpenableColumns.SIZE)
cursor.moveToFirst()
findViewById<TextView>(R.id.filename_text).text = cursor.getString(nameIndex)
findViewById<TextView>(R.id.filesize_text).text = cursor.getLong(sizeIndex).toString()
...
}
https://developer.android.com/training/secure-file-sharing/retrieve-info
fun Uri.getFileNameWithExtension(context: Context): String? {
val name = this.path?.let { path -> File(path).name }.orEmpty()
val extension = MimeTypeMap.getSingleton()
.getExtensionFromMimeType(getMimeType(context)).orEmpty()
return if (name.isNotEmpty() && extension.isNotEmpty()) "$name.$extension" else null
}
fun Uri.getMimeType(context: Context): String? {
return when (scheme) {
ContentResolver.SCHEME_CONTENT -> context.contentResolver.getType(this)
ContentResolver.SCHEME_FILE -> MimeTypeMap.getSingleton().getMimeTypeFromExtension(
MimeTypeMap.getFileExtensionFromUrl(toString()).toLowerCase(Locale.US)
)
else -> null
}
}
This worked for me. Have a look at the official documentation here
String[] projection = {MediaStore.MediaColumns.DISPLAY_NAME};
ContentResolver cr = mctx.getContentResolver();
Cursor metaCursor = cr.query(uri[0], projection, null, null, null);
if (metaCursor != null) {
try {
if (metaCursor.moveToFirst()) {
realFileName = metaCursor.getString(0);
}
} finally {
metaCursor.close();
}
}
If I use ContentResolver, it returns null if uri is from camera captured image in my case so simple function to get file name from uri
public static String getFileNameFromURI(#NonNull Context context, #NonNull Uri uri) {
String result = null;
if("file".equalsIgnoreCase(uri.getScheme())){
result= new File(uri.getPath()).getName();
}
else {
Cursor c = null;
try {
c = context.getContentResolver().query(uri, null, null, null, null);
c.moveToFirst();
result = c.getString(c.getColumnIndex(OpenableColumns.DISPLAY_NAME));
} catch (Exception e) {
// error occurs
} finally {
if (c != null) {
c.close();
}
}
}
return result;
}

Categories

Resources