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 }