1 /* 2 * Copyright (C) 2020 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.wallpaper.util 17 18 import android.content.ContentResolver 19 import android.content.Context 20 import android.content.Intent 21 import android.content.pm.PackageManager 22 import android.content.pm.ProviderInfo 23 import android.net.Uri 24 import android.os.Bundle 25 import android.os.Handler 26 import android.os.Looper 27 import android.text.TextUtils 28 import java.util.concurrent.Executors 29 30 /** Util class for wallpaper preview. */ 31 class PreviewUtils( 32 private val context: Context, 33 authorityMetadataKey: String? = null, 34 authority: String? = null, 35 ) { 36 /** Callback for a call to the provider to render preview */ 37 interface WorkspacePreviewCallback { 38 /** Called with the result from the provider. */ onPreviewRenderednull39 fun onPreviewRendered(resultBundle: Bundle?) 40 } 41 42 private var providerInfo: ProviderInfo? 43 44 constructor( 45 context: Context, 46 authorityMetadataKey: String, 47 ) : this( 48 context = context, 49 authorityMetadataKey = authorityMetadataKey, 50 authority = null, 51 ) 52 53 init { 54 val providerAuthority = 55 authority ?: homeAuthority(context, checkNotNull(authorityMetadataKey)) 56 57 providerInfo = 58 if (!TextUtils.isEmpty(providerAuthority)) { 59 context.packageManager.resolveContentProvider( 60 providerAuthority, 61 0, 62 ) 63 } else { 64 null 65 } 66 67 providerInfo?.let { 68 if (!TextUtils.isEmpty(it.readPermission)) { 69 if ( 70 context.checkSelfPermission(it.readPermission) != 71 PackageManager.PERMISSION_GRANTED 72 ) { 73 providerInfo = null 74 } 75 } 76 } 77 } 78 79 /** 80 * Render preview under the current grid option. 81 * 82 * @param bundle request options to pass on the call. 83 * @param callback to receive the results, it will be called on the main thread. 84 */ renderPreviewnull85 fun renderPreview(bundle: Bundle?, callback: WorkspacePreviewCallback) { 86 EXECUTOR_SERVICE.submit { 87 val result = 88 context.contentResolver.call( 89 getUri(PREVIEW), 90 METHOD_GET_PREVIEW, 91 null, 92 bundle, 93 ) 94 Handler(Looper.getMainLooper()).post { callback.onPreviewRendered(result) } 95 } 96 } 97 98 /** Easy way to generate a Uri with the provider info from this class. */ getUrinull99 fun getUri(path: String?): Uri { 100 return Uri.Builder() 101 .scheme(ContentResolver.SCHEME_CONTENT) 102 .authority(checkNotNull(providerInfo).authority) 103 .appendPath(path) 104 .build() 105 } 106 107 /** Return whether preview is supported. */ supportsPreviewnull108 fun supportsPreview(): Boolean { 109 return providerInfo != null 110 } 111 112 companion object { 113 private const val PREVIEW = "preview" 114 private const val METHOD_GET_PREVIEW = "get_preview" 115 private val EXECUTOR_SERVICE = Executors.newSingleThreadExecutor() 116 homeAuthoritynull117 private fun homeAuthority(context: Context, authorityMetadataKey: String): String? { 118 val homeIntent = Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME) 119 val info = 120 context.packageManager.resolveActivity( 121 homeIntent, 122 PackageManager.MATCH_DEFAULT_ONLY or PackageManager.GET_META_DATA, 123 ) 124 125 return info?.activityInfo?.metaData?.getString(authorityMetadataKey) 126 } 127 } 128 } 129