Compare commits

..

No commits in common. "63ee8be79bb43950105368d2d3d2e1537f4f8953" and "4c221f74ff30414f347c97c64f95fe2f47f2ad99" have entirely different histories.

12 changed files with 50 additions and 116 deletions

View file

@ -8,6 +8,30 @@
<SelectionState runConfigName="app"> <SelectionState runConfigName="app">
<option name="selectionMode" value="DROPDOWN" /> <option name="selectionMode" value="DROPDOWN" />
</SelectionState> </SelectionState>
<SelectionState runConfigName="app-unpriv.androidTest">
<option name="selectionMode" value="DROPDOWN" />
</SelectionState>
<SelectionState runConfigName="app-unpriv.main">
<option name="selectionMode" value="DROPDOWN" />
</SelectionState>
<SelectionState runConfigName="app-unpriv.unitTest">
<option name="selectionMode" value="DROPDOWN" />
</SelectionState>
<SelectionState runConfigName="app.unitTest">
<option name="selectionMode" value="DROPDOWN" />
</SelectionState>
<SelectionState runConfigName="app.androidTest">
<option name="selectionMode" value="DROPDOWN" />
</SelectionState>
<SelectionState runConfigName="app.main">
<option name="selectionMode" value="DROPDOWN" />
</SelectionState>
<SelectionState runConfigName="workspace.OpenEUICC.app-unpriv">
<option name="selectionMode" value="DROPDOWN" />
</SelectionState>
<SelectionState runConfigName="workspace.OpenEUICC.app">
<option name="selectionMode" value="DROPDOWN" />
</SelectionState>
</selectionStates> </selectionStates>
</component> </component>
</project> </project>

View file

@ -17,6 +17,6 @@ open class UnprivilegedUiComponentFactory : DefaultUiComponentFactory() {
override fun createSettingsFragment(): Fragment = override fun createSettingsFragment(): Fragment =
UnprivilegedSettingsFragment() UnprivilegedSettingsFragment()
open fun createQuickCompatibilityFragment(): Fragment = open fun createQuickAvailabilityFragment(): Fragment =
QuickCompatibilityFragment() QuickCompatibilityFragment()
} }

View file

@ -1,5 +1,6 @@
package im.angry.openeuicc.ui package im.angry.openeuicc.ui
import android.content.Intent
import android.os.Bundle import android.os.Bundle
import androidx.activity.enableEdgeToEdge import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
@ -13,12 +14,12 @@ class QuickCompatibilityActivity : AppCompatActivity(), OpenEuiccContextMarker {
enableEdgeToEdge() enableEdgeToEdge()
setContentView(R.layout.activity_quick_compatibility) setContentView(R.layout.activity_quick_compatibility)
val quickCompatibilityFragment = val quickAvailabilityFragment =
(appContainer.uiComponentFactory as UnprivilegedUiComponentFactory) (appContainer.uiComponentFactory as UnprivilegedUiComponentFactory)
.createQuickCompatibilityFragment() .createQuickAvailabilityFragment()
supportFragmentManager.beginTransaction() supportFragmentManager.beginTransaction()
.replace(R.id.quick_compatibility_container, quickCompatibilityFragment) .replace(R.id.quick_availability_container, quickAvailabilityFragment)
.commit() .commit()
} }
} }

View file

@ -9,7 +9,6 @@ import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.Button import android.widget.Button
import android.widget.CheckBox
import android.widget.TextView import android.widget.TextView
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
@ -33,29 +32,20 @@ open class QuickCompatibilityFragment : Fragment(), UnprivilegedEuiccContextMark
data class CompatibilityResult( data class CompatibilityResult(
val compatibility: Compatibility, val compatibility: Compatibility,
val slotsOmapi: List<String> = emptyList(), val slots: List<String> = emptyList()
val slotsIsdr: List<String> = emptyList()
) )
} }
private val conclusion: TextView by lazy { private val conclusion: TextView by lazy {
requireView().requireViewById(R.id.quick_compatibility_conclusion) requireView().requireViewById(R.id.quick_availability_conclusion)
} }
private val resultSlots: TextView by lazy { private val resultSlots: TextView by lazy {
requireView().requireViewById(R.id.quick_compatibility_result_slots) requireView().requireViewById(R.id.quick_availability_result_slots)
}
private val resultSlotsIsdr: TextView by lazy {
requireView().requireViewById(R.id.quick_compatibility_result_slots_isdr)
} }
private val resultNotes: TextView by lazy { private val resultNotes: TextView by lazy {
requireView().requireViewById(R.id.quick_compatibility_result_notes) requireView().requireViewById(R.id.quick_availability_result_notes)
}
private val skipCheckBox: CheckBox by lazy {
requireView().requireViewById(R.id.quick_compatibility_skip)
} }
override fun onCreateView( override fun onCreateView(
@ -63,19 +53,10 @@ open class QuickCompatibilityFragment : Fragment(), UnprivilegedEuiccContextMark
container: ViewGroup?, container: ViewGroup?,
savedInstanceState: Bundle? savedInstanceState: Bundle?
): View = inflater.inflate(R.layout.fragment_quick_compatibility, container, false).apply { ): View = inflater.inflate(R.layout.fragment_quick_compatibility, container, false).apply {
requireViewById<TextView>(R.id.quick_compatibility_device_information) requireViewById<TextView>(R.id.quick_availability_device_information)
.text = formatDeviceInformation() .text = formatDeviceInformation()
requireViewById<Button>(R.id.quick_compatibility_button_continue) requireViewById<Button>(R.id.quick_availability_button_continue)
.setOnClickListener { onContinueToApp() } .setOnClickListener { onContinueToApp() }
// Can't use the lazy field yet
requireViewById<CheckBox>(R.id.quick_compatibility_skip).setOnCheckedChangeListener { compoundButton, b ->
if (compoundButton.isVisible) {
runBlocking {
preferenceRepository.skipQuickCompatibilityFlow
.updatePreference(b)
}
}
}
} }
override fun onStart() { override fun onStart() {
@ -94,31 +75,19 @@ open class QuickCompatibilityFragment : Fragment(), UnprivilegedEuiccContextMark
private fun onCompatibilityUpdate(result: CompatibilityResult) { private fun onCompatibilityUpdate(result: CompatibilityResult) {
conclusion.text = formatConclusion(result) conclusion.text = formatConclusion(result)
if (result.compatibility == Compatibility.COMPATIBLE) { if (result.compatibility == Compatibility.COMPATIBLE) {
// Don't show the message again, ever, if the result is compatible
runBlocking { runBlocking {
preferenceRepository.skipQuickCompatibilityFlow preferenceRepository.skipQuickAvailabilityFlow
.updatePreference(true) .updatePreference(true)
} }
resultSlots.isVisible = true resultSlots.isVisible = true
resultSlots.text = getString( resultSlots.text = getString(
R.string.quick_compatibility_result_slots, R.string.quick_compatibility_result_slots,
ListFormatter.getInstance().format(result.slotsOmapi) ListFormatter.getInstance().format(result.slots)
) )
resultSlotsIsdr.isVisible = true
resultSlotsIsdr.text =
getString(
R.string.quick_compatibility_result_slots_isdr,
if (result.slotsIsdr.isEmpty()) {
getString(R.string.quick_compatibility_unknown)
} else {
ListFormatter.getInstance().format(result.slotsIsdr)
}
)
resultNotes.isVisible = true resultNotes.isVisible = true
} else { } else {
resultNotes.isVisible = true resultNotes.isVisible = true
resultNotes.text = getString(R.string.quick_compatibility_result_notes_incompatible) resultNotes.text = getString(R.string.quick_compatibility_result_notes_incompatible)
skipCheckBox.isVisible = true
} }
} }
@ -127,9 +96,7 @@ open class QuickCompatibilityFragment : Fragment(), UnprivilegedEuiccContextMark
if (!service.isConnected) { if (!service.isConnected) {
return CompatibilityResult(Compatibility.NOT_COMPATIBLE) return CompatibilityResult(Compatibility.NOT_COMPATIBLE)
} }
val readers = service.readers.filter(Reader::isSIM) val slots = service.readers.filter { it.isSIM }.mapNotNull { reader ->
val omapiSlots = readers.mapNotNull(Reader::slotIndex)
val slots = readers.mapNotNull { reader ->
try { try {
// Note: we ONLY check the default ISD-R AID, because this test is for the _device_, // Note: we ONLY check the default ISD-R AID, because this test is for the _device_,
// NOT the eUICC. We don't care what AID a potential eUICC might use, all we need to // NOT the eUICC. We don't care what AID a potential eUICC might use, all we need to
@ -145,15 +112,10 @@ open class QuickCompatibilityFragment : Fragment(), UnprivilegedEuiccContextMark
null null
} }
} }
if (omapiSlots.isEmpty()) { if (slots.isEmpty()) {
return CompatibilityResult(Compatibility.NOT_COMPATIBLE) return CompatibilityResult(Compatibility.NOT_COMPATIBLE)
} }
val formatChannelName = appContainer.customizableTextProvider::formatInternalChannelName return CompatibilityResult(Compatibility.COMPATIBLE, slots = slots.map { "SIM$it" })
return CompatibilityResult(
Compatibility.COMPATIBLE,
slotsOmapi = omapiSlots.map(formatChannelName),
slotsIsdr = slots.map(formatChannelName),
)
} }
open fun formatConclusion(result: CompatibilityResult): String { open fun formatConclusion(result: CompatibilityResult): String {

View file

@ -12,7 +12,7 @@ import kotlinx.coroutines.runBlocking
class UnprivilegedMainActivity : MainActivity(), UnprivilegedEuiccContextMarker { class UnprivilegedMainActivity : MainActivity(), UnprivilegedEuiccContextMarker {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
if (runBlocking { !preferenceRepository.skipQuickCompatibilityFlow.first() }) { if (runBlocking { !preferenceRepository.skipQuickAvailabilityFlow.first() }) {
startActivity(Intent(this, QuickCompatibilityActivity::class.java)) startActivity(Intent(this, QuickCompatibilityActivity::class.java))
} }
} }

View file

@ -5,10 +5,10 @@ import androidx.datastore.preferences.core.booleanPreferencesKey
internal object UnprivilegedPreferenceKeys { internal object UnprivilegedPreferenceKeys {
// ---- Miscellaneous ---- // ---- Miscellaneous ----
val SKIP_QUICK_COMPATIBILITY = booleanPreferencesKey("skip_quick_compatibility") val SKIP_QUICK_AVAILABILITY = booleanPreferencesKey("skip_quick_availability")
} }
class UnprivilegedPreferenceRepository(context: Context) : PreferenceRepository(context) { class UnprivilegedPreferenceRepository(context: Context) : PreferenceRepository(context) {
// ---- Miscellaneous ---- // ---- Miscellaneous ----
val skipQuickCompatibilityFlow = bindFlow(UnprivilegedPreferenceKeys.SKIP_QUICK_COMPATIBILITY, false) val skipQuickAvailabilityFlow = bindFlow(UnprivilegedPreferenceKeys.SKIP_QUICK_AVAILABILITY, false)
} }

View file

@ -5,7 +5,7 @@
android:layout_height="match_parent"> android:layout_height="match_parent">
<FrameLayout <FrameLayout
android:id="@+id/quick_compatibility_container" android:id="@+id/quick_availability_container"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"

View file

@ -8,7 +8,7 @@
android:textAlignment="center"> android:textAlignment="center">
<TextView <TextView
android:id="@+id/quick_compatibility_conclusion" android:id="@+id/quick_availability_conclusion"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginBottom="16dp" android:layout_marginBottom="16dp"
@ -17,7 +17,7 @@
android:textStyle="bold" /> android:textStyle="bold" />
<TextView <TextView
android:id="@+id/quick_compatibility_device_information" android:id="@+id/quick_availability_device_information"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:fontFamily="monospace" android:fontFamily="monospace"
@ -25,38 +25,23 @@
android:textAlignment="center" /> android:textAlignment="center" />
<TextView <TextView
android:id="@+id/quick_compatibility_result_slots" android:id="@+id/quick_availability_result_slots"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginBottom="16dp" android:layout_marginBottom="16dp"
android:visibility="gone" /> android:visibility="gone" />
<TextView <TextView
android:id="@+id/quick_compatibility_result_slots_isdr" android:id="@+id/quick_availability_result_notes"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:visibility="gone" />
<TextView
android:id="@+id/quick_compatibility_result_notes"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/quick_compatibility_result_notes" android:text="@string/quick_compatibility_result_notes"
android:visibility="gone" /> android:visibility="gone" />
<CheckBox
android:id="@+id/quick_compatibility_skip"
android:visibility="gone"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/quick_compatibility_skip" />
<Button <Button
android:id="@+id/quick_compatibility_button_continue" android:id="@+id/quick_availability_button_continue"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text="@string/quick_compatibility_button_continue" /> android:text="@string/quick_compatibility_button_continue" />
</LinearLayout> </LinearLayout>

View file

@ -6,15 +6,4 @@
<!-- Toast --> <!-- Toast -->
<string name="toast_ara_m_copied">ARA-M SHA-1 をクリップボードにコピーしました</string> <string name="toast_ara_m_copied">ARA-M SHA-1 をクリップボードにコピーしました</string>
<string name="toast_prompt_to_enable_sim_toolkit">「%s」アプリを有効化してください</string> <string name="toast_prompt_to_enable_sim_toolkit">「%s」アプリを有効化してください</string>
<string name="quick_compatibility">互換性のチェック</string>
<string name="quick_compatibility_compatible">お使いのスマートフォンは %s 対応 SIM カードを管理できます</string>
<string name="quick_compatibility_not_compatible">お使いのスマートフォンは %s と互換性がありません</string>
<string name="quick_compatibility_not_compatible_but_usb">お使いのスマートフォンは %s と完全な互換性がありません。ただし、USBスマートカードリーダーを使用する場合、ほぼすべての機能を利用できます。</string>
<string name="quick_compatibility_result_slots">アクセス可能なスロット: %s</string>
<string name="quick_compatibility_result_slots_isdr">ISD-R アクセス: %s</string>
<string name="quick_compatibility_result_notes">注: これらの結果は参考用です。以上に記載されていない SIM スロットでも、SIM カードを挿入すれば利用できる可能性があります。</string>
<string name="quick_compatibility_result_notes_incompatible">注:現在 SIM カードが挿入されていない場合は、SIM カードを挿入してから再度互換性チェックをお試しください。どの SIM カードでも構いません。</string>
<string name="quick_compatibility_button_continue">つづく</string>
<string name="quick_compatibility_skip">このメッセージを再度表示しない</string>
<string name="quick_compatibility_unknown">不明</string>
</resources> </resources>

View file

@ -2,16 +2,4 @@
<string name="compatibility_check">兼容性检查</string> <string name="compatibility_check">兼容性检查</string>
<string name="open_sim_toolkit">打开 SIM 卡应用程序</string> <string name="open_sim_toolkit">打开 SIM 卡应用程序</string>
<string name="toast_ara_m_copied">ARA-M SHA-1 已拷贝到剪贴板</string> <string name="toast_ara_m_copied">ARA-M SHA-1 已拷贝到剪贴板</string>
<string name="toast_prompt_to_enable_sim_toolkit">请启用您的“%s”应用程序</string>
<string name="quick_compatibility">简易兼容性检测</string>
<string name="quick_compatibility_compatible">您的手机可以管理兼容 %s 的卡片</string>
<string name="quick_compatibility_not_compatible">您的手机与 %s 不兼容</string>
<string name="quick_compatibility_not_compatible_but_usb">您的手机与 %s 不完全兼容,但可以使用 USB 读卡器获得几乎全部功能</string>
<string name="quick_compatibility_result_slots">可读取的卡槽: %s</string>
<string name="quick_compatibility_result_slots_isdr">ISD-R 访问: %s</string>
<string name="quick_compatibility_result_notes">注意:以上结果仅供参考。即使某些卡槽没有被列举出来,插卡后也可能可用。</string>
<string name="quick_compatibility_result_notes_incompatible">注意:如果您目前没有插卡,请插任意 SIM 卡后重试兼容性检测。</string>
<string name="quick_compatibility_button_continue">继续</string>
<string name="quick_compatibility_skip">不再显示此消息</string>
<string name="quick_compatibility_unknown">未知</string>
</resources> </resources>

View file

@ -2,16 +2,4 @@
<string name="compatibility_check">相容性檢查</string> <string name="compatibility_check">相容性檢查</string>
<string name="open_sim_toolkit">啟動 SIM 卡應用程式</string> <string name="open_sim_toolkit">啟動 SIM 卡應用程式</string>
<string name="toast_ara_m_copied">ARA-M SHA-1 已複製到剪貼簿</string> <string name="toast_ara_m_copied">ARA-M SHA-1 已複製到剪貼簿</string>
<string name="toast_prompt_to_enable_sim_toolkit">請啟用您的“%s”應用程式</string>
<string name="quick_compatibility">簡易相容性檢測</string>
<string name="quick_compatibility_compatible">您的手機可以管理相容 %s 的卡片</string>
<string name="quick_compatibility_not_compatible">您的手機與 %s 不相容</string>
<string name="quick_compatibility_not_compatible_but_usb">您的手機與 %s 不完全相容,但可以使用 USB 讀卡機獲得幾乎全部功能</string>
<string name="quick_compatibility_result_slots">可讀取的卡槽: %s</string>
<string name="quick_compatibility_result_slots_isdr">ISD-R 訪問: %s</string>
<string name="quick_compatibility_result_notes">注意:以上結果僅供參考。即使某些卡槽沒有被列舉出來,插卡後也可能可用。</string>
<string name="quick_compatibility_result_notes_incompatible">注意:如果您目前沒有插卡,請插任何 SIM 卡後重試相容性檢測。</string>
<string name="quick_compatibility_button_continue">繼續</string>
<string name="quick_compatibility_skip">不再顯示此訊息</string>
<string name="quick_compatibility_unknown">未知</string>
</resources> </resources>

View file

@ -16,11 +16,8 @@
<string name="quick_compatibility_compatible">Your smartphone can manage %s-compatible cards</string> <string name="quick_compatibility_compatible">Your smartphone can manage %s-compatible cards</string>
<string name="quick_compatibility_not_compatible">Your smartphone is not compatible with %s</string> <string name="quick_compatibility_not_compatible">Your smartphone is not compatible with %s</string>
<string name="quick_compatibility_not_compatible_but_usb">Your smartphone is not fully compatible with %s. However, you can still use a USB smart card reader for near-full functionality.</string> <string name="quick_compatibility_not_compatible_but_usb">Your smartphone is not fully compatible with %s. However, you can still use a USB smart card reader for near-full functionality.</string>
<string name="quick_compatibility_result_slots">Accessible slots: %s</string> <string name="quick_compatibility_result_slots">SIM card slots accessible: %s</string>
<string name="quick_compatibility_result_slots_isdr">ISD-R access: %s</string>
<string name="quick_compatibility_result_notes">Note: these results are for reference only. Even if a SIM slot is not listed above, it <i>may</i> be compatible as well once a SIM card is inserted.</string> <string name="quick_compatibility_result_notes">Note: these results are for reference only. Even if a SIM slot is not listed above, it <i>may</i> be compatible as well once a SIM card is inserted.</string>
<string name="quick_compatibility_result_notes_incompatible">Note: if you currently do not have any SIM card inserted, try the compatibility check again after inserting one. Any SIM card will do.</string> <string name="quick_compatibility_result_notes_incompatible">Note: if you currently do not have any SIM card inserted, try the compatibility check again after inserting one. Any SIM card will do.</string>
<string name="quick_compatibility_button_continue">Continue</string> <string name="quick_compatibility_button_continue">Continue</string>
<string name="quick_compatibility_skip">Don\'t show this message again</string>
<string name="quick_compatibility_unknown">Unknown</string>
</resources> </resources>