diff --git a/.forgejo/workflows/build-debug.yml b/.forgejo/workflows/build-debug.yml index 1dcc692..51e802c 100644 --- a/.forgejo/workflows/build-debug.yml +++ b/.forgejo/workflows/build-debug.yml @@ -35,11 +35,12 @@ jobs: - name: Build Debug APKs run: ./gradlew --no-daemon assembleDebug + - name: Copy Artifacts + run: find . -name 'app*-debug.apk' -exec cp {} . \; + - name: Upload Artifacts uses: https://gitea.angry.im/actions/upload-artifact@v3 with: name: Debug APKs compression-level: 0 - path: | - app-unpriv/build/outputs/apk/debug/app-unpriv-debug.apk - app/build/outputs/apk/debug/app-debug.apk + path: app*-debug.apk diff --git a/app-common/src/main/java/im/angry/openeuicc/core/LocalProfileAssistantWrapper.kt b/app-common/src/main/java/im/angry/openeuicc/core/LocalProfileAssistantWrapper.kt index 22ece46..aab9e63 100644 --- a/app-common/src/main/java/im/angry/openeuicc/core/LocalProfileAssistantWrapper.kt +++ b/app-common/src/main/java/im/angry/openeuicc/core/LocalProfileAssistantWrapper.kt @@ -52,6 +52,8 @@ class LocalProfileAssistantWrapper(orig: LocalProfileAssistant) : override fun handleNotification(seqNumber: Long): Boolean = lpa.handleNotification(seqNumber) + override fun euiccMemoryReset() = lpa.euiccMemoryReset() + override fun setNickname(iccid: String, nickname: String): Boolean = lpa.setNickname(iccid, nickname) diff --git a/app-common/src/main/java/im/angry/openeuicc/core/OmapiApduInterface.kt b/app-common/src/main/java/im/angry/openeuicc/core/OmapiApduInterface.kt index b63f343..71aa386 100644 --- a/app-common/src/main/java/im/angry/openeuicc/core/OmapiApduInterface.kt +++ b/app-common/src/main/java/im/angry/openeuicc/core/OmapiApduInterface.kt @@ -38,8 +38,8 @@ class OmapiApduInterface( check(!this::lastChannel.isInitialized) { "Can only open one channel" } - lastChannel = session.openLogicalChannel(aid)!!; - return 1; + lastChannel = session.openLogicalChannel(aid)!! + return 1 } override fun logicalChannelClose(handle: Int) { diff --git a/app-common/src/main/java/im/angry/openeuicc/ui/EuiccManagementFragment.kt b/app-common/src/main/java/im/angry/openeuicc/ui/EuiccManagementFragment.kt index b7462e2..8947480 100644 --- a/app-common/src/main/java/im/angry/openeuicc/ui/EuiccManagementFragment.kt +++ b/app-common/src/main/java/im/angry/openeuicc/ui/EuiccManagementFragment.kt @@ -20,6 +20,7 @@ import android.widget.Toast import androidx.appcompat.app.AlertDialog import androidx.core.view.ViewCompat import androidx.core.view.WindowInsetsCompat +import androidx.core.view.isVisible import androidx.core.view.updateLayoutParams import androidx.fragment.app.Fragment import androidx.lifecycle.lifecycleScope @@ -339,6 +340,8 @@ open class EuiccManagementFragment : Fragment(), EuiccProfilesChangedListener, private val name: TextView = root.requireViewById(R.id.name) private val state: TextView = root.requireViewById(R.id.state) private val provider: TextView = root.requireViewById(R.id.provider) + private val profileClassLabel: TextView = root.requireViewById(R.id.profile_class_label) + private val profileClass: TextView = root.requireViewById(R.id.profile_class) private val profileMenu: ImageButton = root.requireViewById(R.id.profile_menu) init { @@ -364,6 +367,10 @@ open class EuiccManagementFragment : Fragment(), EuiccProfilesChangedListener, private lateinit var profile: LocalProfileInfo fun setProfile(profile: LocalProfileInfo) { + if (unfilteredProfileListFlow.value) { + profileClassLabel.isVisible = true + profileClass.isVisible = true + } this.profile = profile name.text = profile.displayName @@ -375,6 +382,13 @@ open class EuiccManagementFragment : Fragment(), EuiccProfilesChangedListener, } ) provider.text = profile.providerName + if (profileClass.isVisible) profileClass.setText( + when (profile.profileClass) { + LocalProfileInfo.Clazz.Testing -> R.string.profile_class_testing + LocalProfileInfo.Clazz.Provisioning -> R.string.profile_class_provisioning + LocalProfileInfo.Clazz.Operational -> R.string.profile_class_operational + } + ) iccid.text = profile.iccid iccid.transformationMethod = PasswordTransformationMethod.getInstance() } diff --git a/app-common/src/main/java/im/angry/openeuicc/ui/MainActivity.kt b/app-common/src/main/java/im/angry/openeuicc/ui/MainActivity.kt index 74f2147..7711643 100644 --- a/app-common/src/main/java/im/angry/openeuicc/ui/MainActivity.kt +++ b/app-common/src/main/java/im/angry/openeuicc/ui/MainActivity.kt @@ -109,7 +109,7 @@ open class MainActivity : BaseEuiccAccessActivity(), OpenEuiccContextMarker { override fun onOptionsItemSelected(item: MenuItem): Boolean = when (item.itemId) { R.id.settings -> { - startActivity(Intent(this, SettingsActivity::class.java)); + startActivity(Intent(this, SettingsActivity::class.java)) true } R.id.reload -> { diff --git a/app-common/src/main/java/im/angry/openeuicc/ui/NotificationsActivity.kt b/app-common/src/main/java/im/angry/openeuicc/ui/NotificationsActivity.kt index 31b7d7e..c2a1a0f 100644 --- a/app-common/src/main/java/im/angry/openeuicc/ui/NotificationsActivity.kt +++ b/app-common/src/main/java/im/angry/openeuicc/ui/NotificationsActivity.kt @@ -117,11 +117,14 @@ class NotificationsActivity: BaseEuiccAccessActivity(), OpenEuiccContextMarker { launchTask { notificationAdapter.notifications = euiccChannelManager.withEuiccChannel(logicalSlotId) { channel -> - val profiles = channel.lpa.profiles + val nameMap = buildMap { + for (profile in channel.lpa.profiles) { + put(profile.iccid, profile.displayName) + } + } channel.lpa.notifications.map { - val profile = profiles.find { p -> p.iccid == it.iccid } - LocalProfileNotificationWrapper(it, profile?.displayName ?: "???") + LocalProfileNotificationWrapper(it, nameMap[it.iccid] ?: "???") } } } @@ -136,6 +139,8 @@ class NotificationsActivity: BaseEuiccAccessActivity(), OpenEuiccContextMarker { inner class NotificationViewHolder(private val root: View): RecyclerView.ViewHolder(root), View.OnCreateContextMenuListener, OnMenuItemClickListener { private val address: TextView = root.requireViewById(R.id.notification_address) + private val sequenceNumber: TextView = + root.requireViewById(R.id.notification_sequence_number) private val profileName: TextView = root.requireViewById(R.id.notification_profile_name) private lateinit var notification: LocalProfileNotificationWrapper @@ -157,6 +162,7 @@ class NotificationsActivity: BaseEuiccAccessActivity(), OpenEuiccContextMarker { } } + private fun operationToLocalizedText(operation: LocalProfileNotification.Operation) = root.context.getText( when (operation) { @@ -170,6 +176,10 @@ class NotificationsActivity: BaseEuiccAccessActivity(), OpenEuiccContextMarker { notification = value address.text = value.inner.notificationAddress + sequenceNumber.text = root.context.getString( + R.string.profile_notification_sequence_number_format, + value.inner.seqNumber + ) profileName.text = Html.fromHtml( root.context.getString(R.string.profile_notification_name_format, operationToLocalizedText(value.inner.profileManagementOperation), diff --git a/app-common/src/main/res/layout/euicc_profile.xml b/app-common/src/main/res/layout/euicc_profile.xml index 06aa2b8..83aae8d 100644 --- a/app-common/src/main/res/layout/euicc_profile.xml +++ b/app-common/src/main/res/layout/euicc_profile.xml @@ -62,18 +62,43 @@ android:singleLine="true" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toBottomOf="@id/state" - app:layout_constraintBottom_toTopOf="@+id/iccid_label"/> + app:layout_constraintBottom_toTopOf="@+id/profile_class_label"/> + + + + diff --git a/app-common/src/main/res/layout/notification_item.xml b/app-common/src/main/res/layout/notification_item.xml index 6b7253c..5d56b3a 100644 --- a/app-common/src/main/res/layout/notification_item.xml +++ b/app-common/src/main/res/layout/notification_item.xml @@ -15,6 +15,15 @@ app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="parent" /> + + 有効済み 無効済み プロバイダー: - ICCID: 有効化 無効化 削除 @@ -89,7 +88,6 @@ 削除しました 有効化しました 無効化しました - <b>%1$s</b> %2$s (%3$s) 処理 削除 eUICC 情報 diff --git a/app-common/src/main/res/values/strings.xml b/app-common/src/main/res/values/strings.xml index d0813d2..8ea6e20 100644 --- a/app-common/src/main/res/values/strings.xml +++ b/app-common/src/main/res/values/strings.xml @@ -13,7 +13,11 @@ Enabled Disabled Provider: - ICCID: + Class: + Testing + Provisioning + Operational + ICCID: Enable Disable @@ -103,7 +107,8 @@ Deleted Enabled Disabled - <b>%1$s</b> %2$s (%3$s) + <b>%1$s</b> %2$s (%3$s) + #%d Process Delete diff --git a/app/src/main/java/im/angry/openeuicc/core/TelephonyManagerApduInterface.kt b/app/src/main/java/im/angry/openeuicc/core/TelephonyManagerApduInterface.kt index ef877b4..6b09368 100644 --- a/app/src/main/java/im/angry/openeuicc/core/TelephonyManagerApduInterface.kt +++ b/app/src/main/java/im/angry/openeuicc/core/TelephonyManagerApduInterface.kt @@ -39,7 +39,7 @@ class TelephonyManagerApduInterface( val hex = aid.encodeHex() val channel = tm.iccOpenLogicalChannelByPortCompat(port.card.physicalSlotIndex, port.portIndex, hex, 0) if (channel.status != IccOpenLogicalChannelResponse.STATUS_NO_ERROR || channel.channel == IccOpenLogicalChannelResponse.INVALID_CHANNEL) { - throw IllegalArgumentException("Cannot open logical channel $hex via TelephonManager on slot ${port.card.physicalSlotIndex} port ${port.portIndex}"); + throw IllegalArgumentException("Cannot open logical channel $hex via TelephonManager on slot ${port.card.physicalSlotIndex} port ${port.portIndex}") } lastChannel = channel.channel return lastChannel diff --git a/app/src/main/java/im/angry/openeuicc/util/PrivilegedTelephonyCompat.kt b/app/src/main/java/im/angry/openeuicc/util/PrivilegedTelephonyCompat.kt index 4c1e19f..dbd39f2 100644 --- a/app/src/main/java/im/angry/openeuicc/util/PrivilegedTelephonyCompat.kt +++ b/app/src/main/java/im/angry/openeuicc/util/PrivilegedTelephonyCompat.kt @@ -94,6 +94,7 @@ val TelephonyManager.uiccCardsInfoCompat: List fun TelephonyManager.iccOpenLogicalChannelByPortCompat( slotIndex: Int, portIndex: Int, aid: String?, p2: Int ): IccOpenLogicalChannelResponse = + @Suppress("UNNECESSARY_NOT_NULL_ASSERTION") if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { iccOpenLogicalChannelByPort(slotIndex, portIndex, aid, p2)!! } else { diff --git a/libs/lpac-jni/build.gradle.kts b/libs/lpac-jni/build.gradle.kts index ff34d56..93f6082 100644 --- a/libs/lpac-jni/build.gradle.kts +++ b/libs/lpac-jni/build.gradle.kts @@ -16,9 +16,9 @@ android { externalNativeBuild { ndkBuild { cFlags( - "-fmacro-prefix-map=${project.projectDir.toString()}=/fake/path/", - "-fdebug-prefix-map=${project.projectDir.toString()}=/fake/path/", - "-ffile-prefix-map=${project.projectDir.toString()}=/fake/path/" + "-fmacro-prefix-map=${project.projectDir}=/fake/path/", + "-fdebug-prefix-map=${project.projectDir}=/fake/path/", + "-ffile-prefix-map=${project.projectDir}=/fake/path/" ) } } diff --git a/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/LocalProfileAssistant.kt b/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/LocalProfileAssistant.kt index cf870e1..58f25aa 100644 --- a/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/LocalProfileAssistant.kt +++ b/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/LocalProfileAssistant.kt @@ -37,6 +37,8 @@ interface LocalProfileAssistant { fun deleteNotification(seqNumber: Long): Boolean fun handleNotification(seqNumber: Long): Boolean + fun euiccMemoryReset() + fun setNickname( iccid: String, nickname: String ): Boolean diff --git a/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/LpacJni.kt b/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/LpacJni.kt index 1e64c69..09c0117 100644 --- a/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/LpacJni.kt +++ b/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/LpacJni.kt @@ -33,6 +33,8 @@ internal object LpacJni { // Cancel any ongoing es9p and/or es10b sessions external fun cancelSessions(handle: Long) + // ES10c + external fun es10cEuiccMemoryReset(handle: Long): Int // es10cex (actually part of es10b) external fun es10cexGetEuiccInfo2(handle: Long): Long diff --git a/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/impl/LocalProfileAssistantImpl.kt b/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/impl/LocalProfileAssistantImpl.kt index 4dbb181..0cbebf0 100644 --- a/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/impl/LocalProfileAssistantImpl.kt +++ b/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/impl/LocalProfileAssistantImpl.kt @@ -241,6 +241,10 @@ class LocalProfileAssistantImpl( override fun setNickname(iccid: String, nickname: String): Boolean = LpacJni.es10cSetNickname(contextHandle, iccid, nickname) == 0 + override fun euiccMemoryReset() { + LpacJni.es10cEuiccMemoryReset(contextHandle) + } + @Synchronized override fun close() { if (!finalized) { diff --git a/libs/lpac-jni/src/main/jni/lpac-jni/lpac-jni.c b/libs/lpac-jni/src/main/jni/lpac-jni/lpac-jni.c index f081f8e..8f4752b 100644 --- a/libs/lpac-jni/src/main/jni/lpac-jni/lpac-jni.c +++ b/libs/lpac-jni/src/main/jni/lpac-jni/lpac-jni.c @@ -245,6 +245,15 @@ Java_net_typeblog_lpac_1jni_LpacJni_es10cexGetEuiccInfo2(JNIEnv *env, jobject th return (jlong) info; } + +JNIEXPORT jint JNICALL +Java_net_typeblog_lpac_1jni_LpacJni_es10cEuiccMemoryReset(JNIEnv *env, jobject thiz, jlong handle) { + struct euicc_ctx *ctx = (struct euicc_ctx *) handle; + int ret; + ret = es10c_euicc_memory_reset(ctx); + return ret; +} + JNIEXPORT jstring JNICALL Java_net_typeblog_lpac_1jni_LpacJni_stringDeref(JNIEnv *env, jobject thiz, jlong curr) { return toJString(env, *((char **) curr));