Loading AndroidManifest.xml +6 −0 Original line number Diff line number Diff line Loading @@ -2811,6 +2811,12 @@ </intent-filter> </activity> <activity android:enableOnBackInvokedCallback="true" android:name=".supervision.SupervisionDashboardLoadingActivity" android:label="@string/supervision_settings_title" android:exported="false"/> <activity android:name=".supervision.SupervisionDashboardActivity" android:label="@string/supervision_settings_title" Loading res/layout/supervision_dashboard_loading_screen.xml 0 → 100644 +34 −0 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?><!-- ~ Copyright (C) 2025 The Android Open Source Project ~ ~ Licensed under the Apache License, Version 2.0 (the "License"); ~ you may not use this file except in compliance with the License. ~ You may obtain a copy of the License at ~ ~ http://www.apache.org/licenses/LICENSE-2.0 ~ ~ Unless required by applicable law or agreed to in writing, software ~ distributed under the License is distributed on an "AS IS" BASIS, ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ~ See the License for the specific language governing permissions and ~ limitations under the License. --> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true" android:layout_gravity="center_horizontal"> <com.google.android.material.progressindicator.LinearProgressIndicator android:theme="@style/Theme.Material3.DynamicColors.DayNight" android:id="@+id/linearProgressIndicator" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="4dp" android:layout_marginStart="18dp" android:layout_marginEnd="18dp" android:indeterminate="true" app:trackThickness="@dimen/settingslib_expressive_space_extrasmall4" /> </RelativeLayout> src/com/android/settings/supervision/SupervisionDashboardActivity.kt +7 −3 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.settings.supervision import android.content.Intent import android.os.Bundle import com.android.settings.CatalystSettingsActivity Loading @@ -29,10 +30,13 @@ class SupervisionDashboardActivity : SupervisionDashboardScreen.KEY, SupervisionDashboardFragment::class.java, ) { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // TODO(b/418837620) Show a loading screen if supervision app with required component is not // present. if (!hasNecessarySupervisionComponent()) { val loadingActivity = Intent(this, SupervisionDashboardLoadingActivity::class.java) startActivity(loadingActivity) finish() } } } src/com/android/settings/supervision/SupervisionDashboardLoadingActivity.kt 0 → 100644 +101 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.settings.supervision import android.content.Intent import android.content.pm.PackageManager import android.os.Bundle import android.view.MenuItem import androidx.fragment.app.FragmentActivity import androidx.lifecycle.lifecycleScope import com.android.settings.R import com.android.settings.core.CategoryMixin import com.android.settings.overlay.FeatureFactory.Companion.featureFactory import com.android.settingslib.collapsingtoolbar.R.drawable.settingslib_expressive_icon_back as EXPRESSIVE_BACK_ICON import com.android.settingslib.drawer.CategoryKey.CATEGORY_SUPERVISION import com.android.settingslib.widget.SettingsThemeHelper import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay import kotlinx.coroutines.launch class SupervisionDashboardLoadingActivity : FragmentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // Get the supervision package name from the system config val supervisionPackage = resources.getString(com.android.internal.R.string.config_systemSupervision) if (supervisionPackage == null) { finish() return } setContentView(R.layout.supervision_dashboard_loading_screen) // Enable supervision app lifecycleScope.launch(Dispatchers.Default) { packageManager.setApplicationEnabledSetting( supervisionPackage, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0, ) // Update category after enabling supervision app CategoryMixin(this@SupervisionDashboardLoadingActivity).updateCategories() val dashboardFeatureProvider = featureFactory.dashboardFeatureProvider while ( !hasNecessarySupervisionComponent(supervisionPackage) || dashboardFeatureProvider.getTilesForCategory(CATEGORY_SUPERVISION) == null ) { delay(100) // Check every 100 ms (adjust as needed) } lifecycleScope.launch(Dispatchers.Main) { val dashboardActivity = Intent( this@SupervisionDashboardLoadingActivity, SupervisionDashboardActivity::class.java, ) startActivity(dashboardActivity) finish() } } } override fun onResume() { super.onResume() val actionBar = getActionBar() if (actionBar != null) { actionBar.elevation = 0f actionBar.setDisplayHomeAsUpEnabled(true) if (SettingsThemeHelper.isExpressiveTheme(this)) { actionBar.setHomeAsUpIndicator(EXPRESSIVE_BACK_ICON) } } } override fun onOptionsItemSelected(item: MenuItem): Boolean { if (item.itemId == android.R.id.home) { finish() return true } return super.onOptionsItemSelected(item) } } src/com/android/settings/supervision/SupervisionHelper.kt +11 −0 Original line number Diff line number Diff line Loading @@ -18,10 +18,12 @@ package com.android.settings.supervision import android.app.KeyguardManager import android.app.role.RoleManager import android.content.Context import android.content.Intent import android.os.UserHandle import android.os.UserManager import android.os.UserManager.USER_TYPE_PROFILE_SUPERVISING import android.util.Log import com.android.settings.supervision.ipc.SupervisionMessengerClient.Companion.SUPERVISION_MESSENGER_SERVICE_BIND_ACTION import com.android.settingslib.supervision.SupervisionLog.TAG val Context.isSupervisingCredentialSet: Boolean Loading Loading @@ -53,3 +55,12 @@ val Context.supervisionPackageName: String? // supervision role is exclusive, only one app may hold this role in a user return roleHolders.firstOrNull() } fun Context.hasNecessarySupervisionComponent() = hasNecessarySupervisionComponent(supervisionPackageName) fun Context.hasNecessarySupervisionComponent(packageName: String?): Boolean { if (packageName == null) return false val intent = Intent(SUPERVISION_MESSENGER_SERVICE_BIND_ACTION).setPackage(packageName) return packageManager?.queryIntentServices(intent, 0)?.isNotEmpty() == true } Loading
AndroidManifest.xml +6 −0 Original line number Diff line number Diff line Loading @@ -2811,6 +2811,12 @@ </intent-filter> </activity> <activity android:enableOnBackInvokedCallback="true" android:name=".supervision.SupervisionDashboardLoadingActivity" android:label="@string/supervision_settings_title" android:exported="false"/> <activity android:name=".supervision.SupervisionDashboardActivity" android:label="@string/supervision_settings_title" Loading
res/layout/supervision_dashboard_loading_screen.xml 0 → 100644 +34 −0 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?><!-- ~ Copyright (C) 2025 The Android Open Source Project ~ ~ Licensed under the Apache License, Version 2.0 (the "License"); ~ you may not use this file except in compliance with the License. ~ You may obtain a copy of the License at ~ ~ http://www.apache.org/licenses/LICENSE-2.0 ~ ~ Unless required by applicable law or agreed to in writing, software ~ distributed under the License is distributed on an "AS IS" BASIS, ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ~ See the License for the specific language governing permissions and ~ limitations under the License. --> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true" android:layout_gravity="center_horizontal"> <com.google.android.material.progressindicator.LinearProgressIndicator android:theme="@style/Theme.Material3.DynamicColors.DayNight" android:id="@+id/linearProgressIndicator" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="4dp" android:layout_marginStart="18dp" android:layout_marginEnd="18dp" android:indeterminate="true" app:trackThickness="@dimen/settingslib_expressive_space_extrasmall4" /> </RelativeLayout>
src/com/android/settings/supervision/SupervisionDashboardActivity.kt +7 −3 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.settings.supervision import android.content.Intent import android.os.Bundle import com.android.settings.CatalystSettingsActivity Loading @@ -29,10 +30,13 @@ class SupervisionDashboardActivity : SupervisionDashboardScreen.KEY, SupervisionDashboardFragment::class.java, ) { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // TODO(b/418837620) Show a loading screen if supervision app with required component is not // present. if (!hasNecessarySupervisionComponent()) { val loadingActivity = Intent(this, SupervisionDashboardLoadingActivity::class.java) startActivity(loadingActivity) finish() } } }
src/com/android/settings/supervision/SupervisionDashboardLoadingActivity.kt 0 → 100644 +101 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.settings.supervision import android.content.Intent import android.content.pm.PackageManager import android.os.Bundle import android.view.MenuItem import androidx.fragment.app.FragmentActivity import androidx.lifecycle.lifecycleScope import com.android.settings.R import com.android.settings.core.CategoryMixin import com.android.settings.overlay.FeatureFactory.Companion.featureFactory import com.android.settingslib.collapsingtoolbar.R.drawable.settingslib_expressive_icon_back as EXPRESSIVE_BACK_ICON import com.android.settingslib.drawer.CategoryKey.CATEGORY_SUPERVISION import com.android.settingslib.widget.SettingsThemeHelper import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay import kotlinx.coroutines.launch class SupervisionDashboardLoadingActivity : FragmentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // Get the supervision package name from the system config val supervisionPackage = resources.getString(com.android.internal.R.string.config_systemSupervision) if (supervisionPackage == null) { finish() return } setContentView(R.layout.supervision_dashboard_loading_screen) // Enable supervision app lifecycleScope.launch(Dispatchers.Default) { packageManager.setApplicationEnabledSetting( supervisionPackage, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0, ) // Update category after enabling supervision app CategoryMixin(this@SupervisionDashboardLoadingActivity).updateCategories() val dashboardFeatureProvider = featureFactory.dashboardFeatureProvider while ( !hasNecessarySupervisionComponent(supervisionPackage) || dashboardFeatureProvider.getTilesForCategory(CATEGORY_SUPERVISION) == null ) { delay(100) // Check every 100 ms (adjust as needed) } lifecycleScope.launch(Dispatchers.Main) { val dashboardActivity = Intent( this@SupervisionDashboardLoadingActivity, SupervisionDashboardActivity::class.java, ) startActivity(dashboardActivity) finish() } } } override fun onResume() { super.onResume() val actionBar = getActionBar() if (actionBar != null) { actionBar.elevation = 0f actionBar.setDisplayHomeAsUpEnabled(true) if (SettingsThemeHelper.isExpressiveTheme(this)) { actionBar.setHomeAsUpIndicator(EXPRESSIVE_BACK_ICON) } } } override fun onOptionsItemSelected(item: MenuItem): Boolean { if (item.itemId == android.R.id.home) { finish() return true } return super.onOptionsItemSelected(item) } }
src/com/android/settings/supervision/SupervisionHelper.kt +11 −0 Original line number Diff line number Diff line Loading @@ -18,10 +18,12 @@ package com.android.settings.supervision import android.app.KeyguardManager import android.app.role.RoleManager import android.content.Context import android.content.Intent import android.os.UserHandle import android.os.UserManager import android.os.UserManager.USER_TYPE_PROFILE_SUPERVISING import android.util.Log import com.android.settings.supervision.ipc.SupervisionMessengerClient.Companion.SUPERVISION_MESSENGER_SERVICE_BIND_ACTION import com.android.settingslib.supervision.SupervisionLog.TAG val Context.isSupervisingCredentialSet: Boolean Loading Loading @@ -53,3 +55,12 @@ val Context.supervisionPackageName: String? // supervision role is exclusive, only one app may hold this role in a user return roleHolders.firstOrNull() } fun Context.hasNecessarySupervisionComponent() = hasNecessarySupervisionComponent(supervisionPackageName) fun Context.hasNecessarySupervisionComponent(packageName: String?): Boolean { if (packageName == null) return false val intent = Intent(SUPERVISION_MESSENGER_SERVICE_BIND_ACTION).setPackage(packageName) return packageManager?.queryIntentServices(intent, 0)?.isNotEmpty() == true }