Commit 8c2002b6 authored by jo's avatar jo
Browse files

add the service, save the context in the Application, change...

add the service, save the context in the Application, change applicationHolder's textView in the UIThread
parent 964269d4
......@@ -3,6 +3,7 @@
package="io.eelo.appinstaller">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<application
android:allowBackup="true"
......@@ -20,6 +21,7 @@
</activity>
<activity android:name=".application.ApplicationActivity" />
<activity android:name=".categories.CategoryActivity" />
<service android:name=".application.model.InstallManagerService"/>
</application>
</manifest>
\ No newline at end of file
package io.eelo.appinstaller
import android.support.v7.app.AppCompatActivity
import android.annotation.SuppressLint
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import android.os.Bundle
import android.os.IBinder
import android.os.Message
import android.os.Messenger
import android.support.design.internal.BottomNavigationItemView
import android.support.design.internal.BottomNavigationMenuView
import android.support.design.widget.BottomNavigationView
import android.annotation.SuppressLint
import android.content.Context
import android.support.v4.app.Fragment
import android.support.v7.app.AppCompatActivity
import android.view.MenuItem
import io.eelo.appinstaller.application.model.InstallManager
import io.eelo.appinstaller.application.model.InstallManagerService
import io.eelo.appinstaller.categories.CategoriesFragment
import io.eelo.appinstaller.home.HomeFragment
import io.eelo.appinstaller.search.SearchFragment
......@@ -28,8 +36,12 @@ class MainActivity : AppCompatActivity(), BottomNavigationView.OnNavigationItemS
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
Thread {
val installManager = createInstallManager()
initialiseFragments(installManager)
showFragment(homeFragment)
}.start()
// Show the home fragment by default
showFragment(homeFragment)
bottom_navigation_view.setOnNavigationItemSelectedListener(this)
......@@ -37,6 +49,33 @@ class MainActivity : AppCompatActivity(), BottomNavigationView.OnNavigationItemS
removeShiftMode(bottom_navigation_view)
}
private fun initialiseFragments(installManager: InstallManager) {
searchFragment.initialise(installManager)
updatesFragment.initialise(installManager)
}
private fun createInstallManager(): InstallManager {
startService(Intent(this, InstallManagerService::class.java))
val blocker = Object()
var installManager: InstallManager? = null
bindService(Intent(this, InstallManagerService::class.java), object : ServiceConnection {
override fun onServiceConnected(name: ComponentName, service: IBinder) {
Messenger(service).send(Message.obtain(null, 0, { result: InstallManager ->
installManager = result
synchronized(blocker) {
blocker.notify()
}
}))
}
override fun onServiceDisconnected(name: ComponentName) {}
}, Context.BIND_AUTO_CREATE)
synchronized(blocker) {
blocker.wait()
}
return installManager!!
}
override fun onNavigationItemSelected(item: MenuItem): Boolean {
when {
item.itemId == R.id.menu_home -> {
......@@ -91,5 +130,4 @@ class MainActivity : AppCompatActivity(), BottomNavigationView.OnNavigationItemS
itemView.setChecked(itemView.itemData.isChecked)
}
}
}
package io.eelo.appinstaller.application
import android.annotation.SuppressLint
import android.graphics.Bitmap
import android.os.AsyncTask
import android.support.v7.widget.RecyclerView
import android.view.View
import android.widget.Button
......@@ -37,7 +37,7 @@ class ApplicationViewHolder(private val view: View) : RecyclerView.ViewHolder(vi
applicationViewModel.onApplicationClick(view.context, application!!)
}
}
installButton.setOnClickListener { application?.buttonClicked(view.context) }
installButton.setOnClickListener { application?.buttonClicked() }
}
fun createApplicationView(app: Application) {
......@@ -45,12 +45,11 @@ class ApplicationViewHolder(private val view: View) : RecyclerView.ViewHolder(vi
icon.setImageBitmap((app.data.iconImage as ProxyBitmap).getBitmap())
} else {
icon.setImageDrawable(view.context.resources.getDrawable(R.drawable.ic_app_default))
ImageDownloader(object : OnImageLoaded {
override fun onImageLoaded(bitmap: Bitmap) {
icon.setImageBitmap(bitmap)
app.data.iconImage = ProxyBitmap(bitmap)
}
}).execute(app.data.icon)
ImageDownloader {
icon.setImageBitmap(it)
app.data.iconImage = ProxyBitmap(it)
}.execute(app.data.icon)
}
this.application?.removeListener(this)
this.application = app
......@@ -101,9 +100,16 @@ class ApplicationViewHolder(private val view: View) : RecyclerView.ViewHolder(vi
installButtonText = R.string.action_update
}
}
object : AsyncTask<Void, Void, Void>() {
override fun doInBackground(vararg params: Void?): Void? {
return null
}
installButton.text = view.context.resources.getString(installButtonText)
installButton.isEnabled = isInstallButtonEnabled
override fun onPostExecute(result: Void?) {
installButton.text = view.context.resources.getString(installButtonText)
installButton.isEnabled = isInstallButtonEnabled
}
}.execute()
}
@SuppressLint("SetTextI18n")
......
......@@ -8,7 +8,7 @@ import io.eelo.appinstaller.utlis.Constants
import java.io.IOException
import java.net.URL
class ImageDownloader(private val listener: OnImageLoaded) : AsyncTask<String, Void, Bitmap>() {
class ImageDownloader(private val listener: (Bitmap) -> Unit) : AsyncTask<String, Void, Bitmap>() {
override fun doInBackground(vararg image: String): Bitmap? {
......@@ -23,7 +23,7 @@ class ImageDownloader(private val listener: OnImageLoaded) : AsyncTask<String, V
override fun onPostExecute(bitmap: Bitmap?) {
if (bitmap != null) {
listener.onImageLoaded(bitmap)
listener.invoke(bitmap)
}
}
}
......@@ -8,8 +8,8 @@ import java.util.concurrent.atomic.AtomicInteger
class Application(var data: ApplicationData, context: Context, private val installManager: InstallManager) {
private val uses = AtomicInteger(0)
private val info = ApplicationInfo(data)
private val stateManager = StateManager(info, this, context)
private val info = ApplicationInfo(data, context)
private val stateManager = StateManager(info, this)
fun addListener(listener: ApplicationStateListener) {
stateManager.addListener(listener)
......@@ -28,14 +28,14 @@ class Application(var data: ApplicationData, context: Context, private val insta
}
fun decrementUses() {
uses.decrementAndGet();
uses.decrementAndGet()
installManager.tryRemove(this)
}
@Synchronized
fun buttonClicked(context: Context) {
fun buttonClicked() {
when (stateManager.state) {
INSTALLED -> info.launch(context)
INSTALLED -> info.launch()
DOWNLOADED -> {
stateManager.changeState(INSTALLING)
installManager.install(data.packageName)
......@@ -45,31 +45,32 @@ class Application(var data: ApplicationData, context: Context, private val insta
installManager.download(data.packageName)
}
DOWNLOADING -> {
}
INSTALLING -> {
}
}
}
fun download(context: Context) {
fun download() {
searchFullData()
downloader = info.createDownloader()
stateManager.notifyDownloading(downloader!!)
Thread {
try {
downloader!!.download()
stateManager.changeState(INSTALLING)
installManager.install(data.packageName)
stateManager.find(context)
} catch (e: IOException) {
stateManager.find(context)
stateManager.notifyError()
}
}.start()
try {
downloader!!.download()
stateManager.changeState(INSTALLING)
installManager.install(data.packageName)
stateManager.find()
} catch (e: IOException) {
e.printStackTrace()
stateManager.find()
stateManager.notifyError()
}
}
fun install(context: Context) {
info.install(context)
stateManager.find(context)
fun install() {
info.install()
stateManager.find()
}
fun isUsed(): Boolean {
......
......@@ -24,6 +24,7 @@ class ApplicationData {
var privacyScore = 0
var hasFullData = false
var downloadLink = ""
constructor(packageName: String) {
this.packageName = packageName
......
package io.eelo.appinstaller.application.model
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import io.eelo.appinstaller.utlis.Constants.APK_FOLDER
import java.io.File
class ApplicationInfo(private val data: ApplicationData) {
class ApplicationInfo(private val data: ApplicationData, private val context: Context) {
private val apkFile = File(APK_FOLDER + data.packageName + "-" + data.lastVersion + ".apk")
fun isLastVersionInstalled(context: Context): Boolean {
fun isLastVersionInstalled(): Boolean {
return try {
val packageInfo = context.packageManager.getPackageInfo(data.packageName, 0)
packageInfo.versionName == data.lastVersion
......@@ -18,7 +19,7 @@ class ApplicationInfo(private val data: ApplicationData) {
}
fun isInstalled(context: Context): Boolean {
fun isInstalled(): Boolean {
return try {
context.packageManager.getPackageInfo(data.packageName, 0)
true
......@@ -32,11 +33,11 @@ class ApplicationInfo(private val data: ApplicationData) {
get() = apkFile.exists()
fun launch(context: Context) {
fun launch() {
context.startActivity(context.packageManager.getLaunchIntentForPackage(data.packageName))
}
fun install(context: Context) {
fun install() {
Installer(apkFile, context).install()
}
......
......@@ -5,7 +5,7 @@ import java.io.*
import java.net.URL
import java.net.URLConnection
class Downloader internal constructor(private val data: ApplicationData, private val apkFile: File) {
class Downloader(private val data: ApplicationData, private val apkFile: File) {
var count = 0
private set
var total = 0
......@@ -14,7 +14,7 @@ class Downloader internal constructor(private val data: ApplicationData, private
@Throws(IOException::class)
fun download() {
val url = URL(Constants.BASE_URL + "apps?action=download&id=" + data.id + "&version=" + data.lastVersion)
val url = URL(Constants.DOWNLOAD_URL + data.downloadLink)
val connection = url.openConnection()
total = connection.contentLength
transferBytes(connection)
......
......@@ -46,7 +46,7 @@ class InstallManager(private val context: Context) {
private fun startDownloads() {
while (true) {
val app = apps[downloading.take()]!!
app.download(context)
app.download()
tryRemove(app)
}
}
......@@ -54,7 +54,7 @@ class InstallManager(private val context: Context) {
private fun startInstalls() {
while (true) {
val app = apps[installing.take()]!!
app.install(context)
app.install()
tryRemove(app)
}
}
......
package io.eelo.appinstaller.application.model
import android.app.Service
import android.content.Intent
import android.os.Handler
import android.os.IBinder
import android.os.Message
import android.os.Messenger
class InstallManagerService : Service() {
private val installManager = InstallManager(this)
private val messenger = Messenger(SimpleHandler(installManager))
override fun onCreate() {
installManager.start()
}
override fun onBind(intent: Intent): IBinder? {
return messenger.binder
}
private class SimpleHandler(private val installManager: InstallManager) : Handler() {
@Suppress("UNCHECKED_CAST")
override fun handleMessage(msg: Message) {
(msg.obj as (InstallManager) -> Unit).invoke(installManager)
}
}
}
package io.eelo.appinstaller.application.model
import android.content.Context
import java.util.*
class StateManager(private val info: ApplicationInfo, private val app: Application, context: Context) {
class StateManager(private val info: ApplicationInfo, private val app: Application) {
private var listeners = Collections.synchronizedList(ArrayList<ApplicationStateListener>())
var state = State.NOT_DOWNLOADED
private set
init {
find(context)
find()
}
fun find(context: Context) {
changeState(if (info.isLastVersionInstalled(context)) {
fun find() {
changeState(if (info.isLastVersionInstalled()) {
State.INSTALLED
} else if (info.isInstalled(context)) {
} else if (info.isInstalled()) {
if (info.isDownloaded) State.DOWNLOADED else State.NOT_UPDATED
} else if (info.isDownloaded) {
State.DOWNLOADED
......
......@@ -21,6 +21,7 @@ import io.eelo.appinstaller.common.ApplicationListAdapter
import io.eelo.appinstaller.search.viewModel.SearchViewModel
import android.app.Activity
import android.view.inputmethod.InputMethodManager
import io.eelo.appinstaller.application.model.InstallManager
class SearchFragment : Fragment(), SearchView.OnQueryTextListener, SearchView.OnSuggestionListener {
......@@ -31,12 +32,17 @@ class SearchFragment : Fragment(), SearchView.OnQueryTextListener, SearchView.On
private lateinit var progressBar: ProgressBar
private val SUGGESTION_KEY = "suggestion"
private var applicationList = ArrayList<Application>()
private var installManager:InstallManager? = null
fun initialise(installManager: InstallManager) {
this.installManager = installManager
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val view = inflater.inflate(R.layout.fragment_search, container, false)
searchViewModel = ViewModelProviders.of(activity!!).get(SearchViewModel::class.java)
searchViewModel.initialise(context!!)
searchViewModel.initialise(installManager!!)
focusView = view.findViewById(R.id.view)
focusView.requestFocus()
searchView = view.findViewById(R.id.search_view)
......
......@@ -21,10 +21,8 @@ class SearchModel : SearchModelInterface {
}
}
override fun initialise(context: Context) {
if (installManager == null) {
installManager = InstallManager(context)
}
override fun initialise(installManager: InstallManager) {
this.installManager = installManager
}
override fun searchSuggestions(searchQuery: String) {
......
package io.eelo.appinstaller.search.model
import android.content.Context
import io.eelo.appinstaller.application.model.Application
import io.eelo.appinstaller.application.model.InstallManager
interface SearchModelInterface {
fun initialise(context: Context)
fun initialise(installManager: InstallManager)
fun searchSuggestions(searchQuery: String)
......
......@@ -4,13 +4,14 @@ import android.arch.lifecycle.MutableLiveData
import android.arch.lifecycle.ViewModel
import android.content.Context
import io.eelo.appinstaller.application.model.Application
import io.eelo.appinstaller.application.model.InstallManager
import io.eelo.appinstaller.search.model.SearchModel
class SearchViewModel : ViewModel(), SearchViewModelInterface {
private val searchModel = SearchModel()
override fun initialise(context: Context) {
searchModel.initialise(context)
override fun initialise(installManager: InstallManager) {
searchModel.initialise(installManager)
}
override fun getSuggestions(): MutableLiveData<ArrayList<String>> {
......
package io.eelo.appinstaller.search.viewModel
import android.arch.lifecycle.MutableLiveData
import android.content.Context
import io.eelo.appinstaller.application.model.Application
import io.eelo.appinstaller.application.model.InstallManager
interface SearchViewModelInterface {
fun initialise(context: Context)
fun initialise(installManager: InstallManager)
fun getSuggestions(): MutableLiveData<ArrayList<String>>
......
......@@ -16,6 +16,11 @@ import io.eelo.appinstaller.updates.viewModel.UpdatesViewModel
class UpdatesFragment : Fragment() {
private lateinit var updatesViewModel: UpdatesViewModel
private var installManager: InstallManager? = null
fun initialise(installManager: InstallManager) {
this.installManager = installManager
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val view = inflater.inflate(R.layout.fragment_updates, container, false)
......@@ -24,7 +29,7 @@ class UpdatesFragment : Fragment() {
val recyclerView = view.findViewById<RecyclerView>(R.id.app_list)
initializeRecyclerView(recyclerView)
updatesViewModel.initialise(InstallManager(context!!))//TODO
updatesViewModel.initialise(installManager!!)
// Bind recycler view adapter to search results list in view model
updatesViewModel.getApplications().observe(this, Observer {
......
......@@ -4,12 +4,13 @@ object Constants {
// Global
const val BASE_URL = "https://api.cleanapk.org/"
const val DOWNLOAD_URL = "https://apk.cleanapk.org/"
// Search
const val RESULTS_PER_PAGE = 20
// Application
const val APK_FOLDER = ""
const val APK_FOLDER = "apks/"
// Categories
const val CATEGORY_KEY = "category_key"
......
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