1 /* 2 * Copyright (C) 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License 15 */ 16 package com.android.tv.settings.device.apps 17 18 import android.app.Activity 19 import android.app.tvsettings.TvSettingsEnums 20 import android.content.Context 21 import android.os.Bundle 22 import android.provider.DeviceConfig 23 import android.text.TextUtils 24 import android.view.LayoutInflater 25 import android.view.View 26 import android.view.ViewGroup 27 import androidx.annotation.Keep 28 import androidx.lifecycle.Lifecycle 29 import androidx.lifecycle.lifecycleScope 30 import androidx.lifecycle.repeatOnLifecycle 31 import androidx.preference.Preference 32 import com.android.settingslib.core.AbstractPreferenceController 33 import com.android.tv.settings.PreferenceControllerFragment 34 import com.android.tv.settings.R 35 import com.android.tv.settings.library.util.LibUtils 36 import com.android.tv.settings.overlay.FlavorUtils 37 import com.android.tv.settings.util.InstrumentationUtils 38 import com.android.tv.settings.util.SliceUtilsKt 39 import com.android.tv.twopanelsettings.slices.SlicePreference 40 import kotlinx.coroutines.launch 41 42 /** 43 * Fragment for managing recent apps, and apps permissions. 44 */ 45 @Keep 46 class AppsFragment : PreferenceControllerFragment() { 47 onCreateViewnull48 override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, 49 savedInstanceState: Bundle?): View { 50 findPreference<Preference>(KEY_PERMISSIONS)?.apply { 51 isVisible = TextUtils.isEmpty( 52 arguments?.getString(AppsActivity.EXTRA_VOLUME_UUID)) 53 onPreferenceClickListener = Preference.OnPreferenceClickListener { 54 InstrumentationUtils.logEntrySelected(TvSettingsEnums.APPS_APP_PERMISSIONS) 55 false 56 } 57 } 58 findPreference<Preference>(KEY_HIBERNATED_APPS)?.isVisible = isHibernationEnabled 59 60 viewLifecycleOwner.lifecycleScope.launch { 61 lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) { 62 val securityPreference = findPreference<Preference>(KEY_SECURITY) 63 val overlaySecuritySlicePreference = 64 findPreference<Preference>(KEY_OVERLAY_SECURITY) 65 val updateSlicePreference = findPreference<Preference>(KEY_UPDATE) 66 if (FlavorUtils.getFeatureFactory(requireContext()).getBasicModeFeatureProvider() 67 .isBasicMode(requireContext())) { 68 showSecurityPreference(securityPreference, overlaySecuritySlicePreference) 69 updateSlicePreference?.isVisible = false 70 } else { 71 if (isOverlaySecuritySlicePreferenceEnabled(overlaySecuritySlicePreference)) { 72 showOverlaySecuritySlicePreference( 73 overlaySecuritySlicePreference, securityPreference) 74 } else { 75 showSecurityPreference(securityPreference, overlaySecuritySlicePreference) 76 } 77 updateSlicePreference?.isVisible = 78 isUpdateSlicePreferenceEnabled(updateSlicePreference) 79 } 80 } 81 } 82 return checkNotNull(super.onCreateView(inflater, container, savedInstanceState)) 83 } 84 isOverlaySecuritySlicePreferenceEnablednull85 private suspend fun isOverlaySecuritySlicePreferenceEnabled( 86 overlaySecuritySlicePreference: Preference?): Boolean { 87 return (overlaySecuritySlicePreference is SlicePreference 88 && SliceUtilsKt.isSettingsSliceEnabled(requireContext(), 89 overlaySecuritySlicePreference.uri, 90 TOP_LEVEL_SLICE_URI)) 91 } 92 showOverlaySecuritySlicePreferencenull93 private fun showOverlaySecuritySlicePreference( 94 overlaySecuritySlicePreference: Preference?, 95 securityPreference: Preference?) { 96 overlaySecuritySlicePreference?.isVisible = true 97 securityPreference?.isVisible = false 98 } 99 showSecurityPreferencenull100 private fun showSecurityPreference( 101 securityPreference: Preference?, 102 overlaySecuritySlicePreference: Preference?) { 103 securityPreference?.isVisible = true 104 overlaySecuritySlicePreference?.isVisible = false 105 106 } 107 isUpdateSlicePreferenceEnablednull108 private suspend fun isUpdateSlicePreferenceEnabled( 109 updateSlicePreference: Preference?): Boolean { 110 return (updateSlicePreference is SlicePreference 111 && SliceUtilsKt.isSettingsSliceEnabled( 112 requireContext(), 113 updateSlicePreference.uri, 114 TOP_LEVEL_SLICE_URI)) 115 } 116 getPreferenceScreenResIdnull117 override fun getPreferenceScreenResId(): Int { 118 return when (FlavorUtils.getFlavor(context)) { 119 FlavorUtils.FLAVOR_X, FlavorUtils.FLAVOR_VENDOR -> R.xml.apps_x 120 else -> R.xml.apps 121 } 122 } 123 onCreatePreferenceControllersnull124 override fun onCreatePreferenceControllers(context: Context): 125 List<AbstractPreferenceController> { 126 val activity: Activity? = activity 127 val app = activity?.application 128 val controllers: MutableList<AbstractPreferenceController> = ArrayList() 129 controllers.add(RecentAppsPreferenceController(getContext(), app)) 130 return controllers 131 } 132 getPageIdnull133 override fun getPageId(): Int { 134 return TvSettingsEnums.APPS 135 } 136 137 companion object { 138 private const val KEY_PERMISSIONS = "Permissions" 139 private const val KEY_SECURITY = "security" 140 private const val KEY_OVERLAY_SECURITY = "overlay_security" 141 private const val KEY_UPDATE = "update" 142 private const val TOP_LEVEL_SLICE_URI = "top_level_settings_slice_uri" 143 private const val KEY_HIBERNATED_APPS = "see_unused_apps" 144 @JvmStatic prepareArgsnull145 fun prepareArgs(b: Bundle, volumeUuid: String?, volumeName: String?) { 146 b.putString(AppsActivity.EXTRA_VOLUME_UUID, volumeUuid) 147 b.putString(AppsActivity.EXTRA_VOLUME_NAME, volumeName) 148 } 149 newInstancenull150 fun newInstance(volumeUuid: String?, volumeName: String?): AppsFragment { 151 val b = Bundle(2) 152 prepareArgs(b, volumeUuid, volumeName) 153 val f = AppsFragment() 154 f.arguments = b 155 return f 156 } 157 158 private val isHibernationEnabled: Boolean 159 get() = DeviceConfig.getBoolean( 160 DeviceConfig.NAMESPACE_APP_HIBERNATION, 161 LibUtils.PROPERTY_APP_HIBERNATION_ENABLED, /* defaultValue= */ false) 162 } 163 }