Merge pull request #36 from finnmglas/feature/apps-list

Feature/apps list
This commit is contained in:
Finn M Glas 2020-05-27 12:27:46 +02:00 committed by GitHub
commit 0154874b0f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 197 additions and 110 deletions

View file

@ -2,22 +2,20 @@ 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 */
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@ -42,54 +40,25 @@ 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) "view" -> activity_choose_heading.text = getString(R.string.choose_title_view)
else if (action == "pick") "pick" -> activity_choose_heading.text = getString(R.string.choose_title)
activity_choose_heading.text = getString(R.string.choose_title) }
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)
// creating TextView programmatically layoutManager = viewManager
val tvdynamic = TextView(this) adapter = viewAdapter
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)
} }
} }
@ -98,7 +67,6 @@ class ChooseActivity : AppCompatActivity() {
if (requestCode == REQUEST_UNINSTALL) { if (requestCode == REQUEST_UNINSTALL) {
if (resultCode == Activity.RESULT_OK) { if (resultCode == Activity.RESULT_OK) {
Toast.makeText(this, getString(R.string.choose_removed_toast), Toast.LENGTH_LONG).show() Toast.makeText(this, getString(R.string.choose_removed_toast), Toast.LENGTH_LONG).show()
updateAppList(packageManager)
finish() finish()
} else if (resultCode == Activity.RESULT_FIRST_USER) { } else if (resultCode == Activity.RESULT_FIRST_USER) {
Toast.makeText(this, getString(R.string.choose_not_removed_toast), Toast.LENGTH_LONG).show() Toast.makeText(this, getString(R.string.choose_not_removed_toast), Toast.LENGTH_LONG).show()

View file

@ -10,6 +10,8 @@ import android.util.DisplayMetrics
import android.view.* import android.view.*
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.GestureDetectorCompat import androidx.core.view.GestureDetectorCompat
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_main.* import kotlinx.android.synthetic.main.activity_main.*
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
@ -17,6 +19,9 @@ import java.util.*
import kotlin.concurrent.fixedRateTimer import kotlin.concurrent.fixedRateTimer
import kotlin.math.abs import kotlin.math.abs
// used for the apps drawer / menu (ChooseActivity)
lateinit var viewAdapter: RecyclerView.Adapter<*>
lateinit var viewManager: RecyclerView.LayoutManager
class MainActivity : AppCompatActivity(), class MainActivity : AppCompatActivity(),
GestureDetector.OnGestureListener, GestureDetector.OnDoubleTapListener { GestureDetector.OnGestureListener, GestureDetector.OnDoubleTapListener {
@ -32,7 +37,6 @@ class MainActivity : AppCompatActivity(),
// timers // timers
private var clockTimer = Timer() private var clockTimer = Timer()
private var tooltipTimer = Timer() private var tooltipTimer = Timer()
private var loadAppsTimer = Timer()
private var settingsIconShown = false private var settingsIconShown = false
@ -77,6 +81,9 @@ class MainActivity : AppCompatActivity(),
// As older APIs somehow do not recognize the xml defined onClick // As older APIs somehow do not recognize the xml defined onClick
activity_main_settings_icon.setOnClickListener() { openSettings() } activity_main_settings_icon.setOnClickListener() { openSettings() }
// Load apps list first - speed up settings that way
AsyncTask.execute { viewAdapter = AppsRecyclerAdapter( this, "", "") }
// First Startup // First Startup
if (!sharedPref.getBoolean("startedBefore", false)){ if (!sharedPref.getBoolean("startedBefore", false)){
startActivity(Intent(this, FirstStartupActivity::class.java)) startActivity(Intent(this, FirstStartupActivity::class.java))
@ -125,18 +132,11 @@ class MainActivity : AppCompatActivity(),
activity_main_date_view.text = d activity_main_date_view.text = d
} }
} }
val pm = packageManager
loadAppsTimer = fixedRateTimer("loadAppsTimer", true, 0L, 30000) {
AsyncTask.execute { updateAppList(pm) }
}
} }
override fun onPause() { override fun onPause() {
super.onPause() super.onPause()
clockTimer.cancel() clockTimer.cancel()
loadAppsTimer.cancel()
} }
private fun openSettings(){ private fun openSettings(){

View file

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

View file

@ -0,0 +1,97 @@
package com.finnmglas.launcher.choose
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.content.pm.ApplicationInfo
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 androidx.recyclerview.widget.RecyclerView
import com.finnmglas.launcher.R
import com.finnmglas.launcher.extern.FontAwesome
import com.finnmglas.launcher.extern.REQUEST_CHOOSE_APP
import com.finnmglas.launcher.extern.REQUEST_UNINSTALL
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
var delete: FontAwesome = itemView.findViewById(R.id.choose_row_app_delete)
override fun onClick(v: View) {
val pos = adapterPosition
val context: Context = v.context
val appPackageName = appsList[pos].packageName.toString()
when (action){
"view" -> {
val launchIntent: Intent = context.packageManager
.getLaunchIntentForPackage(appPackageName)!!
context.startActivity(launchIntent)
}
"pick" -> {
val returnIntent = Intent()
returnIntent.putExtra("value", appPackageName)
returnIntent.putExtra("forApp", forApp)
activity.setResult(REQUEST_CHOOSE_APP, returnIntent)
activity.finish()
}
}
}
init { itemView.setOnClickListener(this) }
}
override fun onBindViewHolder(viewHolder: ViewHolder, i: Int) {
val appLabel = appsList[i].label.toString()
val appPackageName = appsList[i].packageName.toString()
val appIcon = appsList[i].icon
val isSystemApp = appsList[i].isSystemApp
viewHolder.textView.text = appLabel
viewHolder.img.setImageDrawable(appIcon)
viewHolder.delete.setOnClickListener{
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)
}
viewHolder.delete.visibility = if(isSystemApp || action == "pick") View.INVISIBLE else View.VISIBLE
}
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

@ -7,7 +7,6 @@ import android.content.DialogInterface
import android.content.Intent import android.content.Intent
import android.content.SharedPreferences import android.content.SharedPreferences
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.content.pm.ResolveInfo
import android.graphics.* import android.graphics.*
import android.net.Uri import android.net.Uri
import android.os.Build import android.os.Build
@ -30,8 +29,6 @@ var volumeDownApp = ""
var calendarApp = "" var calendarApp = ""
var clockApp = "" var clockApp = ""
var appsList : MutableList<ResolveInfo> = mutableListOf()
var background : Bitmap? = null var background : Bitmap? = null
var dominantColor = 0 var dominantColor = 0
@ -126,13 +123,6 @@ fun isInstalled(uri: String, context: Context): Boolean {
return false return false
} }
fun updateAppList(pm : PackageManager) {
val intent = Intent(Intent.ACTION_MAIN)
.addCategory(Intent.CATEGORY_LAUNCHER)
appsList = pm.queryIntentActivities(intent, 0)
appsList.sortBy { it.activityInfo.loadLabel(pm).toString() }
}
private fun getIntent(packageName: String, context: Context): Intent? { private fun getIntent(packageName: String, context: Context): Intent? {
val intent: Intent? = context.packageManager.getLaunchIntentForPackage(packageName) val intent: Intent? = context.packageManager.getLaunchIntentForPackage(packageName)
intent?.addCategory(Intent.CATEGORY_LAUNCHER) intent?.addCategory(Intent.CATEGORY_LAUNCHER)

View file

@ -42,9 +42,8 @@ class SettingsFragmentApps : Fragment() {
setButtonColor(fragment_settings_apps_choose_vol_up_btn, vibrantColor) setButtonColor(fragment_settings_apps_choose_vol_up_btn, vibrantColor)
setButtonColor(fragment_settings_apps_choose_vol_down_btn, vibrantColor) setButtonColor(fragment_settings_apps_choose_vol_down_btn, vibrantColor)
setButtonColor(fragment_settings_apps_launch_btn, vibrantColor) setButtonColor(fragment_settings_apps_btn, vibrantColor)
setButtonColor(fragment_settings_apps_install_btn, vibrantColor) setButtonColor(fragment_settings_apps_install_btn, vibrantColor)
setButtonColor(fragment_settings_apps_remove_btn, vibrantColor)
} }
// Action - selecting buttons // Action - selecting buttons
@ -56,9 +55,9 @@ class SettingsFragmentApps : Fragment() {
fragment_settings_apps_choose_vol_down_btn.setOnClickListener{ chooseApp("volumeDownApp")} fragment_settings_apps_choose_vol_down_btn.setOnClickListener{ chooseApp("volumeDownApp")}
// App management buttons // App management buttons
fragment_settings_apps_launch_btn.setOnClickListener{ fragment_settings_apps_btn.setOnClickListener{
val intent = Intent(this.context, ChooseActivity::class.java) val intent = Intent(this.context, ChooseActivity::class.java)
intent.putExtra("action", "launch") intent.putExtra("action", "view")
startActivity(intent) startActivity(intent)
} }
fragment_settings_apps_install_btn.setOnClickListener{ fragment_settings_apps_install_btn.setOnClickListener{
@ -72,11 +71,6 @@ class SettingsFragmentApps : Fragment() {
.show() .show()
} }
} }
fragment_settings_apps_remove_btn.setOnClickListener{
val intent = Intent(this.context, ChooseActivity::class.java)
intent.putExtra("action", "uninstall")
startActivity(intent)
}
super.onStart() super.onStart()
} }

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

@ -160,10 +160,10 @@
</TableLayout> </TableLayout>
<Button <Button
android:id="@+id/fragment_settings_apps_launch_btn" android:id="@+id/fragment_settings_apps_btn"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/settings_launch" android:text="@string/settings_apps"
android:textAllCaps="false" /> android:textAllCaps="false" />
<Button <Button
@ -173,10 +173,4 @@
android:text="@string/settings_install" android:text="@string/settings_install"
android:textAllCaps="false" /> android:textAllCaps="false" />
<Button
android:id="@+id/fragment_settings_apps_remove_btn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/settings_uninstall"
android:textAllCaps="false" />
</LinearLayout> </LinearLayout>

View file

@ -0,0 +1,45 @@
<?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="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="60sp"
android:layout_marginLeft="60sp"
android:layout_marginEnd="5dp"
android:layout_marginRight="5dp"
android:gravity="start"
android:text=""
android:textSize="20sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/choose_row_app_delete"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.finnmglas.launcher.extern.FontAwesome
android:id="@+id/choose_row_app_delete"
android:layout_width="20sp"
android:layout_height="wrap_content"
android:gravity="center"
android:text="@string/fas_trash"
android:textSize="20sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -26,8 +26,7 @@
<string name="settings_select_launcher">Launcher wählen</string> <string name="settings_select_launcher">Launcher wählen</string>
<string name="settings_reset">Zurücksetzen</string> <string name="settings_reset">Zurücksetzen</string>
<string name="settings_reset_message">All deine Einstellungen gehen verloren. Weitermachen?</string> <string name="settings_reset_message">All deine Einstellungen gehen verloren. Weitermachen?</string>
<string name="settings_launch">Apps öffnen</string> <string name="settings_apps">Alle Anwendungen</string>
<string name="settings_uninstall">Apps entfernen</string>
<string name="settings_install">Apps installieren</string> <string name="settings_install">Apps installieren</string>
<string name="settings_home">Zurück</string> <string name="settings_home">Zurück</string>
@ -46,8 +45,7 @@
<!-- Choose Activity --> <!-- Choose Activity -->
<string name="choose_title">App wählen</string> <string name="choose_title">App wählen</string>
<string name="choose_title_launch">Apps öffnen</string> <string name="choose_title_view">Alle Apps</string>
<string name="choose_title_remove">Apps entfernen</string>
<string name="choose_back_settings">Zurück</string> <string name="choose_back_settings">Zurück</string>

View file

@ -26,9 +26,8 @@
<string name="settings_select_launcher">Choisir Launcher</string> <string name="settings_select_launcher">Choisir Launcher</string>
<string name="settings_reset">Réinitialiser</string> <string name="settings_reset">Réinitialiser</string>
<string name="settings_reset_message">Vous allez supprimer toutes vos préférences. Continuer?</string> <string name="settings_reset_message">Vous allez supprimer toutes vos préférences. Continuer?</string>
<string name="settings_launch">Lancer apps</string> <string name="settings_apps">Toutes les applications</string>
<string name="settings_uninstall">Désinstaller apps</string> <string name="settings_install">Installer applications</string>
<string name="settings_install">Installer apps</string>
<string name="settings_home">Retourner</string> <string name="settings_home">Retourner</string>
<string name="settings_toast_store_not_found">Pas trouvé le PlayStore</string> <string name="settings_toast_store_not_found">Pas trouvé le PlayStore</string>
@ -46,8 +45,7 @@
<!-- Choose Activity --> <!-- Choose Activity -->
<string name="choose_title">Choisir App</string> <string name="choose_title">Choisir App</string>
<string name="choose_title_launch">Lancer Apps</string> <string name="choose_title_view">Applications</string>
<string name="choose_title_remove">Désinstaller</string>
<string name="choose_back_settings">Retourner</string> <string name="choose_back_settings">Retourner</string>

View file

@ -10,6 +10,7 @@
<string name="fas_calendar" translatable="false">&#xf133;</string> <string name="fas_calendar" translatable="false">&#xf133;</string>
<string name="fas_donate" translatable="false">&#xf4b9;</string> <string name="fas_donate" translatable="false">&#xf4b9;</string>
<string name="fas_share" translatable="false">&#xf064;</string> <string name="fas_share" translatable="false">&#xf064;</string>
<string name="fas_trash" translatable="false">&#xf1f8;</string>
<!-- icons that can be used with type="brands" --> <!-- icons that can be used with type="brands" -->
<string name="fab_apple" translatable="false">&#xf179;</string> <string name="fab_apple" translatable="false">&#xf179;</string>

View file

@ -34,9 +34,8 @@
<string name="settings_select_launcher">Select Launcher</string> <string name="settings_select_launcher">Select Launcher</string>
<string name="settings_reset">Reset Settings</string> <string name="settings_reset">Reset Settings</string>
<string name="settings_reset_message">You are going to discard all your preferences. Continue?</string> <string name="settings_reset_message">You are going to discard all your preferences. Continue?</string>
<string name="settings_launch">Launch Apps</string> <string name="settings_apps">View all apps</string>
<string name="settings_uninstall">Uninstall Apps</string> <string name="settings_install">Install apps</string>
<string name="settings_install">Install Apps</string>
<string name="settings_home">Back Home</string> <string name="settings_home">Back Home</string>
<string name="settings_toast_store_not_found">PlayStore not found</string> <string name="settings_toast_store_not_found">PlayStore not found</string>
@ -55,8 +54,7 @@
<!-- Choose Activity --> <!-- Choose Activity -->
<string name="choose_title">Choose App</string> <string name="choose_title">Choose App</string>
<string name="choose_title_launch">Launch Apps</string> <string name="choose_title_view">All Apps</string>
<string name="choose_title_remove">Uninstall Apps</string>
<string name="choose_back_settings">Back to Settings</string> <string name="choose_back_settings">Back to Settings</string>