1 /* 2 * Copyright 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 17 package com.android.photopicker 18 19 import android.content.BroadcastReceiver 20 import android.content.ComponentName 21 import android.content.Context 22 import android.content.Intent 23 import android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED 24 import android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED 25 import android.content.pm.PackageManager.DONT_KILL_APP 26 import android.util.Log 27 import com.android.photopicker.core.configuration.DeviceConfigProxy 28 import com.android.photopicker.core.configuration.DeviceConfigProxyImpl 29 import com.android.photopicker.core.configuration.NAMESPACE_MEDIAPROVIDER 30 31 /** 32 * BroadcastReceiver that receives a wake up signal from MediaProvider whenever the 33 * [NAMESPACE_MEDIAPROVIDER] DeviceConfig is updated. 34 */ 35 class PhotopickerDeviceConfigReceiver : BroadcastReceiver() { 36 37 // Leave as var so that tests can replace this value 38 var deviceConfig: DeviceConfigProxy = DeviceConfigProxyImpl() 39 40 companion object { 41 const val TAG = "PhotopickerDeviceConfigReceiver" 42 /** A list of activities that need to be enabled or disabled based on flag state. */ 43 val activities = listOf("MainActivity", "PhotopickerGetContentActivity", 44 "PhotopickerUserSelectActivity") 45 } 46 onReceivenull47 override fun onReceive(context: Context, intent: Intent) { 48 Log.d(TAG, "onReceive: will evaluate Photopicker components with new DeviceConfig.") 49 50 // Update Photopicker's various activities based on the current device config. 51 updateActivityState(context) 52 } 53 54 /** Update the Activity state of Photopicker based on the current DeviceConfig. */ updateActivityStatenull55 private fun updateActivityState(context: Context) { 56 57 // Photopicker's activities are based on the enable_modern_picker flag 58 val modernPhotopickerIsEnabled = 59 deviceConfig.getFlag( 60 namespace = NAMESPACE_MEDIAPROVIDER, 61 key = "enable_modern_picker", 62 defaultValue = false 63 ) 64 65 val packageName = MainActivity::class.java.getPackage()?.getName() 66 checkNotNull(packageName) { "Package name is required to update activity state." } 67 68 for (activity in activities) { 69 Log.d(TAG, "Setting $modernPhotopickerIsEnabled state for $packageName.$activity") 70 val name = ComponentName(context, packageName + "." + activity) 71 setComponentState(context, modernPhotopickerIsEnabled, name) 72 } 73 } 74 75 /** 76 * Set a Photopicker component's enabled setting. 77 * 78 * @param context The running context 79 * @param enabled Whether the component should be enabled 80 * @param componentName The name of the component to change 81 */ setComponentStatenull82 private fun setComponentState( 83 context: Context, 84 enabled: Boolean, 85 componentName: ComponentName 86 ) { 87 88 val state = 89 when (enabled) { 90 true -> COMPONENT_ENABLED_STATE_ENABLED 91 false -> COMPONENT_ENABLED_STATE_DISABLED 92 } 93 94 context.packageManager.setComponentEnabledSetting(componentName, state, DONT_KILL_APP) 95 } 96 } 97