[6/n] Show special footer for SIM cards with MEP support
This commit is contained in:
parent
e708deea7c
commit
81b61c76c4
|
@ -12,6 +12,7 @@ abstract class EuiccChannel(
|
|||
val cardId = port.card.cardId
|
||||
val name = "SLOT $logicalSlotId"
|
||||
val removable = port.card.isRemovable
|
||||
val isMEP = port.card.isMultipleEnabledProfilesSupported
|
||||
|
||||
abstract val lpa: LocalProfileAssistant
|
||||
val valid: Boolean
|
||||
|
|
|
@ -8,6 +8,7 @@ import android.view.LayoutInflater
|
|||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.ImageButton
|
||||
import android.widget.PopupMenu
|
||||
import android.widget.TextView
|
||||
|
@ -26,7 +27,7 @@ import kotlinx.coroutines.launch
|
|||
import kotlinx.coroutines.withContext
|
||||
import java.lang.Exception
|
||||
|
||||
class EuiccManagementFragment : Fragment(), EuiccFragmentMarker, EuiccProfilesChangedListener {
|
||||
open class EuiccManagementFragment : Fragment(), EuiccFragmentMarker, EuiccProfilesChangedListener {
|
||||
companion object {
|
||||
const val TAG = "EuiccManagementFragment"
|
||||
|
||||
|
@ -38,7 +39,7 @@ class EuiccManagementFragment : Fragment(), EuiccFragmentMarker, EuiccProfilesCh
|
|||
private lateinit var fab: FloatingActionButton
|
||||
private lateinit var profileList: RecyclerView
|
||||
|
||||
private val adapter = EuiccProfileAdapter(listOf())
|
||||
private val adapter = EuiccProfileAdapter()
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
|
@ -76,6 +77,8 @@ class EuiccManagementFragment : Fragment(), EuiccFragmentMarker, EuiccProfilesCh
|
|||
refresh()
|
||||
}
|
||||
|
||||
protected open suspend fun onCreateFooterViews(parent: ViewGroup): List<View> = listOf()
|
||||
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
private fun refresh() {
|
||||
swipeRefresh.isRefreshing = true
|
||||
|
@ -88,6 +91,7 @@ class EuiccManagementFragment : Fragment(), EuiccFragmentMarker, EuiccProfilesCh
|
|||
|
||||
withContext(Dispatchers.Main) {
|
||||
adapter.profiles = profiles.operational
|
||||
adapter.footerViews = onCreateFooterViews(profileList)
|
||||
adapter.notifyDataSetChanged()
|
||||
swipeRefresh.isRefreshing = false
|
||||
}
|
||||
|
@ -130,7 +134,30 @@ class EuiccManagementFragment : Fragment(), EuiccFragmentMarker, EuiccProfilesCh
|
|||
channel.lpa.disableProfile(iccid)
|
||||
}
|
||||
|
||||
inner class ViewHolder(private val root: View) : RecyclerView.ViewHolder(root) {
|
||||
sealed class ViewHolder(root: View) : RecyclerView.ViewHolder(root) {
|
||||
enum class Type(val value: Int) {
|
||||
PROFILE(0),
|
||||
FOOTER(1);
|
||||
|
||||
companion object {
|
||||
fun fromInt(value: Int) =
|
||||
Type.values().first { it.value == value }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inner class FooterViewHolder: ViewHolder(FrameLayout(requireContext())) {
|
||||
fun attach(view: View) {
|
||||
view.parent?.let { (it as ViewGroup).removeView(view) }
|
||||
(itemView as FrameLayout).addView(view)
|
||||
}
|
||||
|
||||
fun detach() {
|
||||
(itemView as FrameLayout).removeAllViews()
|
||||
}
|
||||
}
|
||||
|
||||
inner class ProfileViewHolder(private val root: View) : ViewHolder(root) {
|
||||
private val iccid: TextView = root.findViewById(R.id.iccid)
|
||||
private val name: TextView = root.findViewById(R.id.name)
|
||||
private val state: TextView = root.findViewById(R.id.state)
|
||||
|
@ -208,16 +235,49 @@ class EuiccManagementFragment : Fragment(), EuiccFragmentMarker, EuiccProfilesCh
|
|||
}
|
||||
}
|
||||
|
||||
inner class EuiccProfileAdapter(var profiles: List<LocalProfileInfo>) : RecyclerView.Adapter<ViewHolder>() {
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||
val view = LayoutInflater.from(parent.context).inflate(R.layout.euicc_profile, parent, false)
|
||||
return ViewHolder(view)
|
||||
}
|
||||
inner class EuiccProfileAdapter : RecyclerView.Adapter<ViewHolder>() {
|
||||
var profiles: List<LocalProfileInfo> = listOf()
|
||||
var footerViews: List<View> = listOf()
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder =
|
||||
when (ViewHolder.Type.fromInt(viewType)) {
|
||||
ViewHolder.Type.PROFILE -> {
|
||||
val view = LayoutInflater.from(parent.context).inflate(R.layout.euicc_profile, parent, false)
|
||||
ProfileViewHolder(view)
|
||||
}
|
||||
ViewHolder.Type.FOOTER -> {
|
||||
FooterViewHolder()
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItemViewType(position: Int): Int =
|
||||
when {
|
||||
position < profiles.size -> {
|
||||
ViewHolder.Type.PROFILE.value
|
||||
}
|
||||
position >= profiles.size && position < profiles.size + footerViews.size -> {
|
||||
ViewHolder.Type.FOOTER.value
|
||||
}
|
||||
else -> -1
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
holder.setProfile(profiles[position])
|
||||
when (holder) {
|
||||
is ProfileViewHolder -> {
|
||||
holder.setProfile(profiles[position])
|
||||
}
|
||||
is FooterViewHolder -> {
|
||||
holder.attach(footerViews[position - profiles.size])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int = profiles.size
|
||||
override fun onViewRecycled(holder: ViewHolder) {
|
||||
if (holder is FooterViewHolder) {
|
||||
holder.detach()
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int = profiles.size + footerViews.size
|
||||
}
|
||||
}
|
|
@ -11,6 +11,7 @@ import android.widget.Spinner
|
|||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import im.angry.openeuicc.common.R
|
||||
import im.angry.openeuicc.core.EuiccChannel
|
||||
import im.angry.openeuicc.core.EuiccChannelManager
|
||||
import im.angry.openeuicc.util.*
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
|
@ -72,6 +73,9 @@ open class MainActivity : AppCompatActivity() {
|
|||
return true
|
||||
}
|
||||
|
||||
protected open fun createEuiccManagementFragment(channel: EuiccChannel): EuiccManagementFragment =
|
||||
EuiccManagementFragment.newInstance(channel.slotId, channel.portId)
|
||||
|
||||
private suspend fun init() {
|
||||
withContext(Dispatchers.IO) {
|
||||
manager.enumerateEuiccChannels()
|
||||
|
@ -88,7 +92,7 @@ open class MainActivity : AppCompatActivity() {
|
|||
withContext(Dispatchers.Main) {
|
||||
manager.knownChannels.forEach { channel ->
|
||||
spinnerAdapter.add(channel.name)
|
||||
fragments.add(EuiccManagementFragment.newInstance(channel.slotId, channel.portId))
|
||||
fragments.add(createEuiccManagementFragment(channel))
|
||||
}
|
||||
|
||||
if (fragments.isNotEmpty()) {
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
package im.angry.openeuicc.ui
|
||||
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.Button
|
||||
import im.angry.openeuicc.R
|
||||
|
||||
class PrivilegedEuiccManagementFragment: EuiccManagementFragment() {
|
||||
companion object {
|
||||
fun newInstance(slotId: Int, portId: Int): EuiccManagementFragment =
|
||||
newInstanceEuicc(PrivilegedEuiccManagementFragment::class.java, slotId, portId)
|
||||
}
|
||||
|
||||
override suspend fun onCreateFooterViews(parent: ViewGroup): List<View> =
|
||||
if (channel.isMEP) {
|
||||
val view = layoutInflater.inflate(R.layout.footer_mep, parent, false)
|
||||
view.findViewById<Button>(R.id.footer_mep_slot_mapping).setOnClickListener {
|
||||
(requireActivity() as PrivilegedMainActivity).showSlotMappingFragment()
|
||||
}
|
||||
listOf(view)
|
||||
} else {
|
||||
listOf()
|
||||
}
|
||||
}
|
|
@ -4,6 +4,7 @@ import android.view.Menu
|
|||
import android.view.MenuItem
|
||||
import android.widget.Toast
|
||||
import im.angry.openeuicc.R
|
||||
import im.angry.openeuicc.core.EuiccChannel
|
||||
import im.angry.openeuicc.util.*
|
||||
|
||||
class PrivilegedMainActivity : MainActivity() {
|
||||
|
@ -20,6 +21,9 @@ class PrivilegedMainActivity : MainActivity() {
|
|||
return true
|
||||
}
|
||||
|
||||
internal fun showSlotMappingFragment() =
|
||||
SlotMappingFragment().show(supportFragmentManager, SlotMappingFragment.TAG)
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean = when (item.itemId) {
|
||||
R.id.dsds -> {
|
||||
tm.dsdsEnabled = !item.isChecked
|
||||
|
@ -28,9 +32,12 @@ class PrivilegedMainActivity : MainActivity() {
|
|||
true
|
||||
}
|
||||
R.id.slot_mapping -> {
|
||||
SlotMappingFragment().show(supportFragmentManager, SlotMappingFragment.TAG)
|
||||
showSlotMappingFragment()
|
||||
true
|
||||
}
|
||||
else -> super.onOptionsItemSelected(item)
|
||||
}
|
||||
|
||||
override fun createEuiccManagementFragment(channel: EuiccChannel): EuiccManagementFragment =
|
||||
PrivilegedEuiccManagementFragment.newInstance(channel.slotId, channel.portId)
|
||||
}
|
32
app/src/main/res/layout/footer_mep.xml
Normal file
32
app/src/main/res/layout/footer_mep.xml
Normal file
|
@ -0,0 +1,32 @@
|
|||
<?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"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/footer_mep_text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="40dp"
|
||||
android:layout_marginEnd="40dp"
|
||||
android:gravity="center"
|
||||
android:text="@string/footer_mep"
|
||||
android:textStyle="italic"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toTopOf="@id/footer_mep_slot_mapping"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/footer_mep_slot_mapping"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/slot_mapping"
|
||||
android:textColor="?attr/colorAccent"
|
||||
style="?android:attr/borderlessButtonStyle"
|
||||
app:layout_constraintTop_toBottomOf="@id/footer_mep_text"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -6,6 +6,8 @@
|
|||
|
||||
<string name="toast_dsds_switched">DSDS state switched. Please wait until the modem restarts.</string>
|
||||
|
||||
<string name="footer_mep">Multiple Enabled Profiles (MEP) is supported by this slot. To enable or disable this feature, use the \"Slot Mapping\" tool.</string>
|
||||
|
||||
<string name="slot_mapping">Slot Mapping</string>
|
||||
<string name="slot_mapping_logical_slot">Logical slot %d:</string>
|
||||
<string name="slot_mapping_port">Slot %d Port %d</string>
|
||||
|
|
Loading…
Reference in a new issue