/* * Copyright (C) 2008 Josh Guilfoyle <jasta@devtcg.org> * * 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, or (at your option) any * later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. */ package org.devtcg.five.provider; import org.devtcg.five.provider.AbstractTableMerger.SyncableColumns; import android.content.Context; import android.database.Cursor; import android.net.Uri; import android.provider.BaseColumns; /** * Structured representation of the Five Meta Data ContentProvider. * * @todo This class needs to be refactored significantly. It's gotten way too * muddled and confused... */ public final class Five { public static final String AUTHORITY = "org.devtcg.five"; public static Uri makeArtistPhotoUri(long id) { return Five.Music.Artists.CONTENT_URI.buildUpon() .appendEncodedPath(String.valueOf(id)) .appendEncodedPath("photo") .build(); } public static Uri makeAlbumArtworkUri(long id) { return Five.Music.Albums.CONTENT_URI.buildUpon() .appendPath(String.valueOf(id)) .appendPath("artwork") .build(); } public static Uri makeAlbumArtworkBigUri(long id) { return Five.Music.Albums.CONTENT_URI.buildUpon() .appendEncodedPath(String.valueOf(id)) .appendEncodedPath("artwork") .appendEncodedPath("big") .build(); } public static Uri makeArtistAlbumsUri(Uri artistUri) { return artistUri.buildUpon().appendEncodedPath("albums").build(); } private static String makeCreateDeletedTablesSQL(String deletedTable) { return "CREATE TABLE " + deletedTable + " (" + SyncableColumns._ID + " INTEGER PRIMARY KEY, " + SyncableColumns._SYNC_ID + " INTEGER, " + SyncableColumns._SYNC_TIME + " BIGINT)"; } /** * Concrete synchronization source. Under this implementation, a TCP * server on the Internet. */ public interface Sources extends BaseColumns { public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.five.source"; public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.five.source"; /** Access URI. */ public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/sources"); /** Hostname or IP address. */ public static final String HOST = "host"; /** Listening port. */ public static final String PORT = "port"; /** * Hashed mutation of the password originally given by the user (cannot * be decoded, sent verbatim to the server as an authentication token) */ public static final String PASSWORD = "password"; /** * Last successful sync time in milliseconds. This field should be used * for display purposes only. */ public static final String LAST_SYNC_TIME = "revision"; /** * Current status as updated by the sync process. This is used a way to * watch the sync progress. */ public static final String STATUS = "status"; public static final class SQL { public static final String TABLE = "sources"; public static final String CREATE = "CREATE TABLE " + TABLE + " (" + "_id INTEGER PRIMARY KEY AUTOINCREMENT, " + HOST + " TEXT UNIQUE NOT NULL, " + PORT + " INTEGER NOT NULL, " + PASSWORD + " TEXT NOT NULL, " + LAST_SYNC_TIME + " INTEGER, " + STATUS + " TEXT " + ");"; // public static final String INSERT_DUMMY = // "INSERT INTO " + TABLE + " (" + // NAME + ", " + // HOST + ", " + // PORT + ", " + // REVISION + // ") VALUES (" + // "\"Home\", " + // "\"10.1.0.175\", " + // "5545, " + // "0 " + // ");"; public static final String DROP = "DROP TABLE IF EXISTS " + TABLE; } } // /** // * Generic columns available for all types of media. // * // * @deprecated this abstraction away from the Songs table is complicated and // * unnecessary, and will therefore be removed in the future. // */ // public interface Content extends SyncableColumns // { // public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.five.media"; // public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.five.media"; // // /** Access URI. */ // public static final Uri CONTENT_URI = // Uri.parse("content://" + AUTHORITY + "/content"); // // /** Access URI for exclusively cached entries. */ // public static final Uri CONTENT_URI_CACHED = // Uri.parse("content://" + AUTHORITY + "/cache"); // // /** // * Server content ID. This is the item's GUID at the server. Not // * to be confused by similarly named fields which key into this // * table. // */ // public static final String CONTENT_ID = "content_id"; // // /** Server source. */ // public static final String SOURCE_ID = "source_id"; // // /** Media meta data. */ // public static final String MIME_TYPE = "mime_type"; // // /** Raw media size in bytes. */ // public static final String SIZE = "size"; // // /** Timestamp of the cached entry, if present. */ // public static final String CACHED_TIMESTAMP = "cached_timestamp"; // // /** Reference to cache table if cached; otherwise NULL. */ // public static final String CACHED_PATH = "cached_path"; // // public static final class SQL // { // public static final String TABLE = "content"; // // public static final String CREATE = // "CREATE TABLE " + TABLE + " (" + // _ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " + // _SYNC_ID + " INTEGER, " + // _SYNC_TIME + " BIGINT, " + // CONTENT_ID + " INTEGER NOT NULL, " + // SOURCE_ID + " INTEGER NOT NULL, " + // MIME_TYPE + " TEXT NOT NULL, " + // SIZE + " INTEGER NOT NULL, " + // CACHED_TIMESTAMP + " INTEGER, " + // CACHED_PATH + " TEXT " + // ");"; // // public static final String[] INDEX = // { // "CREATE UNIQUE INDEX " + // TABLE + "_" + SOURCE_ID + "_" + CONTENT_ID + // " ON " + TABLE + " (" + // SOURCE_ID + ", " + // CONTENT_ID + " " + // ");", // "CREATE INDEX " + // TABLE + "_" + CACHED_TIMESTAMP + // " ON " + TABLE + " (" + // CACHED_TIMESTAMP + // ");", // "CREATE UNIQUE INDEX " + // TABLE + "_" + _SYNC_ID + // " ON " + TABLE + " (" + // _SYNC_ID + // ");", // }; // // public static final String DROP = // "DROP TABLE IF EXISTS " + TABLE + ";"; // } // } public interface Images extends BaseColumns { public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.five.image"; public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.five.image"; /** Access URI. */ public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/media/images"); /** Key to access potentially cached or remote data. */ public static final String CONTENT_ID = "content_id"; /** Title, if any; otherwise, filename. */ public static final String TITLE = "title"; /** Image dimension: width. */ public static final String NATIVE_WIDTH = "width"; /** Image dimension: height. */ public static final String NATIVE_HEIGHT = "height"; } public static final class Music { /** * Last time an item (album, song, playlist, ...) was listened to * on the device (client-side). */ public static final String LAST_PLAYED = "last_played"; public interface Songs extends SyncableColumns { public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.five.music.song"; public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.five.music.song"; /** Access URI. */ public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/media/music/songs"); public static final Uri CONTENT_DELETED_URI = Uri.parse("content://" + AUTHORITY + "/media/music/songs/deleted"); /** * Server source, used to join Content and Songs during sync * merging. * <p> * XXX: This is broken by AbstractTableMerger, which only cares * about _SYNC_ID and not jointly _SYNC_ID and SOURCE_ID. */ public static final String SOURCE_ID = "source_id"; /** Media meta data. */ public static final String MIME_TYPE = "mime_type"; /** Raw media size in bytes. */ public static final String SIZE = "size"; /** Timestamp of the cached entry, if present. */ public static final String CACHED_TIMESTAMP = "cached_timestamp"; /** Reference to cache table if cached; otherwise NULL. */ public static final String CACHED_PATH = "cached_path"; /** MusicBrainz identifier. */ public static final String MBID = "mbid"; /** Title / Song / Content description. */ public static final String TITLE = "title"; /** Album / Movie (soundtrack, etc) / Show title. */ public static final String ALBUM = "album"; public static final String ALBUM_ID = "album_id"; /** Lead performer / Soloist / Composer. */ public static final String ARTIST = "artist"; public static final String ARTIST_ID = "artist_id"; /** Running time in seconds. */ public static final String LENGTH = "length"; /** Average or estimated bitrate. */ public static final String BITRATE = "bitrate"; /** Track number / Position in set. */ public static final String TRACK = "track_num"; /** Set number, if in one. */ public static final String SET = "set_num"; /** Music style / Content type. */ public static final String GENRE = "genre"; /** Date that this song was first introduced into the collection. */ public static final String DISCOVERY_DATE = "discovery_date"; public static final class SQL { public static final String TABLE = "music_songs"; public static final String DELETED_TABLE = "music_songs_deleted"; public static final String[] CREATE = { "CREATE TABLE " + TABLE + " (" + _ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " + _SYNC_ID + " INTEGER, " + _SYNC_TIME + " BIGINT, " + SOURCE_ID + " INTEGER, " + MIME_TYPE + " TEXT NOT NULL, " + SIZE + " INTEGER NOT NULL, " + CACHED_TIMESTAMP + " INTEGER, " + CACHED_PATH + " TEXT, " + MBID + " INTEGER, " + TITLE + " TEXT COLLATE UNICODE NOT NULL, " + ARTIST_ID + " INTEGER NOT NULL, " + ALBUM_ID + " INTEGER, " + LENGTH + " INTEGER NOT NULL, " + BITRATE + " INTEGER, " + TRACK + " INTEGER, " + GENRE + " TEXT, " + SET + " INTEGER, " + DISCOVERY_DATE + " DATETIME, " + LAST_PLAYED + " DATETIME " + ");", makeCreateDeletedTablesSQL(DELETED_TABLE), }; public static final String[] INDEX = { "CREATE INDEX " + TABLE + "_" + ARTIST_ID + " ON " + TABLE + " (" + ARTIST_ID + ");", "CREATE INDEX " + TABLE + "_" + ALBUM_ID + " ON " + TABLE + " (" + ALBUM_ID + ");", "CREATE INDEX " + TABLE + "_" + CACHED_TIMESTAMP + " ON " + TABLE + " (" + CACHED_TIMESTAMP + ");", "CREATE UNIQUE INDEX " + TABLE + "_" + _SYNC_ID + " ON " + TABLE + " (" + _SYNC_ID + ");", }; public static final String[] DROP = { "DROP TABLE IF EXISTS " + TABLE, "DROP TABLE IF EXISTS " + DELETED_TABLE, }; } } public interface Artists extends SyncableColumns { public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.five.music.artist"; public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.five.music.artist"; /** Access URI. */ public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/media/music/artists"); public static final Uri CONTENT_DELETED_URI = Uri.parse("content://" + AUTHORITY + "/media/music/artists/deleted"); /** MusicBrainz identifier. */ public static final String MBID = "mbid"; /** Performing name (significant portion for sort purposes; excludes "The"). */ public static final String NAME = "name"; /** Full name, including prefix. */ public static final String FULL_NAME = "full_name"; /** Leading text not included for sorting purposes. */ public static final String NAME_PREFIX = "name_prefix"; /** Band or performer photograph (content URI). */ public static final String PHOTO = "photo"; /** General musical style, if applicable. */ public static final String GENRE = "genre"; /** Date that this artist was first introduced into the collection. */ public static final String DISCOVERY_DATE = "discovery_date"; /** Number of unique albums belonging to this artist in the * collection. */ public static final String NUM_ALBUMS = "num_albums"; /** Number of songs belonging to this artist. */ public static final String NUM_SONGS = "num_songs"; public static final class SQL { public static final String TABLE = "music_artists"; public static final String DELETED_TABLE = TABLE + "_deleted"; public static final String[] CREATE = { "CREATE TABLE " + TABLE + " (" + _ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " + _SYNC_ID + " INTEGER, " + _SYNC_TIME + " BIGINT, " + MBID + " INTEGER, " + NAME + " TEXT COLLATE UNICODE NOT NULL, " + NAME_PREFIX + " TEXT, " + PHOTO + " TEXT, " + GENRE + " TEXT, " + DISCOVERY_DATE + " DATETIME, " + NUM_ALBUMS + " INTEGER, " + NUM_SONGS + " INTEGER " + ")", makeCreateDeletedTablesSQL(DELETED_TABLE), }; public static final String[] INDEX = { "CREATE UNIQUE INDEX " + TABLE + "_" + _SYNC_ID + " ON " + TABLE + " (" + _SYNC_ID + ");", }; public static final String[] DROP = { "DROP TABLE IF EXISTS " + TABLE, "DROP TABLE IF EXISTS " + DELETED_TABLE, }; } } public interface Albums extends SyncableColumns { public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.five.music.album"; public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.five.music.album"; /** Access URI. */ public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/media/music/albums"); public static final Uri CONTENT_DELETED_URI = Uri.parse("content://" + AUTHORITY + "/media/music/albums/deleted"); /** Access URI for "complete" albums only. */ public static final Uri CONTENT_URI_COMPLETE = Uri.parse("content://" + AUTHORITY + "/media/music/albums/complete"); /** MusicBrainz identifier. */ public static final String MBID = "mbid"; /** Album name (less prefix). */ public static final String NAME = "name"; /** Full name, including prefix. */ public static final String FULL_NAME = "full_name"; /** Leading text not included for sorting purposes. */ public static final String NAME_PREFIX = "name_prefix"; /** Artist. */ public static final String ARTIST = "artist"; public static final String ARTIST_ID = "artist_id"; /** Album artwork / Cover photo (content URI). */ public static final String ARTWORK = "artwork"; public static final String ARTWORK_BIG = "artwork_big"; /** Original release date. */ public static final String RELEASE_DATE = "release_date"; /** TODO: Expand on this idea... */ public static final String SET = "set"; /** Date that this album was first introduced into the collection. */ public static final String DISCOVERY_DATE = "discovery_date"; /** Number of songs belonging to this album. */ public static final String NUM_SONGS = "num_songs"; public static final class SQL { public static final String TABLE = "music_albums"; public static final String DELETED_TABLE = "music_albums_deleted"; public static final String[] CREATE = { "CREATE TABLE " + TABLE + " (" + _ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " + _SYNC_ID + " INTEGER, " + _SYNC_TIME + " BIGINT, " + MBID + " INTEGER, " + NAME + " TEXT COLLATE UNICODE NOT NULL, " + NAME_PREFIX + " TEXT, " + ARTIST_ID + " INTEGER, " + ARTWORK + " TEXT, " + ARTWORK_BIG + " TEXT, " + RELEASE_DATE + " DATETIME, " + DISCOVERY_DATE + " DATETIME, " + NUM_SONGS + " INTEGER " + ")", makeCreateDeletedTablesSQL(DELETED_TABLE), }; public static final String[] INDEX = { "CREATE INDEX " + TABLE + "_" + ARTIST_ID + " ON " + TABLE + " (" + ARTIST_ID + ");", "CREATE UNIQUE INDEX " + TABLE + "_" + _SYNC_ID + " ON " + TABLE + " (" + _SYNC_ID + ");", }; public static final String[] DROP = { "DROP TABLE IF EXISTS " + TABLE, "DROP TABLE IF EXISTS " + DELETED_TABLE, }; } } public interface Playlists extends SyncableColumns { public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.five.music.playlists"; public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.five.music.playlists"; /** Access URI. */ public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/media/music/playlists"); public static final Uri CONTENT_DELETED_URI = Uri.parse("content://" + AUTHORITY + "/media/music/playlists/deleted"); /** User-prescribed name and description. */ public static final String NAME = "name"; /** Playlist create date (might be guessed). */ public static final String CREATED_DATE = "created_date"; /** Number of songs in this play queue. */ public static final String NUM_SONGS = "num_songs"; public static final class SQL { public static final String TABLE = "music_playlists"; public static final String DELETED_TABLE = "music_playlists_deleted"; public static final String[] CREATE = { "CREATE TABLE " + TABLE + " (" + _ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " + _SYNC_ID + " INTEGER, " + _SYNC_TIME + " BIGINT, " + NAME + " TEXT COLLATE UNICODE NOT NULL, " + CREATED_DATE + " DATETIME, " + NUM_SONGS + " INTEGER " + ");", makeCreateDeletedTablesSQL(DELETED_TABLE), }; public static final String[] DROP = { "DROP TABLE IF EXISTS " + TABLE, "DROP TABLE IF EXISTS " + DELETED_TABLE, }; } } /** _ID is the same as {@link Songs}. */ public interface PlaylistSongs extends SyncableColumns { public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.five.music.playlists.songs"; public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.five.music.playlists.songs"; /** Access URI. */ public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/media/music/playlists/songs"); public static final Uri CONTENT_DELETED_URI = Uri.parse("content://" + AUTHORITY + "/media/music/playlists/songs/deleted"); /** Playlist ID. */ public static final String PLAYLIST_ID = "playlist_id"; /** Position in playlist. */ public static final String POSITION = "position"; /** Reference to song. */ public static final String SONG_ID = "song_id"; public static final class SQL { public static final String TABLE = "music_playlist_songs"; public static final String DELETED_TABLE = "music_playlist_songs_deleted"; public static final String[] CREATE = { "CREATE TABLE " + TABLE + " (" + _ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " + _SYNC_ID + " INTEGER, " + _SYNC_TIME + " BIGINT, " + PLAYLIST_ID + " INTEGER NOT NULL, " + SONG_ID + " INTEGER NOT NULL, " + POSITION + " INTEGER NOT NULL " + ");", makeCreateDeletedTablesSQL(DELETED_TABLE), }; public static final String[] INDEX = { "CREATE INDEX " + TABLE + "_" + PLAYLIST_ID + " ON " + TABLE + " (" + PLAYLIST_ID + ");", }; public static final String[] DROP = { "DROP TABLE IF EXISTS " + TABLE, "DROP TABLE IF EXISTS " + DELETED_TABLE, }; } } public interface AdjustCounts { /** * Efficiently updates NUM_ALBUMS, NUM_SONGS on Artists, Albums, * and Playlists. */ public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/media/music/adjust_counts"); } } }