File indexing completed on 2024-05-05 04:50:32

0001 /*
0002    SPDX-FileCopyrightText: 2018 (c) Matthieu Gallien <matthieu_gallien@yahoo.fr>
0003 
0004    SPDX-License-Identifier: LGPL-3.0-or-later
0005  */
0006 
0007 #include "androidfilelisting.h"
0008 
0009 #include "android/androidcommon.h"
0010 
0011 #include "elisa_settings.h"
0012 #include "elisautils.h"
0013 
0014 #include "filescanner.h"
0015 
0016 #include <KLocalizedString>
0017 
0018 #include <QThread>
0019 #include <QFileInfo>
0020 #include <QAtomicInt>
0021 
0022 // C++ code
0023 #include <jni.h>
0024 #include <QAndroidJniObject>
0025 #include <QtAndroid>
0026 
0027 #include <algorithm>
0028 
0029 class AndroidFileListingPrivate
0030 {
0031 public:
0032     QHash<QString, DataTypes::ListTrackDataType> mAllAlbums;
0033 
0034     QHash<QUrl, QDateTime> mAllFiles;
0035 
0036     DataTypes::ListTrackDataType mNewTracks;
0037 
0038     QHash<QString, QUrl> mCovers;
0039 
0040     QAtomicInt mStopRequest = 0;
0041 };
0042 
0043 AndroidFileListing::AndroidFileListing(QObject *parent)
0044     : AbstractFileListing(parent), d(std::make_unique<AndroidFileListingPrivate>())
0045 {
0046     AndroidFileListing::mCurrentInstance = this;
0047 
0048     registerNativeMethods();
0049 }
0050 
0051 AndroidFileListing::~AndroidFileListing() = default;
0052 
0053 void AndroidFileListing::applicationAboutToQuit()
0054 {
0055     AbstractFileListing::applicationAboutToQuit();
0056     d->mStopRequest = 1;
0057 }
0058 
0059 AndroidFileListing *AndroidFileListing::mCurrentInstance = nullptr;
0060 
0061 AndroidFileListing *AndroidFileListing::currentInstance()
0062 {
0063     return mCurrentInstance;
0064 }
0065 
0066 void AndroidFileListing::registerNativeMethods()
0067 {
0068 }
0069 
0070 void AndroidFileListing::executeInit(QHash<QUrl, QDateTime> allFiles)
0071 {
0072     qCInfo(orgKdeElisaAndroid()) << "AndroidFileListing::executeInit";
0073     AbstractFileListing::executeInit(std::move(allFiles));
0074 }
0075 
0076 void AndroidFileListing::triggerRefreshOfContent()
0077 {
0078     qCInfo(orgKdeElisaAndroid()) << "AndroidFileListing::triggerRefreshOfContent";
0079     Q_EMIT indexingStarted();
0080 
0081     if (QtAndroid::checkPermission(QStringLiteral("android.permission.READ_EXTERNAL_STORAGE")) == QtAndroid::PermissionResult::Denied) {
0082         QtAndroid::requestPermissionsSync({QStringLiteral("android.permission.READ_EXTERNAL_STORAGE")});
0083     }
0084 
0085     if (QtAndroid::checkPermission(QStringLiteral("android.permission.READ_EXTERNAL_STORAGE")) == QtAndroid::PermissionResult::Denied) {
0086         qCInfo(orgKdeElisaAndroid()) << "AndroidFileListing::triggerRefreshOfContent" << "not scanning files due to missing permission";
0087         return;
0088     }
0089 
0090     AbstractFileListing::triggerRefreshOfContent();
0091 
0092     QAndroidJniObject musicList = QAndroidJniObject::callStaticObjectMethod("org/kde/elisa/ElisaActivity",
0093                                               "listAudioFiles",
0094                                               "(Landroid/content/Context;)Ljava/util/ArrayList;",
0095                                               QtAndroid::androidContext().object());
0096 
0097     auto nbTracks = musicList.callMethod<jint>("size");
0098 
0099     for (int i = 0; i < nbTracks; ++i) {
0100         auto newTrack = DataTypes::TrackDataType{};
0101 
0102         auto track = musicList.callObjectMethod("get", "(I)Ljava/lang/Object;", i);
0103 
0104         newTrack[DataTypes::TitleRole] = track.callObjectMethod("getTitle", "()Ljava/lang/String;").toString();
0105         newTrack[DataTypes::ArtistRole] = track.callObjectMethod("getArtist", "()Ljava/lang/String;").toString();
0106         newTrack[DataTypes::AlbumRole] = track.callObjectMethod("getAlbumName", "()Ljava/lang/String;").toString();
0107         newTrack[DataTypes::AlbumArtistRole] = track.callObjectMethod("getAlbumArtist", "()Ljava/lang/String;").toString();
0108         newTrack[DataTypes::TrackNumberRole] = track.callMethod<jint>("getTrackNumber");
0109         newTrack[DataTypes::DiscNumberRole] = track.callMethod<jint>("getDiscNumber");
0110         newTrack[DataTypes::DurationRole] = QTime::fromMSecsSinceStartOfDay(track.callMethod<jlong>("getDuration"));
0111         newTrack[DataTypes::ResourceRole] = QUrl::fromLocalFile(track.callObjectMethod("getResourceURI", "()Ljava/lang/String;").toString());
0112         newTrack[DataTypes::ImageUrlRole] = QUrl::fromLocalFile(track.callObjectMethod("getAlbumCover", "()Ljava/lang/String;").toString());
0113         newTrack[DataTypes::GenreRole] = track.callObjectMethod("getGenre", "()Ljava/lang/String;").toString();
0114         newTrack[DataTypes::ComposerRole] = track.callObjectMethod("getComposer", "()Ljava/lang/String;").toString();
0115 
0116         QFileInfo scanFileInfo(newTrack.resourceURI().toLocalFile());
0117         newTrack[DataTypes::FileModificationTime] = scanFileInfo.metadataChangeTime();
0118 
0119         newTrack[DataTypes::RatingRole] = 0;
0120         newTrack[DataTypes::ElementTypeRole] = ElisaUtils::Track;
0121 
0122         qCInfo(orgKdeElisaAndroid()) << "AndroidFileListing::triggerRefreshOfContent" << newTrack;
0123 
0124         d->mNewTracks.push_back(newTrack);
0125     }
0126 
0127     Q_EMIT tracksList(d->mNewTracks, d->mCovers);
0128 
0129     Q_EMIT indexingFinished();
0130 }
0131 
0132 DataTypes::TrackDataType AndroidFileListing::scanOneFile(const QUrl &scanFile, const QFileInfo &scanFileInfo, FileSystemWatchingModes watchForFileSystemChanges)
0133 {
0134     auto newTrack = DataTypes::TrackDataType{};
0135 
0136     return newTrack;
0137 }
0138 
0139 #include "moc_androidfilelisting.cpp"