feat: support provisioning (#187)

This commit is contained in:
BinTianqi
2026-02-24 19:27:24 +08:00
parent 8c4a4c68ca
commit ed330a2b63
6 changed files with 188 additions and 0 deletions

View File

@@ -94,6 +94,20 @@
<action android:name="android.app.action.CHECK_POLICY_COMPLIANCE" /> <action android:name="android.app.action.CHECK_POLICY_COMPLIANCE" />
</intent-filter> </intent-filter>
</activity> </activity>
<activity
android:name=".activity.ProvisioningActivity"
android:exported="true">
<intent-filter>
<action android:name="android.app.action.GET_PROVISIONING_MODE" />
</intent-filter>
</activity>
<activity
android:name=".activity.ProvisioningPolicyComplianceActivity"
android:exported="true">
<intent-filter>
<action android:name="android.app.action.ADMIN_POLICY_COMPLIANCE" />
</intent-filter>
</activity>
<receiver <receiver
android:name=".Receiver" android:name=".Receiver"

View File

@@ -0,0 +1,32 @@
package com.bintianqi.owndroid.activity
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.viewModels
import androidx.annotation.RequiresApi
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import com.bintianqi.owndroid.MyApplication
import com.bintianqi.owndroid.feature.provisioning.ProvisioningScreen
import com.bintianqi.owndroid.feature.provisioning.ProvisioningViewModel
import com.bintianqi.owndroid.ui.theme.OwnDroidTheme
@RequiresApi(29)
class ProvisioningActivity: ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val myApp = application as MyApplication
val vm by viewModels<ProvisioningViewModel>()
vm.params = vm.getParamsFromIntent(intent)
setContent {
val theme by myApp.container.themeState.collectAsState()
OwnDroidTheme(theme) {
ProvisioningScreen(vm.params) {
setResult(RESULT_OK, vm.buildResultIntent(it))
finish()
}
}
}
}
}

View File

@@ -0,0 +1,15 @@
package com.bintianqi.owndroid.activity
import android.os.Bundle
import androidx.activity.ComponentActivity
import com.bintianqi.owndroid.R
import com.bintianqi.owndroid.utils.popToast
class ProvisioningPolicyComplianceActivity: ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setResult(RESULT_OK)
popToast(R.string.app_name)
finish()
}
}

View File

@@ -0,0 +1,9 @@
package com.bintianqi.owndroid.feature.provisioning
class ProvisioningParams(
val imei: String?, val serial: String?, val modes: List<Int>
)
class ProvisioningOptions(
val skipEncryption: Boolean
)

View File

@@ -0,0 +1,87 @@
package com.bintianqi.owndroid.feature.provisioning
import android.app.admin.DevicePolicyManager
import androidx.annotation.RequiresApi
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Button
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.bintianqi.owndroid.R
import com.bintianqi.owndroid.ui.FullWidthCheckBoxItem
import com.bintianqi.owndroid.utils.BottomPadding
import com.bintianqi.owndroid.utils.HorizontalPadding
import com.bintianqi.owndroid.utils.adaptiveInsets
@RequiresApi(29)
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun ProvisioningScreen(params: ProvisioningParams, callback: (ProvisioningOptions) -> Unit) {
Scaffold(
topBar = {
TopAppBar(
{ Text(stringResource(R.string.app_name)) }
)
},
contentWindowInsets = adaptiveInsets()
) { paddingValues ->
Column(
Modifier
.padding(paddingValues)
.verticalScroll(rememberScrollState())
) {
Column(Modifier.padding(horizontal = HorizontalPadding)) {
if (!params.imei.isNullOrEmpty()) {
Text("IMEI", style = MaterialTheme.typography.titleMedium)
Text(params.imei, Modifier.padding(bottom = 8.dp))
}
if (!params.serial.isNullOrEmpty()) {
Text(
stringResource(R.string.serial_number),
style = MaterialTheme.typography.titleMedium
)
Text(params.serial, Modifier.padding(bottom = 8.dp))
}
}
if (DevicePolicyManager.PROVISIONING_MODE_FULLY_MANAGED_DEVICE in params.modes) {
Spacer(Modifier.height(10.dp))
var skipEncryption by remember { mutableStateOf(false) }
FullWidthCheckBoxItem(R.string.skip_encryption, skipEncryption) {
skipEncryption = it
}
Button(
{
callback(ProvisioningOptions(skipEncryption))
},
Modifier
.fillMaxWidth()
.padding(HorizontalPadding, 4.dp)
) {
Text(stringResource(R.string.continue_str))
}
} else {
Text(
stringResource(R.string.unsupported),
style = MaterialTheme.typography.titleLarge
)
}
Spacer(Modifier.height(BottomPadding))
}
}
}

View File

@@ -0,0 +1,31 @@
package com.bintianqi.owndroid.feature.provisioning
import android.app.admin.DevicePolicyManager
import android.content.Intent
import android.os.Build
import androidx.annotation.RequiresApi
import androidx.lifecycle.ViewModel
@RequiresApi(29)
class ProvisioningViewModel : ViewModel() {
lateinit var params: ProvisioningParams
fun getParamsFromIntent(intent: Intent): ProvisioningParams {
val modes = if (Build.VERSION.SDK_INT >= 31) intent.getIntegerArrayListExtra(
DevicePolicyManager.EXTRA_PROVISIONING_ALLOWED_PROVISIONING_MODES
) else null
return ProvisioningParams(
intent.getStringExtra(DevicePolicyManager.EXTRA_PROVISIONING_IMEI),
intent.getStringExtra(DevicePolicyManager.EXTRA_PROVISIONING_SERIAL_NUMBER),
modes ?: listOf(DevicePolicyManager.PROVISIONING_MODE_FULLY_MANAGED_DEVICE)
)
}
fun buildResultIntent(options: ProvisioningOptions): Intent {
val intent = Intent()
intent.putExtra(
DevicePolicyManager.EXTRA_PROVISIONING_SKIP_ENCRYPTION, options.skipEncryption
)
return intent
}
}