#include "androidutils.h" #include "contentdevice.h" #include #include ContentDevice::ContentDevice(QObject *parent) : QIODevice(parent), _context(QtAndroid::androidContext()), _url() { Q_ASSERT(_context.isValid()); } ContentDevice::ContentDevice(const QUrl &url, QObject *parent) : QIODevice(parent), _context(QtAndroid::androidContext()), _url(url) { Q_ASSERT(_context.isValid()); } ContentDevice::ContentDevice(const QAndroidJniObject &context, const QUrl &url, QObject *parent) : QIODevice(parent), _context(context), _url(url) { Q_ASSERT(_context.isValid()); } void ContentDevice::setContext(const QAndroidJniObject &context) { _context = context; Q_ASSERT(_context.isValid()); } bool ContentDevice::isSequential() const { return true; } bool ContentDevice::open(QIODevice::OpenMode mode) { if(!QIODevice::open(mode)) return false; QAndroidJniEnvironment env; try { auto uri = QAndroidJniObject::callStaticObjectMethod("android/net/Uri", "parse", "(Ljava/lang/String;)Landroid/net/Uri;", QAndroidJniObject::fromString(_url.toString(QUrl::FullyEncoded)).object()); AndroidUtils::javaThrow(); if(!uri.isValid()) return false; auto contentResolver = _context.callObjectMethod("getContentResolver", "()Landroid/content/ContentResolver;"); AndroidUtils::javaThrow(); if(!contentResolver.isValid()) return false; switch(mode) { case QIODevice::ReadOnly: _stream = contentResolver.callObjectMethod("openInputStream", "(Landroid/net/Uri;)Ljava/io/InputStream;", uri.object()); break; case QIODevice::WriteOnly: _stream = contentResolver.callObjectMethod("openOutputStream", "(Landroid/net/Uri;)Ljava/io/OutputStream;", uri.object()); break; default: setErrorString(tr("You can only open ContentDevice with QIODevice::ReadOnly OR QIODevice::WriteOnly. Other flags are not supported")); QIODevice::close(); return false; } AndroidUtils::javaThrow(); if(!_stream.isValid()) return false; return true; } catch(QException &e) { QIODevice::close(); setErrorString(e.what()); return false; } } void ContentDevice::close() { if(_stream.isValid()) { _stream.callMethod("close"); _stream = QAndroidJniObject(); } QIODevice::close(); } qint64 ContentDevice::bytesAvailable() const { if(openMode().testFlag(QIODevice::ReadOnly) && _stream.isValid()) return (qint64)_stream.callMethod("available"); return -1; } void ContentDevice::flush() { if(openMode().testFlag(QIODevice::WriteOnly) && _stream.isValid()) _stream.callMethod("flush"); } QUrl ContentDevice::url() const { return _url; } void ContentDevice::setUrl(QUrl url) { if (_url == url) return; _url = url; emit urlChanged(url); } qint64 ContentDevice::readData(char *data, qint64 maxlen) { QAndroidJniEnvironment env; auto array = env->NewByteArray((jsize)maxlen); try { auto cnt = _stream.callMethod("read", "([B)I", array); AndroidUtils::javaThrow(); if(cnt > 0) env->GetByteArrayRegion(array, 0, cnt, reinterpret_cast(data)); env->DeleteLocalRef(array); return (qint64)cnt; } catch(QException &e) { setErrorString(e.what()); env->DeleteLocalRef(array); return -1; } } qint64 ContentDevice::writeData(const char *data, qint64 len) { QAndroidJniEnvironment env; auto array = env->NewByteArray((jsize)len); env->SetByteArrayRegion (array, 0, len, reinterpret_cast(data)); try { _stream.callMethod("write", "([B)V", array); AndroidUtils::javaThrow(); env->DeleteLocalRef(array); return len; } catch(QException &e) { setErrorString(e.what()); env->DeleteLocalRef(array); return -1; } }