/*************************************************************************** * __________ __ ___. * Open \______ \ ____ ____ | | _\_ |__ _______ ___ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ * $Id$ * * Copyright (C) 2006 Dave Chapman * * All files in this archive are subject to the GNU General Public License. * See the file COPYING in the source tree root for full license agreement. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ****************************************************************************/ #include #include "config.h" #include "lcd.h" #ifdef HAVE_REMOTE_LCD #include "lcd-remote.h" #endif #include "backdrop.h" #if LCD_DEPTH >= 8 static fb_data main_backdrop[LCD_HEIGHT][LCD_WIDTH] __attribute__ ((aligned (16))); static fb_data wps_backdrop[LCD_HEIGHT][LCD_WIDTH] __attribute__ ((aligned (16))); #elif LCD_DEPTH == 2 static fb_data main_backdrop[LCD_FBHEIGHT][LCD_FBWIDTH]; static fb_data wps_backdrop[LCD_FBHEIGHT][LCD_FBWIDTH]; #endif #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 static fb_remote_data remote_wps_backdrop[LCD_REMOTE_FBHEIGHT][LCD_REMOTE_FBWIDTH]; static bool remote_wps_backdrop_valid = false; #endif static bool main_backdrop_valid = false; static bool wps_backdrop_valid = false; /* load a backdrop into a buffer */ static bool load_backdrop(char* filename, fb_data* backdrop_buffer) { struct bitmap bm; int ret; /* load the image */ bm.data=(char*)backdrop_buffer; ret = read_bmp_file(filename, &bm, sizeof(main_backdrop), FORMAT_NATIVE | FORMAT_DITHER); if ((ret > 0) && (bm.width == LCD_WIDTH) && (bm.height == LCD_HEIGHT)) { return true; } else { return false; } } bool load_main_backdrop(char* filename) { main_backdrop_valid = load_backdrop(filename, &main_backdrop[0][0]); return main_backdrop_valid; } bool load_wps_backdrop(char* filename) { wps_backdrop_valid = load_backdrop(filename, &wps_backdrop[0][0]); return wps_backdrop_valid; } void unload_main_backdrop(void) { main_backdrop_valid = false; } void unload_wps_backdrop(void) { wps_backdrop_valid = false; } void show_main_backdrop(void) { lcd_set_backdrop(main_backdrop_valid ? &main_backdrop[0][0] : NULL); } void show_wps_backdrop(void) { /* if no wps backdrop, fall back to main backdrop */ if(wps_backdrop_valid) { lcd_set_backdrop(&wps_backdrop[0][0]); } else { show_main_backdrop(); } } #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 static bool load_remote_backdrop(char* filename, fb_remote_data* backdrop_buffer) { struct bitmap bm; int ret; /* load the image */ bm.data=(char*)backdrop_buffer; ret = read_bmp_file(filename, &bm, sizeof(main_backdrop), FORMAT_NATIVE | FORMAT_DITHER | FORMAT_REMOTE); if ((ret > 0) && (bm.width == LCD_REMOTE_WIDTH) && (bm.height == LCD_REMOTE_HEIGHT)) { return true; } else { return false; } } bool load_remote_wps_backdrop(char* filename) { remote_wps_backdrop_valid = load_remote_backdrop(filename, &remote_wps_backdrop[0][0]); return remote_wps_backdrop_valid; } void unload_remote_wps_backdrop(void) { remote_wps_backdrop_valid = false; } void show_remote_wps_backdrop(void) { /* if no wps backdrop, fall back to main backdrop */ if(remote_wps_backdrop_valid) { lcd_remote_set_backdrop(&remote_wps_backdrop[0][0]); } else { show_remote_main_backdrop(); } } void show_remote_main_backdrop(void) { lcd_remote_set_backdrop(NULL); } #endif > 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
/***************************************************************************
 *             __________               __   ___.
 *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
 *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
 *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
 *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
 *                     \/            \/     \/    \/            \/
 * $Id$
 *
 * Copyright (C) 2010 Thomas Martitz
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
 * KIND, either express or implied.
 *
 ****************************************************************************/

#include <jni.h>
#include <stdio.h>
#include <sys/mman.h>
#include "notification.h"
#include "appevents.h"
#include "metadata.h"
#include "albumart.h"
#include "misc.h"
#include "thread.h"
#include "debug.h"

extern JNIEnv *env_ptr;
extern jclass RockboxService_class;
extern jobject RockboxService_instance;

static jmethodID updateNotification, finishNotification;
static jobject NotificationManager_instance;
static jstring title, artist, album, albumart;

/* completely arbitrary dimensions. neded for find_albumart() */
static const struct dim dim = { .width = 200, .height = 200 };
#define NZV(a) (a && a[0])

/*
 * notify about track change, and show track info */
static void track_changed_callback(void *param)
{
    struct mp3entry* id3 = ((struct track_event *)param)->id3;
    JNIEnv e = *env_ptr;
    if (id3)
    {
        /* passing NULL to DeleteLocalRef() is OK */
        e->DeleteLocalRef(env_ptr, title);
        e->DeleteLocalRef(env_ptr, artist);
        e->DeleteLocalRef(env_ptr, album);
        e->DeleteLocalRef(env_ptr, albumart);

        char buf[200];
        const char * ptitle = id3->title;
        if (!ptitle && *id3->path)
        {   /* pass the filename as title if id3 info isn't available */
            ptitle = strip_extension(buf, sizeof(buf), strrchr(id3->path,'/') + 1);
        }

        title = e->NewStringUTF(env_ptr, ptitle ?: "");
        artist = e->NewStringUTF(env_ptr, id3->artist ?: "");
        album = e->NewStringUTF(env_ptr, id3->album ?: "");

        albumart = NULL;
        if (id3->has_embedded_albumart && id3->albumart.type == AA_TYPE_JPG)
        {   /* extract albumart to a temporary file using mmap() */
            snprintf(buf, sizeof(buf), "/sdcard/rockbox/.temp_albumart_%d.jpg",
                     thread_self());
            int dst_fd = creat(buf, 0666);
            if (dst_fd >= 0)
            {
                int src_fd = open(id3->path, O_RDONLY);
                off_t o_pos = id3->albumart.pos;
                off_t pa_pos = o_pos & ~(sysconf(_SC_PAGE_SIZE) - 1);
                if (src_fd >= 0)
                {   /* align to page boundary */
                    int pos_diff = o_pos - pa_pos;
                    unsigned char* p = mmap(NULL, id3->albumart.size + pos_diff,
                                        PROT_READ, MAP_SHARED, src_fd, pa_pos);
                    if (p != MAP_FAILED)
                    {
                        write(dst_fd, p + pos_diff, id3->albumart.size);
                        munmap(p, id3->albumart.size + pos_diff);
                        albumart = e->NewStringUTF(env_ptr, buf);
                    }
                    close(src_fd);
                }
                close(dst_fd);
            }
        }
        else if (find_albumart(id3, buf, sizeof(buf), &dim))
        {
            albumart = e->NewStringUTF(env_ptr, buf);
        }

        e->CallVoidMethod(env_ptr, NotificationManager_instance,
                      updateNotification, title, artist, album, albumart);
    }
}

/*
 * notify about track finishing */
static void track_finished_callback(void *param)
{
    if (((struct track_event *)param)->flags & TEF_REWIND)
        return; /* Not a true track end */

    JNIEnv e = *env_ptr;
    e->CallVoidMethod(env_ptr, NotificationManager_instance,
                      finishNotification);

    /* delete temporary albumart file */
    char buf[MAX_PATH];
    snprintf(buf, sizeof(buf), "/sdcard/rockbox/.temp_albumart_%d.jpg",
                     thread_self());
    unlink(buf);
}

void notification_init(void)
{
    JNIEnv e = *env_ptr;
    jfieldID nNM = e->GetFieldID(env_ptr, RockboxService_class,
                    "mFgRunner", "Lorg/rockbox/Helper/RunForegroundManager;");
    NotificationManager_instance = e->GetObjectField(env_ptr,
                                                RockboxService_instance, nNM);
    if (NotificationManager_instance == NULL)
    {
        DEBUGF("Failed to get RunForegroundManager instance. Performance will be bad");
        return;
    }

    jclass class = e->GetObjectClass(env_ptr, NotificationManager_instance);
    updateNotification = e->GetMethodID(env_ptr, class, "updateNotification",
                                         "(Ljava/lang/String;"
                                         "Ljava/lang/String;"
                                         "Ljava/lang/String;"
                                         "Ljava/lang/String;)V");
    finishNotification = e->GetMethodID(env_ptr, class, "finishNotification",
                                        "()V");

    add_event(PLAYBACK_EVENT_TRACK_CHANGE, false, track_changed_callback);
    add_event(PLAYBACK_EVENT_TRACK_FINISH, false, track_finished_callback);
}