diff --git a/README.en.md b/README.en.md index a735c58..6179280 100644 --- a/README.en.md +++ b/README.en.md @@ -68,7 +68,7 @@ only if installing Shizuku using ADB ### Install Pixel IMS application 1. As for now, there are two ways to obtain the application. Choose you favourite way and install the application. - Via [Play Store](https://play.google.com/store/apps/details?id=dev.bluehouse.enablevolte) - - From [Github Releases](https://github.com/kyujin-cho/pixel-volte-patch/releases/download/1.2.7/dev.bluehouse.enablevolte.apk), by downloading APK file + - From [Github Releases](https://github.com/kyujin-cho/pixel-volte-patch/releases/download/1.2.8/dev.bluehouse.enablevolte.apk), by downloading APK file 2. Start installed application. 3. Tap "Allow all the time" when seeing prompt asking for Shizuku permission. ![image-5](https://github.com/kyujin-cho/pixel-volte-patch/raw/main/assets/Screenshot_20230208-235239.png) diff --git a/README.md b/README.md index 0b054f5..d7cb69a 100644 --- a/README.md +++ b/README.md @@ -62,7 +62,7 @@ English version available [here](https://github.com/kyujin-cho/pixel-volte-patch ### Pixel IMS 어플리케이션 설치 1. 현재 다음 두 가지 방법으로 Pixel IMS 앱을 설치할 수 있습니다. - - [Github Releases](https://github.com/kyujin-cho/pixel-volte-patch/releases/download/1.2.7/dev.bluehouse.enablevolte.apk) 에서 APK 다운로드 후 설치 + - [Github Releases](https://github.com/kyujin-cho/pixel-volte-patch/releases/download/1.2.8/dev.bluehouse.enablevolte.apk) 에서 APK 다운로드 후 설치 - [Play Store](https://play.google.com/store/apps/details?id=dev.bluehouse.enablevolte) 에서 다운로드 2. 설치한 어플리케이션을 실행합니다. 3. 다음과 같이 Shizuku 권한을 묻는 팝업 창이 뜰 경우 "모든 경우에 허용" 을 선택합니다. diff --git a/app/build.gradle b/app/build.gradle index 8ab5374..c8b229a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -11,8 +11,8 @@ android { applicationId "dev.bluehouse.enablevolte" minSdk 29 targetSdk 33 - versionCode 12 - versionName "1.2.7" + versionCode 13 + versionName "1.2.8" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" vectorDrawables { diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 63993e8..b6efb38 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -11,7 +11,7 @@ android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/Theme.EnableVoLTE" - tools:targetApi="31" + tools:targetApi="33" android:localeConfig="@xml/locales_config"> + + + + + + + + + + + + + + + + + + + + + + + + Tile.STATE_ACTIVE + false -> Tile.STATE_INACTIVE + null -> Tile.STATE_UNAVAILABLE + } + qsTile.subtitle = getString( + when (imsActivated) { + true -> R.string.registered + false -> R.string.unregistered + null -> R.string.unknown + }, + ) + qsTile.updateTile() + } + + override fun onStartListening() { + super.onStartListening() + this.refreshStatus() + } + + override fun onClick() { + super.onClick() + moder?.restartIMSRegistration() + this.refreshStatus() + } +} diff --git a/app/src/main/java/dev/bluehouse/enablevolte/Moder.kt b/app/src/main/java/dev/bluehouse/enablevolte/Moder.kt index 70a4f78..b07e846 100644 --- a/app/src/main/java/dev/bluehouse/enablevolte/Moder.kt +++ b/app/src/main/java/dev/bluehouse/enablevolte/Moder.kt @@ -77,6 +77,11 @@ open class Moder { } class CarrierModer(private val context: Context) : Moder() { + fun getActiveSubscriptionInfoForSimSlotIndex(index: Int): SubscriptionInfo? { + val sub = this.loadCachedInterface { sub } + return sub.getActiveSubscriptionInfoForSimSlotIndex(index, null, null) + } + val subscriptions: List get() { val sub = this.loadCachedInterface { sub } @@ -260,6 +265,9 @@ class SubscriptionModer(val subscriptionId: Int) : Moder() { return config.get(key) } + val simSlotIndex: Int + get() = this.loadCachedInterface { sub }.getSlotIndex(subscriptionId) + val isVoLteConfigEnabled: Boolean get() = this.getBooleanValue(CarrierConfigManager.KEY_CARRIER_VOLTE_AVAILABLE_BOOL) diff --git a/app/src/main/java/dev/bluehouse/enablevolte/Utils.kt b/app/src/main/java/dev/bluehouse/enablevolte/Utils.kt index cee7991..359dd5d 100644 --- a/app/src/main/java/dev/bluehouse/enablevolte/Utils.kt +++ b/app/src/main/java/dev/bluehouse/enablevolte/Utils.kt @@ -33,7 +33,7 @@ fun checkShizukuPermission(code: Int): ShizukuStatus { } val SubscriptionInfo.uniqueName: String - get() = "${this.subscriptionId} - ${this.displayName}" + get() = "${this.displayName} (SIM ${this.simSlotIndex + 1})" fun getLatestAppVersion(handler: (String) -> Unit) { "https://api.github.com/repos/kyujin-cho/pixel-volte-patch/releases" diff --git a/app/src/main/java/dev/bluehouse/enablevolte/VoLTEConfigToggleQSTileService.kt b/app/src/main/java/dev/bluehouse/enablevolte/VoLTEConfigToggleQSTileService.kt new file mode 100644 index 0000000..ac333e6 --- /dev/null +++ b/app/src/main/java/dev/bluehouse/enablevolte/VoLTEConfigToggleQSTileService.kt @@ -0,0 +1,90 @@ +package dev.bluehouse.enablevolte + +import android.service.quicksettings.Tile +import android.service.quicksettings.TileService +import android.telephony.CarrierConfigManager +import org.lsposed.hiddenapibypass.HiddenApiBypass +import java.lang.IllegalStateException + +class SIM1VoLTEConfigToggleQSTileService : VoLTEConfigToggleQSTileService(0) +class SIM2VoLTEConfigToggleQSTileService : VoLTEConfigToggleQSTileService(1) + +open class VoLTEConfigToggleQSTileService(private val simSlotIndex: Int) : TileService() { + private val TAG = "SIM${simSlotIndex}VoLTEConfigToggleQSTileService" + + init { + HiddenApiBypass.addHiddenApiExemptions("L") + HiddenApiBypass.addHiddenApiExemptions("I") + } + + private val moder: SubscriptionModer? get() { + val carrierModer = CarrierModer(this.applicationContext) + + try { + if (checkShizukuPermission(0) == ShizukuStatus.GRANTED && carrierModer.deviceSupportsIMS) { + carrierModer.subscriptions + val sub = carrierModer.getActiveSubscriptionInfoForSimSlotIndex(this.simSlotIndex) + ?: return null + return SubscriptionModer(sub.subscriptionId) + } + } catch (_: IllegalStateException) {} + return null + } + + private val volteEnabled: Boolean? get() { + /* + * true: VoLTE enabled + * false: VoLTE disabled + * null: cannot determine status (Shizuku not running or permission not granted, SIM slot not active, ...) + */ + val moder = this.moder ?: return null + try { + return moder.isVoLteConfigEnabled + } catch (_: IllegalStateException) {} + return null + } + + override fun onTileAdded() { + super.onTileAdded() + if (this.volteEnabled == null) { + qsTile.state = Tile.STATE_UNAVAILABLE + } + } + + override fun onStartListening() { + super.onStartListening() + qsTile.state = when (this.volteEnabled) { + true -> Tile.STATE_ACTIVE + false -> Tile.STATE_INACTIVE + null -> Tile.STATE_UNAVAILABLE + } + qsTile.subtitle = getString( + when (this.volteEnabled) { + true -> R.string.enabled + false -> R.string.disabled + null -> R.string.unknown + }, + ) + qsTile.updateTile() + } + + private fun toggleVoLTEStatus() { + val moder = this.moder ?: return + val volteEnabled = this.volteEnabled ?: return + moder.updateCarrierConfig(CarrierConfigManager.KEY_CARRIER_VOLTE_AVAILABLE_BOOL, !volteEnabled) + moder.restartIMSRegistration() + qsTile.state = if (volteEnabled) Tile.STATE_INACTIVE else Tile.STATE_ACTIVE + qsTile.subtitle = getString(if (volteEnabled) R.string.disabled else R.string.enabled) + qsTile.updateTile() + } + + // Called when the user taps on your tile in an active or inactive state. + override fun onClick() { + super.onClick() + if (isLocked) { + unlockAndRun { toggleVoLTEStatus() } + } else { + toggleVoLTEStatus() + } + } +} diff --git a/app/src/main/java/dev/bluehouse/enablevolte/pages/Config.kt b/app/src/main/java/dev/bluehouse/enablevolte/pages/Config.kt index ce3ae1e..baed722 100644 --- a/app/src/main/java/dev/bluehouse/enablevolte/pages/Config.kt +++ b/app/src/main/java/dev/bluehouse/enablevolte/pages/Config.kt @@ -1,6 +1,10 @@ package dev.bluehouse.enablevolte.pages +import android.app.StatusBarManager +import android.content.ComponentName +import android.graphics.drawable.Icon import android.os.Build +import android.os.Build.VERSION import android.telephony.CarrierConfigManager import android.util.Log import android.widget.Toast @@ -71,6 +75,8 @@ fun Config(navController: NavController, subId: Int) { var reversedConfigurableItems by rememberSaveable { mutableStateOf>(mapOf()) } var loading by rememberSaveable { mutableStateOf(true) } val scope = rememberCoroutineScope() + val simSlotIndex = moder.simSlotIndex + val statusBarManager: StatusBarManager = context.getSystemService(StatusBarManager::class.java) fun loadFlags() { Log.d(TAG, "loadFlags") @@ -337,6 +343,40 @@ fun Config(navController: NavController, subId: Int) { } } + if (VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + HeaderText(text = stringResource(R.string.qstile)) + ClickablePropertyView( + label = stringResource(R.string.add_status_tile), + value = "", + ) { + statusBarManager.requestAddTileService( + ComponentName( + context, + // TODO: what happens if someone tries to use this feature from a triple(or even dual)-SIM phone? + Class.forName("dev.bluehouse.enablevolte.SIM${simSlotIndex + 1}IMSStatusQSTileService"), + ), + context.getString(R.string.qs_status_tile_title, (simSlotIndex + 1).toString()), + Icon.createWithResource(context, R.drawable.ic_launcher_foreground), + {}, + {}, + ) + } + ClickablePropertyView( + label = stringResource(R.string.add_toggle_tile), + value = "", + ) { + statusBarManager.requestAddTileService( + ComponentName( + context, + Class.forName("dev.bluehouse.enablevolte.SIM${simSlotIndex + 1}VoLTEConfigToggleQSTileService"), + ), + context.getString(R.string.qs_toggle_tile_title, (simSlotIndex + 1).toString()), + Icon.createWithResource(context, R.drawable.ic_launcher_foreground), + {}, + {}, + ) + } + } HeaderText(text = stringResource(R.string.miscellaneous)) ClickablePropertyView( label = stringResource(R.string.reset_all_settings), diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 8df022e..6f358a3 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -33,6 +33,8 @@ 已注册 未注册 + Enabled + Disabled 有新版本 %1$s 可用! 启用/禁用功能 显示设置 @@ -67,6 +69,15 @@ 已加载 %1$s 共 %2$s 更改值 搜索 + Quick Settings Tile + IMS Status (SIM %1$s) + IMS Status (SIM 1) + IMS Status (SIM 2) + VoLTE Config (SIM %1$s) + VoLTE Config (SIM 1) + VoLTE Config (SIM 2) + Add IMS status display tile + Add VoLTE config toggle tile SIM 配置 配置转储查看器 \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 7b9938d..1c90b69 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -32,6 +32,8 @@ Registered Unregistered + Enabled + Disabled Newer version %1$s available! Enable/Disable Feature Cosmetic Toggles @@ -66,6 +68,15 @@ Loaded %1$s of %2$s Edit Value Search + Quick Settings Tile + IMS Status (SIM %1$s) + IMS Status (SIM 1) + IMS Status (SIM 2) + VoLTE Config (SIM %1$s) + VoLTE Config (SIM 1) + VoLTE Config (SIM 2) + Add IMS status display tile + Add VoLTE config toggle tile SIM Config Config Dump Viewer