Cherish: Import BasePreferenceController and DashboardFragment from Krypton
Signed-off-by: Hưng Phan <phandinhhungvp2001@gmail.com>
This commit is contained in:
committed by
Hưng Phan
parent
799d906931
commit
aa23b6c0f3
65
res/layout/app_list_item.xml
Normal file
65
res/layout/app_list_item.xml
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 2021 AOSP-Krypton Project
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
-->
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:settings="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:minHeight="?android:attr/listPreferredItemHeight"
|
||||||
|
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
|
||||||
|
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
|
||||||
|
android:background="?android:attr/selectableItemBackground"
|
||||||
|
android:clipChildren="false"
|
||||||
|
android:clipToPadding="false">
|
||||||
|
|
||||||
|
<androidx.preference.internal.PreferenceImageView
|
||||||
|
android:id="@+id/icon"
|
||||||
|
android:layout_width="48dp"
|
||||||
|
android:layout_height="48dp"
|
||||||
|
android:layout_marginTop="4dp"
|
||||||
|
android:layout_marginBottom="4dp"
|
||||||
|
android:scaleType="centerInside"
|
||||||
|
settings:layout_constraintStart_toStartOf="parent"
|
||||||
|
settings:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/label"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="@dimen/default_margin"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceListItem"
|
||||||
|
android:textColor="?android:attr/textColorPrimary"
|
||||||
|
settings:layout_constraintStart_toEndOf="@id/icon"
|
||||||
|
settings:layout_constraintEnd_toStartOf="@id/checkBox"
|
||||||
|
settings:layout_constraintTop_toTopOf="@id/icon" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/packageName"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||||
|
android:textColor="?android:attr/textColorSecondary"
|
||||||
|
settings:layout_constraintStart_toStartOf="@id/label"
|
||||||
|
settings:layout_constraintEnd_toEndOf="@id/label"
|
||||||
|
settings:layout_constraintTop_toBottomOf="@id/label"
|
||||||
|
settings:layout_constraintBottom_toBottomOf="@id/icon" />
|
||||||
|
|
||||||
|
<CheckBox
|
||||||
|
android:id="@+id/checkBox"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:focusable="false"
|
||||||
|
android:clickable="false"
|
||||||
|
settings:layout_constraintBottom_toBottomOf="@id/icon"
|
||||||
|
settings:layout_constraintEnd_toEndOf="parent"
|
||||||
|
settings:layout_constraintTop_toTopOf="@id/icon" />
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
27
res/layout/app_list_layout.xml
Normal file
27
res/layout/app_list_layout.xml
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 2021-2022 AOSP-Krypton Project
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
-->
|
||||||
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/apps_list"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent" />
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/loading_progress"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center" />
|
||||||
|
</FrameLayout>
|
||||||
21
res/menu/app_list_menu.xml
Normal file
21
res/menu/app_list_menu.xml
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 2021 AOSP-Krypton Project
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
-->
|
||||||
|
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/search"
|
||||||
|
android:title="@string/search"
|
||||||
|
android:icon="@drawable/ic_find_in_page_24px"
|
||||||
|
android:showAsAction="ifRoom|collapseActionView"
|
||||||
|
android:actionViewClass="android.widget.SearchView" />
|
||||||
|
</menu>
|
||||||
@@ -30,4 +30,7 @@
|
|||||||
<dimen name="fod_picker_item_margin">10dp</dimen>
|
<dimen name="fod_picker_item_margin">10dp</dimen>
|
||||||
<dimen name="fod_picker_item_size">100dp</dimen>
|
<dimen name="fod_picker_item_size">100dp</dimen>
|
||||||
<dimen name="fod_picker_item_padding">20dp</dimen>
|
<dimen name="fod_picker_item_padding">20dp</dimen>
|
||||||
|
|
||||||
|
<dimen name="default_margin">16dp</dimen>
|
||||||
|
<dimen name="default_padding">16dp</dimen>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -110,4 +110,7 @@
|
|||||||
|
|
||||||
<!-- Volume rocker wake -->
|
<!-- Volume rocker wake -->
|
||||||
<string name="volume_rocker_wake_title">Volume rocker wake</string>
|
<string name="volume_rocker_wake_title">Volume rocker wake</string>
|
||||||
|
|
||||||
|
<string name="search">Search</string>
|
||||||
|
<string name="search_apps">Search apps</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
70
src/com/cherish/settings/CherishBasePreferenceController.kt
Normal file
70
src/com/cherish/settings/CherishBasePreferenceController.kt
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 AOSP-Krypton Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.cherish.settings
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.util.Log
|
||||||
|
|
||||||
|
import com.android.settings.core.BasePreferenceController
|
||||||
|
import com.android.settings.core.PreferenceControllerMixin
|
||||||
|
import com.android.settingslib.search.SearchIndexableRaw
|
||||||
|
|
||||||
|
abstract class CherishBasePreferenceController(
|
||||||
|
private val context: Context,
|
||||||
|
private val key: String,
|
||||||
|
): BasePreferenceController(context, key),
|
||||||
|
PreferenceControllerMixin {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates non-indexable keys for search provider.
|
||||||
|
*
|
||||||
|
* Called by SearchIndexProvider#getNonIndexableKeys
|
||||||
|
*/
|
||||||
|
override fun updateNonIndexableKeys(keys: MutableList<String>) {
|
||||||
|
val shouldSuppressFromSearch = !isAvailable()
|
||||||
|
|| getAvailabilityStatus() == AVAILABLE_UNSEARCHABLE
|
||||||
|
if (shouldSuppressFromSearch) {
|
||||||
|
if (preferenceKey?.isBlank() == true) {
|
||||||
|
Log.w(TAG, "Skipping updateNonIndexableKeys due to empty key " + toString())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (keys.contains(key)) {
|
||||||
|
Log.w(TAG, "Skipping updateNonIndexableKeys, key already in list. " + toString())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
keys.add(key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates raw data for search provider.
|
||||||
|
*
|
||||||
|
* Called by SearchIndexProvider#getRawDataToIndex
|
||||||
|
*/
|
||||||
|
override open fun updateRawDataToIndex(rawData: MutableList<SearchIndexableRaw>) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates dynamic raw data for search provider.
|
||||||
|
*
|
||||||
|
* Called by SearchIndexProvider#getDynamicRawDataToIndex
|
||||||
|
*/
|
||||||
|
override open fun updateDynamicRawDataToIndex(rawData: MutableList<SearchIndexableRaw>) {}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val TAG = "CherishBasePreferenceController"
|
||||||
|
}
|
||||||
|
}
|
||||||
317
src/com/cherish/settings/fragments/AppListFragment.kt
Normal file
317
src/com/cherish/settings/fragments/AppListFragment.kt
Normal file
@@ -0,0 +1,317 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021-2022 AOSP-Krypton Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.cherish.settings.fragment
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.pm.PackageInfo
|
||||||
|
import android.content.pm.PackageManager
|
||||||
|
import android.graphics.drawable.Drawable
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.Menu
|
||||||
|
import android.view.MenuInflater
|
||||||
|
import android.view.MenuItem
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.CheckBox
|
||||||
|
import android.widget.ImageView
|
||||||
|
import android.widget.ProgressBar
|
||||||
|
import android.widget.SearchView
|
||||||
|
import android.widget.TextView
|
||||||
|
|
||||||
|
import androidx.core.view.ViewCompat
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import androidx.recyclerview.widget.ListAdapter
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
|
||||||
|
import com.android.settings.R
|
||||||
|
import com.google.android.material.appbar.AppBarLayout
|
||||||
|
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.cancel
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.sync.Mutex
|
||||||
|
import kotlinx.coroutines.sync.withLock
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [Fragment] that hosts a [RecyclerView] with a vertical
|
||||||
|
* list of application info. Items display an icon, name
|
||||||
|
* and package name of the application, along with a [CheckBox]
|
||||||
|
* indicating whether the item is selected or not.
|
||||||
|
*/
|
||||||
|
abstract class AppListFragment: Fragment(R.layout.app_list_layout), MenuItem.OnActionExpandListener {
|
||||||
|
|
||||||
|
private val mutex = Mutex()
|
||||||
|
|
||||||
|
private lateinit var fragmentScope: CoroutineScope
|
||||||
|
private lateinit var progressBar: ProgressBar
|
||||||
|
private lateinit var appBarLayout: AppBarLayout
|
||||||
|
private lateinit var packageManager: PackageManager
|
||||||
|
private lateinit var recyclerView: RecyclerView
|
||||||
|
private lateinit var adapter: AppListAdapter
|
||||||
|
|
||||||
|
private val packageList = mutableListOf<PackageInfo>()
|
||||||
|
|
||||||
|
private var searchText = ""
|
||||||
|
private var displayCategory: Int = CATEGORY_USER_ONLY
|
||||||
|
private var packageFilter: ((PackageInfo) -> Boolean) = { true }
|
||||||
|
private var packageComparator: ((PackageInfo, PackageInfo) -> Int) = { a, b ->
|
||||||
|
getLabel(a).compareTo(getLabel(b))
|
||||||
|
}
|
||||||
|
|
||||||
|
private var needsToHideProgressBar = false
|
||||||
|
|
||||||
|
override fun onAttach(context: Context) {
|
||||||
|
super.onAttach(context)
|
||||||
|
fragmentScope = CoroutineScope(Dispatchers.Main)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
setHasOptionsMenu(true)
|
||||||
|
packageManager = requireContext().packageManager
|
||||||
|
packageList.addAll(packageManager.getInstalledPackages(0))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Override this function to set the title of this fragment.
|
||||||
|
*/
|
||||||
|
abstract protected fun getTitle(): Int
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
requireActivity().setTitle(getTitle())
|
||||||
|
appBarLayout = requireActivity().findViewById(R.id.app_bar)
|
||||||
|
progressBar = view.findViewById(R.id.loading_progress)
|
||||||
|
adapter = AppListAdapter()
|
||||||
|
recyclerView = view.findViewById<RecyclerView>(R.id.apps_list).also {
|
||||||
|
it.layoutManager = LinearLayoutManager(context)
|
||||||
|
it.adapter = adapter
|
||||||
|
}
|
||||||
|
needsToHideProgressBar = true
|
||||||
|
refreshList()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract function for subclasses to override for providing
|
||||||
|
* an inital list of packages that should appear as selected.
|
||||||
|
*/
|
||||||
|
abstract protected fun getInitialCheckedList(): List<String>
|
||||||
|
|
||||||
|
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||||
|
inflater.inflate(R.menu.app_list_menu, menu)
|
||||||
|
val searchItem = menu.findItem(R.id.search).also {
|
||||||
|
it.setOnActionExpandListener(this)
|
||||||
|
}
|
||||||
|
val searchView = searchItem.actionView as SearchView
|
||||||
|
searchView.setQueryHint(getString(R.string.search_apps));
|
||||||
|
searchView.setOnQueryTextListener(object: SearchView.OnQueryTextListener {
|
||||||
|
override fun onQueryTextSubmit(query: String) = false
|
||||||
|
|
||||||
|
override fun onQueryTextChange(newText: String): Boolean {
|
||||||
|
fragmentScope.launch {
|
||||||
|
mutex.withLock {
|
||||||
|
searchText = newText
|
||||||
|
}
|
||||||
|
refreshList()
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onMenuItemActionExpand(item: MenuItem): Boolean {
|
||||||
|
// To prevent a large space on tool bar.
|
||||||
|
appBarLayout.setExpanded(false /*expanded*/, false /*animate*/)
|
||||||
|
// To prevent user expanding the collapsing tool bar view.
|
||||||
|
ViewCompat.setNestedScrollingEnabled(recyclerView, false)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onMenuItemActionCollapse(item: MenuItem): Boolean {
|
||||||
|
// We keep the collapsed status after user cancel the search function.
|
||||||
|
appBarLayout.setExpanded(false /*expanded*/, false /*animate*/)
|
||||||
|
// Allow user to expande the tool bar view.
|
||||||
|
ViewCompat.setNestedScrollingEnabled(recyclerView, true)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDetach() {
|
||||||
|
fragmentScope.cancel()
|
||||||
|
super.onDetach()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the type of apps that should be displayed in the list.
|
||||||
|
* Defaults to [CATEGORY_USER_ONLY].
|
||||||
|
*
|
||||||
|
* @param category one of [CATEGORY_SYSTEM_ONLY],
|
||||||
|
* [CATEGORY_USER_ONLY], [CATEGORY_BOTH]
|
||||||
|
*/
|
||||||
|
fun setDisplayCategory(category: Int) {
|
||||||
|
fragmentScope.launch {
|
||||||
|
mutex.withLock {
|
||||||
|
displayCategory = category
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a custom filter to filter out items from the list.
|
||||||
|
*
|
||||||
|
* @param customFilter a function that takes a [PackageInfo] and
|
||||||
|
* returns a [Boolean] indicating whether to show the item or not.
|
||||||
|
*/
|
||||||
|
fun setCustomFilter(customFilter: ((packageInfo: PackageInfo) -> Boolean)) {
|
||||||
|
fragmentScope.launch {
|
||||||
|
mutex.withLock {
|
||||||
|
packageFilter = customFilter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a [Comparator] for sorting the elements in the list..
|
||||||
|
*
|
||||||
|
* @param comparator a function that takes two [PackageInfo]'s and returns
|
||||||
|
* an [Int] representing their relative priority.
|
||||||
|
*/
|
||||||
|
fun setComparator(comparator: ((a: PackageInfo, b: PackageInfo) -> Int)) {
|
||||||
|
fragmentScope.launch {
|
||||||
|
mutex.withLock {
|
||||||
|
packageComparator = comparator
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when user selected list is updated.
|
||||||
|
*
|
||||||
|
* @param list a [List<String>] of selected items.
|
||||||
|
*/
|
||||||
|
open protected fun onListUpdate(list: List<String>) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when user selected an application.
|
||||||
|
*
|
||||||
|
* @param packageName the package name of the selected app.
|
||||||
|
*/
|
||||||
|
open protected fun onAppSelected(packageName: String) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when user deselected an application.
|
||||||
|
*
|
||||||
|
* @param packageName the package name of the deselected app.
|
||||||
|
*/
|
||||||
|
open protected fun onAppDeselected(packageName: String) {}
|
||||||
|
|
||||||
|
protected fun refreshList() {
|
||||||
|
fragmentScope.launch {
|
||||||
|
val list = withContext(Dispatchers.Default) {
|
||||||
|
mutex.withLock {
|
||||||
|
packageList.filter {
|
||||||
|
when (displayCategory) {
|
||||||
|
CATEGORY_SYSTEM_ONLY -> it.applicationInfo.isSystemApp()
|
||||||
|
CATEGORY_USER_ONLY -> !it.applicationInfo.isSystemApp()
|
||||||
|
else -> true
|
||||||
|
} &&
|
||||||
|
getLabel(it).contains(searchText, true) &&
|
||||||
|
packageFilter(it)
|
||||||
|
}.sortedWith(packageComparator).map { appInfofromPackage(it) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
adapter.submitList(list)
|
||||||
|
if (needsToHideProgressBar) {
|
||||||
|
progressBar.visibility = View.GONE
|
||||||
|
needsToHideProgressBar = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun appInfofromPackage(packageInfo: PackageInfo): AppInfo =
|
||||||
|
AppInfo(
|
||||||
|
packageInfo.packageName,
|
||||||
|
getLabel(packageInfo),
|
||||||
|
packageInfo.applicationInfo.loadIcon(packageManager),
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun getLabel(packageInfo: PackageInfo) =
|
||||||
|
packageInfo.applicationInfo.loadLabel(packageManager).toString()
|
||||||
|
|
||||||
|
private inner class AppListAdapter :
|
||||||
|
ListAdapter<AppInfo, AppListViewHolder>(itemCallback)
|
||||||
|
{
|
||||||
|
private val checkedList = getInitialCheckedList().toMutableList()
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
|
||||||
|
AppListViewHolder(layoutInflater.inflate(
|
||||||
|
R.layout.app_list_item, parent, false))
|
||||||
|
|
||||||
|
override fun onBindViewHolder(holder: AppListViewHolder, position: Int) {
|
||||||
|
val item = getItem(position)
|
||||||
|
val pkg = item.packageName
|
||||||
|
holder.label.setText(item.label)
|
||||||
|
holder.packageName.setText(pkg)
|
||||||
|
holder.icon.setImageDrawable(item.icon)
|
||||||
|
holder.checkBox.setChecked(checkedList.contains(pkg))
|
||||||
|
holder.itemView.setOnClickListener {
|
||||||
|
if (checkedList.contains(pkg)){
|
||||||
|
checkedList.remove(pkg)
|
||||||
|
onAppDeselected(pkg)
|
||||||
|
} else {
|
||||||
|
checkedList.add(pkg)
|
||||||
|
onAppSelected(pkg)
|
||||||
|
}
|
||||||
|
notifyItemChanged(position)
|
||||||
|
onListUpdate(checkedList.toList())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class AppListViewHolder(itemView: View) :
|
||||||
|
RecyclerView.ViewHolder(itemView) {
|
||||||
|
val icon: ImageView = itemView.findViewById(R.id.icon)
|
||||||
|
val label: TextView = itemView.findViewById(R.id.label)
|
||||||
|
val packageName: TextView = itemView.findViewById(R.id.packageName)
|
||||||
|
val checkBox: CheckBox = itemView.findViewById(R.id.checkBox)
|
||||||
|
}
|
||||||
|
|
||||||
|
private data class AppInfo(
|
||||||
|
val packageName: String,
|
||||||
|
val label: String,
|
||||||
|
val icon: Drawable,
|
||||||
|
)
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val TAG = "AppListFragment"
|
||||||
|
|
||||||
|
const val CATEGORY_SYSTEM_ONLY = 0
|
||||||
|
const val CATEGORY_USER_ONLY = 1
|
||||||
|
const val CATEGORY_BOTH = 2
|
||||||
|
|
||||||
|
private val itemCallback = object : DiffUtil.ItemCallback<AppInfo>() {
|
||||||
|
override fun areItemsTheSame(oldInfo: AppInfo, newInfo: AppInfo) =
|
||||||
|
oldInfo.packageName == newInfo.packageName
|
||||||
|
|
||||||
|
override fun areContentsTheSame(oldInfo: AppInfo, newInfo: AppInfo) =
|
||||||
|
oldInfo == newInfo
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 AOSP-Krypton Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.cherish.settings.fragment
|
||||||
|
|
||||||
|
import androidx.preference.Preference
|
||||||
|
|
||||||
|
import com.android.internal.logging.nano.MetricsProto
|
||||||
|
import com.android.settings.dashboard.DashboardFragment
|
||||||
|
|
||||||
|
abstract class CherishDashboardFragment: DashboardFragment() {
|
||||||
|
override fun getMetricsCategory(): Int = MetricsProto.MetricsEvent.CHERISH_SETTINGS
|
||||||
|
|
||||||
|
override fun onDisplayPreferenceDialog(preference: Preference) {
|
||||||
|
super.onDisplayPreferenceDialog(preference)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val REQUEST_KEY = "CherishDashboardFragment#RequestKey"
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user