Not getting Audios from Android 11 even download and other music files - android-studio

Here I am receiving only media Alarm Ringtones in android 11 but found all audios in other devices on android 10 and below versions
Here in picture you can see i am getting only Alarm bells in android 11

I found solution of this problem. In android 11 now Android introduces new Table MediaStore.Downloads to get other audio files:
#SuppressLint("Range")
suspend fun getAllAudioFiles(): ArrayList<AudioModel> {
val list = ArrayList<AudioModel>()
val files = ArrayList<File>()
list.clear()
withContext(Dispatchers.IO) {
try {
val columns = arrayOf(
MediaStore.Audio.Media.DATA,
MediaStore.Audio.Media.TITLE,
MediaStore.Audio.Media.SIZE,
MediaStore.Audio.Media.DURATION,
MediaStore.Audio.Media._ID,
)
//Some audio may be explicitly marked as not being music
//Some audio may be explicitly marked as not being music
val selection = MediaStore.Audio.Media.IS_MUSIC + " == 0"
//For Android 10 and Android 11
val cursor = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
MergeCursor(
arrayOf(
context.contentResolver.query(
MediaStore.Downloads.INTERNAL_CONTENT_URI,
columns, null,
null,
null
),
context.contentResolver.query(
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
columns, null,
null,
null
)
)
)
} else {
//For Below Android 11
MergeCursor(
arrayOf(
context.contentResolver.query(
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
columns, null,
null,
null
)
)
)
}
cursor?.moveToFirst()
// files.clear()
while (!cursor?.isAfterLast!!) {
val model = AudioModel()
val path =
cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.DATA))
// files.add(File(path))
val id =
cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media._ID))
val title =
cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.TITLE))
var duration =""
try {
duration =
cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.DURATION))
.toLong().convertLongToDurationTime()
}catch (e:Exception){
duration = "-1"
}
val size =
cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.SIZE))
.toLong().convertToLongTMbSize()
model.duration = duration
model.path = path
model.id = id
model.title = title
model.size = size
list.add(model)
cursor.moveToNext()
}
cursor.close()
} catch (e: Exception) {
e.printStackTrace()
}
}
return list
}
reference here: https://developer.android.com/training/data-storage/shared/media

Related

What's the right way to actually get this search functionality to work?

I have this app which displays a list of "coins" to the users . This list was parsed from an JSON API and I used Jetpack Compose for the UI. I implemented
Here is the code of the Jetpack composable list of "coins"
#Composable
fun CoinListScreen(
navController: NavController,
viewModel: CoinListViewModel = hiltViewModel(),
) {
val state = viewModel.state.value
Surface {
Box(modifier = Modifier.fillMaxSize()) {
Column {
androidx.compose.foundation.Image(painter = painterResource(id = R.drawable.ic_baseline_currency_bitcoin_24),
contentDescription = "BTC",
modifier = Modifier
.fillMaxWidth()
.align(CenterHorizontally)
.size(50.dp, 50.dp)
)
SearchBar(
hint = "Search..",
modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
){
viewModel.searchCoinsList(it) **//here I'm calling my search function from the view model, inside my search bar**
}
LazyColumn(modifier = Modifier.fillMaxSize()) {
items(state.coins) { coin ->
Spacer(modifier = Modifier.height(5.dp))
CoinListItem(
coin = coin,
onItemClick = {
navController.navigate(Screen.CoinDetailScreen.route + "/${coin.id}")
}
)
Divider()
}
}
}
if (state.error.isNotBlank()) {
Text(
text = state.error,
color = MaterialTheme.colors.error,
textAlign = TextAlign.Center,
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 20.dp)
.align(Alignment.Center)
)
}
if (state.isLoading) {
CircularProgressIndicator(modifier = Modifier.align(Alignment.Center))
}
}
}
}
**//and this Is my composable search bar**
#Composable
fun SearchBar(
modifier: Modifier = Modifier,
hint: String = "",
onSearch: (String) -> Unit = {}
) {
var text by remember {
mutableStateOf("")
}
var isHint by remember {
mutableStateOf(hint != "")
}
Box(modifier = modifier){
BasicTextField(
value = text,
onValueChange = {
text = it
onSearch(it)
},
maxLines = 1,
singleLine = true,
modifier = Modifier
.fillMaxWidth()
.shadow(5.dp, CircleShape)
.background(Color.White, CircleShape)
.padding(horizontal = 20.dp, vertical = 12.dp)
.onFocusChanged {
isHint = it.isFocused != true
}
)
if(isHint){
Text(
text = hint,
color = Color.LightGray,
modifier = Modifier.padding(horizontal = 20.dp, vertical = 12.dp)
)
}
}
}
and this is my view model, this is where I'm implementing the search function, this is where I'm lost, variables that I'm searching for are name, rank, and symbol from the Coin domain list
#HiltViewModel //injecting the use case
class CoinListViewModel #Inject constructor (
private val getCoinsUseCase: GetCoinsUseCase,
) : ViewModel() {
//vmstate Live Template, only the view model touches it
private val _state =
mutableStateOf(CoinListState())
val state: State<CoinListState> = _state
**//for search purposes , this is where I'm lost**
private var coinsList = mutableStateOf<List<Coin>>(listOf())
private var cachedCoinsList = listOf<Coin>()
private var isSearchStarting = true
private var isSearching = mutableStateOf(false)
init {
getCoins()
}
**//for search purposes , this is where I'm lost**
fun searchCoinsList(query: String){
val listToSearch = if(isSearchStarting){
coinsList.value
} else {
cachedCoinsList
}
viewModelScope.launch(Dispatchers.Default) {
if(query.isEmpty()){
coinsList.value = cachedCoinsList
isSearching.value = false
isSearchStarting = true
return#launch
}
val results = listToSearch.filter {
//val iterate: Int = coins.size
it.name.contains(query.trim(), ignoreCase = true) ||
(it.rank.toString() == query.trim()) ||
it.symbol.contains(query.trim(), ignoreCase = true)
}
if(isSearchStarting){
cachedCoinsList = coinsList.value
isSearchStarting = false
}
coinsList.value = results
isSearching.value = true
}
}
//function that calls our GetCoinsUseCase and puts the data inside the state object
//to display that in the UI
private fun getCoins() {
//overwrote the invoke function earlier for the use case which allows us to call the use case as a function
getCoinsUseCase().onEach { result ->
when (result) {
is Resource.SUCCESS -> {
_state.value =
CoinListState(coins = result.data ?: arrayListOf())
}
is Resource.ERROR -> {
_state.value =
CoinListState(
error = result.message ?: "An unexpected error occurred"
)
}
is Resource.LOADING -> {
_state.value = CoinListState(isLoading = true)
}
}
}.launchIn(viewModelScope)
}
}
CoinsListState data class used in view model
data class CoinListState(
val isLoading: Boolean = false,
val coins: ArrayList<Coin> = arrayListOf(),
val error: String = ""
)
this is my "GetCoinsUseCase" to get the coins
class GetCoinsUseCase #Inject constructor(
private val repository: CoinRepository
) {
// overwriting the operator fun invoke allows us to call the use case
//GetCoinsUseCase as if it was a function, and we return a flow because
// we want to emit states LOADING -> for progress bar, SUCCESS -> attach list of coins,
// and ERROR
operator fun invoke(): kotlinx.coroutines.flow.Flow<Resource<ArrayList<Coin>>> = flow {
try {
emit(Resource.LOADING<ArrayList<Coin>>())
//we mapped it to toCoin because we returning a list of coin, not coinDTO
val coins = repository.getCoins().map { it.toCoin() }
emit(Resource.SUCCESS<ArrayList<Coin>>(coins as ArrayList<Coin>))
}catch (e: HttpException){
emit(Resource.ERROR<ArrayList<Coin>>(e.localizedMessage ?: "An unexpected error occurred"))
}catch (e: IOException){
emit(Resource.ERROR<ArrayList<Coin>>("Couldn't reach server. Check connection"))
}
}
}
just the coin repository that is implemented in another place
interface CoinRepository {
//repository definitions
suspend fun getCoins() : ArrayList<CoinDTO>
suspend fun getCoinById(coinId: String) : CoinDetailDTO
}
This is my domain - Domain - only contains the data needed
data class Coin(
var id: String,
var isActive: Boolean,
var name: String,
var rank: Int,
var symbol: String
)
and this is how I'm mapping it
data class CoinDTO(
val id: String,
#SerializedName("is_active")
val isActive: Boolean,
#SerializedName("is_new")
val isNew: Boolean,
val name: String,
val rank: Int,
val symbol: String,
val type: String
)
fun CoinDTO.toCoin(): Coin {
return Coin(
id = id,
isActive = isActive,
name = name,
rank = rank,
symbol = symbol,
// logo = CoinDetailLogo(logo = String()).logo
)
}
Coin list item if needed for reference, this is what is displayed to the user in the list
#Composable
fun CoinListItem (
coin: Coin,
onItemClick: (Coin) -> Unit
) {
Row(
modifier = Modifier
.fillMaxWidth()
.clickable { onItemClick(coin) }
.padding(20.dp),
horizontalArrangement = Arrangement.SpaceBetween
) {
Text(
text = "${coin.rank}. ${coin.name} (${coin.symbol})",
style = MaterialTheme.typography.body1,
overflow = TextOverflow.Ellipsis
)
Text(
text = if(coin.isActive) "active" else "inactive",
color = if(coin.isActive) Color.Green else Color.Red,
fontStyle = FontStyle.Italic,
textAlign = TextAlign.End,
style = MaterialTheme.typography.body2,
modifier = Modifier.align(CenterVertically)
)
}
}
as well as the "Resource" generic for states
//UIStates
sealed class Resource<T>(val data: T? = null, val message: String? = null) {
class SUCCESS<T>(data: T) : Resource<T>(data)
class ERROR<T>(message: String, data: T? = null) : Resource<T>(data, message)
class LOADING<T>(data: T? = null) : Resource<T>(data)
}
again, given this info, how can I get the function searchCoinList in the view model to correctly view the searched data (name, rank, or symbol) when it is called in the CoinListScreen inside the Search Bar. Thank you so much
It seems like you want to implement a basic instant search functionality. It's pretty easy to achieve using Kotlin's StateFlow and its operators. Consider the following implementation with description:
// CoinListViewModel
private val queryFlow = MutableStateFlow("")
private val coinsList = mutableStateOf<List<Coin>>(listOf())
init {
queryFlow
.debounce(300) // filters out values that are followed by the newer values within the given timeout. The latest value is always emitted.
.filterNot { query -> userInput.isEmpty() } // filter the unwanted string like an empty string in this case to avoid the unnecessary network call.
.distinctUntilChanged() // to avoid duplicate network calls
.flowOn(Dispatchers.IO) // Changes the context where this flow is executed to Dispatchers.IO
.flatMapLatest { query -> // to avoid the network call results which are not needed more for displaying to the user
getCoinsUseCase(query).catch { emitAll(flowOf(emptyList())}
}
.onEach { coins: List<Coin> -> // go through each list of Coins
coinsList.value = coins
}
.launchIn(viewModelScope)
}
fun searchCoinsList(query: String) {
queryFlow.value = query
}

registerForActivityResult resultCode get 0 value

I'm trying to use registerForActivityResult but the result of it is 0, which mean that it doesn't get the result from the activity. The code was working perfectly last month when i did it, but i don't know why it made the error today, i tried to check for error in the code, but i dont think there is one.
Here is the function to use the camera :
private fun UseCamera() {
val takePictureIntent = Intent (MediaStore.ACTION_IMAGE_CAPTURE)
val imagePath = File(Environment.getExternalStorageDirectory(), "Pictures")
val photoFile = File(imagePath, "my_picture.jpg")
FilePath = FileProvider.getUriForFile(this, FILE_AUTHORITY, photoFile )
Log.w("FilePath",FilePath.toString())
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, FilePath)
takePictureIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
getPreviewImage.launch(takePictureIntent)
Log.w("UseCamera","Successful")
}
and here is the registerForResultActivity :
getPreviewImage = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
result -> Log.e("Preview Image", result.resultCode.toString())
if (result.resultCode == RESULT_OK) {
if (!forfood){
Log.i("File Path", FilePath.toString())
val SelectedImage = FilePath
val PicRef = StorageRef.child(preferences.getValue("username").toString())
.child("kiosk_pic/" + ImageID)
PicRef.putFile(SelectedImage).addOnSuccessListener {
Toast.makeText(this, "Uploaded", Toast.LENGTH_SHORT).show()
PicRef.downloadUrl.addOnSuccessListener {
preferences.setValue("kiosk_pic", it.toString())
ref.child(preferences.getValue("username").toString()).child("kiosk_picture").setValue(it.toString())
setKioskImage(preferences.getValue("kiosk_pic").toString(),ImageID)
}
}
.addOnFailureListener {
Toast.makeText(this, "Upload Fail", Toast.LENGTH_SHORT).show()
}
.addOnProgressListener {
Toast.makeText(this, "Uploading", Toast.LENGTH_SHORT).show()
}
} else {
Log.i("File Path",FilePath.toString())
val SelectedImage = FilePath
if (add){
iv_addimage.setImageURI(SelectedImage)
}else{
iv_changeimage.setImageURI(SelectedImage)
}
}
}
}
i added the log and the result was this everytime i use the camera :
W/UseCamera: Successfull
D/OpenGLRenderer: endAllActiveAnimators on 0xea49f7f0 (AlertController$RecycleListView) with handle 0xc1acc9b0
E/Preview Image: 0
what did i do wrong here? since it worked perfectly before
EDIT
and also the log says this :
W/InputEventReceiver: Attempted to finish an input event but the input event receiver has already been disposed.
I have fix the problem by changing the UseCamera function code. im not really sure, but i think the problem was this part :
val imagePath = File(Environment.getExternalStorageDirectory(), "Pictures")
val photoFile = File(imagePath, "my_picture.jpg")
since im not really sure, my guess is that the temporary file that was created was missing right after the picture was taken so then make the resultcode return RESULT_CANCELED
i change my code to this:
private fun UseCamera() {
val takePictureIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
val imageFile = getExternalFilesDir (Environment.DIRECTORY_PICTURES)
val tempFile = File.createTempFile("my_picture",".jpg",imageFile)
FilePath = FileProvider.getUriForFile(this, FILE_AUTHORITY,tempFile)
Log.e("File Path", FilePath.toString())
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT,FilePath)
getPreviewImage.launch(takePictureIntent)
}
and change the provider path to this
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="picture" path="Android/data/com.example.njajal/files/Pictures"/>
</paths>
i hope my answer, help some people with the same problem
if any one using java so use it
define first it to oncreate method :
ActivityResultLauncher<Intent> mStartForResult = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> {
Log.d("Capture_img", ": "+result.getData());
if (result.getResultCode()==Activity.RESULT_OK){
Intent intent = result.getData();
Uri uri = Objects.requireNonNull(intent).getData();
String path = uri.getPath();
File ff = new File("" +path);
String pffImage = ff.getName();
String path111 = GloabalMethods.imageCompressor(getContext(), path,pffImage);
File user_img = new File(""+path111);
Bitmap myBitmap = BitmapFactory.decodeFile(user_img.getAbsolutePath());
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
myBitmap.compress(Bitmap.CompressFormat.JPEG,80,bytes);
binaryImage = Base64.encodeToString(bytes.toByteArray(),Base64.DEFAULT);
Log.d("RRRRRRRRRRRRRRRR", "onActivityResult: "+uri);
capture_image.setImageBitmap(myBitmap);
capture_image.setTag("yes");
} after that call
ImagePicker.with(requireActivity()) .crop() //Crop image(Optional), Check Customization for more option .compress(1024)
//Final image size will be less thanMB(Optional)
.maxResultSize(1080, 1080).createIntent(intent -> { mStartForResult.launch(intent); return null; } );

How to save Room database data for orientation change

I create a search actor page where all movie for a specific actor appear using the database. The movies from the database does appear but when I rotate the screen, it disapear. I am trying to save the data using onSaveInstanceState but not sure how to.
Here what i've done so far:
var tv4 = findViewById<TextView>(R.id.tv4)
var edit1 = findViewById<EditText>(R.id.edit1)
var searchActor = findViewById<Button>(R.id.searchActor)
if (savedInstanceState != null){
}
val db = Room.databaseBuilder(this,AppDatabase::class.java,
"myDatabase").build()
//Step 2) Create the DAO object of the DB
val dao = db.getDao()
searchActor.setOnClickListener {
runBlocking {
launch {
val allfilm = dao.searchMovie()
val actorName = edit1.text.toString().lowercase()
tv4.setText("")
for (m in allfilm){
if (m!!.actor!!.contains(actorName, false))
tv4.append(m.title + "\n")
}
}
}
}
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
}
}

Flutter - how do I get the duration of a picked video file on Web?

I've tried everything and failed to determine the duration of a picked video file on Flutter Web. All libraries on pub.dev need a 'File' and this is not available on the web.
I've not been able to get this from the metadata either.
What worked for me, though I am unhappy with the solution approach is:
Widget buildHiddenVideoPlayer(Key key) {
var _videoElement = html.VideoElement();
_videoElement.id = 'htmlHiddenVideoID';
_videoElement.autoplay = true;
_videoElement.muted = true;
_videoElement.loop = true;
_videoElement.controls = false;
_videoElement.defaultMuted = true;
if (fileData != null) {
_videoElement.src = xfile.path; // where xfile is the file picked as XFile
}
// ignore: undefined_prefixed_name
ui.platformViewRegistry.registerViewFactory(
'htmlHiddenVideoID',
(int viewId) => _videoElement,
);
return HtmlElementView(
key: key,
viewType: 'htmlHiddenVideoID',
);
}
This widget is hidden in a 5 x 5 sized box behind a iFrame widget (in my implementation)
Then when I need the duration of a picked file:
VideoElement element = document.getElementById('htmlHiddenVideoID') as VideoElement;
setState(() {
element.src = pickedFile.path;
});
while (true) {
await Future.delayed(const Duration(milliseconds: 200), () {});
duration = element.duration;
if (!duration.isNaN) break; // duration is not returned immediately in many cases
}
element.pause(); // stops the hidden video from playing and consuming resources

concurrent query and insert have any side effect in android with objectbox?

In my android project, I use objectbox as database, if I insert with lock and query without lock, is there any side effect ? such as crash and so on.
fun query(uniqueId: String = ""): MutableList<T> {
if (box.store.isClosed) return mutableListOf()
val query = box.query()
withQueryBuilder(query, uniqueId)
//开始
return query.build().find()
}
private fun putInner(entity: T): Long {
synchronized(box.store) {
if (box.store.isClosed) return -1
if (entity.unique.isBlank()) {
entity.unique = entity.providerUnique()
}
entity.timestamp = System.currentTimeMillis()
return try {
box.put(entity).let { id -> entity.id = id }
entity.id
} catch (ex: Exception) {
-1
}
}
}

Resources