@@ -11,245 +11,168 @@ import kotlinx.coroutines.*
1111import java.util.*
1212
1313class AdapterAppChooser (
14- private val context : Context ,
15- private var apps : ArrayList <AppInfo >,
16- private val multiple : Boolean
14+ private val context : Context ,
15+ private var apps : ArrayList <AppInfo >,
16+ private val multiple : Boolean
1717) : BaseAdapter(), Filterable {
18+
1819 interface SelectStateListener {
1920 fun onSelectChange (selected : List <AppInfo >)
2021 }
2122
2223 open class AppInfo {
23- var appName: String = " "
24- var packageName: String = " "
25-
26- // 是否未找到此应用
24+ var appName: String? = null
25+ var packageName: String? = null
2726 var notFound: Boolean = false
2827 var selected: Boolean = false
2928 }
3029
3130 private var selectStateListener: SelectStateListener ? = null
3231 private var filter: Filter ? = null
32+
3333 internal var filterApps: ArrayList <AppInfo > = apps
3434 private val mLock = Any ()
3535
36- private class ArrayFilter (private var adapter : AdapterAppChooser ) : Filter() {
37- override fun publishResults (constraint : CharSequence? , results : FilterResults ? ) {
38- adapter.filterApps = results!! .values as ArrayList <AppInfo >
39- if (results.count > 0 ) {
40- adapter.notifyDataSetChanged()
41- } else {
42- adapter.notifyDataSetInvalidated()
43- }
44- }
45-
46- private fun searchStr (valueText : String , keyword : String ): Boolean {
47- // First match against the whole, non-splitted value
48- if (valueText.contains(keyword)) {
49- return true
50- } else {
51- val words = valueText.split(" " .toRegex()).dropLastWhile({ it.isEmpty() }).toTypedArray()
52- val wordCount = words.size
53-
54- // Start at index 0, in case valueText starts with space(s)
55- for (k in 0 until wordCount) {
56- if (words[k].contains(keyword)) {
57- return true
58- }
59- }
60- }
61- return false
62- }
36+ private class ArrayFilter (private val adapter : AdapterAppChooser ) : Filter() {
6337
6438 override fun performFiltering (constraint : CharSequence? ): FilterResults {
6539 val results = FilterResults ()
66- val prefix: String = constraint?.toString() ? : " "
40+ val prefix = constraint?.toString()?.lowercase () ? : " "
6741
6842 if (prefix.isEmpty()) {
69- val list: ArrayList <AppInfo >
7043 synchronized(adapter.mLock) {
71- list = ArrayList <AppInfo >(adapter.apps)
44+ results.values = ArrayList (adapter.apps)
45+ results.count = adapter.apps.size
7246 }
73- results.values = list
74- results.count = list.size
75- } else {
76- val prefixString = prefix.lowercase()
47+ return results
48+ }
7749
78- val values: ArrayList <AppInfo >
79- synchronized(adapter.mLock) {
80- values = ArrayList <AppInfo >(adapter.apps)
81- }
82- val selected = adapter.getSelectedItems()
83-
84- val count = values.size
85- val newValues = ArrayList <AppInfo >()
86-
87- for (i in 0 until count) {
88- val value = values[i]
89- if (selected.contains(value)) {
90- newValues.add(value)
91- } else {
92- val labelText = value.appName.lowercase()
93- val valueText = value.packageName.lowercase()
94- if (searchStr(labelText, prefixString)) {
95- newValues.add(value)
96- } else if (searchStr(valueText, prefixString)) {
97- newValues.add(value)
98- }
99- }
50+ val selected = adapter.getSelectedItems()
51+ val newValues = ArrayList <AppInfo >()
52+
53+ for (item in adapter.apps) {
54+ if (selected.contains(item)) {
55+ newValues.add(item)
56+ continue
10057 }
10158
102- results.values = newValues
103- results.count = newValues.size
59+ val name = item.appName?.lowercase() ? : " "
60+ val pkg = item.packageName?.lowercase() ? : " "
61+
62+ if (name.contains(prefix) || pkg.contains(prefix)) {
63+ newValues.add(item)
64+ }
10465 }
10566
67+ results.values = newValues
68+ results.count = newValues.size
10669 return results
10770 }
71+
72+ override fun publishResults (constraint : CharSequence? , results : FilterResults ? ) {
73+ if (results?.values is ArrayList <* >) {
74+ @Suppress(" UNCHECKED_CAST" )
75+ adapter.filterApps = results.values as ArrayList <AppInfo >
76+ adapter.notifyDataSetChanged()
77+ }
78+ }
10879 }
10980
11081 override fun getFilter (): Filter {
111- if (filter == null ) {
112- filter = ArrayFilter (this )
113- }
82+ if (filter == null ) filter = ArrayFilter (this )
11483 return filter!!
11584 }
11685
11786 private val iconCaches = LruCache <String , Drawable >(100 )
11887
119- init {
120- filterApps.sortBy { ! it.selected }
121- }
88+ override fun getCount (): Int = filterApps.size
12289
123- override fun getCount (): Int {
124- return filterApps.size
125- }
90+ override fun getItem (position : Int ): AppInfo = filterApps[position]
12691
127- override fun getItem (position : Int ): AppInfo {
128- return filterApps[position]
129- }
92+ override fun getItemId (position : Int ): Long = position.toLong()
13093
131- override fun getItemId (position : Int ): Long {
132- return position.toLong()
94+ override fun getView (position : Int , view : View ? , parent : ViewGroup ): View {
95+ val convertView = view ? : View .inflate(
96+ context,
97+ if (multiple) R .layout.app_multiple_chooser_item
98+ else R .layout.app_single_chooser_item,
99+ null
100+ )
101+
102+ updateRow(position, convertView)
103+ return convertView
133104 }
134105
135106 private fun loadIcon (app : AppInfo ): Deferred <Drawable ?> {
136107 return GlobalScope .async(Dispatchers .IO ) {
137- val packageName = app.packageName
138- val icon: Drawable ? = iconCaches.get(packageName)
139- if (icon == null && ! app.notFound) {
108+ val pkg = app.packageName ? : return @async null
109+ val cached = iconCaches.get(pkg)
110+ if (cached != null ) return @async cached
111+
112+ if (! app.notFound) {
140113 try {
141- val installInfo = context.packageManager.getPackageInfo(packageName, 0 )
142- iconCaches.put(
143- packageName,
144- installInfo.applicationInfo?.loadIcon(context.packageManager)
145- )
114+ val info = context.packageManager.getPackageInfo(pkg, 0 )
115+ val icon = info.applicationInfo?.loadIcon(context.packageManager)
116+ if (icon != null ) iconCaches.put(pkg, icon)
146117 } catch (_: Exception ) {
147118 app.notFound = true
148- } finally {
149119 }
150- return @async iconCaches.get(packageName)
151- } else {
152- return @async icon
153120 }
154- }
155- }
156-
157- override fun getView (position : Int , view : View ? , parent : ViewGroup ): View {
158- var convertView = view
159- if (convertView == null ) {
160- convertView = View .inflate(context, if (multiple) {
161- R .layout.app_multiple_chooser_item
162- } else {
163- R .layout.app_single_chooser_item
164- }, null )
165- }
166- updateRow(position, convertView!! )
167- return convertView
168- }
169-
170- fun updateRow (position : Int , listView : OverScrollGridView , AppInfo : AppInfo ) {
171- try {
172- val visibleFirstPosi = listView.firstVisiblePosition
173- val visibleLastPosi = listView.lastVisiblePosition
174-
175- if (position in visibleFirstPosi.. visibleLastPosi) {
176- filterApps[position] = AppInfo
177- val view = listView.getChildAt(position - visibleFirstPosi)
178- updateRow(position, view)
179- }
180- } catch (_: Exception ) {
121+ iconCaches.get(pkg)
181122 }
182123 }
183124
184125 fun updateRow (position : Int , convertView : View ) {
185126 val item = getItem(position)
186127
187- val viewHolder = if (convertView.tag != null ) {
188- convertView.tag as ViewHolder
189- } else {
190- ViewHolder ().apply {
191- itemTitle = convertView.findViewById(R .id.ItemTitle )
192- itemDesc = convertView.findViewById(R .id.ItemDesc )
193- imgView = convertView.findViewById(R .id.ItemIcon )
194- checkBox = convertView.findViewById(R .id.ItemChecBox )
195- }
128+ val holder = (convertView.tag as ? ViewHolder ) ? : ViewHolder (convertView).also {
129+ convertView.tag = it
196130 }
197131
198- val packageName = item.packageName
199- viewHolder.packageName = packageName
132+ holder.itemTitle.text = item.appName ? : " "
133+ holder.itemDesc.text = item.packageName ? : " "
134+ holder.checkBox?.isChecked = item.selected
200135
201136 convertView.setOnClickListener {
202- if (multiple || item.selected) {
203- if (multiple) {
204- item.selected = ! item.selected
205- viewHolder.checkBox?.isChecked = item.selected
206- }
137+ if (multiple) {
138+ item.selected = ! item.selected
139+ holder.checkBox?.isChecked = item.selected
207140 } else {
208- val current = apps.find { it.selected }
209- current?.selected = false
141+ apps.forEach { it.selected = false }
210142 item.selected = true
211143 notifyDataSetChanged()
212144 }
213145 selectStateListener?.onSelectChange(getSelectedItems())
214146 }
215147
216- viewHolder.run {
217- itemTitle?.text = item.appName
218- itemDesc?.text = item.packageName
219- checkBox?.isChecked = item.selected
220-
221- val imgView = imgView!!
222- imgView.tag = packageName
223- GlobalScope .launch(Dispatchers .Main ) {
224- val icon = loadIcon(item).await()
225- if (icon != null && imgView.tag == packageName) {
226- imgView.setImageDrawable(icon)
227- }
148+ val pkg = item.packageName
149+ holder.imgView.tag = pkg
150+
151+ GlobalScope .launch(Dispatchers .Main ) {
152+ val icon = loadIcon(item).await()
153+ if (icon != null && holder.imgView.tag == pkg) {
154+ holder.imgView.setImageDrawable(icon)
228155 }
229156 }
230157 }
231158
232159 fun setSelectAllState (allSelected : Boolean ) {
233- apps.forEach {
234- it.selected = allSelected
235- }
160+ apps.forEach { it.selected = allSelected }
236161 notifyDataSetChanged()
162+ selectStateListener?.onSelectChange(getSelectedItems())
237163 }
238164
239- fun setSelectStateListener (selectStateListener : SelectStateListener ? ) {
240- this .selectStateListener = selectStateListener
241- }
165+ fun getSelectedItems (): List <AppInfo > =
166+ apps.filter { it.selected }
242167
243- fun getSelectedItems (): List < AppInfo > {
244- return apps.filter { it.selected }
168+ fun setSelectStateListener ( listener : SelectStateListener ? ) {
169+ this .selectStateListener = listener
245170 }
246171
247- class ViewHolder {
248- internal var packageName: String? = null
249-
250- internal var itemTitle: TextView ? = null
251- internal var itemDesc: TextView ? = null
252- internal var imgView: ImageView ? = null
253- internal var checkBox: CompoundButton ? = null
172+ class ViewHolder (view : View ) {
173+ val itemTitle: TextView = view.findViewById(R .id.ItemTitle )
174+ val itemDesc: TextView = view.findViewById(R .id.ItemDesc )
175+ val imgView: ImageView = view.findViewById(R .id.ItemIcon )
176+ val checkBox: CompoundButton ? = view.findViewById(R .id.ItemChecBox )
254177 }
255- }
178+ }
0 commit comments