1 /* 2 * Copyright (C) 2022 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.systemui.screenshot 18 19 import android.content.ClipData 20 import android.content.ClipDescription 21 import android.content.ComponentName 22 import android.content.ContentProvider 23 import android.content.Context 24 import android.content.Intent 25 import android.net.Uri 26 import com.android.systemui.R 27 28 object ActionIntentCreator { 29 /** @return a chooser intent to share the given URI. */ 30 fun createShare(uri: Uri): Intent = createShare(uri, subject = null, text = null) 31 32 /** @return a chooser intent to share the given URI with the optional provided subject. */ 33 fun createShareWithSubject(uri: Uri, subject: String): Intent = 34 createShare(uri, subject = subject) 35 36 /** @return a chooser intent to share the given URI with the optional provided extra text. */ 37 fun createShareWithText(uri: Uri, extraText: String): Intent = 38 createShare(uri, text = extraText) 39 40 private fun createShare(rawUri: Uri, subject: String? = null, text: String? = null): Intent { 41 val uri = uriWithoutUserId(rawUri) 42 43 // Create a share intent, this will always go through the chooser activity first 44 // which should not trigger auto-enter PiP 45 val sharingIntent = 46 Intent(Intent.ACTION_SEND).apply { 47 setDataAndType(uri, "image/png") 48 putExtra(Intent.EXTRA_STREAM, uri) 49 50 // Include URI in ClipData also, so that grantPermission picks it up. 51 // We don't use setData here because some apps interpret this as "to:". 52 clipData = 53 ClipData( 54 ClipDescription("content", arrayOf(ClipDescription.MIMETYPE_TEXT_PLAIN)), 55 ClipData.Item(uri) 56 ) 57 58 subject?.let { putExtra(Intent.EXTRA_SUBJECT, subject) } 59 text?.let { putExtra(Intent.EXTRA_TEXT, text) } 60 addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) 61 addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION) 62 } 63 64 return Intent.createChooser(sharingIntent, null) 65 .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK) 66 .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) 67 .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) 68 } 69 70 /** 71 * @return an ACTION_EDIT intent for the given URI, directed to config_screenshotEditor if 72 * available. 73 */ 74 fun createEdit(rawUri: Uri, context: Context): Intent { 75 val uri = uriWithoutUserId(rawUri) 76 val editIntent = Intent(Intent.ACTION_EDIT) 77 78 val editor = context.getString(R.string.config_screenshotEditor) 79 if (editor.isNotEmpty()) { 80 editIntent.component = ComponentName.unflattenFromString(editor) 81 } 82 83 return editIntent 84 .setDataAndType(uri, "image/png") 85 .putExtra(EXTRA_EDIT_SOURCE, EDIT_SOURCE_SCREENSHOT) 86 .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) 87 .addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION) 88 .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) 89 .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK) 90 } 91 92 private const val EXTRA_EDIT_SOURCE = "edit_source" 93 private const val EDIT_SOURCE_SCREENSHOT = "screenshot" 94 } 95 96 /** 97 * URIs here are passed only via Intent which are sent to the target user via Intent. Because of 98 * this, the userId component can be removed to prevent compatibility issues when an app attempts 99 * valid a URI containing a userId within the authority. 100 */ 101 private fun uriWithoutUserId(uri: Uri): Uri { 102 return ContentProvider.getUriWithoutUserId(uri) 103 } 104