Skip to content

mdm: define OnboardingFlow syspolicy on Android #648

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 9, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 10 additions & 5 deletions android/src/main/java/com/tailscale/ipn/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import androidx.navigation.navArgument
import com.tailscale.ipn.mdm.MDMSettings
import com.tailscale.ipn.mdm.ShowHide
import com.tailscale.ipn.ui.model.Ipn
import com.tailscale.ipn.ui.notifier.Notifier
import com.tailscale.ipn.ui.theme.AppTheme
Expand Down Expand Up @@ -123,6 +124,9 @@ class MainActivity : ComponentActivity() {
App.get()
vpnViewModel = ViewModelProvider(App.get()).get(VpnViewModel::class.java)

val rm = getSystemService(Context.RESTRICTIONS_SERVICE) as RestrictionsManager
MDMSettings.update(App.get(), rm)

// (jonathan) TODO: Force the app to be portrait on small screens until we have
// proper landscape layout support
if (!isLandscapeCapable()) {
Expand Down Expand Up @@ -290,9 +294,7 @@ class MainActivity : ComponentActivity() {
onNavigateHome = backTo("main"), backTo("userSwitcher"))
}
}

// Show the intro screen one time
if (!introScreenViewed()) {
if (shouldDisplayOnboarding()) {
navController.navigate("intro")
setIntroScreenViewed(true)
}
Expand Down Expand Up @@ -446,8 +448,11 @@ class MainActivity : ComponentActivity() {
startActivity(intent)
}

private fun introScreenViewed(): Boolean {
return getSharedPreferences("introScreen", Context.MODE_PRIVATE).getBoolean("seen", false)
private fun shouldDisplayOnboarding(): Boolean {
val onboardingFlowShowHide = MDMSettings.onboardingFlow.flow.value.value
val introSeen =
getSharedPreferences("introScreen", Context.MODE_PRIVATE).getBoolean("seen", false)
return (onboardingFlowShowHide == ShowHide.Show && !introSeen)
}

private fun setIntroScreenViewed(seen: Boolean) {
Expand Down
3 changes: 3 additions & 0 deletions android/src/main/java/com/tailscale/ipn/mdm/MDMSettings.kt
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,9 @@ object MDMSettings {
// Overrides the value provided by os.Hostname() in Go
val hostname = StringMDMSetting("Hostname", "Device Hostname")

// Allows admins to skip the get started intro screen
val onboardingFlow = ShowHideMDMSetting("OnboardingFlow", "Suppress the intro screen")

val allSettings by lazy {
MDMSettings::class
.declaredMemberProperties
Expand Down
2 changes: 2 additions & 0 deletions android/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,8 @@
<string name="run_as_exit_node_visibility">Run as exit node visibility</string>
<string name="defines_an_auth_key_that_will_be_used_for_login">Defines an auth key that will be used for login.</string>
<string name="auth_key">Auth Key</string>
<string name="skips_the_intro_page_shown_to_users_that_open_the_app_for_the_first_time">Skips the intro page shown to users that open the app for the first time</string>
<string name="onboarding_flow">Skip the Onboarding Flow</string>

<!-- Permissions Management -->
<string name="permissions">Permissions</string>
Expand Down
8 changes: 8 additions & 0 deletions android/src/main/res/xml/app_restrictions.xml
Original file line number Diff line number Diff line change
Expand Up @@ -134,4 +134,12 @@
android:key="Hostname"
android:restrictionType="string"
android:title="@string/hostname" />

<restriction
android:description="@string/skips_the_intro_page_shown_to_users_that_open_the_app_for_the_first_time"
android:entries="@array/show_hide_labels"
android:entryValues="@array/show_hide"
android:key="OnboardingFlow"
android:restrictionType="choice"
android:title="@string/onboarding_flow" />
</restrictions>