Compare commits
No commits in common. "54f02ff638b3eaf017c00210ec71d7eabb5a9fb3" and "f2a98b4fcb810e72d6e9ef4918d0f90c71e3cae8" have entirely different histories.
54f02ff638
...
f2a98b4fcb
4 changed files with 57 additions and 149 deletions
|
@ -3,23 +3,17 @@ package im.angry.openeuicc.service
|
||||||
import android.service.euicc.*
|
import android.service.euicc.*
|
||||||
import android.telephony.euicc.DownloadableSubscription
|
import android.telephony.euicc.DownloadableSubscription
|
||||||
import android.telephony.euicc.EuiccInfo
|
import android.telephony.euicc.EuiccInfo
|
||||||
|
import com.truphone.lpa.LocalProfileAssistant
|
||||||
import com.truphone.lpa.LocalProfileInfo
|
import com.truphone.lpa.LocalProfileInfo
|
||||||
import com.truphone.lpad.progress.Progress
|
|
||||||
import com.truphone.util.TextUtil
|
|
||||||
import im.angry.openeuicc.OpenEuiccApplication
|
import im.angry.openeuicc.OpenEuiccApplication
|
||||||
import im.angry.openeuicc.core.EuiccChannel
|
|
||||||
import im.angry.openeuicc.util.*
|
|
||||||
|
|
||||||
class OpenEuiccService : EuiccService() {
|
class OpenEuiccService : EuiccService() {
|
||||||
private val openEuiccApplication
|
private fun findLpa(slotId: Int): LocalProfileAssistant? =
|
||||||
get() = application as OpenEuiccApplication
|
(application as OpenEuiccApplication).euiccChannelManager
|
||||||
|
.findEuiccChannelBySlotBlocking(slotId)?.lpa
|
||||||
private fun findChannel(slotId: Int): EuiccChannel? =
|
|
||||||
openEuiccApplication.euiccChannelManager
|
|
||||||
.findEuiccChannelBySlotBlocking(slotId)
|
|
||||||
|
|
||||||
override fun onGetEid(slotId: Int): String? =
|
override fun onGetEid(slotId: Int): String? =
|
||||||
findChannel(slotId)?.lpa?.eid
|
findLpa(slotId)?.eid
|
||||||
|
|
||||||
override fun onGetOtaStatus(slotId: Int): Int {
|
override fun onGetOtaStatus(slotId: Int): Int {
|
||||||
// Not implemented
|
// Not implemented
|
||||||
|
@ -52,7 +46,7 @@ class OpenEuiccService : EuiccService() {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onGetEuiccProfileInfoList(slotId: Int): GetEuiccProfileInfoListResult? {
|
override fun onGetEuiccProfileInfoList(slotId: Int): GetEuiccProfileInfoListResult? {
|
||||||
val profiles = (findChannel(slotId) ?: return null).lpa.profiles.filter {
|
val profiles = (findLpa(slotId) ?: return null).profiles.filter {
|
||||||
it.profileClass != LocalProfileInfo.Clazz.Testing
|
it.profileClass != LocalProfileInfo.Clazz.Testing
|
||||||
}.map {
|
}.map {
|
||||||
EuiccProfileInfo.Builder(it.iccidLittleEndian).apply {
|
EuiccProfileInfo.Builder(it.iccidLittleEndian).apply {
|
||||||
|
@ -82,28 +76,8 @@ class OpenEuiccService : EuiccService() {
|
||||||
return EuiccInfo("Unknown") // TODO: Can we actually implement this?
|
return EuiccInfo("Unknown") // TODO: Can we actually implement this?
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDeleteSubscription(slotId: Int, iccid: String): Int {
|
override fun onDeleteSubscription(slotId: Int, iccid: String?): Int {
|
||||||
try {
|
TODO("Not yet implemented")
|
||||||
val channel = findChannel(slotId) ?: return RESULT_FIRST_USER
|
|
||||||
val iccidBig = TextUtil.iccidLittleToBig(iccid)
|
|
||||||
|
|
||||||
val profile = channel.lpa.profiles.find {
|
|
||||||
it.iccid == iccidBig
|
|
||||||
} ?: return RESULT_FIRST_USER
|
|
||||||
|
|
||||||
if (profile.state == LocalProfileInfo.State.Enabled) {
|
|
||||||
// Must disable the profile first
|
|
||||||
return RESULT_FIRST_USER
|
|
||||||
}
|
|
||||||
|
|
||||||
return if (channel.lpa.deleteProfile(iccidBig, Progress()) == "0") {
|
|
||||||
RESULT_OK
|
|
||||||
} else {
|
|
||||||
RESULT_FIRST_USER
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
|
||||||
return RESULT_FIRST_USER
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated("Deprecated in Java")
|
@Deprecated("Deprecated in Java")
|
||||||
|
@ -112,44 +86,11 @@ class OpenEuiccService : EuiccService() {
|
||||||
iccid: String?,
|
iccid: String?,
|
||||||
forceDeactivateSim: Boolean
|
forceDeactivateSim: Boolean
|
||||||
): Int {
|
): Int {
|
||||||
try {
|
TODO("Not yet implemented")
|
||||||
val channel = findChannel(slotId) ?: return RESULT_FIRST_USER
|
|
||||||
if (iccid == null) {
|
|
||||||
// Disable active profile
|
|
||||||
val activeProfile = channel.lpa.profiles.find {
|
|
||||||
it.state == LocalProfileInfo.State.Enabled
|
|
||||||
} ?: return RESULT_OK
|
|
||||||
|
|
||||||
return if (channel.lpa.disableProfile(activeProfile.iccid, Progress()) == "0") {
|
|
||||||
RESULT_OK
|
|
||||||
} else {
|
|
||||||
RESULT_FIRST_USER
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
val iccidBig = TextUtil.iccidLittleToBig(iccid)
|
|
||||||
return if (channel.lpa.enableProfile(iccidBig, Progress()) == "0") {
|
|
||||||
RESULT_OK
|
|
||||||
} else {
|
|
||||||
RESULT_FIRST_USER
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
|
||||||
return RESULT_FIRST_USER
|
|
||||||
} finally {
|
|
||||||
openEuiccApplication.euiccChannelManager.invalidate()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onUpdateSubscriptionNickname(slotId: Int, iccid: String, nickname: String?): Int {
|
override fun onUpdateSubscriptionNickname(slotId: Int, iccid: String?, nickname: String?): Int {
|
||||||
val channel = findChannel(slotId) ?: return RESULT_FIRST_USER
|
TODO("Not yet implemented")
|
||||||
val success = channel.lpa
|
|
||||||
.setNickname(TextUtil.iccidLittleToBig(iccid), nickname)
|
|
||||||
openEuiccApplication.subscriptionManager.tryRefreshCachedEuiccInfo(channel.cardId)
|
|
||||||
return if (success) {
|
|
||||||
RESULT_OK
|
|
||||||
} else {
|
|
||||||
RESULT_FIRST_USER
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated("Deprecated in Java")
|
@Deprecated("Deprecated in Java")
|
||||||
|
|
|
@ -14,8 +14,8 @@
|
||||||
|
|
||||||
package com.truphone.lpa
|
package com.truphone.lpa
|
||||||
|
|
||||||
import com.truphone.util.TextUtil.iccidBigToLittle
|
|
||||||
import java.lang.IllegalArgumentException
|
import java.lang.IllegalArgumentException
|
||||||
|
import java.lang.StringBuilder
|
||||||
|
|
||||||
data class LocalProfileInfo(
|
data class LocalProfileInfo(
|
||||||
val iccid: String,
|
val iccid: String,
|
||||||
|
@ -56,5 +56,14 @@ data class LocalProfileInfo(
|
||||||
"2" -> Clazz.Operational
|
"2" -> Clazz.Operational
|
||||||
else -> throw IllegalArgumentException("Unknown profile class $clazz")
|
else -> throw IllegalArgumentException("Unknown profile class $clazz")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun iccidBigToLittle(iccid: String): String {
|
||||||
|
val builder = StringBuilder()
|
||||||
|
for (i in 0 until iccid.length / 2) {
|
||||||
|
builder.append(iccid[i * 2 + 1])
|
||||||
|
if (iccid[i * 2] != 'F') builder.append(iccid[i * 2])
|
||||||
|
}
|
||||||
|
return builder.toString()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
package com.truphone.util;
|
||||||
|
|
||||||
|
public class TextUtil {
|
||||||
|
private static final char[] HEX_DIGITS = {'0', '1', '2', '3', '4', '5',
|
||||||
|
'6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts the given byte array to its hex representation.
|
||||||
|
*
|
||||||
|
* @param data The byte array to convert.
|
||||||
|
* @return Hex-encoded data as a string.
|
||||||
|
* @see #toHexString(byte[], int, int)
|
||||||
|
*/
|
||||||
|
public static String toHexString(byte[] data) {
|
||||||
|
return data == null ? null : toHexString(data, 0, data.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts the given byte array slice to its hex representation.
|
||||||
|
*
|
||||||
|
* @param data The byte array to convert.
|
||||||
|
* @param offset Slice start.
|
||||||
|
* @param length Slice length.
|
||||||
|
* @return Hex-encoded data as a string.
|
||||||
|
*/
|
||||||
|
public static String toHexString(final byte[] data, int offset, int length) {
|
||||||
|
final char[] result = new char[length << 1];
|
||||||
|
length += offset;
|
||||||
|
for (int i = 0; offset < length; ++offset) {
|
||||||
|
result[i++] = HEX_DIGITS[(data[offset] >>> 4) & 0x0F];
|
||||||
|
result[i++] = HEX_DIGITS[data[offset] & 0x0F];
|
||||||
|
}
|
||||||
|
return new String(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,78 +0,0 @@
|
||||||
package com.truphone.util
|
|
||||||
|
|
||||||
import java.lang.StringBuilder
|
|
||||||
|
|
||||||
object TextUtil {
|
|
||||||
private val HEX_DIGITS = charArrayOf(
|
|
||||||
'0', '1', '2', '3', '4', '5',
|
|
||||||
'6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
|
|
||||||
)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts the given byte array to its hex representation.
|
|
||||||
*
|
|
||||||
* @param data The byte array to convert.
|
|
||||||
* @return Hex-encoded data as a string.
|
|
||||||
* @see .toHexString
|
|
||||||
*/
|
|
||||||
@JvmStatic
|
|
||||||
fun toHexString(data: ByteArray?): String? {
|
|
||||||
return if (data == null) null else toHexString(data, 0, data.size)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts the given byte array slice to its hex representation.
|
|
||||||
*
|
|
||||||
* @param data The byte array to convert.
|
|
||||||
* @param offset Slice start.
|
|
||||||
* @param length Slice length.
|
|
||||||
* @return Hex-encoded data as a string.
|
|
||||||
*/
|
|
||||||
@JvmStatic
|
|
||||||
fun toHexString(data: ByteArray, offset: Int, length: Int): String {
|
|
||||||
var offset = offset
|
|
||||||
var length = length
|
|
||||||
val result = CharArray(length shl 1)
|
|
||||||
length += offset
|
|
||||||
var i = 0
|
|
||||||
while (offset < length) {
|
|
||||||
result[i++] = HEX_DIGITS[data[offset].toInt() ushr 4 and 0x0F]
|
|
||||||
result[i++] = HEX_DIGITS[data[offset].toInt() and 0x0F]
|
|
||||||
++offset
|
|
||||||
}
|
|
||||||
return String(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts a big-endian representation of ICCID into little-endian
|
|
||||||
* Big-endian representation is used internally in communication with the SIM.
|
|
||||||
*
|
|
||||||
* @param iccid The ICCID to be converted
|
|
||||||
*/
|
|
||||||
fun iccidBigToLittle(iccid: String): String {
|
|
||||||
val builder = StringBuilder()
|
|
||||||
for (i in 0 until iccid.length / 2) {
|
|
||||||
builder.append(iccid[i * 2 + 1])
|
|
||||||
if (iccid[i * 2] != 'F') builder.append(iccid[i * 2])
|
|
||||||
}
|
|
||||||
return builder.toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts a little-endian representation of ICCID into big-endian
|
|
||||||
*
|
|
||||||
* @param iccid The ICCID to be converted
|
|
||||||
*/
|
|
||||||
fun iccidLittleToBig(iccidLittle: String): String {
|
|
||||||
val builder = StringBuilder()
|
|
||||||
for (i in 0 until iccidLittle.length / 2) {
|
|
||||||
builder.append(iccidLittle[i * 2 + 1])
|
|
||||||
builder.append(iccidLittle[i * 2])
|
|
||||||
}
|
|
||||||
if (iccidLittle.length % 2 == 1) {
|
|
||||||
builder.append('F')
|
|
||||||
builder.append(iccidLittle[iccidLittle.length - 1])
|
|
||||||
}
|
|
||||||
return builder.toString()
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Add table
Reference in a new issue