Replace apps list with a RecyclerView

this is way faster, more efficient - and it even enables the app to show 
app icone, which Closes #31
This commit is contained in:
Finn M Glas 2020-05-27 10:59:19 +02:00
parent c8f202d570
commit 4c131e4aed
No known key found for this signature in database
GPG key ID: 25037A2E81AB459C
5 changed files with 161 additions and 59 deletions

View file

@ -2,21 +2,22 @@ package com.finnmglas.launcher
import android.app.Activity import android.app.Activity
import android.content.Intent import android.content.Intent
import android.graphics.Color
import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.view.View import android.view.View
import android.view.WindowManager import android.view.WindowManager
import android.widget.TextView
import android.widget.Toast import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.finnmglas.launcher.choose.AppsRecyclerAdapter
import com.finnmglas.launcher.extern.* import com.finnmglas.launcher.extern.*
import kotlinx.android.synthetic.main.activity_choose.* import kotlinx.android.synthetic.main.activity_choose.*
class ChooseActivity : AppCompatActivity() { class ChooseActivity : AppCompatActivity() {
/** Activity Lifecycle functions */ private lateinit var viewAdapter: RecyclerView.Adapter<*>
private lateinit var viewManager: RecyclerView.LayoutManager
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@ -42,56 +43,31 @@ class ChooseActivity : AppCompatActivity() {
// As older APIs somehow do not recognize the xml defined onClick // As older APIs somehow do not recognize the xml defined onClick
activity_choose_close.setOnClickListener() { finish() } activity_choose_close.setOnClickListener() { finish() }
// get info about which action this activity is open for
val bundle = intent.extras val bundle = intent.extras
val action = bundle!!.getString("action") // why choose an app val action = bundle!!.getString("action") // why choose an app
val forApp = bundle.getString("forApp") // which app we choose val forApp = bundle.getString("forApp") // which app we choose
if (action == "launch") when (action) {
activity_choose_heading.text = getString(R.string.choose_title_launch) "launch" -> activity_choose_heading.text = getString(R.string.choose_title_launch)
else if (action == "pick") "pick" -> activity_choose_heading.text = getString(R.string.choose_title)
activity_choose_heading.text = getString(R.string.choose_title) "uninstall" -> activity_choose_heading.text = getString(R.string.choose_title_remove)
else if (action == "uninstall") }
activity_choose_heading.text = getString(R.string.choose_title_remove)
/* Build Layout */ // set up the list / recycler
viewManager = LinearLayoutManager(this)
viewAdapter = AppsRecyclerAdapter( this, action, forApp)
for (resolveInfo in appsList) { activity_choose_apps_recycler_view.apply {
val app = resolveInfo.activityInfo // improve performance (since content changes don't change the layout size)
setHasFixedSize(true)
layoutManager = viewManager
adapter = viewAdapter
}
}
// creating TextView programmatically /*
val tvdynamic = TextView(this) }*/
tvdynamic.textSize = 24f
tvdynamic.text = app.loadLabel(packageManager).toString()
tvdynamic.setTextColor(Color.parseColor("#cccccc"))
if (action == "launch"){
tvdynamic.setOnClickListener { startActivity(packageManager.getLaunchIntentForPackage(app.packageName)) }
}
else if (action == "pick"){
tvdynamic.setOnClickListener {
val returnIntent = Intent()
returnIntent.putExtra("value", app.packageName)
returnIntent.putExtra("forApp", forApp)
setResult(
REQUEST_CHOOSE_APP,
returnIntent
)
finish()
}
}
else if (action == "uninstall"){
tvdynamic.setOnClickListener {
val intent = Intent(Intent.ACTION_UNINSTALL_PACKAGE)
intent.data = Uri.parse("package:" + app.packageName)
intent.putExtra(Intent.EXTRA_RETURN_RESULT, true)
startActivityForResult(intent,
REQUEST_UNINSTALL
)
}
}
activity_choose_apps_list.addView(tvdynamic)
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data) super.onActivityResult(requestCode, resultCode, data)

View file

@ -0,0 +1,9 @@
package com.finnmglas.launcher.choose
import android.graphics.drawable.Drawable
class AppInfo {
var label: CharSequence? = null
var packageName: CharSequence? = null
var icon: Drawable? = null
}

View file

@ -0,0 +1,93 @@
package com.finnmglas.launcher.choose
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import android.widget.Toast
import androidx.recyclerview.widget.RecyclerView
import com.finnmglas.launcher.R
import com.finnmglas.launcher.extern.*
class AppsRecyclerAdapter(val activity: Activity, val action: String?, val forApp: String?):
RecyclerView.Adapter<AppsRecyclerAdapter.ViewHolder>() {
private val appsList: MutableList<AppInfo>
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView),
View.OnClickListener {
var textView: TextView = itemView.findViewById(R.id.choose_row_app_name)
var img: ImageView = itemView.findViewById(R.id.choose_row_app_icon) as ImageView
override fun onClick(v: View) {
val pos = adapterPosition
val context: Context = v.context
val appPackageName = appsList[pos].packageName.toString()
when (action){
"launch" -> {
val launchIntent: Intent = context.packageManager
.getLaunchIntentForPackage(appPackageName)!!
context.startActivity(launchIntent)
Toast.makeText(v.context, appsList[pos].label.toString(), Toast.LENGTH_LONG)
.show()
}
"pick" -> {
val returnIntent = Intent()
returnIntent.putExtra("value", appPackageName)
returnIntent.putExtra("forApp", forApp)
activity.setResult(REQUEST_CHOOSE_APP, returnIntent)
activity.finish()
}
"uninstall" -> {
val intent = Intent(Intent.ACTION_UNINSTALL_PACKAGE)
intent.data = Uri.parse("package:$appPackageName")
intent.putExtra(Intent.EXTRA_RETURN_RESULT, true)
activity.startActivityForResult(intent, REQUEST_UNINSTALL)
}
}
}
init { itemView.setOnClickListener(this) }
}
override fun onBindViewHolder(viewHolder: ViewHolder, i: Int) {
val appLabel = appsList[i].label.toString()
val appPackage = appsList[i].packageName.toString()
val appIcon = appsList[i].icon
val textView = viewHolder.textView
textView.text = appLabel
val imageView: ImageView = viewHolder.img
imageView.setImageDrawable(appIcon)
}
override fun getItemCount(): Int { return appsList.size }
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val inflater = LayoutInflater.from(parent.context)
val view: View = inflater.inflate(R.layout.recycler_apps_row, parent, false)
return ViewHolder(view)
}
init {
val pm: PackageManager = activity.packageManager
appsList = ArrayList()
val i = Intent(Intent.ACTION_MAIN, null)
i.addCategory(Intent.CATEGORY_LAUNCHER)
val allApps = pm.queryIntentActivities(i, 0)
for (ri in allApps) {
val app = AppInfo()
app.label = ri.loadLabel(pm)
app.packageName = ri.activityInfo.packageName
app.icon = ri.activityInfo.loadIcon(pm)
appsList.add(app)
}
}
}

View file

@ -58,25 +58,19 @@
</com.google.android.material.appbar.AppBarLayout> </com.google.android.material.appbar.AppBarLayout>
<ScrollView <androidx.recyclerview.widget.RecyclerView
android:layout_width="0dp" android:id="@+id/activity_choose_apps_recycler_view"
android:layout_height="0dp" android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginStart="16dp" android:layout_marginStart="16dp"
android:layout_marginLeft="16dp" android:layout_marginLeft="16dp"
android:layout_marginTop="16dp" android:layout_marginTop="86dp"
android:layout_marginEnd="16dp" android:layout_marginEnd="16dp"
android:layout_marginRight="16dp" android:layout_marginRight="16dp"
android:layout_marginBottom="16dp" android:scrollbars="vertical"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/activity_choose_app_bar"> app:layout_constraintTop_toBottomOf="@id/activity_choose_app_bar" />
<LinearLayout
android:id="@+id/activity_choose_apps_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" />
</ScrollView>
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="15sp">
<ImageView
android:id="@+id/choose_row_app_icon"
android:layout_width="40sp"
android:layout_height="40sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="ContentDescription" />
<TextView
android:id="@+id/choose_row_app_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="60sp"
android:layout_marginLeft="60sp"
android:text=""
android:textSize="20sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>