/* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.wallpaper.util import android.content.ContentResolver import android.content.Context import android.content.Intent import android.content.pm.PackageManager import android.content.pm.ProviderInfo import android.net.Uri import android.os.Bundle import android.os.Handler import android.os.Looper import android.os.Message import android.os.RemoteException import android.text.TextUtils import android.util.Log import com.android.wallpaper.model.Screen import java.util.concurrent.Executors /** Util class for wallpaper preview. */ class PreviewUtils( private val context: Context, authorityMetadataKey: String? = null, authority: String? = null, val screen: Screen, ) : BasePreviewUtils { /** Callback for a call to the provider to render preview */ interface WorkspacePreviewCallback { /** Called with the result from the provider. */ fun onPreviewRendered(resultBundle: Bundle?) } private var providerInfo: ProviderInfo? constructor( context: Context, authorityMetadataKey: String, screen: Screen, ) : this( context = context.applicationContext, authorityMetadataKey = authorityMetadataKey, authority = null, screen = screen, ) init { val providerAuthority = authority ?: homeAuthority(context, checkNotNull(authorityMetadataKey)) ?: "" providerInfo = if (!TextUtils.isEmpty(providerAuthority)) { context.packageManager.resolveContentProvider(providerAuthority, 0) } else { null } providerInfo?.let { if (!TextUtils.isEmpty(it.readPermission)) { if ( context.checkSelfPermission(it.readPermission) != PackageManager.PERMISSION_GRANTED ) { Log.i(TAG, "No permission to query authority $authority") providerInfo = null } } } } /** * Render preview under the current grid option. * * @param bundle request options to pass on the call. * @param callback to receive the results, it will be called on the main thread. */ fun renderPreview(bundle: Bundle?, callback: WorkspacePreviewCallback) { EXECUTOR_SERVICE.submit { val result = context.contentResolver.call(getUri(PREVIEW), METHOD_GET_PREVIEW, null, bundle) Handler(Looper.getMainLooper()).post { callback.onPreviewRendered(result) } } } /** Cleans up the preview on the renderer side */ fun cleanUp(workspaceCallback: Message?) { try { // Send any message to clean up the corresponding preview on the renderer side. workspaceCallback?.replyTo?.send(workspaceCallback) } catch (remoteException: RemoteException) { Log.e(TAG, "Fail to clean up the workspace preview", remoteException) } } /** Easy way to generate a Uri with the provider info from this class. */ override fun getUri(path: String?): Uri { return Uri.Builder() .scheme(ContentResolver.SCHEME_CONTENT) .authority(checkNotNull(providerInfo).authority) .appendPath(path) .build() } /** Return whether preview is supported. */ override fun supportsPreview(): Boolean { return providerInfo != null } companion object { private const val TAG = "PreviewUtils" private const val PREVIEW = "preview" private const val METHOD_GET_PREVIEW = "get_preview" private val EXECUTOR_SERVICE = Executors.newSingleThreadExecutor() private fun homeAuthority(context: Context, authorityMetadataKey: String): String? { val homeIntent = Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME) val info = context.packageManager.resolveActivity( homeIntent, PackageManager.MATCH_DEFAULT_ONLY or PackageManager.GET_META_DATA, ) val providerAuthority = info?.activityInfo?.metaData?.getString(authorityMetadataKey) if (providerAuthority == null) { Log.i(TAG, "Couldn't resolve $authorityMetadataKey from $homeIntent") } return providerAuthority } } }