fun showNotification(){
val path = Environment.getExternalStorageDirectory().toString() + "/Android/media/"
val uri = Uri.parse(path)
val intent = Intent(Intent.ACTION_PICK)
intent.setDataAndType(uri, "*/*")
val activityPendingIntent = PendingIntent.getActivity(
context,
1,
intent,
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) PendingIntent.FLAG_IMMUTABLE else 0
)
val notification = NotificationCompat.Builder(context, COUNTER_CHANNEL_ID)
.setSmallIcon(R.drawable.ic_download_done)
.setContentTitle("Download Finished")
.setContentText("Files at Android/media/")
.setContentIntent(activityPendingIntent)
.build()
notificationManager.notify(1, notification)
}
here is my code, I only manage to open the folder but I couldn't open the files.
What I wanted to happen is simply redirection to the folder and access the files in there. Is this possible? Am I approaching it wrong?
After a thorough searching, I found an answer that works for me..
// my notification function
fun showNotification(){
// an intent to be initialized when:
lateinit var intent: Intent
// A) Android version is 10 or above
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
val sm = context.getSystemService(Context.STORAGE_SERVICE) as StorageManager
intent = sm.primaryStorageVolume.createOpenDocumentTreeIntent()
var startDir = "Android%2Fmedia" // here is the directory you wanted to open. feel free to test based on your needs.
var uri: Uri = intent.getParcelableExtra("android.provider.extra.INITIAL_URI")!!
var scheme = uri.toString()
scheme = scheme.replace("/root/", "/document/");
scheme += "%3A$startDir";
uri = Uri.parse(scheme);
intent.putExtra("android.provider.extra.INITIAL_URI", uri);
// B) Android Versions 9 and below
} else {
val path = Environment.getExternalStorageDirectory().toString() + "/Android/media/yourpackagename" // path of the directory you wanted to open
val uri = Uri.parse(path)
intent = Intent(Intent.ACTION_PICK)
intent.putExtra("android.provider.extra.INITIAL_URI", uri)
intent.setDataAndType(uri, "*/*")
}
val activityPendingIntent = PendingIntent.getActivity(
context,
1,
intent,
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) PendingIntent.FLAG_IMMUTABLE else 0
)
// shows notification
val notification = NotificationCompat.Builder(context, COUNTER_CHANNEL_ID)
.setSmallIcon(R.drawable.ic_download_done)
.setContentTitle("Download Finished")
.setContentText("Locate at Files:Android/media/net.pregi.netmesh2/NetMesh")
.setContentIntent(activityPendingIntent)
.build()
notificationManager.notify(1, notification)
}
Note that for android 9 and below, I only managed to open the folder, but couldn't manage to open the file inside it. Still looking for an answer to this. For reference, here are the links that I've found related to this matter. Still open for suggestions.
Android 11 ACTION_OPEN_DOCUMENT_TREE
How to open specific folder in the storage using intent in android
Related
I want to try to make alarm Android app experiment in Kotlin so it can change audio sound from external storage, say that I already set the "A" audio sound for alarm sound from the external storage. Then, I want to change audio input sound that set into "B" audio sound for alarm sound from the external storage by reselecting it. The problem is, when I already change the audio input for alarm sound from audio "A" to audio "B" by reselecting it, audio "A" (previous audio) still playing the alarm sound instead of audio "B".
So this is the select audio button : (ignore the requestPermission(), supposse the permission is granted)
binding.selectAudio.setOnClickListener()
{
if (checkPermission())
{
openAudio()
}
else
{
requestPermission()
}
}
This is when the app redirected into selecting audio sound and get the path on it:
private fun openAudio()
{
//soundPath = null
onStop()
val openFileIntent = Intent(Intent.ACTION_GET_CONTENT)
openFileIntent.type = "audio/*"
getResult.launch(openFileIntent)
}
private val getResult =
registerForActivityResult(ActivityResultContracts.StartActivityForResult())
{
soundPath = null
if (it.resultCode == RESULT_OK)
{
val uri: Uri? = it.data!!.data
File(uri!!.getPath())
val path = getRealPath(this, uri)
soundPath = path
if (soundPath != null)
{
Toast.makeText(this, "Audio file has been set", Toast.LENGTH_SHORT).show()
}
}
}
This is the set alarm button :
binding.setAlarmBtn.setOnClickListener()
{
createNotificationChannel(soundPath)
setAlarm()
Log.e("notif", "soundpath" + soundPath.toString())
Log.d("soundPath", soundPath.toString())
}
This is the process of setting alarm into certain time :
private fun setAlarm()
{
try
{
alarmManager = getSystemService(ALARM_SERVICE) as AlarmManager
val intent = Intent(this, AlarmReceiver::class.java)
pendingIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_IMMUTABLE)
alarmManager[AlarmManager.RTC_WAKEUP, calendar.timeInMillis] = pendingIntent
Toast.makeText(this, "Alarm set successfully", Toast.LENGTH_SHORT).show()
}
catch (e: Exception)
{
Toast.makeText(this, "Time is not been set", Toast.LENGTH_SHORT).show()
}
}
And finally this is when alarm is playing through notification as well as get audio uri path after input audio sound :
private fun createNotificationChannel(path: String?)
{
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
{
val uri = getUri(path)
val attributes = AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_ALARM).build()
val name : CharSequence = "AlarmReminderChannel"
val description = "Channel For Alarm Manager"
val importance = NotificationManager.IMPORTANCE_HIGH
val channel = NotificationChannel("alarmManagerDemo", name, importance)
channel.description = description
channel.setSound(uri, attributes)
Log.e("notif", "uri" + uri.toString())
Log.e("notif", "uri from channel" + channel.sound.toString())
val notificationManager = getSystemService(NotificationManager::class.java)
notificationManager.createNotificationChannel(channel)
}
}
private fun getUri(path: String?) : Uri?
{
Log.e("notif", "path: "+path )
if(path == null)
{
Log.e("notif", "null" )
return Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" + this.packageName + "/raw/music")
}
else
{
Log.e("notif", "tidak null" )
return Uri.parse(path)
}
}
Also, this is the onReceive sound from BroadcastReceiver :
class AlarmReceiver : BroadcastReceiver()
{
override fun onReceive(context: Context?, intent: Intent?)
{
val bundle : Bundle? = intent!!.extras
val i = Intent(context, DestinationActivity::class.java)
intent!!.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
val pendingIntent = PendingIntent.getActivity(context, 0, i, PendingIntent.FLAG_IMMUTABLE)
val builder = NotificationCompat.Builder(context!!, "alarmManagerDemo")
.setSmallIcon(R.drawable.ic_launcher_background)
.setContentTitle("Demo")
.setContentText("Bla bla bla bla bla bla bla bla")
.setAutoCancel(true)
.setDefaults(NotificationCompat.DEFAULT_ALL)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setContentIntent(pendingIntent)
val notificationManager = NotificationManagerCompat.from(context)
notificationManager.notify(123, builder.build())
}
}
So, how do I solve this to make the alarm sound changed when the alarm is playing new input sound instead of previous input sound?
Android doesn't permit updating the sound of the notification channel by recreating it. You should first delete exist channel, and after create the new.
So, try it:
private fun createNotificationChannel(path: String?) {
...
val notificationManager = getSystemService(NotificationManager::class.java)
notificationManager.deleteNotificationChannel("alarmManagerDemo")
notificationManager.createNotificationChannel(channel)
}
I'm trying to build an auto updater via github. The app so far detects new available versions and downloads the apk file. I however cannot get it to install the apk file.
There are no crashes or Log messages indicating an error. The install dialog just does not show up.
This is my code:
fun downloadAndInstall(link: Uri, fileName: String){
val downloadManager = context.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
val downloadUri = link
val request = DownloadManager.Request(downloadUri)
request.setMimeType(MIME_TYPE)
val destination = context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).toString() + "/" + fileName
val destinationUri = Uri.parse("file://$destination")
request.setDestinationUri(destinationUri)
fun showInstallOption(destination: String) {
val onComplete = object : BroadcastReceiver() {
override fun onReceive(
context: Context,
intent: Intent
) {
val contentUri = FileProvider.getUriForFile(
context,
BuildConfig.APPLICATION_ID + ".provider",
File(destination)
)
val installer = context.packageManager.packageInstaller
val resolver = context.contentResolver
resolver.openInputStream(contentUri)?.use { apkStream ->
val length =
DocumentFile.fromSingleUri(context, contentUri)?.length() ?: -1
val params =
PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL)
val sessionId = installer.createSession(params)
val session = installer.openSession(sessionId)
session.openWrite("INSTALL", 0, length).use { sessionStream ->
apkStream.copyTo(sessionStream)
session.fsync(sessionStream)
}
val intent = Intent(context, InstallReceiver::class.java)
intent.action = "com.blazecode.tsviewer.util.updater.SESSION_API_PACKAGE_INSTALLED"
val pi = PendingIntent.getBroadcast(
context,
3,
intent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
)
session.commit(pi.intentSender)
session.close()
}
Toast.makeText(context, "done", Toast.LENGTH_LONG).show()
}
}
context.registerReceiver(onComplete, IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE))
}
showInstallOption(destination)
downloadManager.enqueue(request)
Toast.makeText(context, context.getString(R.string.downloading), Toast.LENGTH_LONG).show()
}
I tested this on Android 13 and 8, both with the same result. Android 13 is a physical device. Android 8 is an emulator.
In my app, I have several file Uri (NOT URI) store. These are of the form:
content://com.android.providers.downloads.documents/document/427
My intention is, once I click a button, open one of these Uri in a file reader (may it be MS Word, Excel, PDF Reader... depending on the extension and device).
I am currently trying this snippet:
val file = File(Uri.parse(uri).path!!)
val myMime: MimeTypeMap = MimeTypeMap.getSingleton()
val newIntent = Intent(Intent.ACTION_VIEW)
val mimeType: String = myMime.getMimeTypeFromExtension(file.extension).toString()
newIntent.setDataAndType(
FileProvider.getUriForFile(applicationContext, "${applicationContext.packageName}.provider", file), mimeType)
newIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
newIntent.flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
try {
startActivity(newIntent)
} catch (e: ActivityNotFoundException) {
}
But every time I try to open it, I get:
java.lang.IllegalArgumentException: Failed to find configured root that contains /document/427
Could you please tell me what am I missing? No answers I've found here targeted my problem. Thanks in advance!
UPDATE
Thanks to #CommonsWare help, I managed to avoid an Exception, my code now looks like this:
val newIntent = Intent(Intent.ACTION_VIEW)
newIntent.addCategory(Intent.CATEGORY_OPENABLE)
newIntent.data = Uri.parse(uri)
newIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
newIntent.flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
try {
startActivity(newIntent)
} catch (e: ActivityNotFoundException) {
Toast.makeText(this, e.toString(), Toast.LENGTH_LONG).show()
}
I'm getting the Uri from here:
val fileResultLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
viewModel.uploadFile(result, false)
}
fileFab.setOnClickListener {
val intent = Intent()
intent.type = "application/*"
intent.action = Intent.ACTION_OPEN_DOCUMENT
fileResultLauncher.launch(intent)
}
Unfortunately, I'm getting a NoActivityFoundException
Get rid of:
val file = File(Uri.parse(uri).path!!)
...and replace your setDataAndType() call with:
newIntent.setDataAndType(Uri.parse(uri), mimeType)
My android app flow is as follows:
Creates a csv file.
Store it in the default app folder.
Generates a notification of succesful creation
Open the csv in the default app.
I can not be able to open the csv via Intent or other methods so far.
With the following code I'm able to open the explorer but not in the folder path.
var path = this.applicationContext.getExternalFilesDir(null)?.absolutePath.toString()
println("Hey my path is $path")
val csvWriter = CSVWriter(
fileWriter,
CSVWriter.DEFAULT_SEPARATOR,
CSVWriter.NO_QUOTE_CHARACTER,
CSVWriter.DEFAULT_ESCAPE_CHARACTER,
CSVWriter.DEFAULT_LINE_END
)
csvWriter.writeAll(data.toMutableList())
csvWriter.close()
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
addCategory(Intent.CATEGORY_OPENABLE)
type = "application/*"
}
startActivityForResult(intent, 2)
Also, I tried to develop a function but without effective response:
fun open_file(filename: String?) {
val path = File(filesDir, "dl")
val file = File(path, filename)
// Get URI and MIME type of file
val uri = FileProvider.getUriForFile(this, "$PACKAGE_NAME.fileprovider", file)
val mime = contentResolver.getType(uri)
// Open file with user selected app
val intent = Intent()
intent.action = Intent.ACTION_VIEW
intent.setDataAndType(uri, mime)
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
startActivity(intent)
}
I saw some possible solutions developed in java but there are deprecated and / or does not work converted in Kotlin.
Edit:
Given the suggestion of #CommonsWare, I'm trying to save the file in the path given but the user. However, I get the error : No Activity found to handle Intent
val FILE_EXPORT_REQUEST_CODE = 12
val exportIntent = Intent(Intent.ACTION_CREATE_DOCUMENT)
exportIntent.addCategory(Intent.CATEGORY_OPENABLE)
exportIntent.type = "text/csv"
val uri = Uri.parse("$path/file.csv")
exportIntent.data = uri
val filename = "file.csv"
exportIntent.putExtra(Intent.EXTRA_TITLE, filename)
startActivityForResult(exportIntent, FILE_EXPORT_REQUEST_CODE)
Thanks in advance.
I implementing shortcut in my app but this is not working in VIVO 10( Funtouch OS). Please help me. I am already used many method but not success.
Method 1: I am using this code but not working
#SuppressLint("NewApi")
private fun shortcut(){
val shortcutManager = getSystemService(ShortcutManager::class.java)
val nhentaiIntent = Intent(this, MainActivity::class.java)
nhentaiIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
nhentaiIntent.action = Intent.ACTION_VIEW
if (shortcutManager!!.isRequestPinShortcutSupported) {
val pinShortcutInfo = ShortcutInfo.Builder(this, "my-shortcut")
.setIcon(Icon.createWithResource(this, R.mipmap.ic_launcher))
.setShortLabel("hello Shortcut")
.setIntent(nhentaiIntent)
.build()
val pinnedShortcutCallbackIntent = shortcutManager.createShortcutResultIntent(pinShortcutInfo)
val successCallback = PendingIntent.getBroadcast(this, /* request code */ 0, pinnedShortcutCallbackIntent, /* flags */ 0)
shortcutManager.requestPinShortcut(pinShortcutInfo, successCallback.intentSender)
}
}
Method 2: I am also used this code but not working
Intent nhentaiIntent = new Intent(context, MainActivity.class);
nhentaiIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
nhentaiIntent.setAction(Intent.ACTION_VIEW);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
ShortcutManager shortcutManager = context.getSystemService(ShortcutManager.class);
if (shortcutManager.isRequestPinShortcutSupported()) {
ShortcutInfo info = new ShortcutInfo.Builder(context, "Shortcut")
.setIntent(nhentaiIntent)
.setIcon(Icon.createWithResource(context, R.mipmap.ic_launcher))
.setShortLabel("Hello ")
.setLongLabel("Lable")
.build();
Intent addIntent = shortcutManager.createShortcutResultIntent(info);
shortcutManager.requestPinShortcut(info, PendingIntent.getBroadcast(context, 0, addIntent, 0).getIntentSender());
Toast.makeText(context, "supported_launcher", Toast.LENGTH_LONG).show();
} else {
// TODO: Maybe implement this for launchers without pin shortcut support?
// TODO: Should be the same with the fallback for Android < O
// for now just show unsupported
Toast.makeText(context, "unsupported_launcher", Toast.LENGTH_LONG).show();
}
}
Method 3: I am also used this code but not working
private fun addShourcut() {
if (ShortcutManagerCompat.isRequestPinShortcutSupported(applicationContext)) {
val shortcutInfo =
ShortcutInfoCompat.Builder(applicationContext, "#1")
.setIntent(
Intent(applicationContext, MainActivity::class.java).setAction(
Intent.ACTION_MAIN
)
) // !!! intent's action must be set on oreo
.setShortLabel("Test")
.setIcon(
IconCompat.createWithResource(
applicationContext,
R.mipmap.ic_launcher
)
)
.build()
ShortcutManagerCompat.requestPinShortcut(applicationContext, shortcutInfo, null)
} else {
Toast.makeText(
this#MainActivity, "launcher does not support short cut icon",Toast.LENGTH_LONG).show()
}
}
Please help me anyone i spent more time for this issue.
I found that desktop shortcut is not created in default launcher of vivo devices. When I changed default launcher to some other launcher It's let me create desktop shortcut. So as far I did R&d I found below solution it's not complete solution but you can redirect to allow Desktop shortcuts screen using below code.
val sintent = Intent()
sintent .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
sintent .component = ComponentName("com.bbk.launcher2", "com.bbk.launcher2.installshortcut.PurviewActivity")
activity.startActivity(sintent )
I tried to get result if user allowed or not but it's not work for all VIVO devices.
var uri = Uri.parse("content://com.bbk.launcher2.settings/favorites")
var query = activity.contentResolver.query(uri, null, " itemType = ?", arrayOf("30"), null);
if (query != null && query.count > 0) {
var idIndex = query.getColumnIndexOrThrow("_id");
var intentIndex = query.getColumnIndexOrThrow("intent");
var shortcutPermissionIndex = query.getColumnIndexOrThrow("shortcutPermission");
while (query.moveToNext()) {
val long = query.getLong(idIndex)
val intent = query.getString(intentIndex)
val shortcutPermission = query.getInt(shortcutPermissionIndex)
var unflattenFromString = ComponentName.unflattenFromString(intent)
Log.e("bhavin->", "initView: getShortcutPerBtn id=$long packageName= ${unflattenFromString!!.packageName} shortcutPermission= $shortcutPermission")
if (unflattenFromString!!.packageName == activity.packageName && shortcutPermission != 0 && shortcutPermission != 16){
val intent = Intent()
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
intent.component = ComponentName("com.bbk.launcher2", "com.bbk.launcher2.installshortcut.PurviewActivity")
activity.startActivity(intent)
query.close()
return#ensureBackgroundThread
}
else{
Log.e("bhavin->","abcd")
}
}
query.close()
}
For more details you can check this I found this git
Note: I found exception some devices vivo 1902 and Z3
java.lang.SecurityException: Permission Denial: opening provider
com.bbk.launcher2.data.LauncherProvider from ProcessRecord{f8f30af
16137:com.qiutinghe.change/u0a172} (pid=16137, uid=10172) requires
com.bbk.launcher2.permission.READ_SETTINGS or
com.bbk.launcher2.permission.WRITE_SETTINGS
If any one found how to check desktop permission is allowed in Vivo devices please add into this answer.