Loading src/com/android/settings/applications/manageapplications/CloneBackend.java +5 −1 Original line number Diff line number Diff line Loading @@ -90,7 +90,7 @@ public class CloneBackend { * @param packageName * @return error/success code */ int installCloneApp(String packageName) { public int installCloneApp(String packageName) { String userName = "cloneUser"; UserHandle cloneUserHandle = null; boolean newlyCreated = false; Loading Loading @@ -160,4 +160,8 @@ public class CloneBackend { } return SUCCESS; } public int getCloneUserId() { return mCloneUserId; } } src/com/android/settings/applications/manageapplications/ManageApplications.java +20 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package com.android.settings.applications.manageapplications; import static android.util.FeatureFlagUtils.SETTINGS_ENABLE_SPA; import static androidx.recyclerview.widget.RecyclerView.SCROLL_STATE_DRAGGING; import static androidx.recyclerview.widget.RecyclerView.SCROLL_STATE_IDLE; Loading Loading @@ -47,6 +49,7 @@ import android.content.Context; import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.PackageItemInfo; import android.content.pm.UserInfo; import android.content.res.Configuration; import android.graphics.drawable.Drawable; import android.net.Uri; Loading @@ -64,6 +67,7 @@ import android.provider.DeviceConfig; import android.provider.Settings; import android.text.TextUtils; import android.util.ArraySet; import android.util.FeatureFlagUtils; import android.util.IconDrawableFactory; import android.util.Log; import android.view.LayoutInflater; Loading Loading @@ -148,6 +152,8 @@ import com.android.settings.notification.ConfigureNotificationSettings; import com.android.settings.notification.NotificationBackend; import com.android.settings.notification.app.AppNotificationSettings; import com.android.settings.spa.SpaActivity; import com.android.settings.spa.app.appinfo.AppInfoSettingsProvider; import com.android.settings.spa.app.appinfo.CloneAppInfoSettingsProvider; import com.android.settings.widget.LoadingViewController; import com.android.settings.wifi.AppStateChangeWifiStateBridge; import com.android.settings.wifi.ChangeWifiStateDetails; Loading Loading @@ -707,6 +713,20 @@ public class ManageApplications extends InstrumentedFragment startAppInfoFragment(LongBackgroundTasksDetails.class, R.string.long_background_tasks_label); break; case LIST_TYPE_CLONED_APPS: if (!FeatureFlagUtils.isEnabled(getContext(), SETTINGS_ENABLE_SPA)) { return; } int userId = UserHandle.getUserId(mCurrentUid); UserInfo userInfo = mUserManager.getUserInfo(userId); if (userInfo != null && !userInfo.isCloneProfile()) { SpaActivity.startSpaActivity(getContext(), CloneAppInfoSettingsProvider.INSTANCE .getRoute(mCurrentPkgName, userId)); } else { SpaActivity.startSpaActivity(getContext(), AppInfoSettingsProvider.INSTANCE .getRoute(mCurrentPkgName, userId)); } break; // TODO: Figure out if there is a way where we can spin up the profile's settings // process ahead of time, to avoid a long load of data when user clicks on a managed // app. Maybe when they load the list of apps that contains managed profile apps. Loading src/com/android/settings/spa/SettingsSpaEnvironment.kt +2 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import android.content.Context import com.android.settings.spa.app.AllAppListPageProvider import com.android.settings.spa.app.AppsMainPageProvider import com.android.settings.spa.app.appinfo.AppInfoSettingsProvider import com.android.settings.spa.app.appinfo.CloneAppInfoSettingsProvider import com.android.settings.spa.app.backgroundinstall.BackgroundInstalledAppsPageProvider import com.android.settings.spa.app.specialaccess.AlarmsAndRemindersAppListProvider import com.android.settings.spa.app.specialaccess.AllFilesAccessAppListProvider Loading Loading @@ -72,6 +73,7 @@ open class SettingsSpaEnvironment(context: Context) : SpaEnvironment(context) { AppLanguagesPageProvider, UsageStatsPageProvider, BackgroundInstalledAppsPageProvider, CloneAppInfoSettingsProvider, ) + togglePermissionAppListTemplate.createPageProviders(), rootPages = listOf( SettingsPage.create(HomePageProvider.name), Loading src/com/android/settings/spa/app/appinfo/AppCreateButton.kt 0 → 100644 +74 −0 Original line number Diff line number Diff line /* * Copyright (C) 2022 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.spa.app.appinfo import android.app.Activity import android.app.settings.SettingsEnums import android.content.pm.ApplicationInfo import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.Add import androidx.compose.runtime.Composable import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.rememberCoroutineScope import com.android.settings.R import com.android.settings.applications.manageapplications.CloneBackend import com.android.settings.overlay.FeatureFactory import com.android.settings.spa.app.appinfo.AppInfoSettingsProvider.getRoute import com.android.settingslib.spa.framework.compose.LocalNavController import com.android.settingslib.spa.widget.button.ActionButton import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext class AppCreateButton(packageInfoPresenter: PackageInfoPresenter) { private val context = packageInfoPresenter.context val enabledState = mutableStateOf(true) @Composable fun getActionButton(app: ApplicationInfo): ActionButton? { return createButton(app) } @Composable private fun createButton(app: ApplicationInfo): ActionButton { val coroutineScope = rememberCoroutineScope() val navController = LocalNavController.current return ActionButton( text = context.getString(R.string.create), imageVector = Icons.Outlined.Add, enabled = enabledState.value, ) { val cloneBackend = CloneBackend.getInstance(context) FeatureFactory.getFactory(context).metricsFeatureProvider.action(context, SettingsEnums.ACTION_CREATE_CLONE_APP) coroutineScope.launch { enabledState.value = false val result = installCloneApp(app, cloneBackend) if (result == CloneBackend.SUCCESS) { navController.navigate(getRoute(app.packageName, cloneBackend.cloneUserId)) } else { enabledState.value = true } } } } private suspend fun installCloneApp(app: ApplicationInfo, cloneBackend: CloneBackend): Int = withContext(Dispatchers.IO) { cloneBackend.installCloneApp(app.packageName) } } No newline at end of file src/com/android/settings/spa/app/appinfo/AppUninstallButton.kt +10 −1 Original line number Diff line number Diff line Loading @@ -18,6 +18,8 @@ package com.android.settings.spa.app.appinfo import android.content.om.OverlayManager import android.content.pm.ApplicationInfo import android.os.UserHandle import android.os.UserManager import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.Delete import com.android.settings.R Loading @@ -30,6 +32,7 @@ class AppUninstallButton(private val packageInfoPresenter: PackageInfoPresenter) private val context = packageInfoPresenter.context private val appButtonRepository = AppButtonRepository(context) private val overlayManager = context.getSystemService(OverlayManager::class.java)!! private val userManager = context.getSystemService(UserManager::class.java)!! fun getActionButton(app: ApplicationInfo): ActionButton? { if (app.isSystemApp || app.isInstantApp) return null Loading Loading @@ -80,7 +83,8 @@ class AppUninstallButton(private val packageInfoPresenter: PackageInfoPresenter) overlayManager.getOverlayInfo(packageName, userHandle)?.isEnabled == true private fun uninstallButton(app: ApplicationInfo, enabled: Boolean) = ActionButton( text = context.getString(R.string.uninstall_text), text = if (isCloneApp(app)) context.getString(R.string.delete) else context.getString(R.string.uninstall_text), imageVector = Icons.Outlined.Delete, enabled = enabled, ) { onUninstallClicked(app) } Loading @@ -89,4 +93,9 @@ class AppUninstallButton(private val packageInfoPresenter: PackageInfoPresenter) if (appButtonRepository.isUninstallBlockedByAdmin(app)) return packageInfoPresenter.startUninstallActivity() } private fun isCloneApp(app: ApplicationInfo): Boolean { val userInfo = userManager.getUserInfo(UserHandle.getUserId(app.uid)) return userInfo != null && userInfo.isCloneProfile } } Loading
src/com/android/settings/applications/manageapplications/CloneBackend.java +5 −1 Original line number Diff line number Diff line Loading @@ -90,7 +90,7 @@ public class CloneBackend { * @param packageName * @return error/success code */ int installCloneApp(String packageName) { public int installCloneApp(String packageName) { String userName = "cloneUser"; UserHandle cloneUserHandle = null; boolean newlyCreated = false; Loading Loading @@ -160,4 +160,8 @@ public class CloneBackend { } return SUCCESS; } public int getCloneUserId() { return mCloneUserId; } }
src/com/android/settings/applications/manageapplications/ManageApplications.java +20 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package com.android.settings.applications.manageapplications; import static android.util.FeatureFlagUtils.SETTINGS_ENABLE_SPA; import static androidx.recyclerview.widget.RecyclerView.SCROLL_STATE_DRAGGING; import static androidx.recyclerview.widget.RecyclerView.SCROLL_STATE_IDLE; Loading Loading @@ -47,6 +49,7 @@ import android.content.Context; import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.PackageItemInfo; import android.content.pm.UserInfo; import android.content.res.Configuration; import android.graphics.drawable.Drawable; import android.net.Uri; Loading @@ -64,6 +67,7 @@ import android.provider.DeviceConfig; import android.provider.Settings; import android.text.TextUtils; import android.util.ArraySet; import android.util.FeatureFlagUtils; import android.util.IconDrawableFactory; import android.util.Log; import android.view.LayoutInflater; Loading Loading @@ -148,6 +152,8 @@ import com.android.settings.notification.ConfigureNotificationSettings; import com.android.settings.notification.NotificationBackend; import com.android.settings.notification.app.AppNotificationSettings; import com.android.settings.spa.SpaActivity; import com.android.settings.spa.app.appinfo.AppInfoSettingsProvider; import com.android.settings.spa.app.appinfo.CloneAppInfoSettingsProvider; import com.android.settings.widget.LoadingViewController; import com.android.settings.wifi.AppStateChangeWifiStateBridge; import com.android.settings.wifi.ChangeWifiStateDetails; Loading Loading @@ -707,6 +713,20 @@ public class ManageApplications extends InstrumentedFragment startAppInfoFragment(LongBackgroundTasksDetails.class, R.string.long_background_tasks_label); break; case LIST_TYPE_CLONED_APPS: if (!FeatureFlagUtils.isEnabled(getContext(), SETTINGS_ENABLE_SPA)) { return; } int userId = UserHandle.getUserId(mCurrentUid); UserInfo userInfo = mUserManager.getUserInfo(userId); if (userInfo != null && !userInfo.isCloneProfile()) { SpaActivity.startSpaActivity(getContext(), CloneAppInfoSettingsProvider.INSTANCE .getRoute(mCurrentPkgName, userId)); } else { SpaActivity.startSpaActivity(getContext(), AppInfoSettingsProvider.INSTANCE .getRoute(mCurrentPkgName, userId)); } break; // TODO: Figure out if there is a way where we can spin up the profile's settings // process ahead of time, to avoid a long load of data when user clicks on a managed // app. Maybe when they load the list of apps that contains managed profile apps. Loading
src/com/android/settings/spa/SettingsSpaEnvironment.kt +2 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import android.content.Context import com.android.settings.spa.app.AllAppListPageProvider import com.android.settings.spa.app.AppsMainPageProvider import com.android.settings.spa.app.appinfo.AppInfoSettingsProvider import com.android.settings.spa.app.appinfo.CloneAppInfoSettingsProvider import com.android.settings.spa.app.backgroundinstall.BackgroundInstalledAppsPageProvider import com.android.settings.spa.app.specialaccess.AlarmsAndRemindersAppListProvider import com.android.settings.spa.app.specialaccess.AllFilesAccessAppListProvider Loading Loading @@ -72,6 +73,7 @@ open class SettingsSpaEnvironment(context: Context) : SpaEnvironment(context) { AppLanguagesPageProvider, UsageStatsPageProvider, BackgroundInstalledAppsPageProvider, CloneAppInfoSettingsProvider, ) + togglePermissionAppListTemplate.createPageProviders(), rootPages = listOf( SettingsPage.create(HomePageProvider.name), Loading
src/com/android/settings/spa/app/appinfo/AppCreateButton.kt 0 → 100644 +74 −0 Original line number Diff line number Diff line /* * Copyright (C) 2022 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.spa.app.appinfo import android.app.Activity import android.app.settings.SettingsEnums import android.content.pm.ApplicationInfo import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.Add import androidx.compose.runtime.Composable import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.rememberCoroutineScope import com.android.settings.R import com.android.settings.applications.manageapplications.CloneBackend import com.android.settings.overlay.FeatureFactory import com.android.settings.spa.app.appinfo.AppInfoSettingsProvider.getRoute import com.android.settingslib.spa.framework.compose.LocalNavController import com.android.settingslib.spa.widget.button.ActionButton import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext class AppCreateButton(packageInfoPresenter: PackageInfoPresenter) { private val context = packageInfoPresenter.context val enabledState = mutableStateOf(true) @Composable fun getActionButton(app: ApplicationInfo): ActionButton? { return createButton(app) } @Composable private fun createButton(app: ApplicationInfo): ActionButton { val coroutineScope = rememberCoroutineScope() val navController = LocalNavController.current return ActionButton( text = context.getString(R.string.create), imageVector = Icons.Outlined.Add, enabled = enabledState.value, ) { val cloneBackend = CloneBackend.getInstance(context) FeatureFactory.getFactory(context).metricsFeatureProvider.action(context, SettingsEnums.ACTION_CREATE_CLONE_APP) coroutineScope.launch { enabledState.value = false val result = installCloneApp(app, cloneBackend) if (result == CloneBackend.SUCCESS) { navController.navigate(getRoute(app.packageName, cloneBackend.cloneUserId)) } else { enabledState.value = true } } } } private suspend fun installCloneApp(app: ApplicationInfo, cloneBackend: CloneBackend): Int = withContext(Dispatchers.IO) { cloneBackend.installCloneApp(app.packageName) } } No newline at end of file
src/com/android/settings/spa/app/appinfo/AppUninstallButton.kt +10 −1 Original line number Diff line number Diff line Loading @@ -18,6 +18,8 @@ package com.android.settings.spa.app.appinfo import android.content.om.OverlayManager import android.content.pm.ApplicationInfo import android.os.UserHandle import android.os.UserManager import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.Delete import com.android.settings.R Loading @@ -30,6 +32,7 @@ class AppUninstallButton(private val packageInfoPresenter: PackageInfoPresenter) private val context = packageInfoPresenter.context private val appButtonRepository = AppButtonRepository(context) private val overlayManager = context.getSystemService(OverlayManager::class.java)!! private val userManager = context.getSystemService(UserManager::class.java)!! fun getActionButton(app: ApplicationInfo): ActionButton? { if (app.isSystemApp || app.isInstantApp) return null Loading Loading @@ -80,7 +83,8 @@ class AppUninstallButton(private val packageInfoPresenter: PackageInfoPresenter) overlayManager.getOverlayInfo(packageName, userHandle)?.isEnabled == true private fun uninstallButton(app: ApplicationInfo, enabled: Boolean) = ActionButton( text = context.getString(R.string.uninstall_text), text = if (isCloneApp(app)) context.getString(R.string.delete) else context.getString(R.string.uninstall_text), imageVector = Icons.Outlined.Delete, enabled = enabled, ) { onUninstallClicked(app) } Loading @@ -89,4 +93,9 @@ class AppUninstallButton(private val packageInfoPresenter: PackageInfoPresenter) if (appButtonRepository.isUninstallBlockedByAdmin(app)) return packageInfoPresenter.startUninstallActivity() } private fun isCloneApp(app: ApplicationInfo): Boolean { val userInfo = userManager.getUserInfo(UserHandle.getUserId(app.uid)) return userInfo != null && userInfo.isCloneProfile } }