Выберите из поставщика Google Фото с ACTION_GET_CONTENT или OPEN_DOCUMENT
Я понятия не имею, почему это происходит, но я не могу выбрать изображения у поставщика Google Фото. Тестирование по API 27.
С ACTION_GET_CONTENT
Если я использую:
val intent = Intent(Intent.ACTION_GET_CONTENT)
intent.addCategory(Intent.CATEGORY_OPENABLE)
intent.type = "image/*"
- Я вижу Google Фото среди провайдера
- Я могу перейти к некоторой картинке и выбрать ее
- Затем я возвращаюсь к списку провайдеров (не к моему приложению), как если бы провайдер потерпел неудачу в попытке поймать
Когда я открываю провайдера Photos и перемещаюсь по папкам, я вижу много таких:
2019-03-02 12:04:15.164 17641-13395/? W/NetworkManagementSocketTagger: untagSocket(120) failed with errno -22
2019-03-02 12:04:22.528 13217-13217/? E/ResourceType: Style contains key with bad entry: 0x01010586
2019-03-02 12:04:22.535 13217-13217/? W/ResourceType: For resource 0x7f020366, entry index(870) is beyond type entryCount(468)
Когда я нажимаю на картинку, я вижу это:
2019-03-02 12:04:34.150 13217-13217/? W/ResourceType: For resource 0x7f02036c, entry index(876) is beyond type entryCount(468)
2019-03-02 12:04:34.151 13217-13217/? W/ResourceType: For resource 0x7f02036c, entry index(876) is beyond type entryCount(468)
2019-03-02 12:04:34.229 2907-16891/? W/MediaExtractor: FAILED to autodetect media content.
2019-03-02 12:04:34.569 10839-10839/? W/ResourceType: ResTable_typeSpec entry count inconsistent: given 468, previously 1330
С ACTION_OPEN_DOCUMENT
В этом случае я даже не вижу Google Фото в ящике провайдера.
0 ответов
РЕДАКТИРОВАТЬ 2
Я думаю, что нашел решение проблемы. В документации Google упоминается, что доступ к общему файлу даст вам URI.
Серверное приложение отправляет URI содержимого файла обратно клиентскому приложению в Intent. Это намерение передается клиентскому приложению в его переопределении onActivityResult(). Как только клиентское приложение имеет URI содержимого файла, оно может получить доступ к файлу, получив его FileDescriptor.
Ниже приведен обновленный код, который я использую внутри onActivityResult. Обязательно вызовите супер метод onActivityResult, наконец.
super.onActivityResult (requestCode, resultCode, data)
Рабочий код
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
data?.data?.let {
util._log(TAG, it.toString())
}
if (data!!.data != null && data.data != null) {
try {
val stream = if (data.data!!.toString().contains("com.google.android.apps.photos.contentprovider")) {
val ff = contentResolver.openFileDescriptor(data.data!!, "r")
FileInputStream(ff?.fileDescriptor)
} else {
contentResolver.openInputStream(data.data!!)
}
val createFile = createImageFile()
util.copyInputStreamToFile(stream, createFile)
selectedImagePath = createFile.absolutePath
} catch (e: Exception) {
util._log(TAG, Log.getStackTraceString(e))
}
}
super.onActivityResult(requestCode, resultCode, data)
}
РЕДАКТИРОВАТЬ
Также проверьте этот пост
оригинал
Я использую его на Android Oreo 8.1.0(API 27) на моем телефоне Redmi 6 Pro, и он работает нормально.
Вы не опубликовали метод onActivityResult, возможно, именно здесь вам нужно внести некоторые изменения. Я пробовал оба
Ниже мой фрагмент кода
val pickIntent = Intent(Intent.ACTION_VIEW)
pickIntent.type = "image/*"
pickIntent.action = Intent.ACTION_GET_CONTENT
pickIntent.addCategory(Intent.CATEGORY_OPENABLE)
startActivityForResult(pickIntent, SELECT_PICTURE)
и в onActivityResult я анализирую это так
if (data!!.data != null && data.data != null) {
try {
// CommonUtilities._Log(TAG, "Data Type " + data.getType());
if (!isFinishing) {
val inputStream = contentResolver.openInputStream(data.data!!)
val createFile = createImageFile()
copyInputStreamToFile(inputStream!!, createFile)
// CommonUtilities._Log(TAG, "File Path " + createFile.getAbsolutePath());
selectedImagePath = createFile.absolutePath
}
} catch (e: IOException) {
util._log(TAG, Log.getStackTraceString(e))
}
}
Способ создания нового файла
@Throws(IOException::class)
private fun createImageFile(): File {
// Create an image file name
val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.ENGLISH).format(Date())
val imageFileName = "yesqueen_" + timeStamp + "_"
val storageDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)
return File.createTempFile(imageFileName, ".jpg", storageDir)
}
Способ чтения из входного потока
fun copyInputStreamToFile(`in`: InputStream, file: File) {
var out: OutputStream? = null
try {
out = FileOutputStream(file)
val buf = ByteArray(1024)
var len: Int = 0
while (`in`.read(buf).apply { len = this } > 0) {
out.write(buf, 0, len)
}
/*while (`in`.read(buf).let {
len = it
true
}) {
out.write(buf, 0, len)
}*/
/* while ((len = `in`.read(buf)) > 0) {
out.write(buf, 0, len)
}*/
} catch (e: Exception) {
e.printStackTrace()
} finally {
try {
out?.close()
} catch (e: Exception) {
e.printStackTrace()
}
try {
`in`.close()
} catch (e: Exception) {
e.printStackTrace()
}
}
}
У меня была такая же проблема, я не мог получить URI изображения из Google Фото с
ACTION_GET_CONTENT
намерение. Проблема была связана с
launchMode
моей деятельности. Я не смог найти никаких ссылок на документацию по Android. но таким образом проблема полностью решена:
У меня было одно приложение для занятий и мои
ACTION_GET_CONTENT
намерение было примерно таким:
val intent = Intent(Intent.ACTION_GET_CONTENT).apply {
type = "image/*"
}
startActivityForResult(intent, GALLERY_RESULT)
проблема была
singleInstance
режим запуска в определении активности в AndroidManifest.xml.
<activity
android:name=".ui.MainActivity"
android:configChanges="orientation"
android:launchMode="singleInstance"
android:screenOrientation="portrait"
android:theme="@style/AppTheme"
android:windowSoftInputMode="adjustResize|stateHidden"/>
Удалив строку android:launchMode, проблема была решена. Если ваша деятельность должна быть
singleInstance
, создание фиктивного занятия будет хорошим решением. здесь вы можете запустить фиктивную активность для получения результата, а затем выполнить свои намерения внутри его
onCreate
а потом
setResult()
для запрашиваемой вами деятельности:
class ImagePickerActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val intent = Intent(Intent.ACTION_GET_CONTENT).apply {
type = "image/*"
}
if (intent.resolveActivity(packageManager!!) != null) {
startActivityForResult(intent, GALLERY_RESULT)
} else {
Toast.makeText(
this,
"No Gallery APP installed",
Toast.LENGTH_LONG
).show()
finish()
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
//here data is resulted URI from ACTION_GET_CONTENT
//and we pass it to our MainActivy using setResult
setResult(resultCode, data)
finish()
}
}
и вот ваш код в MainActivity:
gallery.setOnClickListener {
startActivityForResult(
Intent(requireActivity(), ImagePickerActivity::class.java),
GALLERY_RESULT
)
}
Я сделал это с помощью этого кода.
val intent = Intent(Intent.ACTION_GET_CONTENT)
intent.addCategory(Intent.CATEGORY_OPENABLE)
intent.type = "image/*"
startActivityForResult(intent,100)
и для результата
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
when (requestCode) {
100 -> {
if (resultCode == Activity.RESULT_OK) {
val bitmap = generateBitmap(this,data!!.data)
//TODO show bitmap to your View
showPicture(bitmap!!)
}
}
}
}
generateBitmap(context,uri)
метод в Котлине
fun generateBitmap(context: Context, uri: Uri): Bitmap? {
var filePath = ""
var cursor: Cursor?
var columnIndex = 0
try {
val column = arrayOf(MediaStore.Images.Media.DATA)
val sel = arrayOf(MediaStore.Images.Media._ID + "=?")
if (uri.toString().startsWith("content://com.google.android.apps.photos.contentprovider")){
val content = this.contentResolver.openInputStream(uri) ?: return null
val pictureBitmap = BitmapFactory.decodeStream(content)
return pictureBitmap
} else {
filePath = ""
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
val wholeID = DocumentsContract.getDocumentId(uri)
val id = arrayOf(wholeID.split(":")[1])
cursor = context.contentResolver.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, column, sel[0], id, null)
columnIndex = cursor.getColumnIndex(column[0])
if (cursor.moveToFirst()) {
filePath = cursor.getString(columnIndex)
}
cursor.close()
} else {
val cursorLoader = CursorLoader(context, uri, column, null, null, null)
val cursor = cursorLoader.loadInBackground()
if (cursor != null) {
var column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA)
cursor.moveToFirst()
filePath = cursor.getString(column_index)
}
}
//TODO generate bitmap from file path
return bitmap(filePath)
}
} catch (e: Exception) {
print(e.message)
}
return null
}
для getBitmap из пути к файлу я использовал этот метод
fun bitmap(path : String) : Bitmap{
val image = File(path)
val bmOptions = BitmapFactory.Options()
return BitmapFactory.decodeFile(image.absolutePath, bmOptions)
}
ACTION_PICK даст возможность выбрать изображение, и вы можете получить путь к файлу
Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Image.Media.EXTERNAL_CONTENT_URI);
intent.setType("image/*");
Intent sIntent = new Intent("com.sec.android.app.myfiles.PICK_DATA");
sIntent.addCategory(Intent.CATEGORY_DEFAULT);
sIntent.setType("image/*");
Intent chooserIntent;
if (getPackageManager().resolveActivity(sIntent, 0) != null) {
// it is device with samsung file manager
chooserIntent = Intent.createChooser(sIntent, "Select file");
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, new Intent[]{intent});
} else {
chooserIntent = Intent.createChooser(intent, "Select file");
}
try {
startActivityForResult(chooserIntent, REQUEST_TAKE_GALLERY_VIDEO);
} catch (android.content.ActivityNotFoundException ex) {
Toast.makeText(getApplicationContext(), "No suitable File Manager was found.", Toast.LENGTH_SHORT).show();
}