How to Install Downloaded APK file programmatically? - android

Following is the code to download and install apk file when download is completed . but i cant open the apk file after download.
private fun downloadAPk(apkUrl: String) {
val request = DownloadManager.Request(Uri.parse(apkUrl))
request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI or DownloadManager.Request.NETWORK_MOBILE)
request.setTitle("Customer Information")
request.setDescription("Downloading...")
request.setDestinationInExternalFilesDir(this,"CI","CustomerInformation.apk")
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
val manager = getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
isDownloaded = manager.enqueue(request)
val broadcast = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
val id = intent?.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID,-1)
if (id == isDownloaded) {
val install = Intent(Intent.ACTION_VIEW);
install.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP;
val uri = ? // dont know how to get path of where file is downloaded
install.setDataAndType(Uri.parse(uri), manager.getMimeTypeForDownloadedFile(isDownloaded));
startActivity(install);
unregisterReceiver(this);
finish()
}
}
}
registerReceiver(broadcast, IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE))
}
i dont know if the code i used in "override onReceive()" will open & install the apk file... any suggessions how to open that downloaded APK file to install it? plz

Related

DownloadManager returned Uri is unusable in Android 13

I am trying to download a file into the external public directory but the Uri returned by downloadManager.getUriForDownloadedFile(requestId) isn't usable. I'm unable to launch an ACTION_OPEN intent with it, even though this same process works for Android 10.
I suspect this has something to do with missing updated permissions on Android 13, but there are no errors logged in logcat.
I am able to get it working as expected by using setDestinationInExternalFilesDir to store the file inside the private applications directory and using a ContentResolver to copy it into the phones external media storage, but that is a lot of code and very verbose. Using setDestinationInExternalPublicDir from DownloadManager is a lot cleaner and concise.
This is how I am creating and enqueuing my request
val request = DownloadManager
.Request(Uri.parse(downloadUrl))
.setDestinationInExternalPublicDir(
Environment.DIRECTORY_MOVIES,
"${UUID.randomUUID()}.mp4"
)
.setMimeType("video/mp4")
.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
.setTitle("Saving...")
.setRequiresCharging(false)
.setAllowedOverMetered(true)
.setAllowedOverRoaming(true)
requestId = downloadManager.enqueue(request)
And this is how I am listening for download completion and attempting to use the Uri.
private val downloadBroadCastReceiver: BroadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
val requestId = intent?.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1) ?: -1
val query = DownloadManager.Query()
query.setFilterById(requestId)
val cursor = downloadManager.query(query)
if (cursor.moveToFirst()) {
val columnIndex = cursor.getColumnIndex(DownloadManager.COLUMN_STATUS)
when (cursor.getInt(columnIndex)) {
DownloadManager.STATUS_SUCCESSFUL -> {
LOG.info("onReceive: Video download completed!")
val uri = downloadManager.getUriForDownloadedFile(requestId)
context.startActivity(
Intent(Intent.ACTION_VIEW, uri).apply {
setDataAndType(uri, "video/mp4")
}
)
}
}
}
}

Why doesn't anything download?

What I'm trying to do is have a basic pdf downloaded whenever I press a button. When I press the button I'm getting the text indicator "done" but nothing is being downloaded
btn_download.setOnClickListener {
var downloadRequest = DownloadManager.Request(
Uri.parse ("http://www.africau.edu/images/default/sample.pdf"))
.setTitle("a pdf")
.setDescription("a pdf")
.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE)
//over data
.setAllowedOverMetered(true)
.setAllowedOverRoaming(true)
val downloadManager = getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
downloadID = downloadManager.enqueue(downloadRequest)
}
var receiver = object:BroadcastReceiver(){
override fun onReceive(context: Context?, intent: Intent?) {
var id= intent?.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1)
if (downloadID == id){
Toast.makeText(applicationContext, "done",Toast.LENGTH_LONG).show()
}
}
}
registerReceiver(receiver, IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE))

Identifying the particular file after downloaded using Download Manager in Android

I am calling below function to download a binary file.
fun downloadFile(
baseActivity: Context,
batteryId: String,
downloadFileUrl: String?,
title: String?
): Long {
val directory =
File(Environment.getExternalStorageDirectory().toString() + "/destination_folder")
if (!directory.exists()) {
directory.mkdirs()
}
//Getting file extension i.e. .bin, .mp4 , .jpg, .png etc..
val fileExtension = downloadFileUrl?.substring(downloadFileUrl.lastIndexOf("."))
val downloadReference: Long
var objDownloadManager: DownloadManager =
baseActivity.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
val uri = Uri.parse(downloadFileUrl)
val request = DownloadManager.Request(uri)
//Firmware file name as batteryId and extension
firmwareFileSubPath = batteryId + fileExtension
request.setDestinationInExternalPublicDir(
Environment.DIRECTORY_DOWNLOADS,
"" + batteryId + fileExtension
)
request.setTitle(title)
downloadReference = objDownloadManager.enqueue(request) ?: 0
return downloadReference
}
Once the file got downloaded I am receiving it in below onReceive() method of Broadcast receiver:
override fun onReceive(context: Context, intent: Intent) {
if (intent.action == DownloadManager.ACTION_DOWNLOAD_COMPLETE) {
intent.extras?.let {
//retrieving the file
val downloadedFileId = it.getLong(DownloadManager.EXTRA_DOWNLOAD_ID)
val downloadManager =
getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
val uri: Uri = downloadManager.getUriForDownloadedFile(downloadedFileId)
viewModel.updateFirmwareFilePathToFirmwareTable(uri)
}
}
}
I am downloading the files one by one and wants to know that which file is downloaded.
Based on the particular file download, I have to update the entry in my local database.
So, here in onReceive() method how can I identify that which specific file is downloaded?
Thanks.
One way to identify your multiple downloads simultaneously is to track id returned from DownloadManager to your local db mapped to given entry when you call objDownloadManager.enqueue(request).
Document of DownloadManager.enquque indicates that:
Enqueue a new download. The download will start automatically once the download manager is ready to execute it and connectivity is available.
So, if you store that id mapped to your local database entry for given record then during onReceive() you can identify back to given record.
override fun onReceive(context: Context, intent: Intent) {
if (intent.action == DownloadManager.ACTION_DOWNLOAD_COMPLETE) {
intent.extras?.let {
//retrieving the file
val downloadedFileId = it.getLong(DownloadManager.EXTRA_DOWNLOAD_ID)
// Find same id from db that you stored previously
val downloadManager =
getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
val uri: Uri = downloadManager.getUriForDownloadedFile(downloadedFileId)
viewModel.updateFirmwareFilePathToFirmwareTable(uri)
}
}
}
Here, it.getLong(DownloadManager.EXTRA_DOWNLOAD_ID) returns you the same id for which download was started previously and enqueue returned.
Document for EXTRA_DOWNLOAD_ID indicates that:
Intent extra included with ACTION_DOWNLOAD_COMPLETE intents, indicating the ID (as a long) of the download that just completed.
You have the Uri of file, now simply get the file name to identify the file, you can use following function to get file name
fun getFileName(uri: Uri): String? {
var result: String? = null
when(uri.scheme){
"content" -> {
val cursor: Cursor? = getContentResolver().query(uri, null, null, null, null)
cursor.use {
if (it != null && it.moveToFirst()) {
result = it.getString(it.getColumnIndex(OpenableColumns.DISPLAY_NAME))
}
}
}
else -> {
val lastSlashIndex = uri.path?.lastIndexOf('/')
if(lastSlashIndex != null && lastSlashIndex != -1) {
result = uri.path!!.substring(lastSlashIndex + 1)
}
}
}
return result
}

Android Image Share to Another App Where is problem?

Im doing an app and i want to share photo just i saved to phone to another apps like instagram twitter.Im not able to do it and i cant see where the mistake is.Here is my code
`private fun getScreenshot(currentPage: Int){
QuickShot.of(requireActivity().findViewById<ConstraintLayout(currentPage))
.setResultListener(this)
.enableLogging()
.setFilename("screen")
.setPath("Spotibud")
.toJPG()
.save()
}
override fun onQuickShotSuccess(path: String?) {
Log.d(TAG, "onQuickShotSuccess: $path")
shareOnInstagram(path!!)
}
override fun onQuickShotFailed(path: String?, errorMsg: String?) {
Log.d(TAG, "onQuickShotFailed: $errorMsg")
}
private fun shareOnInstagram(path: String){
val stickerAssetUri: Uri = Uri.parse(path)
val intent = Intent().apply {
action = Intent.ACTION_SEND
putExtra(Intent.EXTRA_STREAM,stickerAssetUri)
type = "image/*"
}
startActivity(intent)
}`
and my log when app saves image
2021-02-18 17:28:08.750 16355-16355/com.example.contestifyfirsttry D/Home Fragment: onQuickShotSuccess: /Pictures/Spotibud/screen.jpg
also is there any code how i can see error.try catch not worked
now i found the solution this isnt best practice but im sure it makes you to see what you should do
private fun shareOnInstagram(path: String){
var file : File = File("/storage/emulated/0/Pictures/Spotibud/screen.jpg")
if (file.exists()){
Log.d(TAG, "shareOnInstagram: file exists")
val stickerAssetUri: Uri = Uri.fromFile(file)
val sourceApplication = "com.example.contestifyfirsttry"
val intent = Intent("com.instagram.share.ADD_TO_STORY")
intent.putExtra("source_application", sourceApplication)
intent.type = "image/*"
intent.putExtra("interactive_asset_uri", stickerAssetUri)
intent.putExtra("top_background_color", "#33FF33")
intent.putExtra("bottom_background_color", "#FF00FF")
val activity: Activity? = activity
activity!!.grantUriPermission(
"com.instagram.android", stickerAssetUri, Intent.FLAG_GRANT_READ_URI_PERMISSION
)
if (activity!!.packageManager.resolveActivity(intent, 0) != null) {
activity!!.startActivityForResult(intent, 0)
}
}else{
Log.d(TAG, "shareOnInstagram: file dont exists")
}
}

Android Database download online

Hi I am new in Android development and my app is completely database oriented.
In my app I am using the method of copying a database file from the assets folder.
It will increase the size of the apk.
I want to copy it from the internet the first time my app runs on the phone.
How do I download the database file to my app database folder.
This is how I did it:
I have an implementation of DownloadManager that deals with downloading the DB. In my case the DB is significantly big so DownloadManager is a good option for effectively dealing with large downloads.
One thing to note when implementing DownloadManager; It's recommended that you download files first as temporary files and then move them to the final location. This is to avoid weird security issues I faced when doing so. Also download notification visibility may affect what permissions are required, if you decide to have no notifications at all you need to add a DOWNLOAD_WITHOUT_NOTIFICATION.
Permissions required:
<uses-permission android:name="android.permission.DOWNLOAD_WITHOUT_NOTIFICATION" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE " />
DownloadManager implementation
/**
* Manages all DB retrieval and file level validation.
*
*/
class DataBaseInitializationRepository(private val app: Application, private val dbHelper: DatabaseFileHelper) {
fun initiateDB( callback: DownloadCompleteCallback){
val dbUrl = dbHelper.getDbUrl()
val tempDbFile = dbHelper.getTempDbFile()
val permanentDbFile = dbHelper.getPermanentDbFile()
if (!permanentDbFile.exists() && tempDbFile.length() <= 0) {
val downloadManager = app.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
val downLoadDBRequest = DownloadManager.Request(Uri.parse( dbUrl ))
.setTitle( app.getString( R.string.download_db_title ) )
.setDescription(app.getString( R.string.download_db_description ))
.setDestinationInExternalFilesDir( app,
null,
tempDbFile.path
)
.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
val downloadId = downloadManager.enqueue( downLoadDBRequest )
registerReceiver( callback, downloadId )
}else{
callback.onComplete(0L)
}
}
private fun registerReceiver(callback: DownloadCompleteCallback, downloadId: Long){
val receiver = object: BroadcastReceiver(){
override fun onReceive(context: Context?, intent: Intent?) {
val id = intent?.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1)
if (id == downloadId){
//Move index reads to reusable function
val downloadManager = app.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
val query = DownloadManager.Query()
query.setFilterById( downloadId )
val data = downloadManager.query( query )
if(data.moveToFirst() && data.count > 0){
val statusIndex = data.getColumnIndex(DownloadManager.COLUMN_STATUS)
val status = data.getInt( statusIndex )
if(status == DownloadManager.STATUS_SUCCESSFUL){
val localUriIndex = data.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI)
val localFile = File(
data.getString( localUriIndex )
.replace("file://","" )
)
if(localFile.exists()){
permanentlyStoreDb(localFile)
callback.onComplete(id)
}else{
callback.onFail("Initial Database Download Failed - File not found")
}
}else if(status == DownloadManager.STATUS_FAILED){
val reasonIndex = data.getColumnIndex(DownloadManager.COLUMN_REASON)
val reason = data.getInt( reasonIndex )
if(reason == DownloadManager.ERROR_FILE_ALREADY_EXISTS){
callback.onComplete(id)
}else{
callback.onFail("Initial Database Download Failed: $reason")
}
}
}else{
callback.onFail("Initial Database Download Failed - Unable to read download metadata")
}
}
}
}
app.registerReceiver( receiver, IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE) )
}
private fun permanentlyStoreDb(tempFile: File): File {
val permanentDbFile = dbHelper.getPermanentDbFile()
try {
if(tempFile.exists()) {
tempFile.copyTo(
permanentDbFile,
true,
1024
)
tempFile.delete()
}else{
throw IOException("Temporal DB file doesn't exist")
}
}catch (ioex: IOException) {
throw IOException("Unable to copy DB to permanent storage:", ioex)
}
return permanentDbFile
}
/**
* Allows download completion to be notified back to the calling view model
*/
interface DownloadCompleteCallback{
fun onComplete(downloadId: Long)
fun onFail(message: String)
}
}
DatabaseFileHelper contains the logic to determine the temporary file, the permanent DB location and the DB URL where the download will happen. This is the logic I used for the temporary file:
fun getTempDbFile(): File {
return File.createTempFile(<FILE-LOCATION>, null, app.cacheDir)
}
So in case you want to notify a running Activity/Fragment, you only need to pass a DownloadCompleteCallback implementation to this component to get it.
In case you are using Room, just make sure your implementation of RoomDatabase uses the following on your getInstance method
.createFromFile( dbFileHelper.getPermanentDbFile() )
just copy it from web instead of copying it form assets. Hint

Categories

Resources