Commit 512888f4 authored by Nihar Thakkar's avatar Nihar Thakkar
Browse files

Use external storage to download apps

parent 1a8224d3
......@@ -6,6 +6,8 @@
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<application
android:allowBackup="true"
......
package io.eelo.appinstaller
import android.annotation.SuppressLint
import android.content.pm.PackageManager
import android.os.Bundle
import android.support.design.internal.BottomNavigationItemView
import android.support.design.internal.BottomNavigationMenuView
import android.support.design.widget.BottomNavigationView
import android.support.design.widget.Snackbar
import android.support.v4.app.Fragment
import android.support.v7.app.AppCompatActivity
import android.view.MenuItem
......@@ -16,6 +18,7 @@ import io.eelo.appinstaller.home.HomeFragment
import io.eelo.appinstaller.search.SearchFragment
import io.eelo.appinstaller.settings.SettingsFragment
import io.eelo.appinstaller.updates.UpdatesFragment
import io.eelo.appinstaller.utils.Constants
import io.eelo.appinstaller.utils.Constants.CURRENTLY_SELECTED_FRAGMENT_KEY
import kotlinx.android.synthetic.main.activity_main.*
......@@ -120,6 +123,15 @@ class MainActivity : AppCompatActivity(), BottomNavigationView.OnNavigationItemS
}
}
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>,
grantResults: IntArray) {
if (requestCode == Constants.STORAGE_PERMISSION_REQUEST_CODE &&
grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_DENIED) {
Snackbar.make(container, R.string.error_storage_permission_denied,
Snackbar.LENGTH_LONG).show()
}
}
override fun onSaveInstanceState(outState: Bundle?) {
super.onSaveInstanceState(outState)
outState?.putInt(CURRENTLY_SELECTED_FRAGMENT_KEY, currentFragmentId)
......
......@@ -2,6 +2,7 @@ package io.eelo.appinstaller.application
import android.annotation.SuppressLint
import android.content.Intent
import android.content.pm.PackageManager
import android.graphics.Bitmap
import android.os.Bundle
import android.os.CountDownTimer
......@@ -26,6 +27,7 @@ import io.eelo.appinstaller.applicationmanager.ApplicationManagerServiceConnecti
import io.eelo.appinstaller.applicationmanager.ApplicationManagerServiceConnectionCallback
import io.eelo.appinstaller.utils.Common
import io.eelo.appinstaller.utils.Common.toMiB
import io.eelo.appinstaller.utils.Constants
import io.eelo.appinstaller.utils.Constants.APPLICATION_DESCRIPTION_KEY
import io.eelo.appinstaller.utils.Constants.APPLICATION_PACKAGE_NAME_KEY
import io.eelo.appinstaller.utils.Constants.SELECTED_APPLICATION_SCREENSHOT_KEY
......@@ -519,6 +521,17 @@ class ApplicationActivity : AppCompatActivity(), ApplicationStateListener,
}
}
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
if (requestCode == Constants.STORAGE_PERMISSION_REQUEST_CODE) {
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
application.buttonClicked(this)
} else if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_DENIED) {
Snackbar.make(container, R.string.error_storage_permission_denied,
Snackbar.LENGTH_LONG).show()
}
}
}
override fun onResume() {
super.onResume()
if (::application.isInitialized) {
......
package io.eelo.appinstaller.application.model
import android.Manifest
import android.app.Activity
import android.content.Context
import android.content.pm.PackageManager
import android.widget.ImageView
import io.eelo.appinstaller.api.AppDetailRequest
import io.eelo.appinstaller.api.PackageNameSearchRequest
......@@ -10,6 +12,7 @@ import io.eelo.appinstaller.application.model.data.BasicData
import io.eelo.appinstaller.application.model.data.FullData
import io.eelo.appinstaller.applicationmanager.ApplicationManager
import io.eelo.appinstaller.utils.Common
import io.eelo.appinstaller.utils.Constants
import io.eelo.appinstaller.utils.Error
import java.util.concurrent.atomic.AtomicInteger
......@@ -53,7 +56,11 @@ class Application(val packageName: String, private val applicationManager: Appli
fun buttonClicked(activity: Activity) {
when (stateManager.state) {
INSTALLED -> info.launch(activity)
NOT_UPDATED, NOT_DOWNLOADED -> applicationManager.download(this)
NOT_UPDATED, NOT_DOWNLOADED -> {
if (canWriteStorage(activity)) {
applicationManager.download(this)
}
}
INSTALLING -> {
applicationManager.stopInstalling(this)
return
......@@ -68,18 +75,32 @@ class Application(val packageName: String, private val applicationManager: Appli
stateManager.find(activity, basicData!!)
}
private fun canWriteStorage(activity: Activity): Boolean {
return if (android.os.Build.VERSION.SDK_INT >= 23) {
if (activity.checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
activity.requestPermissions(arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE),
Constants.STORAGE_PERMISSION_REQUEST_CODE)
false
} else {
true
}
} else {
true
}
}
fun download(context: Context) {
assertFullData(context)
downloader = Downloader()
stateManager.notifyDownloading(downloader!!)
try {
val canceled = downloader!!.download(context, fullData!!, info.getApkFile(context, basicData!!))
val canceled = downloader!!.download(context, fullData!!, info.getApkFile(basicData!!))
downloader = null
if (!canceled) {
applicationManager.install(this)
}
else {
info.getApkFile(context, basicData!!).delete()
} else {
info.getApkFile(basicData!!).delete()
}
} catch (e: Exception) {
stateManager.notifyError()
......
......@@ -3,6 +3,8 @@ package io.eelo.appinstaller.application.model
import android.content.Context
import android.content.pm.PackageInfo
import android.content.pm.PackageManager
import android.os.Environment
import android.os.Environment.getExternalStorageDirectory
import io.eelo.appinstaller.application.model.data.BasicData
import java.io.File
import java.util.regex.Pattern
......@@ -17,7 +19,7 @@ class ApplicationInfo(private val packageName: String) {
val installedVersionCode = packageInfo.versionCode
val pattern = Pattern.compile("[(]$installedVersionCode[)]")
val matcher = pattern.matcher(lastVersionNumber)
return matcher.find();
return matcher.find()
}
fun isInstalled(context: Context): Boolean {
......@@ -32,8 +34,8 @@ class ApplicationInfo(private val packageName: String) {
}
}
fun getApkFile(context: Context, data: BasicData): File {
return File(context.filesDir, packageName + "-" + data.lastVersionNumber + ".apk")
fun getApkFile(data: BasicData): File {
return File(getExternalStorageDirectory(), Environment.DIRECTORY_DOWNLOADS + packageName + "-" + data.lastVersionNumber + ".apk")
}
fun launch(context: Context) {
......@@ -41,6 +43,6 @@ class ApplicationInfo(private val packageName: String) {
}
fun install(context: Context, data: BasicData) {
Installer(getApkFile(context, data)).install(context)
Installer(getApkFile(data)).install(context)
}
}
......@@ -19,14 +19,14 @@ class StateManager(private val info: ApplicationInfo, private val app: Applicati
} else if (info.isLastVersionInstalled(context,
basicData.lastVersionNumber ?: "")) {
state = State.INSTALLED
info.getApkFile(context, basicData).delete()
info.getApkFile(basicData).delete()
} else if (info.isInstalled(context) && !info.isLastVersionInstalled(context,
basicData.lastVersionNumber ?: "")) {
state = State.NOT_UPDATED
info.getApkFile(context, basicData).delete()
info.getApkFile(basicData).delete()
} else {
state = State.NOT_DOWNLOADED
info.getApkFile(context, basicData).delete()
info.getApkFile(basicData).delete()
}
changeState(state)
}
......
......@@ -2,6 +2,7 @@
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
......
......@@ -78,6 +78,7 @@
<string name="preference_update_notify_available_description">Show a notification when app updates are available</string>
<!-- Errors -->
<string name="error_storage_permission_denied">Storage access is required for downloading apps.</string>
<string name="error_no_internet">Can\'t connect! Please check your internet connection and try again.</string>
<string name="error_server_unavailable">Server unavailable! Please try again later.</string>
<string name="error_request_timeout">Server took too long to respond! Please try again later.</string>
......
<?xml version="1.0" encoding="utf-8"?>
<paths>
<files-path
name="internal"
<external-path
name="external_files"
path="." />
</paths>
\ No newline at end of file
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment