AndroidMediaLibrary.cpp 26.7 KB
Newer Older
1 2 3
#include "AndroidMediaLibrary.h"
#define LOG_TAG "VLC/JNI/AndroidMediaLibrary"
#include "log.h"
4
#define THREAD_NAME "AndroidMedialibrary"
5 6 7 8

#define FLAG_MEDIA_UPDATED_AUDIO       1 << 0
#define FLAG_MEDIA_UPDATED_AUDIO_EMPTY 1 << 1
#define FLAG_MEDIA_UPDATED_VIDEO       1 << 2
9 10 11 12 13
#define FLAG_MEDIA_UPDATED_VIDEO_EMPTY 1 << 3
#define FLAG_MEDIA_ADDED_AUDIO         1 << 4
#define FLAG_MEDIA_ADDED_AUDIO_EMPTY   1 << 5
#define FLAG_MEDIA_ADDED_VIDEO         1 << 6
#define FLAG_MEDIA_ADDED_VIDEO_EMPTY   1 << 7
14 15 16

static pthread_key_t jni_env_key;
static JavaVM *myVm;
17
static bool m_started = false;
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37

static void jni_detach_thread(void *data)
{
   myVm->DetachCurrentThread();
}

static void key_init(void)
{
    pthread_key_create(&jni_env_key, jni_detach_thread);
}

AndroidMediaLibrary::AndroidMediaLibrary(JavaVM *vm, fields *ref_fields, jobject thiz)
    : p_ml( NewMediaLibrary() ), p_fields ( ref_fields )
{
    myVm = vm;
    p_lister = std::make_shared<AndroidDeviceLister>();
    p_ml->setLogger( new AndroidMediaLibraryLogger );
    p_ml->setVerbosity(medialibrary::LogLevel::Info);
    pthread_once(&key_once, key_init);
    JNIEnv *env = getEnv();
38 39
    if (env == NULL) return;
    weak_thiz = env->NewWeakGlobalRef(thiz);
40 41 42 43 44 45 46 47 48
}

AndroidMediaLibrary::~AndroidMediaLibrary()
{
    LOGD("AndroidMediaLibrary delete");
    pthread_key_delete(jni_env_key);
    delete p_ml;
}

49
medialibrary::InitializeResult
50 51
AndroidMediaLibrary::initML(const std::string& dbPath, const std::string& thumbsPath)
{
52
    p_DeviceListerCb = p_ml->setDeviceLister(p_lister);
53
    return p_ml->initialize(dbPath, thumbsPath, this);
54 55
}

56 57 58 59
void
AndroidMediaLibrary::start()
{
    p_ml->start();
60
    m_started = true;
61 62
}

63
bool
64
AndroidMediaLibrary::addDevice(const std::string& uuid, const std::string& path, bool removable)
65 66
{
    p_lister->addDevice(uuid, path, removable);
67
    return p_DeviceListerCb != nullptr && (p_DeviceListerCb->onDeviceMounted(uuid, path));
68 69
}

70 71 72 73 74 75
std::vector<std::tuple<std::string, std::string, bool>>
AndroidMediaLibrary::devices()
{
    return p_lister->devices();
}

76
bool
77
AndroidMediaLibrary::removeDevice(const std::string& uuid, const std::string& path)
78 79
{
    bool removed = p_lister->removeDevice(uuid);
80
    if (removed && p_DeviceListerCb != nullptr)
81
        p_DeviceListerCb->onDeviceUnmounted(uuid, path);
82 83 84 85 86 87 88 89 90
    return removed;
}

void
AndroidMediaLibrary::banFolder(const std::string& path)
{
    p_ml->banFolder(path);
}

91 92 93 94 95 96
void
AndroidMediaLibrary::unbanFolder(const std::string& path)
{
    p_ml->unbanFolder(path);
}

97 98 99 100 101 102
void
AndroidMediaLibrary::discover(const std::string& libraryPath)
{
    p_ml->discover(libraryPath);
}

103 104 105 106 107 108 109 110 111
void
AndroidMediaLibrary::removeEntryPoint(const std::string& entryPoint)
{
    p_ml->removeEntryPoint(entryPoint);
}

std::vector<medialibrary::FolderPtr>
AndroidMediaLibrary::entryPoints()
{
112
    return p_ml->entryPoints()->all();
113 114
}

115 116 117 118
void
AndroidMediaLibrary::pauseBackgroundOperations()
{
    p_ml->pauseBackgroundOperations();
119
    m_paused = true;
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
}

void
AndroidMediaLibrary::setMediaUpdatedCbFlag(int flags)
{
    m_mediaUpdatedType = flags;
}

void
AndroidMediaLibrary::setMediaAddedCbFlag(int flags)
{
    m_mediaAddedType = flags;
}

void
AndroidMediaLibrary::resumeBackgroundOperations()
{
    p_ml->resumeBackgroundOperations();
138
    m_paused = false;
139 140 141 142 143 144 145 146 147 148 149 150 151 152
}

void
AndroidMediaLibrary::reload()
{
    p_ml->reload();
}

void
AndroidMediaLibrary::reload( const std::string& entryPoint )
{
    p_ml->reload(entryPoint);
}

153 154 155 156 157 158
void
AndroidMediaLibrary::forceParserRetry()
{
    p_ml->forceParserRetry();
}

159 160 161 162 163 164
void
AndroidMediaLibrary::forceRescan()
{
    p_ml->forceRescan();
}

165 166 167
bool
AndroidMediaLibrary::increasePlayCount(int64_t mediaId)
{
Geoffrey Métais's avatar
Geoffrey Métais committed
168 169 170
    auto media = p_ml->media(mediaId);
    if (media != nullptr)
        return media->increasePlayCount();
171
    return false;
172 173 174 175 176
}

std::vector<medialibrary::MediaPtr>
AndroidMediaLibrary::lastMediaPlayed()
{
177
    return p_ml->history()->items( 100, 0 );
178 179
}

180
bool
181
AndroidMediaLibrary::addToHistory( const std::string& mrl, const std::string& title)
182
{
183 184 185
    auto media = p_ml->media( mrl );
    if ( media == nullptr )
    {
186
        media = p_ml->addStream( mrl );
187 188 189
        if ( media == nullptr )
            return false;
    }
190
    media->setTitle(title);
191
    return true;
192 193
}

194
std::vector<medialibrary::MediaPtr>
195 196
AndroidMediaLibrary::lastStreamsPlayed()
{
197
    return p_ml->streamHistory()->items( 100, 0 );
198 199 200 201 202 203 204 205
}

bool
AndroidMediaLibrary::clearHistory()
{
    return p_ml->clearHistory();
}

206 207 208 209 210 211
medialibrary::SearchAggregate
AndroidMediaLibrary::search(const std::string& query)
{
    return p_ml->search(query);
}

212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245
medialibrary::Query<medialibrary::IMedia>
AndroidMediaLibrary::searchMedia(const std::string& query, const medialibrary::QueryParameters* params)
{
    return p_ml->searchMedia(query, params);
}

medialibrary::Query<medialibrary::IMedia>
AndroidMediaLibrary::searchAudio(const std::string& query, const medialibrary::QueryParameters* params)
{
    return p_ml->searchAudio(query, params);
}

medialibrary::Query<medialibrary::IMedia>
AndroidMediaLibrary::searchVideo(const std::string& query, const medialibrary::QueryParameters* params)
{
    return p_ml->searchVideo(query, params);
}

medialibrary::Query<medialibrary::IMedia>
AndroidMediaLibrary::searchFromAlbum( int64_t albumId, const std::string& query, const medialibrary::QueryParameters* params )
{
    auto album = p_ml->album(albumId);
    return album == nullptr ? nullptr : album->searchTracks(query, params);
}

medialibrary::Query<medialibrary::IMedia>
AndroidMediaLibrary::searchFromArtist( int64_t artistId, const std::string& query, const medialibrary::QueryParameters* params )
{
    auto artist = p_ml->artist(artistId);
    return artist == nullptr ? nullptr : artist->searchTracks(query, params);
}

medialibrary::Query<medialibrary::IAlbum>
AndroidMediaLibrary::searchAlbumsFromArtist( int64_t artistId, const std::string& query, const medialibrary::QueryParameters* params )
246
{
247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262
    auto artist = p_ml->artist(artistId);
    return artist == nullptr ? nullptr : artist->searchAlbums(query, params);
}

medialibrary::Query<medialibrary::IMedia>
AndroidMediaLibrary::searchFromGenre( int64_t genreId, const std::string& query, const medialibrary::QueryParameters* params )
{
    auto genre = p_ml->genre(genreId);
    return genre == nullptr ? nullptr : genre->searchTracks(query, params);
}

medialibrary::Query<medialibrary::IAlbum>
AndroidMediaLibrary::searchAlbumsFromGenre( int64_t genreId, const std::string& query, const medialibrary::QueryParameters* params )
{
    auto genre = p_ml->genre(genreId);
    return genre == nullptr ? nullptr : genre->searchAlbums(query, params);
263 264
}

265 266
medialibrary::Query<medialibrary::IMedia>
AndroidMediaLibrary::searchFromPLaylist( int64_t playlistId, const std::string& query, const medialibrary::QueryParameters* params )
267
{
268 269
    auto playlist = p_ml->playlist(playlistId);
    return playlist == nullptr ? nullptr : playlist->searchMedia(query, params);
270 271
}

272 273
medialibrary::Query<medialibrary::IPlaylist>
AndroidMediaLibrary::searchPlaylists(const std::string& query, const medialibrary::QueryParameters* params)
274
{
275
    return p_ml->searchPlaylists(query, params);
276 277
}

278 279
medialibrary::Query<medialibrary::IAlbum>
AndroidMediaLibrary::searchAlbums(const std::string& query, const medialibrary::QueryParameters* params)
280
{
281
    return p_ml->searchAlbums(query, params);
282 283
}

284 285
medialibrary::Query<medialibrary::IGenre>
AndroidMediaLibrary::searchGenre(const std::string& query, const medialibrary::QueryParameters* params)
286
{
287 288 289 290 291 292 293
    return p_ml->searchGenre(query, params);
}

medialibrary::Query<medialibrary::IArtist>
AndroidMediaLibrary::searchArtists(const std::string& query, const medialibrary::QueryParameters* params)
{
    return p_ml->searchArtists(query, true, params);
294 295
}

296 297 298 299 300 301 302 303 304 305 306 307
medialibrary::MediaPtr
AndroidMediaLibrary::media(long id)
{
    return p_ml->media(id);
}

medialibrary::MediaPtr
AndroidMediaLibrary::media(const std::string& mrl)
{
    return p_ml->media(mrl);
}

308 309 310
medialibrary::MediaPtr
AndroidMediaLibrary::addMedia(const std::string& mrl)
{
311
    return p_ml->addExternalMedia(mrl);
312 313
}

314 315 316 317 318 319 320
bool
AndroidMediaLibrary::removeExternalMedia(long id)
{
    auto media = p_ml->media(id);
    return media != nullptr && p_ml->removeExternalMedia(media);
}

321 322 323 324 325 326 327 328
medialibrary::MediaPtr
AndroidMediaLibrary::addStream(const std::string& mrl, const std::string& title)
{
    auto media = p_ml->addStream(mrl);
    if (media != nullptr) media->setTitle(title);
    return media;
}

329
medialibrary::Query<medialibrary::IMedia>
330
AndroidMediaLibrary::videoFiles( const medialibrary::QueryParameters* params )
331
{
332
    return p_ml->videoFiles(params);
333 334
}

335
medialibrary::Query<medialibrary::IMedia>
336
AndroidMediaLibrary::audioFiles( const medialibrary::QueryParameters* params )
337
{
338
    return p_ml->audioFiles(params);
339 340
}

341
medialibrary::Query<medialibrary::IAlbum>
342
AndroidMediaLibrary::albums(const medialibrary::QueryParameters* params)
343
{
344
    return p_ml->albums(params);
345 346
}

347 348 349 350 351 352
medialibrary::AlbumPtr
AndroidMediaLibrary::album(int64_t albumId)
{
    return p_ml->album(albumId);
}

353
medialibrary::Query<medialibrary::IArtist>
354
AndroidMediaLibrary::artists(bool includeAll, const medialibrary::QueryParameters* params)
355
{
356
    return p_ml->artists(includeAll, params);
357 358
}

359 360 361 362 363 364
medialibrary::ArtistPtr
AndroidMediaLibrary::artist(int64_t artistId)
{
    return p_ml->artist(artistId);
}

365
medialibrary::Query<medialibrary::IGenre>
366
AndroidMediaLibrary::genres(const medialibrary::QueryParameters* params)
367
{
368
    return p_ml->genres(params);
369 370
}

371 372 373 374 375 376
medialibrary::GenrePtr
AndroidMediaLibrary::genre(int64_t genreId)
{
    return p_ml->genre(genreId);
}

377
medialibrary::Query<medialibrary::IPlaylist>
378
AndroidMediaLibrary::playlists(const medialibrary::QueryParameters* params)
379
{
380
    return p_ml->playlists(params);
381 382 383 384 385 386 387 388 389 390 391 392 393 394
}

medialibrary::PlaylistPtr
AndroidMediaLibrary::playlist( int64_t playlistId )
{
    return p_ml->playlist(playlistId);
}

medialibrary::PlaylistPtr
AndroidMediaLibrary::PlaylistCreate( const std::string &name )
{
    return p_ml->createPlaylist(name);
}

395
medialibrary::Query<medialibrary::IMedia>
396
AndroidMediaLibrary::tracksFromAlbum( int64_t albumId, const medialibrary::QueryParameters* params )
397
{
398
    auto album = p_ml->album(albumId);
399
    return album == nullptr ? nullptr : album->tracks(params);
400 401
}

402
medialibrary::Query<medialibrary::IMedia>
403
AndroidMediaLibrary::mediaFromArtist( int64_t artistId, const medialibrary::QueryParameters* params )
404
{
405
    auto artist = p_ml->artist(artistId);
406
    return artist == nullptr ? nullptr : artist->tracks(params);
407 408
}

409
medialibrary::Query<medialibrary::IAlbum>
410
AndroidMediaLibrary::albumsFromArtist( int64_t artistId, const medialibrary::QueryParameters* params )
411
{
412
    auto artist = p_ml->artist(artistId);
413
    return artist == nullptr ? nullptr : artist->albums(params);
414 415
}

416
medialibrary::Query<medialibrary::IMedia>
417
AndroidMediaLibrary::mediaFromGenre( int64_t genreId, const medialibrary::QueryParameters* params )
418
{
419
    auto genre = p_ml->genre(genreId);
420
    return genre == nullptr ? nullptr : genre->tracks(params);
421 422
}

423
medialibrary::Query<medialibrary::IAlbum>
424
AndroidMediaLibrary::albumsFromGenre( int64_t genreId, const medialibrary::QueryParameters* params )
425
{
426
    auto genre = p_ml->genre(genreId);
427
    return genre == nullptr ? nullptr : genre->albums(params);
428 429
}

430
medialibrary::Query<medialibrary::IArtist>
431
AndroidMediaLibrary::artistsFromGenre( int64_t genreId, const medialibrary::QueryParameters* params )
432
{
433
    auto genre = p_ml->genre(genreId);
434
    return genre == nullptr ? nullptr : genre->artists(params);
435 436
}

437
medialibrary::Query<medialibrary::IMedia>
438 439
AndroidMediaLibrary::mediaFromPlaylist( int64_t playlistId )
{
440
    auto playlist =  p_ml->playlist(playlistId);
441
    return playlist == nullptr ? nullptr : playlist->media();
442 443 444 445 446
}

bool
AndroidMediaLibrary::playlistAppend(int64_t playlistId, int64_t mediaId) {
    medialibrary::PlaylistPtr playlist = p_ml->playlist(playlistId);
447
    return playlist == nullptr ? false : playlist->append(mediaId);
448 449 450 451 452
}

bool
AndroidMediaLibrary::playlistAdd(int64_t playlistId, int64_t mediaId, unsigned int position) {
    medialibrary::PlaylistPtr playlist = p_ml->playlist(playlistId);
453
    return playlist == nullptr ? false : playlist->add(mediaId, position);
454 455 456 457 458
}

bool
AndroidMediaLibrary::playlistMove(int64_t playlistId, int64_t mediaId, unsigned int position) {
    medialibrary::PlaylistPtr playlist = p_ml->playlist(playlistId);
459
    return playlist == nullptr ? false : playlist->move(mediaId, position);
460 461 462 463 464
}

bool
AndroidMediaLibrary::playlistRemove(int64_t playlistId, int64_t mediaId) {
    medialibrary::PlaylistPtr playlist = p_ml->playlist(playlistId);
465
    return playlist == nullptr ? false : playlist->remove(mediaId);
466 467 468 469 470 471 472 473
}

bool
AndroidMediaLibrary::PlaylistDelete( int64_t playlistId )
{
    return p_ml->deletePlaylist(playlistId);
}

474
medialibrary::Query<medialibrary::IFolder>
475
AndroidMediaLibrary::folders(const medialibrary::QueryParameters* params, medialibrary::IMedia::Type type)
476
{
477
    return p_ml->folders(type, params);
478 479 480 481 482 483 484 485 486 487 488 489 490 491 492
}

medialibrary::Query<medialibrary::IMedia>
AndroidMediaLibrary::mediaFromFolder(int64_t folderId, medialibrary::IMedia::Type type, const medialibrary::QueryParameters* params )
{
    medialibrary::FolderPtr folder = p_ml->folder(folderId);
    return folder != nullptr ? folder->media(type, params) : nullptr;
}

medialibrary::Query<medialibrary::IFolder> AndroidMediaLibrary::subFolders(int64_t folderId, const medialibrary::QueryParameters* params )
{
    medialibrary::FolderPtr folder = p_ml->folder(folderId);
    return folder != nullptr ? folder->subfolders(params) : nullptr;
}

493 494 495 496 497 498 499
void
AndroidMediaLibrary::requestThumbnail( int64_t media_id )
{
    medialibrary::MediaPtr media = p_ml->media(media_id);
    if (media != nullptr) p_ml->requestThumbnail(media);
}

500
void
501
AndroidMediaLibrary::onMediaAdded( std::vector<medialibrary::MediaPtr> mediaList )
502
{
503
    if (m_mediaAddedType & (FLAG_MEDIA_ADDED_AUDIO | FLAG_MEDIA_ADDED_VIDEO | FLAG_MEDIA_ADDED_AUDIO_EMPTY | FLAG_MEDIA_ADDED_VIDEO_EMPTY)) {
504 505 506
        JNIEnv *env = getEnv();
        if (env == NULL /*|| env->IsSameObject(weak_thiz, NULL)*/)
            return;
507
        jobjectArray mediaRefs, results;
508
        int index;
509
        if ((m_mediaAddedType & (FLAG_MEDIA_ADDED_AUDIO|FLAG_MEDIA_ADDED_VIDEO)) == 0)
510 511 512 513 514 515 516
        {
            index = 0;
            mediaRefs = (jobjectArray) env->NewObjectArray(0, p_fields->MediaWrapper.clazz, NULL);
        } else
        {
            mediaRefs = (jobjectArray) env->NewObjectArray(mediaList.size(), p_fields->MediaWrapper.clazz, NULL);
            index = -1;
517
            jobject item;
518 519
            for (medialibrary::MediaPtr const& media : mediaList) {
                medialibrary::IMedia::Type type = media->type();
520 521 522 523 524
                if ((type == medialibrary::IMedia::Type::Audio && m_mediaAddedType & FLAG_MEDIA_ADDED_AUDIO) ||
                        (type == medialibrary::IMedia::Type::Video && m_mediaAddedType & FLAG_MEDIA_ADDED_VIDEO))
                    item = mediaToMediaWrapper(env, p_fields, media);
                else
                    item = nullptr;
525
                env->SetObjectArrayElement(mediaRefs, ++index, item);
526 527
                if (item != nullptr)
                    env->DeleteLocalRef(item);
528 529 530 531 532
            }
        }

        if (index > -1)
        {
533
            if (weak_thiz)
534
            {
Geoffrey Métais's avatar
Geoffrey Métais committed
535
                results = filteredArray(env, mediaRefs, p_fields->MediaWrapper.clazz, -1);
536
                env->CallVoidMethod(weak_thiz, p_fields->MediaLibrary.onMediaAddedId, results);
537 538 539
                env->DeleteLocalRef(results);
            } else
                env->DeleteLocalRef(mediaRefs);
540 541 542 543
        }
    }
}

544
void AndroidMediaLibrary::onMediaModified( std::vector<medialibrary::MediaPtr> mediaList )
545 546 547 548 549 550
{
    if (m_mediaUpdatedType & FLAG_MEDIA_UPDATED_AUDIO || m_mediaUpdatedType & FLAG_MEDIA_UPDATED_VIDEO
            || m_mediaUpdatedType & FLAG_MEDIA_UPDATED_AUDIO_EMPTY) {
        JNIEnv *env = getEnv();
        if (env == NULL)
            return;
551
        jobjectArray mediaRefs, results;
552
        int index;
553
        if ((m_mediaUpdatedType & (FLAG_MEDIA_UPDATED_AUDIO|FLAG_MEDIA_UPDATED_VIDEO)) == 0)
554 555 556 557 558 559 560
        {
            index = 0;
            mediaRefs = (jobjectArray) env->NewObjectArray(0, p_fields->MediaWrapper.clazz, NULL);
        } else
        {
            mediaRefs = (jobjectArray) env->NewObjectArray(mediaList.size(), p_fields->MediaWrapper.clazz, NULL);
            index = -1;
561
            jobject item;
562 563
            for (medialibrary::MediaPtr const& media : mediaList) {
                medialibrary::IMedia::Type type = media->type();
564 565 566 567 568
                if ((type == medialibrary::IMedia::Type::Audio && m_mediaUpdatedType & FLAG_MEDIA_UPDATED_AUDIO) ||
                        (type == medialibrary::IMedia::Type::Video && m_mediaUpdatedType & FLAG_MEDIA_UPDATED_VIDEO))
                    item = mediaToMediaWrapper(env, p_fields, media);
                else
                    item = nullptr;
569
                env->SetObjectArrayElement(mediaRefs, ++index, item);
570 571
                if (item != nullptr)
                    env->DeleteLocalRef(item);
572 573 574 575
            }
        }
        if (index > -1)
        {
Geoffrey Métais's avatar
Geoffrey Métais committed
576
            results = filteredArray(env, mediaRefs, p_fields->MediaWrapper.clazz, -1);
577
            if (weak_thiz)
578
            {
579
                env->CallVoidMethod(weak_thiz, p_fields->MediaLibrary.onMediaUpdatedId, results);
580 581 582
                env->DeleteLocalRef(results);
            } else
                env->DeleteLocalRef(mediaRefs);
583 584 585 586
        }
    }
}

587
void AndroidMediaLibrary::onMediaDeleted( std::vector<int64_t> ids )
588
{
589 590 591 592 593
    if (m_mediaAddedType & (FLAG_MEDIA_ADDED_AUDIO_EMPTY|FLAG_MEDIA_ADDED_AUDIO|FLAG_MEDIA_ADDED_VIDEO|FLAG_MEDIA_ADDED_VIDEO_EMPTY))
    {
        JNIEnv *env = getEnv();
        if (env != NULL && weak_thiz) env->CallVoidMethod(weak_thiz, p_fields->MediaLibrary.onMediaDeletedId);
    }
594 595
}

596
void AndroidMediaLibrary::onArtistsAdded( std::vector<medialibrary::ArtistPtr> artists )
597
{
Geoffrey Métais's avatar
Geoffrey Métais committed
598
    if (m_mediaAddedType & (FLAG_MEDIA_ADDED_AUDIO_EMPTY|FLAG_MEDIA_ADDED_AUDIO))
599 600
    {
        JNIEnv *env = getEnv();
Geoffrey Métais's avatar
Geoffrey Métais committed
601 602
        if (env == NULL) return;
        if (weak_thiz) env->CallVoidMethod(weak_thiz, p_fields->MediaLibrary.onArtistsAddedId);
603 604 605
    }
}

606
void AndroidMediaLibrary::onArtistsModified( std::vector<medialibrary::ArtistPtr> artist )
607
{
608
    if (m_mediaUpdatedType & (FLAG_MEDIA_UPDATED_AUDIO|FLAG_MEDIA_UPDATED_AUDIO_EMPTY))
609 610
    {
        JNIEnv *env = getEnv();
611 612
        if (env == NULL) return;
        if (weak_thiz)
613
        {
614
            env->CallVoidMethod(weak_thiz, p_fields->MediaLibrary.onArtistsModifiedId);
615 616 617 618
        }
    }
}

619
void AndroidMediaLibrary::onArtistsDeleted( std::vector<int64_t> ids )
620
{
621 622 623 624 625 626 627 628
    if (m_mediaUpdatedType & (FLAG_MEDIA_UPDATED_AUDIO|FLAG_MEDIA_UPDATED_AUDIO_EMPTY))
    {
        JNIEnv *env = getEnv();
        if (env != NULL || weak_thiz)
        {
            env->CallVoidMethod(weak_thiz, p_fields->MediaLibrary.onArtistsDeletedId);
        }
    }
629 630
}

631
void AndroidMediaLibrary::onAlbumsAdded( std::vector<medialibrary::AlbumPtr> albums )
632
{
633
    if (m_mediaAddedType & (FLAG_MEDIA_ADDED_AUDIO|FLAG_MEDIA_ADDED_AUDIO_EMPTY))
634 635
    {
        JNIEnv *env = getEnv();
636 637
        if (env == NULL) return;
        if (weak_thiz)
638
        {
639
            env->CallVoidMethod(weak_thiz, p_fields->MediaLibrary.onAlbumsAddedId);
640 641 642 643
        }
    }
}

644
void AndroidMediaLibrary::onAlbumsModified( std::vector<medialibrary::AlbumPtr> albums )
645
{
646
    if (m_mediaUpdatedType & (FLAG_MEDIA_UPDATED_AUDIO|FLAG_MEDIA_UPDATED_AUDIO_EMPTY))
647 648
    {
        JNIEnv *env = getEnv();
649 650
        if (env == NULL) return;
        if (weak_thiz)
651
        {
652
            env->CallVoidMethod(weak_thiz, p_fields->MediaLibrary.onAlbumsModifiedId);
653 654 655 656
        }
    }
}

657
void AndroidMediaLibrary::onPlaylistsAdded( std::vector<medialibrary::PlaylistPtr> playlists )
658
{
659
    if (m_mediaAddedType & (FLAG_MEDIA_ADDED_AUDIO|FLAG_MEDIA_ADDED_AUDIO_EMPTY))
660 661 662 663 664 665 666 667
    {
        JNIEnv *env = getEnv();
        if (env == NULL) return;
        if (weak_thiz)
        {
            env->CallVoidMethod(weak_thiz, p_fields->MediaLibrary.onPlaylistsAddedId);
        }
    }
668 669 670

}

671
void AndroidMediaLibrary::onPlaylistsModified( std::vector<medialibrary::PlaylistPtr> playlist )
672
{
673
    if (m_mediaUpdatedType & (FLAG_MEDIA_UPDATED_AUDIO|FLAG_MEDIA_UPDATED_AUDIO_EMPTY))
674 675 676 677 678 679 680 681
    {
        JNIEnv *env = getEnv();
        if (env == NULL) return;
        if (weak_thiz)
        {
            env->CallVoidMethod(weak_thiz, p_fields->MediaLibrary.onPlaylistsModifiedId);
        }
    }
682 683
}

684
void AndroidMediaLibrary::onPlaylistsDeleted( std::vector<int64_t> ids )
685
{
686
    if (m_mediaUpdatedType & (FLAG_MEDIA_UPDATED_AUDIO|FLAG_MEDIA_UPDATED_AUDIO_EMPTY))
687 688 689 690 691 692 693 694
    {
        JNIEnv *env = getEnv();
        if (env == NULL) return;
        if (weak_thiz)
        {
            env->CallVoidMethod(weak_thiz, p_fields->MediaLibrary.onPlaylistsDeletedId);
        }
    }
695 696
}

697
void AndroidMediaLibrary::onGenresAdded( std::vector<medialibrary::GenrePtr> )
698
{
699
    if (m_mediaAddedType & (FLAG_MEDIA_ADDED_AUDIO|FLAG_MEDIA_ADDED_AUDIO_EMPTY))
700 701 702 703 704 705 706 707
    {
        JNIEnv *env = getEnv();
        if (env == NULL) return;
        if (weak_thiz)
        {
            env->CallVoidMethod(weak_thiz, p_fields->MediaLibrary.onGenresAddedId);
        }
    }
708 709
}

710
void AndroidMediaLibrary::onGenresModified( std::vector<medialibrary::GenrePtr> )
711
{
712
    if (m_mediaUpdatedType & (FLAG_MEDIA_UPDATED_AUDIO|FLAG_MEDIA_UPDATED_AUDIO_EMPTY))
713 714 715 716 717 718 719 720
    {
        JNIEnv *env = getEnv();
        if (env == NULL) return;
        if (weak_thiz)
        {
            env->CallVoidMethod(weak_thiz, p_fields->MediaLibrary.onGenresModifiedId);
        }
    }
721 722
}

723
void AndroidMediaLibrary::onGenresDeleted( std::vector<int64_t> )
724
{
725
    if (m_mediaUpdatedType & (FLAG_MEDIA_UPDATED_AUDIO|FLAG_MEDIA_UPDATED_AUDIO_EMPTY))
726 727 728 729 730 731 732 733
    {
        JNIEnv *env = getEnv();
        if (env == NULL) return;
        if (weak_thiz)
        {
            env->CallVoidMethod(weak_thiz, p_fields->MediaLibrary.onGenresDeletedId);
        }
    }
734 735
}

736
void AndroidMediaLibrary::onAlbumsDeleted( std::vector<int64_t> )
737
{
738
    if (m_mediaUpdatedType & (FLAG_MEDIA_UPDATED_AUDIO|FLAG_MEDIA_UPDATED_AUDIO_EMPTY))
739 740 741 742 743 744 745 746
    {
        JNIEnv *env = getEnv();
        if (env == NULL) return;
        if (weak_thiz)
        {
            env->CallVoidMethod(weak_thiz, p_fields->MediaLibrary.onAlbumsDeletedId);
        }
    }
747 748 749 750 751 752
}

void AndroidMediaLibrary::onDiscoveryStarted( const std::string& entryPoint )
{
    ++m_nbDiscovery;
    JNIEnv *env = getEnv();
753
    if (env == NULL) return;
754
    jstring ep = env->NewStringUTF(entryPoint.c_str());
755
    if (weak_thiz)
756
    {
757
        env->CallVoidMethod(weak_thiz, p_fields->MediaLibrary.onDiscoveryStartedId, ep);
758 759 760 761 762 763 764
    }
    env->DeleteLocalRef(ep);
}

void AndroidMediaLibrary::onDiscoveryProgress( const std::string& entryPoint )
{
    JNIEnv *env = getEnv();
765
    if (env == NULL) return;
766
    jstring ep = env->NewStringUTF(entryPoint.c_str());
767
    if (weak_thiz)
768
    {
769
        env->CallVoidMethod(weak_thiz, p_fields->MediaLibrary.onDiscoveryProgressId, ep);
770 771 772 773 774
    }
    env->DeleteLocalRef(ep);

}

775
void AndroidMediaLibrary::onDiscoveryCompleted( const std::string& entryPoint, bool success )
776 777 778 779 780 781
{
    --m_nbDiscovery;
    JNIEnv *env = getEnv();
    if (env == NULL)
        return;
    jstring ep = env->NewStringUTF(entryPoint.c_str());
782 783
    if (weak_thiz)
    {
784
        if (m_progress)
785 786
            env->CallVoidMethod(weak_thiz, p_fields->MediaLibrary.onParsingStatsUpdatedId, m_progress);
        env->CallVoidMethod(weak_thiz, p_fields->MediaLibrary.onDiscoveryCompletedId, ep);
787 788 789 790
    }
    env->DeleteLocalRef(ep);
}

791 792
void AndroidMediaLibrary::onReloadStarted( const std::string& entryPoint )
{
793
    JNIEnv *env = getEnv();
794
    if (env == NULL) return;
795
    jstring ep = env->NewStringUTF(entryPoint.c_str());
796 797 798
    if (weak_thiz)
    {
        env->CallVoidMethod(weak_thiz, p_fields->MediaLibrary.onReloadStartedId, ep);
799 800
    }
    env->DeleteLocalRef(ep);
801 802
}

803
void AndroidMediaLibrary::onReloadCompleted( const std::string& entryPoint, bool success )
804
{
805
    JNIEnv *env = getEnv();
806
    if (env == NULL) return;
807
    jstring ep = env->NewStringUTF(entryPoint.c_str());
808 809
    if (weak_thiz)
    {
810
        if (m_progress)
811 812
            env->CallVoidMethod(weak_thiz, p_fields->MediaLibrary.onParsingStatsUpdatedId, m_progress);
        env->CallVoidMethod(weak_thiz, p_fields->MediaLibrary.onReloadCompletedId, ep);
813 814
    }
    env->DeleteLocalRef(ep);
815 816 817 818
}

void AndroidMediaLibrary::onEntryPointBanned( const std::string& entryPoint, bool success )
{
819
    JNIEnv *env = getEnv();
820
    if (env == NULL) return;
821
    jstring ep = env->NewStringUTF(entryPoint.c_str());
822 823 824
    if (weak_thiz)
    {
        env->CallVoidMethod(weak_thiz, p_fields->MediaLibrary.onEntryPointBannedId, ep, success);
825 826
    }
    env->DeleteLocalRef(ep);
827 828 829 830
}

void AndroidMediaLibrary::onEntryPointUnbanned( const std::string& entryPoint, bool success )
{
831 832 833 834
    JNIEnv *env = getEnv();
    if (env == NULL)
        return;
    jstring ep = env->NewStringUTF(entryPoint.c_str());
835 836 837
    if (weak_thiz)
    {
        env->CallVoidMethod(weak_thiz, p_fields->MediaLibrary.onEntryPointUnbannedId, ep, success);
838 839
    }
    env->DeleteLocalRef(ep);
840 841 842 843
}

void AndroidMediaLibrary::onEntryPointRemoved( const std::string& entryPoint, bool success )
{
844
    JNIEnv *env = getEnv();
845
    if (env == NULL) return;
846
    jstring ep = env->NewStringUTF(entryPoint.c_str());
847 848 849
    if (weak_thiz)
    {
        env->CallVoidMethod(weak_thiz, p_fields->MediaLibrary.onEntryPointRemovedId, ep, success);
850 851
    }
    env->DeleteLocalRef(ep);
852 853
}

854 855 856 857
void AndroidMediaLibrary::onParsingStatsUpdated( uint32_t percent)
{
    m_progress = percent;
    JNIEnv *env = getEnv();
858
    if (env == NULL) return;
859
    jint progress = percent;
860
    if (weak_thiz)
861
    {
862
        env->CallVoidMethod(weak_thiz, p_fields->MediaLibrary.onParsingStatsUpdatedId, progress);
863 864 865
    }
}

866 867 868 869

void AndroidMediaLibrary::onBackgroundTasksIdleChanged( bool isIdle )
{
    JNIEnv *env = getEnv();
870 871
    if (env == NULL) return;
    if (weak_thiz)
872
    {
873
        env->CallVoidMethod(weak_thiz, p_fields->MediaLibrary.onBackgroundTasksIdleChangedId, isIdle);
874 875 876
    }
}

877 878 879 880 881 882 883 884 885 886
void AndroidMediaLibrary::onMediaThumbnailReady( medialibrary::MediaPtr media, bool success )
{
    JNIEnv *env = getEnv();
    if (env != NULL && weak_thiz)
    {
        auto item = mediaToMediaWrapper(env, p_fields, media);
        env->CallVoidMethod(weak_thiz, p_fields->MediaLibrary.onMediaThumbnailReadyId, item, success);
    }
}

887 888 889 890 891 892 893 894 895 896
JNIEnv *
AndroidMediaLibrary::getEnv() {
    JNIEnv *env = (JNIEnv *)pthread_getspecific(jni_env_key);
    if (!env)
    {
        switch (myVm->GetEnv((void**)(&env), VLC_JNI_VERSION))
        {
        case JNI_OK:
            break;
        case JNI_EDETACHED:
897 898 899 900 901 902
            /* attach the thread to the Java VM */
            JavaVMAttachArgs args;
            args.version = VLC_JNI_VERSION;
            args.name = THREAD_NAME;
            args.group = NULL;
            if (myVm->AttachCurrentThread(&env, &args) != JNI_OK)
903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920
                return NULL;
            if (pthread_setspecific(jni_env_key, env) != 0)
            {
                detachCurrentThread();
                return NULL;
            }
            break;
        default:
            LOGE("failed to get env");
        }
    }
    return env;
}

void
AndroidMediaLibrary::detachCurrentThread() {
    myVm->DetachCurrentThread();
}