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 17 package com.android.wallpaper.picker.category.ui.view 18 19 import android.Manifest 20 import android.app.Activity 21 import android.content.ActivityNotFoundException 22 import android.content.Intent 23 import android.content.pm.PackageManager 24 import android.util.Log 25 import androidx.activity.result.ActivityResultLauncher 26 import com.android.wallpaper.module.InjectorProvider 27 import com.android.wallpaper.picker.MyPhotosStarter 28 import com.android.wallpaper.picker.MyPhotosStarter.PermissionChangedListener 29 import com.android.wallpaper.picker.WallpaperPickerDelegate 30 import com.android.wallpaper.picker.category.ui.view.CategoriesFragment.Companion.READ_IMAGE_PERMISSION 31 import javax.inject.Inject 32 import javax.inject.Singleton 33 34 /** 35 * This class handles all the operations related to photo picker and MyPhotos tile in the category 36 * page. 37 */ 38 @Singleton 39 class MyPhotosStarterImpl @Inject constructor() : MyPhotosStarter { 40 41 private val permissionChangedListeners: MutableList<PermissionChangedListener> = mutableListOf() 42 requestCustomPhotoPickernull43 override fun requestCustomPhotoPicker( 44 listener: PermissionChangedListener, 45 activity: Activity, 46 photoPickerLauncher: ActivityResultLauncher<Intent>, 47 ) { 48 // TODO (b/282073506): Figure out a better way to have better photos experience 49 if (!isReadExternalStoragePermissionGranted(activity)) { 50 val wrappedListener: PermissionChangedListener = 51 object : PermissionChangedListener { 52 override fun onPermissionsGranted() { 53 listener.onPermissionsGranted() 54 showCustomPhotoPicker(photoPickerLauncher) 55 } 56 57 override fun onPermissionsDenied(dontAskAgain: Boolean) { 58 listener.onPermissionsDenied(dontAskAgain) 59 } 60 } 61 requestExternalStoragePermission(wrappedListener, activity) 62 return 63 } 64 65 showCustomPhotoPicker(photoPickerLauncher) 66 } 67 isReadExternalStoragePermissionGrantednull68 private fun isReadExternalStoragePermissionGranted(activity: Activity): Boolean { 69 return activity.packageManager.checkPermission( 70 Manifest.permission.READ_MEDIA_IMAGES, 71 activity.packageName, 72 ) == PackageManager.PERMISSION_GRANTED 73 } 74 requestExternalStoragePermissionnull75 private fun requestExternalStoragePermission( 76 listener: PermissionChangedListener?, 77 activity: Activity, 78 ) { 79 if (listener != null) { 80 permissionChangedListeners.add(listener) 81 } 82 activity.requestPermissions( 83 arrayOf<String>(READ_IMAGE_PERMISSION), 84 WallpaperPickerDelegate.READ_EXTERNAL_STORAGE_PERMISSION_REQUEST_CODE, 85 ) 86 } 87 showCustomPhotoPickernull88 private fun showCustomPhotoPicker(photoPickerLauncher: ActivityResultLauncher<Intent>) { 89 val injector = InjectorProvider.getInjector() 90 try { 91 val intent: Intent = injector.getMyPhotosIntentProvider().getMyPhotosIntent() 92 photoPickerLauncher.launch(intent) 93 } catch (e: ActivityNotFoundException) { 94 val fallback: Intent? = injector.getMyPhotosIntentProvider().fallbackIntent 95 if (fallback != null) { 96 Log.i(TAG, "Couldn't launch photo picker with main intent, trying with fallback") 97 photoPickerLauncher.launch(fallback) 98 } else { 99 Log.e( 100 TAG, 101 "Couldn't launch photo picker with main intent and no fallback is " + 102 "available", 103 ) 104 throw e 105 } 106 } 107 } 108 109 /** 110 * This method is not implemented on purpose since the other method that allows specifying a 111 * custom activity is already implemented which achieves the main purpose of requesting the 112 * photo picker. This method is only added for backward compatibility purposes so we can 113 * continue to use the same interface as earlier. 114 */ requestCustomPhotoPickernull115 override fun requestCustomPhotoPicker(listener: PermissionChangedListener?) { 116 TODO("Not yet implemented") 117 } 118 119 companion object { 120 private const val TAG = "WallpaperPickerDelegate2" 121 } 122 } 123