mpxplugins/serviceplugins/collectionplugins/mpxsqlitedbplugin/src/mpxdbhandler.cpp
/*
* Copyright (c) 2007 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description: This class is used by db plugin for all database related
* functionality. The main responsibilities are:
*
*/
// INCLUDE FILES
#include <bautils.h>
#ifdef RD_MULTIPLE_DRIVE
#include <driveinfo.h>
#include <pathinfo.h>
#endif //RD_MULTIPLE_DRIVE
#include <mpxcollectiondbres.rsg>
#include <mpxmediageneraldefs.h>
#include <mpxmediacontainerdefs.h>
#include <mpxmediamusicdefs.h>
#include <mpxmediaaudiodefs.h>
#include <mpxmedia.h>
#include <mpxmediaarray.h>
#include <mpxcollectionpath.h>
#include <mpxlog.h>
#include "mpxresource.h"
#include "mpxdbcommonutil.h"
#include "mpxdbutil.h"
#include "mpxcollectiondbdef.h"
#include "mpxdbpluginqueries.h"
#include "mpxcollectiondbmanager.h"
#include "mpxdbplaylist.h"
#include "mpxdbplaylistsongs.h"
#include "mpxdbcategory.h"
#include "mpxdbauxiliary.h"
#include "mpxdbautoplaylist.h"
#include "mpxdbhandler.h"
#include "mpxdbartist.h"
#include "mpxdbalbum.h"
#include "mpxdbgenre.h"
#include "mpxdbcomposer.h"
// CONSTANTS
_LIT(KMPXVirtualPlaylistExt, ".vir");
static const TInt KMaxOpInTransaction = 100;
const TInt KSqlDbCorrupted = -321;
#if defined (__MTP_PROTOCOL_SUPPORT)
#include <centralrepository.h>
// MTP CenRep Key UID
const TUid KMPXMtpSettings = {0x101FFC53};
// MTP CenRep Key for Delete contents
const TUint32 KMPXMtpSaveDeletedRecordFlag = 0x00000001;
#endif
// ============================ MEMBER FUNCTIONS ==============================
// ----------------------------------------------------------------------------
// Two-phased constructor.
// ----------------------------------------------------------------------------
//
CMPXDbHandler* CMPXDbHandler::NewL(
RFs& aFs,
CMPXResource& aResource)
{
MPX_FUNC("CMPXDbHandler::NewL");
CMPXDbHandler* self = CMPXDbHandler::NewLC(aFs, aResource);
CleanupStack::Pop(self);
return self;
}
// ----------------------------------------------------------------------------
// Two-phased constructor.
// ----------------------------------------------------------------------------
//
CMPXDbHandler* CMPXDbHandler::NewLC(
RFs& aFs,
CMPXResource& aResource)
{
MPX_FUNC("CMPXDbHandler::NewLC");
CMPXDbHandler* self = new (ELeave) CMPXDbHandler(aFs, aResource);
CleanupStack::PushL(self);
self->ConstructL();
return self;
}
// ----------------------------------------------------------------------------
// Destructor
// ----------------------------------------------------------------------------
//
CMPXDbHandler::~CMPXDbHandler()
{
MPX_FUNC("CMPXDbHandler::~CMPXDbHandler");
delete iAutoPlaylist;
delete iDbMusic;
delete iDbPlaylist;
delete iDbArtist;
delete iDbAlbum;
delete iDbGenre;
delete iDbComposer;
delete iDbAuxiliary;
delete iDbManager;
delete iMimeTypes;
delete iExtensions;
delete iExtensionsMime;
delete iExtensionsDrm;
iDbDrives.Close();
}
// ----------------------------------------------------------------------------
// C++ default constructor can NOT contain any code, that might leave
// ----------------------------------------------------------------------------
//
CMPXDbHandler::CMPXDbHandler(
RFs& aFs,
CMPXResource& aResource) :
iFs(aFs),
iResource(aResource)
{
MPX_FUNC("CMPXDbHandler::CMPXDbHandler");
}
// ----------------------------------------------------------------------------
// Symbian 2nd phase constructor can leave.
// ----------------------------------------------------------------------------
//
void CMPXDbHandler::ConstructL()
{
MPX_FUNC("CMPXDbHandler::ConstructL");
iMimeTypes = iResource.ReadDesCArrayL(R_MC_MIME_TYPES);
iExtensions = iResource.ReadDesCArrayL(R_MC_MUSIC_FILE_EXTENSIONS);
iExtensionsMime = iResource.ReadDesCArrayL(R_MC_FILE_EXTENSIONS_MIME);
iExtensionsDrm = iResource.ReadDesCArrayL(R_MC_FILE_EXTENSIONS_DRM);
// make sure all databases are created and valid
iDbManager = CMPXCollectionDbManager::NewL(iFs);
CDesCArrayFlat* musicFolders =
#ifdef RD_MULTIPLE_DRIVE
GetMusicFoldersL();
#else
iResource.ReadDesCArrayL(R_MC_DEFAULT_MUSIC_FOLDERS);
#endif
// create the music folders and initialize iDbDrives
CleanupStack::PushL(musicFolders);
ProcessMusicFoldersL(*musicFolders);
CleanupStack::PopAndDestroy(musicFolders);
// Create the db infrastructure,
//
iDbMusic = CMPXDbMusic::NewL(*iDbManager, iResource, *this);
iDbPlaylist = CMPXDbPlaylist::NewL(*iDbManager, *this);
iDbArtist = CMPXDbArtist::NewL(*iDbManager, EMPXArtist, *this);
iDbAlbum = CMPXDbAlbum::NewL(*iDbManager, EMPXAlbum, *this);
iDbGenre = CMPXDbGenre::NewL(*iDbManager, EMPXGenre);
iDbComposer = CMPXDbComposer::NewL(*iDbManager, EMPXComposer);
iAutoPlaylist = CMPXDbAutoPlaylist::NewL(*iDbManager, iFs, iResource);
iDbAuxiliary = CMPXDbAuxiliary::NewL(*iDbManager);
MPX_TRAPD(err, iDbManager->InitDatabasesL(iDbDrives));
iCollectionOpen = ETrue;
// If KErrCorrupt is returned, a database file was found to be corrupted
// and was replaced with a new one. The db plugin can ignore this error and continue
// because a new db file was successfully created in a subsequent retry.
if ((err != KErrNone) && (err != KErrCorrupt) && (err != KErrDiskFull))
{
// leave to signal the caller that there was an error why creating and opening
// one or more of the databases
User::Leave(err);
}
else if (err == KErrDiskFull)
{
iOutOfDisk = ETrue;
}
else
{
// do nothing
}
// Verify the volume ids of each drive matches the database
MPX_TRAP(err,VerifyVolumeIdL());
if ((err != KErrNone) && (err != KErrDiskFull))
{
// leave to signal the caller that there was an error why creating and opening
// one or more of the databases
User::Leave(err);
}
else if (err == KErrDiskFull)
{
iOutOfDisk = ETrue;
}
//#ifdef _DEBUG
// iDbManager->PrintDatabaseL(); // PREQ2536 the files sqlrowsetutil.h and sqlrowsetutil.cpp has been removed
//#endif
MPX_DEBUG2("CMPXDbHandler::ConstructL DbCount[%d]", iDbManager->DatabaseCount());
}
// ----------------------------------------------------------------------------
// Add song to collection
// ----------------------------------------------------------------------------
//
TUint32 CMPXDbHandler::AddSongL(
const CMPXMedia& aMedia,
CMPXMessageArray* aMessageArray)
{
MPX_FUNC("CMPXDbHandler::AddSongL");
BeginTransactionL();
TUint32 songId(0);
MPX_TRAPD(err, songId = DoAddSongL(aMedia,aMessageArray));
if (iOutOfDisk && (err == KErrNotFound))
{
err = KErrDiskFull;
}
EndTransactionL(err);
return songId;
}
// ----------------------------------------------------------------------------
// Add song to collection with no database transaction
// ----------------------------------------------------------------------------
//
TUint32 CMPXDbHandler::AddSongWithNoTransactionL(
const CMPXMedia& aMedia,
CMPXMessageArray* aMessageArray)
{
MPX_FUNC("CMPXDbHandler::AddSongWithNoTransactionL");
TUint32 songId(0);
MPX_TRAPD(err, songId = DoAddSongL(aMedia,aMessageArray));
if (iOutOfDisk && (err == KErrNotFound))
{
err = KErrDiskFull;
}
User::LeaveIfError(err);
return songId;
}
// ----------------------------------------------------------------------------
// Add playlist to collection
// ----------------------------------------------------------------------------
//
TUint32 CMPXDbHandler::AddPlaylistL(
const CMPXMedia& aMedia)
{
MPX_FUNC("CMPXDbHandler::AddPlaylistL");
BeginTransactionL();
TUint32 playlistId(0);
MPX_TRAPD(err, playlistId = DoAddPlaylistL(aMedia));
EndTransactionL(err);
return playlistId;
}
// ----------------------------------------------------------------------------
// Add song to playlist
// ----------------------------------------------------------------------------
//
TUint32 CMPXDbHandler::AddSongToPlaylistL(
const CMPXMedia& aMedia)
{
MPX_FUNC("CMPXDbHandler::AddSongToPlaylistL");
BeginTransactionL();
TUint32 playlistId(0);
MPX_TRAPD(err, playlistId = DoAddSongToPlaylistL(aMedia));
EndTransactionL(err);
return playlistId;
}
// ----------------------------------------------------------------------------
// Update a song in the collection
// ----------------------------------------------------------------------------
//
CMPXDbActiveTask::TChangeVisibility CMPXDbHandler::UpdateSongL(
const CMPXMedia& aMedia,
CMPXMessageArray& aItemChangedMessages)
{
MPX_FUNC("CMPXDbHandler::UpdateSongL");
BeginTransactionL();
CMPXDbActiveTask::TChangeVisibility visibleChange(CMPXDbActiveTask::ENotVisibile);
MPX_TRAPD(err, visibleChange = DoUpdateSongL(aMedia, aItemChangedMessages));
EndTransactionL(err);
return visibleChange;
}
// ----------------------------------------------------------------------------
// Update a playlist in the collection
// ----------------------------------------------------------------------------
//
void CMPXDbHandler::UpdatePlaylistL(
const CMPXMedia& aMedia,
CMPXMessageArray& aMessageArray)
{
MPX_FUNC("CMPXDbHandler::UpdatePlaylistL");
BeginTransactionL();
MPX_TRAPD(err, DoUpdatePlaylistL(aMedia, aMessageArray));
EndTransactionL(err);
}
// ----------------------------------------------------------------------------
// Updates the playlist songs
// ----------------------------------------------------------------------------
//
void CMPXDbHandler::UpdatePlaylistSongsL(
const CMPXMedia& aMedia,
CMPXMessage& aMessage)
{
MPX_FUNC("CMPXDbHandler::UpdatePlaylistSongsL");
BeginTransactionL();
MPX_TRAPD(err, DoUpdatePlaylistSongsL(aMedia, aMessage));
EndTransactionL(err);
}
// ----------------------------------------------------------------------------
// Reorder a song in a playlist
// ----------------------------------------------------------------------------
//
void CMPXDbHandler::ReorderPlaylistL(
const TMPXItemId& aPlaylistId,
const TMPXItemId& aSongId,
TUint aOriginalOrdinal,
TUint aNewOrdinal,
CMPXMessage& aMessage)
{
MPX_DEBUG5("-->CMPXDbHandler::ReorderPlaylistL(0x%x, 0x%x, %d, %d)",
aPlaylistId.iId2, aSongId.iId2, aOriginalOrdinal, aNewOrdinal);
BeginTransactionL();
MPX_TRAPD(err, DoReorderPlaylistL(aPlaylistId, aSongId, aOriginalOrdinal, aNewOrdinal, aMessage));
EndTransactionL(err);
MPX_DEBUG2("<--CMPXDbHandler::ReorderPlaylistL() error=%d", err);
}
// ----------------------------------------------------------------------------
// Remove the entire music collection database
// ----------------------------------------------------------------------------
//
void CMPXDbHandler::RemoveEntireCollectionL()
{
MPX_FUNC("CMPXDbHandler::RemoveEntireCollectionL");
BeginTransactionL();
MPX_TRAPD(err, iDbManager->RecreateAllDatabasesL());
EndTransactionL(err);
}
// ----------------------------------------------------------------------------
// Delete a song from collection
// The function notifies collection model to perform deletion
// ----------------------------------------------------------------------------
//
void CMPXDbHandler::RemoveSongL(
TUint32 aSongId,
CDesCArray& aUriArray,
CMPXMessageArray& aItemChangedMessages,
TBool aDeleteRecord)
{
MPX_FUNC("CMPXDbHandler::RemoveSongL");
MPX_TRAPD(err, DoRemoveSongL(aSongId, aUriArray, aItemChangedMessages, aDeleteRecord));
MPX_TRAP(err, DoRemoveSongFromPlaylistL(aSongId,aItemChangedMessages));
}
// ----------------------------------------------------------------------------
// Removes a category of songs from the music collection,
// and its corresponding category in the lookup table
// ----------------------------------------------------------------------------
//
void CMPXDbHandler::RemoveSongsMatchingCategoryL(
TMPXGeneralCategory aCategory,
TUint32 aCategoryId,
CDesCArray& aUriArray,
CMPXMessageArray& aItemChangedMessages)
{
MPX_FUNC("CMPXDbHandler::RemoveSongsMatchingCategoryL");
BeginTransactionL();
MPX_TRAPD(err, DoRemoveSongsMatchingCategoryL(aCategory, aCategoryId, aUriArray, aItemChangedMessages));
EndTransactionL(err);
}
// ----------------------------------------------------------------------------------------------------------
// Delete songs for the specified artist and album from collection
// The function notifies collection model to perform deletion
// ----------------------------------------------------------------------------------------------------------
//
void CMPXDbHandler::RemoveSongsMatchingArtistAndAlbumL(
TUint32 aArtistId,
TUint32 aAlbumId,
CDesCArray& aUriArray,
CMPXMessageArray& aItemChangedMessages)
{
MPX_FUNC("CMPXDbHandler::RemoveSongsMatchingArtistAndAlbumL");
BeginTransactionL();
MPX_TRAPD(err, DoRemoveSongsMatchingArtistAndAlbumL(aArtistId, aAlbumId, aUriArray,
aItemChangedMessages));
EndTransactionL(err);
}
// ----------------------------------------------------------------------------
// Remove all playlists from collection
// ----------------------------------------------------------------------------
//
void CMPXDbHandler::RemoveAllPlaylistsL()
{
MPX_FUNC("CMPXDbHandler::RemoveAllPlaylistsL");
BeginTransactionL();
MPX_TRAPD(err, DoRemoveAllPlaylistsL());
EndTransactionL(err);
}
// ----------------------------------------------------------------------------
// Remove specified playlist
// ----------------------------------------------------------------------------
//
void CMPXDbHandler::RemovePlaylistL(
TUint32 aPlaylistId,
CDesCArray& aUriArray,
CMPXMessageArray& aItemChangedMessages)
{
MPX_FUNC("CMPXDbHandler::RemovePlaylistL");
BeginTransactionL();
MPX_TRAPD(err, DoRemovePlaylistL(aPlaylistId, aUriArray, aItemChangedMessages));
EndTransactionL(err);
}
// ----------------------------------------------------------------------------
// Remove song from playlist songs table
// ----------------------------------------------------------------------------
//
void CMPXDbHandler::RemoveSongFromPlaylistL(
TUint32 aPlaylistId,
const TMPXItemId& aSongId,
TInt aOrdinal,
CMPXMessageArray& aItemChangedMessages)
{
MPX_FUNC("CMPXDbHandler::RemoveSongFromPlaylistL");
MPX_DEBUG5("CMPXDbHandler::RemoveSongFromPlaylistL(playlist 0x%x, songId [0x%x,0x%x], ordinal %d)",
aPlaylistId, aSongId.iId1, aSongId.iId2, aOrdinal);
MPX_TRAPD(err, DoRemoveSongFromPlaylistL(aPlaylistId, aSongId, aOrdinal, aItemChangedMessages));
if ( err && InTransaction() )
{
// only end transaction if there's an error
EndTransactionL( err );
}
}
// ----------------------------------------------------------------------------
// Cleanup records marked as deleted. This is designated for MTP to clean up records marked as deleted
// at the end of its session.
// ----------------------------------------------------------------------------
//
void CMPXDbHandler::CleanupDeletedRecordsL()
{
MPX_FUNC("CMPXDbHandler::CleanupDeletedRecordsL");
BeginTransactionL();
MPX_TRAPD(err, DoCleanupDeletedRecordsL());
EndTransactionL(err);
}
// ----------------------------------------------------------------------------
// Read all songs and cache them into an array ordered by song name
// ----------------------------------------------------------------------------
//
void CMPXDbHandler::GetAllSongsL(
CMPXMediaArray* aMediaArray,
const TArray<TMPXAttribute>& aAttrs)
{
MPX_FUNC("CMPXDbHandler::GetAllSongsL");
iDbMusic->GetAllSongsL(aAttrs, *aMediaArray);
}
// ----------------------------------------------------------------------------
// Read a limited # of songs and cache them into an array ordered by song name
// ----------------------------------------------------------------------------
//
void CMPXDbHandler::GetAllSongsLimitedL(const TArray<TMPXAttribute>& aAttrs,
CMPXMediaArray& aMediaArray, TInt aLimit)
{
MPX_FUNC("CMPXDbHandler::GetAllSongsLimitedL");
iDbMusic->GetAllSongsLimitedL( aAttrs, aMediaArray, aLimit );
}
// ----------------------------------------------------------------------------
// Read all songs and cache them into an array ordered by song name
// ----------------------------------------------------------------------------
//
void CMPXDbHandler::GetSongsInBlockL(
CMPXMediaArray* aMediaArray,
const TArray<TMPXAttribute>& aAttrs,
TPtrC aTitle,
TUint aNumOfSongs,
TBool aAsc)
{
MPX_FUNC("CMPXDbHandler::GetSongsInBlockL");
iDbMusic->GetSongsInBlockL(aAttrs, *aMediaArray, aTitle, aNumOfSongs, aAsc);
}
// ----------------------------------------------------------------------------
// Read songs at a particular offset
// ----------------------------------------------------------------------------
//
void CMPXDbHandler::GetSongsAtOffsetL( CMPXMediaArray* aMediaArray,
const TArray<TMPXAttribute>& aAttrs,
TInt aOffset,
TInt aCount )
{
MPX_DEBUG1("CMPXDbHandler::GetSongsAtOffsetL <--");
iDbMusic->GetSongsAtOffsetL( *aMediaArray, aAttrs, aOffset, aCount );
}
// ----------------------------------------------------------------------------
// Get all songs matching the given artist ID
// ----------------------------------------------------------------------------
//
void CMPXDbHandler::GetSongsMatchingArtistL(
TUint aArtistId,
const TArray<TMPXAttribute>& aAttrs,
CMPXMediaArray* aMediaArray)
{
MPX_FUNC("CMPXDbHandler::GetSongsMatchingArtistL");
iDbMusic->GetSongsForArtistL(aArtistId, aAttrs, *aMediaArray);
}
// ----------------------------------------------------------------------------
// Get all songs matching the given album ID
// ----------------------------------------------------------------------------
//
void CMPXDbHandler::GetSongsMatchingAlbumL(
TUint aAlbumId,
const TArray<TMPXAttribute>& aAttrs,
CMPXMediaArray* aMediaArray)
{
MPX_FUNC("CMPXDbHandler::GetSongsMatchingAlbumL");
iDbMusic->GetSongsForAlbumL(aAlbumId, aAttrs, *aMediaArray);
}
// ----------------------------------------------------------------------------------------------------------
// Get all songs matching the given artist and album ID
// ----------------------------------------------------------------------------------------------------------
//
void CMPXDbHandler::GetSongsMatchingArtistAndAlbumL(
TUint aArtistId,
TUint aAlbumId,
const TArray<TMPXAttribute>& aAttrs,
CMPXMediaArray* aMediaArray)
{
MPX_FUNC("CMPXDbHandler::GetSongsMatchingArtistAndAlbumL");
iDbMusic->GetSongsForArtistAndAlbumL(aArtistId, aAlbumId, aAttrs, *aMediaArray);
}
// ----------------------------------------------------------------------------
// Get all songs matching the given genre ID
// ----------------------------------------------------------------------------
//
void CMPXDbHandler::GetSongsMatchingGenreL(
TUint aGenreId,
const TArray<TMPXAttribute>& aAttrs,
CMPXMediaArray* aMediaArray)
{
MPX_FUNC("CMPXDbHandler::GetSongsMatchingGenreL");
iDbMusic->GetSongsForGenreL(aGenreId, aAttrs, *aMediaArray);
}
// ----------------------------------------------------------------------------
// Get all songs matching the given composer ID
// ----------------------------------------------------------------------------
//
void CMPXDbHandler::GetSongsMatchingComposerL(
TUint aComposerId,
const TArray<TMPXAttribute>& aAttrs,
CMPXMediaArray* aMediaArray)
{
MPX_FUNC("CMPXDbHandler::GetSongsMatchingComposerL");
iDbMusic->GetSongsForComposerL(aComposerId, aAttrs, *aMediaArray);
}
// ----------------------------------------------------------------------------
// Get all songs that belong to the given playlist
// ----------------------------------------------------------------------------
//
void CMPXDbHandler::GetSongsMatchingPlaylistL(
TUint aPlaylistId,
const TArray<TMPXAttribute>& aAttrs,
CMPXMediaArray* aMediaArray)
{
MPX_FUNC("CMPXDbHandler::GetSongsMatchingPlaylistL");
GetPlaylistSongsL(aPlaylistId, aAttrs, *aMediaArray);
}
// ----------------------------------------------------------------------------
// Get song matching the given song ID
// ----------------------------------------------------------------------------
//
void CMPXDbHandler::GetSongL(
TUint32 aSongId,
const TArray<TMPXAttribute>& aAttrs,
CMPXMedia& aMedia)
{
MPX_FUNC("CMPXDbHandler::GetSongL");
iDbMusic->GetSongL(aSongId, aAttrs, aMedia);
}
// ----------------------------------------------------------------------------
// GetSongL
// ----------------------------------------------------------------------------
//
void CMPXDbHandler::GetSongL(
TUint32 aSongId,
const TArray<TMPXAttribute>& aAttrs,
CMPXMediaArray& aMediaArray)
{
MPX_FUNC("CMPXDbHandler::GetSongL");
CMPXMedia* media = CMPXMedia::NewL();
CleanupStack::PushL(media);
GetSongL(aSongId, aAttrs, *media);
aMediaArray.AppendL(*media);
CleanupStack::PopAndDestroy(media);
}
// ----------------------------------------------------------------------------
// Get song matching the given song ID and playlist ID
// ----------------------------------------------------------------------------
//
void CMPXDbHandler::GetPlaylistSongL(
TUint32 aSongId,
TUint32 aPlaylistId,
const TArray<TMPXAttribute>& aAttrs,
CMPXMedia& aMedia)
{
MPX_DEBUG3("-->CMPXDbHandler::GetPlaylistSongL songId[0x%x] playlistId[0x%x]", aSongId, aPlaylistId);
// complete the song information from the Music table
MPX_TRAPD(err, iDbMusic->GetSongL(aSongId, aAttrs, aMedia));
//
// song not found in Music table
//
if (err == KErrNotFound)
{
//
// Leave with KErrNotFound if one of the following is true:
// 1) the requested song is in an auto playlist. Since auto-playlist isn't
// stored in playlist tables, we won't be able to retrieve info elsewhere
// 2) the requested song is in a user playlist but we cannot find the song
// info from playlist tables either
//
if (EMPXNoAutoPlaylist != iAutoPlaylist->AutoPlaylistTypeL(aPlaylistId) ||
!iDbPlaylist->Songs().GetSongL(aPlaylistId, aSongId, aAttrs, aMedia))
{
User::Leave(KErrNotFound);
}
}
//
// Unable to read information from Music table
//
else
{
// ignore the error if KErrNotFound
User::LeaveIfError(err);
}
MPX_DEBUG1("<--CMPXDbHandler::GetPlaylistSongL");
}
// ----------------------------------------------------------------------------
// GetPlaylistSongL
// ----------------------------------------------------------------------------
//
void CMPXDbHandler::GetPlaylistSongL(
TUint32 aSongId,
TUint32 aPlaylistId,
const TArray<TMPXAttribute>& aAttrs,
CMPXMediaArray& aMediaArray)
{
MPX_FUNC("CMPXDbHandler::GetPlaylistSongL");
CMPXMedia* media = CMPXMedia::NewL();
CleanupStack::PushL(media);
GetPlaylistSongL(aSongId, aPlaylistId, aAttrs, *media);
aMediaArray.AppendL(*media);
CleanupStack::PopAndDestroy(media);
}
// ----------------------------------------------------------------------------
// Get song matching the given URI
// ----------------------------------------------------------------------------
//
TUint32 CMPXDbHandler::GetSongIdMatchingUriL(
const TDesC& aUri)
{
MPX_FUNC("CMPXDbHandler::GetSongIdMatchingUriL");
return MPXDbCommonUtil::GenerateUniqueIdL(iFs, EMPXCollection, aUri, EFalse);
}
// ----------------------------------------------------------------------------
// Get all artists
// ----------------------------------------------------------------------------
//
void CMPXDbHandler::GetAllArtistsL(
const TArray<TMPXAttribute>& aAttrs,
CMPXMediaArray* aMediaArray)
{
MPX_FUNC("CMPXDbHandler::GetAllArtistsL");
iDbArtist->GetAllCategoryItemsL(aAttrs, *aMediaArray);
}
// ----------------------------------------------------------------------------
// Get all albums
// ----------------------------------------------------------------------------
//
void CMPXDbHandler::GetAllAlbumsL(
const TArray<TMPXAttribute>& aAttrs,
CMPXMediaArray* aMediaArray)
{
MPX_FUNC("CMPXDbHandler::GetAllAlbumsL");
iDbAlbum->GetAllCategoryItemsL(aAttrs, *aMediaArray);
}
// ----------------------------------------------------------------------------
// Get all albums for the given artist ID
// ----------------------------------------------------------------------------
//
void CMPXDbHandler::GetAlbumsMatchingArtistL(
TUint aArtistId,
const TArray<TMPXAttribute>& aAttrs,
CMPXMediaArray& aMediaArray)
{
MPX_FUNC("CMPXDbHandler::GetAlbumsMatchingArtistL");
RArray<TMPXAttribute> attributes;
CleanupClosePushL( attributes );
TBool tryGetSongCount = EFalse;
TInt attrCount(aAttrs.Count());
TInt i = 0;
for (i = 0; i < attrCount; i++)
{
TInt contentId(aAttrs[i].ContentId());
TUint attributeId(aAttrs[i].AttributeId());
if (contentId == KMPXMediaIdGeneral && attributeId & EMPXMediaGeneralCount)
{
MPX_DEBUG1(" EMPXMediaGeneralCount");
attributes.Append(TMPXAttribute(KMPXMediaIdGeneral, attributeId & ~EMPXMediaGeneralCount));
tryGetSongCount = ETrue;
break;
}
attributes.Append(aAttrs[i]);
}
for (TInt j = i+1; j < attrCount; j++)
{
attributes.Append(aAttrs[j]);
}
iDbAlbum->GetSubCategoryItemsL(EMPXArtist, aArtistId, attributes.Array(), aMediaArray);
CleanupStack::PopAndDestroy(&attributes);
TInt pPath(0);
if (aMediaArray.Count())
{
CMPXMedia* pMedia = aMediaArray[0];
if (pMedia->IsSupported(KMPXMediaGeneralValue))
{
pPath = pMedia->ValueTObjectL<TInt>(KMPXMediaGeneralValue);
MPX_ASSERT(pPath);
}
}
TInt albumCount(aMediaArray.Count());
if (albumCount)
{
if ( tryGetSongCount )
{
TInt startIndex = pPath ? 1 : 0;
for (TInt i = startIndex; i < albumCount; i++)
{
CMPXMedia* media = aMediaArray[i];
TUint32 albumId((media->ValueTObjectL<TMPXItemId>(KMPXMediaGeneralId)));
TInt songCount = iDbAlbum->GetSongsCountInAlbumMatchingArtistL(aArtistId, albumId);
media->SetTObjectValueL<TInt>(KMPXMediaGeneralCount, songCount );
MPX_DEBUG2(" SongCount[%d]", songCount );
}
}
}
}
// ----------------------------------------------------------------------------
// Get all genres
// ----------------------------------------------------------------------------
//
void CMPXDbHandler::GetAllGenresL(
const TArray<TMPXAttribute>& aAttrs,
CMPXMediaArray* aMediaArray)
{
MPX_FUNC("CMPXDbHandler::GetAllGenresL");
iDbGenre->GetAllCategoryItemsL(aAttrs, *aMediaArray);
}
// ----------------------------------------------------------------------------
// Get all composers
// ----------------------------------------------------------------------------
//
void CMPXDbHandler::GetAllComposersL(
const TArray<TMPXAttribute>& aAttrs,
CMPXMediaArray* aMediaArray)
{
MPX_FUNC("CMPXDbHandler::GetAllComposersL");
iDbComposer->GetAllCategoryItemsL(aAttrs, *aMediaArray);
}
// ----------------------------------------------------------------------------
// Get the playlist ID of the playlist that matches the given URI
// ----------------------------------------------------------------------------
//
TUint32 CMPXDbHandler::GetPlaylistIdMatchingUriL(
const TDesC& aUri)
{
MPX_FUNC("CMPXDbHandler::GetPlaylistIdMatchingUriL");
return iDbPlaylist->GetIdL(aUri);
}
// ----------------------------------------------------------------------------
// CMPXDbHandler::IsAutoPlaylistL
// ----------------------------------------------------------------------------
//
TBool CMPXDbHandler::IsAutoPlaylistL(
TUint32 aPlaylistId)
{
MPX_FUNC("CMPXDbHandler::IsAutoPlaylistL");
return (iAutoPlaylist->AutoPlaylistTypeL(aPlaylistId) != EMPXNoAutoPlaylist);
}
// ----------------------------------------------------------------------------
// Get all user playlist names
// ----------------------------------------------------------------------------
//
void CMPXDbHandler::GetAllPlaylistsL(
CMPXMediaArray* aMediaArray,
const TArray<TMPXAttribute>& aAttrs)
{
MPX_FUNC("CMPXDbHandler::GetAllPlaylistsL");
iDbPlaylist->GetAllPlaylistsL(aAttrs, *aMediaArray);
}
// ----------------------------------------------------------------------------
// Get all system playlist names
// ----------------------------------------------------------------------------
//
void CMPXDbHandler::GetAllSystemPlaylistNamesL(
CMPXMediaArray* aMediaArray)
{
MPX_FUNC("CMPXDbHandler::GetAllSystemPlaylistNamesL()");
iAutoPlaylist->GetAllPlaylistsL(*aMediaArray);
}
// ----------------------------------------------------------------------------
// Get the name of the row matching the given ID
// ----------------------------------------------------------------------------
//
HBufC* CMPXDbHandler::GetNameMatchingIdL(
const TUint32 aId) const
{
MPX_FUNC("CMPXDbHandler::GetNameMatchingIdL()");
HBufC* name(NULL);
TMPXGeneralCategory category(MPX_ITEM_CATEGORY(aId));
switch (category)
{
case EMPXCollection:
{
// song name
name = iDbMusic->GetNameL(aId);
break;
}
case EMPXPlaylist:
{
// playlist name
if (iAutoPlaylist->AutoPlaylistTypeL(aId) != EMPXNoAutoPlaylist)
{
name = iAutoPlaylist->AutoPlaylistNameL(aId).AllocL();
}
else
{
name = iDbPlaylist->GetNameL(aId);
}
break;
}
default:
{
// category name
name = DbCategoryL(category)->GetNameL(aId);
break;
}
}
return name;
}
// ----------------------------------------------------------------------------
// Get the URI of the row matching the given ID
// ----------------------------------------------------------------------------
//
HBufC* CMPXDbHandler::GetUriMatchingIdL(
const TUint32 aId) const
{
MPX_FUNC("CMPXDbHandler::GetUriMatchingIdL");
HBufC* uri(NULL);
switch (MPX_ITEM_CATEGORY(aId))
{
case EMPXCollection:
{
// song URI
uri = iDbMusic->GetUriL(aId);
break;
}
case EMPXPlaylist:
{
// playlist URI
uri = iDbPlaylist->GetUriL(aId);
break;
}
default:
User::Leave(KErrNotSupported);
}
return uri;
}
// ----------------------------------------------------------------------------
// Get category
// ----------------------------------------------------------------------------
//
void CMPXDbHandler::GetCategoryL(
const TUint32 aCategoryId,
TMPXGeneralCategory aCategory,
const TArray<TMPXAttribute>& aAttrs,
CMPXMedia* aMedia)
{
MPX_FUNC("CMPXDbHandler::GetCategoryL");
switch (aCategory)
{
case EMPXPlaylist:
{
if (iAutoPlaylist->AutoPlaylistTypeL(aCategoryId) != EMPXNoAutoPlaylist)
{
iAutoPlaylist->GetPlaylistL(aCategoryId, aAttrs, *aMedia);
}
else
{
iDbPlaylist->GetPlaylistL(aCategoryId, aAttrs, *aMedia);
}
break;
}
default:
{
DbCategoryL(aCategory)->GetCategoryItemL(aCategoryId, aAttrs, *aMedia);
break;
}
}
}
// ----------------------------------------------------------------------------
// Get the duration for all songs
// ----------------------------------------------------------------------------
//
TInt CMPXDbHandler::GetAllSongsDurationL()
{
MPX_FUNC("CMPXDbHandler::GetAllSongsDurationL");
return iDbMusic->AllSongsDurationL();
}
// ----------------------------------------------------------------------------
// Get the duration for an artist
// ----------------------------------------------------------------------------
//
TInt CMPXDbHandler::GetArtistDurationL(
TInt aArtistId)
{
MPX_FUNC("CMPXDbHandler::GetArtistDurationL");
return iDbMusic->ArtistDurationL(aArtistId);
}
// ----------------------------------------------------------------------------
// Get the duration for an album
// ----------------------------------------------------------------------------
//
TInt CMPXDbHandler::GetAlbumDurationL(
TInt aAlbumId)
{
MPX_FUNC("CMPXDbHandler::GetAlbumDurationL");
return iDbMusic->AlbumDurationL(aAlbumId);
}
// ----------------------------------------------------------------------------
// Get the duration for an artist/album combination
// ----------------------------------------------------------------------------
//
TInt CMPXDbHandler::GetArtistAlbumDurationL(
TInt aArtistId,
TInt aAlbumId)
{
MPX_FUNC("CMPXDbHandler::GetArtistAlbumDurationL");
return iDbMusic->ArtistAlbumDurationL(aArtistId, aAlbumId);
}
// ----------------------------------------------------------------------------
// Get the duration for a composer
// ----------------------------------------------------------------------------
//
TInt CMPXDbHandler::GetComposerDurationL(
TInt aComposerId)
{
MPX_FUNC("CMPXDbHandler::GetComposerDurationL");
return iDbMusic->ComposerDurationL(aComposerId);
}
// ----------------------------------------------------------------------------
// Get the duration for a genre
// ----------------------------------------------------------------------------
//
TInt CMPXDbHandler::GetGenreDurationL(
TInt aGenreId)
{
MPX_FUNC("CMPXDbHandler::GetGenreDurationL");
return iDbMusic->GenreDurationL(aGenreId);
}
// ----------------------------------------------------------------------------
// Get the duration for a user playlist
// ----------------------------------------------------------------------------
//
TInt CMPXDbHandler::GetUserPlaylistDurationL(
TInt aPlaylistId)
{
MPX_FUNC("CMPXDbHandler::GetUserPlaylistDurationL");
RArray<TMPXAttribute> attributes;
CleanupClosePushL(attributes);
attributes.AppendL(KMPXMediaGeneralId);
attributes.AppendL(TMPXAttribute(KMPXMediaIdGeneral, EMPXMediaGeneralDuration));
CMPXMediaArray* mediaArray = CMPXMediaArray::NewL();
CleanupStack::PushL(mediaArray);
GetPlaylistSongsL(aPlaylistId, attributes.Array(), *mediaArray);
TInt duration(0);
TInt count(mediaArray->Count());
for (TInt index = 0; index < count; ++index)
{
CMPXMedia* media((*mediaArray)[index]);
if (media->IsSupported(KMPXMediaGeneralDuration))
{
duration += media->ValueTObjectL<TInt>(KMPXMediaGeneralDuration);
}
}
CleanupStack::PopAndDestroy(mediaArray);
CleanupStack::PopAndDestroy(&attributes);
return duration;
}
// ----------------------------------------------------------------------------
// Get the duration for a playlist
// ----------------------------------------------------------------------------
//
TInt CMPXDbHandler::GetPlaylistDurationL(
TInt aPlaylistId)
{
MPX_FUNC("CMPXDbHandler::GetPlaylistDurationL");
TInt duration(0);
if (aPlaylistId == iAutoPlaylist->AutoPlaylistIdL(EMPXRecentlyPlayedPlaylist))
{
duration = iDbMusic->RecentlyPlayedDurationL();
}
else if (aPlaylistId == iAutoPlaylist->AutoPlaylistIdL(EMPXMostPlayedPlaylist))
{
duration = iDbMusic->MostPlayedDurationL();
}
else if (aPlaylistId == iAutoPlaylist->AutoPlaylistIdL(EMPXRecentlyAddedPlaylist))
{
duration = iDbMusic->RecentlyAddedDurationL();
}
else
{
duration = GetUserPlaylistDurationL(aPlaylistId);
}
return duration;
}
// ----------------------------------------------------------------------------
// Find the number of items of a specified type
// ----------------------------------------------------------------------------
//
TInt CMPXDbHandler::NumberOfItemsL(
TMPXGeneralCategory aCategory)
{
MPX_FUNC("CMPXDbHandler::NumberOfItemsL");
TInt count(0);
switch(aCategory)
{
case EMPXSong:
{
count = iDbMusic->CountL();
break;
}
case EMPXPlaylist:
{
// return the total number of playlists, including the system ones
count = iDbPlaylist->CountL() + EMPXAutoPlaylistCount;
break;
}
default:
{
count = DbCategoryL(aCategory)->CountL();
break;
}
}
return count;
}
// ----------------------------------------------------------------------------
// CMPXDbHandler::FindAllLC
// ----------------------------------------------------------------------------
//
CMPXMedia* CMPXDbHandler::FindAllLC(
const CMPXMedia& aCriteria,
const TArray<TMPXAttribute>& aAttrs)
{
MPX_FUNC("CMPXDbHandler::FindAllLC");
// leave if the given media doesn't contain the following attributes
if (!aCriteria.IsSupported(KMPXMediaGeneralType) ||
!aCriteria.IsSupported(KMPXMediaGeneralCategory))
{
User::Leave(KErrArgument);
}
RArray<TInt> supportedIds;
CleanupClosePushL(supportedIds);
supportedIds.AppendL(KMPXMediaIdContainer);
MPXDbCommonUtil::FillInSupportedUIDsL(aAttrs, supportedIds);
CMPXMedia* entries = CMPXMedia::NewL(supportedIds.Array());
CleanupStack::PopAndDestroy(&supportedIds);
CleanupStack::PushL(entries);
CMPXMediaArray* array = CMPXMediaArray::NewL();
CleanupStack::PushL(array);
FindAllL(aCriteria, aAttrs, array);
entries->SetTObjectValueL<TMPXGeneralType>(KMPXMediaGeneralType, EMPXGroup);
entries->SetTObjectValueL<TMPXGeneralCategory>(KMPXMediaGeneralCategory,
aCriteria.ValueTObjectL<TMPXGeneralCategory>(KMPXMediaGeneralCategory));
entries->SetCObjectValueL(KMPXMediaArrayContents, array);
entries->SetTObjectValueL<TInt>(KMPXMediaArrayCount, array->Count());
CleanupStack::PopAndDestroy(array);
return entries;
}
// ----------------------------------------------------------------------------
// Set the last refreshed time into the collection
// ----------------------------------------------------------------------------
//
void CMPXDbHandler::SetLastRefreshedTimeL(
TTime aTime)
{
MPX_FUNC("CMPXDbHandler::SetLastRefreshedTimeL");
BeginTransactionL();
MPX_TRAPD(err, iDbAuxiliary->SetLastRefreshedTimeL(aTime));
EndTransactionL(err);
}
// ----------------------------------------------------------------------------
// Get the last refreshed time from the collection
// ----------------------------------------------------------------------------
//
TTime CMPXDbHandler::GetLastRefreshedTimeL()
{
MPX_FUNC("CMPXDbHandler::GetLastRefreshedTimeL");
return iDbAuxiliary->LastRefreshedTimeL();
}
// ----------------------------------------------------------------------------
// Set the db corrupted state for all drives
// ----------------------------------------------------------------------------
//
void CMPXDbHandler::SetDBCorruptedL(
TBool aCorrupted)
{
MPX_FUNC("CMPXDbHandler::SetDBCorruptedL");
BeginTransactionL();
MPX_TRAPD(err, iDbAuxiliary->SetDBCorruptedL(aCorrupted));
EndTransactionL(err);
}
// ----------------------------------------------------------------------------
// Gets the db corrupted state for all drives
// ----------------------------------------------------------------------------
//
TBool CMPXDbHandler::IsDBCorruptedL()
{
MPX_FUNC("CMPXDbHandler::IsDBCorruptedL");
return iDbAuxiliary->DBCorruptedL();
}
// ----------------------------------------------------------------------------
// Have the databases been created?
// ----------------------------------------------------------------------------
//
TBool CMPXDbHandler::DatabaseCreated()
{
MPX_FUNC("CMPXDbHandler::DatabaseCreatedL");
TBool AuxilaryDbIsRefreshed(EFalse);
TRAP_IGNORE(AuxilaryDbIsRefreshed = iDbAuxiliary->IsRefreshedL());
// If none of the databases were available, ie out of disk we return EFalse
return iDbManager->IsInitialized() && AuxilaryDbIsRefreshed;
}
// ----------------------------------------------------------------------------
// Open a database
// ----------------------------------------------------------------------------
//
void CMPXDbHandler::OpenDatabaseL(
TInt aDrive)
{
MPX_FUNC("CMPXDbHandler::OpenDatabaseL");
MPX_DEBUG2( "CMPXDbHandler::OpenDatabaseL: %i", aDrive);
iDbManager->OpenDatabaseL(aDrive);
// Verify the volume ID after a remount event
VerifyVolumeIdL();
}
// ----------------------------------------------------------------------------
// Close a database
// ----------------------------------------------------------------------------
//
void CMPXDbHandler::CloseDatabaseL(
TInt aDrive)
{
MPX_FUNC("CMPXDbHandler::CloseDatabaseL");
MPX_DEBUG2( "CMPXDbHandler::CloseDatabaseL drive: %i", aDrive );
iDbManager->CloseDatabaseL(aDrive);
}
// ----------------------------------------------------------------------------
// Re-create all databases
// ----------------------------------------------------------------------------
//
void CMPXDbHandler::ReCreateDatabasesL()
{
MPX_FUNC("CMPXDbHandler::ReCreateDatabasesL");
iDbManager->RecreateAllDatabasesL();
}
// ----------------------------------------------------------------------------
// Set handler refresh status
// ----------------------------------------------------------------------------
//
void CMPXDbHandler::RefreshStartL()
{
MPX_FUNC("CMPXDbHandler::RefreshStartL");
iOutOfDisk = EFalse;
// Re-open databases
// This is needed for the case where we were OOD before, but user
// has cleared some space but now try to refresh
MPX_TRAPD(err, iDbManager->InitDatabasesL(iDbDrives));
iCollectionOpen = ETrue;
// Update (synchronize) music basic table if it's not
// in sync with music table
if(iSynchronizeBasicTable)
{
iDbMusic->RefreshEndL();
}
iSynchronizeBasicTable = ETrue;
if(err == KErrDiskFull)
{
iOutOfDisk = ETrue;
}
if(!iOutOfDisk)
{
MPX_TRAP(err,CheckDiskSpaceOnDrivesL());
if(err == KErrDiskFull)
{
iOutOfDisk = ETrue;
}
}
iDbMusic->RefreshStartL();
BeginTransactionL();
iRefresh = ETrue;
}
// ----------------------------------------------------------------------------
// Re-set handler refresh status
// ----------------------------------------------------------------------------
//
void CMPXDbHandler::RefreshEndL()
{
MPX_FUNC("CMPXDbHandler::RefreshEndL");
iRefresh = EFalse;
EndTransactionL(KErrNone);
if (!iOutOfDisk)
{
// Write last refreshed time as current time
// This also sets corrupt = 0
TTime curTime;
curTime.HomeTime();
SetLastRefreshedTimeL(curTime);
}
iDbMusic->RefreshEndL();
//Update of music basic table fails when the collection is not open
//Next time the collection is opened the music basic table must be updated
if (iCollectionOpen )
{
iSynchronizeBasicTable = EFalse;
}
}
// ----------------------------------------------------------------------------
// Notification of Mtp status change
// ----------------------------------------------------------------------------
//
void CMPXDbHandler::MtpStartL()
{
iMtpInUse = ETrue;
iOpOnDbCount = 0;
iDbManager->BeginL();
}
// ----------------------------------------------------------------------------
// Notification of Mtp status change
// ----------------------------------------------------------------------------
//
void CMPXDbHandler::MtpEndL()
{
iMtpInUse = EFalse;
iOpOnDbCount = 0;
iDbManager->CommitL();
}
// ----------------------------------------------------------------------------
// Get all records count for music
// ----------------------------------------------------------------------------
//
TUint CMPXDbHandler::GetMusicCountL(TInt aDrive)
{
MPX_FUNC("CMPXDbHandler::GetMusicCountL");
TUint total(0);
//music
total += iDbMusic->GetDriveTrackCountL(aDrive);
return total;
}
// ----------------------------------------------------------------------------
// Get all records count for playlists
// ----------------------------------------------------------------------------
//
TUint CMPXDbHandler::GetPlaylistCountL(TInt aDrive)
{
MPX_FUNC("CMPXDbHandler::GetPlaylistCountL");
TUint total(0);
//playlist
total += iDbPlaylist->GetDrivePlaylistCountL(aDrive);
return total;
}
// ----------------------------------------------------------------------------
// Get all records count for music and playlists
// ----------------------------------------------------------------------------
//
TUint CMPXDbHandler::GetTotalCountL(TInt aDrive)
{
MPX_FUNC("CMPXDbHandler::GetTotalCountL");
TUint total(0);
//music
total += iDbMusic->GetDriveTrackCountL(aDrive);
//playlist
total += iDbPlaylist->GetDrivePlaylistCountL(aDrive);
return total;
}
// ----------------------------------------------------------------------------
// Get all records count for music and playlists
// ----------------------------------------------------------------------------
//
void CMPXDbHandler::GetMusicUriArrayL(TInt aDrive, TInt aFromID, TInt aRecords,
CDesCArray& aUriArr, TInt& aLastID)
{
MPX_FUNC("CMPXDbHandler::GetMusicUriArrayL");
iDbMusic->GetMusicUriArrayL(aDrive,aFromID,aRecords,aUriArr,aLastID);
}
// ----------------------------------------------------------------------------
// Get all records count for music and playlists
// ----------------------------------------------------------------------------
//
void CMPXDbHandler::GetPlaylistUriArrayL(TInt aDrive, TInt aFromID, TInt aRecords,
CDesCArray& aUriArr, TInt& aLastID)
{
MPX_FUNC("CMPXDbHandler::GetPlaylistUriArrayL");
iDbPlaylist->GetPlaylistUriArrayL(aDrive,aFromID,aRecords,aUriArr,aLastID);
}
// ----------------------------------------------------------------------------
// Starts a transaction on all databases
// ----------------------------------------------------------------------------
//
void CMPXDbHandler::BeginTransactionL()
{
MPX_FUNC("CMPXDbHandler::BeginTransactionL");
if(!iMtpInUse)
{
iDbManager->BeginL();
}
}
// ----------------------------------------------------------------------------
// Ends a transaction on all databases
// ----------------------------------------------------------------------------
//
void CMPXDbHandler::EndTransactionL(
TInt aError)
{
MPX_FUNC("CMPXDbHandler::EndTransactionL");
if(iMtpInUse)
{
if (aError)
{
iOpOnDbCount = 0;
iDbManager->RollbackL();
User::Leave(aError);
}
if(iOpOnDbCount >= KMaxOpInTransaction)
{
MPX_DEBUG2("CMPXDbHandler::EndTransactionL - %d>KMaxOpInTransaction Commiting",iOpOnDbCount);
iOpOnDbCount = 0;
iDbManager->CommitL();
iDbManager->BeginL();
}
}
else
{
if (aError)
{
MPX_DEBUG2("CMPXDbHandler::EndTransactionL - Rollback [%d]", aError);
iDbManager->RollbackL();
// KSqlDbCorrupted indicates DB corrupted, need to recreate.
if ( aError != KSqlDbCorrupted )
{
User::Leave(aError);
}
}
else
{
iDbManager->CommitL();
}
}
}
// ----------------------------------------------------------------------------
// Checks if the database is currently in a transaction
// ----------------------------------------------------------------------------
//
TBool CMPXDbHandler::InTransaction()
{
MPX_FUNC("CMPXDbHandler::InTransaction");
return iDbManager->InTransaction();
}
// ----------------------------------------------------------------------------
// Notifies the handler that the collection will be closed.
// It is called before closing the collection.
// ----------------------------------------------------------------------------
//
void CMPXDbHandler::PreCloseCollectionL()
{
MPX_FUNC("CMPXDbHandler::PreCloseCollectionL");
// Complete pending transaction and set the latest refresh time
// before closing the databases if collection close event occurs
// before the end of the refresh operation
if(iRefresh)
{
EndTransactionL(KErrNone);
if (!iOutOfDisk)
{
// Write last refreshed time as current time
// This also sets corrupt = 0
TTime curTime;
curTime.HomeTime();
SetLastRefreshedTimeL(curTime);
}
}
}
// ----------------------------------------------------------------------------
// Notifies the handler that the collection was closed.
// ----------------------------------------------------------------------------
//
void CMPXDbHandler::CollectionClosed()
{
MPX_FUNC("CMPXDbHandler::CollectionClosed");
iCollectionOpen = EFalse;
}
// ----------------------------------------------------------------------------
//Notifies the handler that the collection was opened.
// ----------------------------------------------------------------------------
//
void CMPXDbHandler::CollectionOpenedL()
{
MPX_FUNC("CMPXDbHandler::CollectionOpened");
iCollectionOpen = ETrue;
// Update (synchronize) music basic table if it's not
// in sync with music table
if(iSynchronizeBasicTable)
{
iDbMusic->RefreshEndL();
iSynchronizeBasicTable = EFalse;
}
}
// ----------------------------------------------------------------------------
// Add song to collection
// ----------------------------------------------------------------------------
//
TUint32 CMPXDbHandler::DoAddSongL(
const CMPXMedia& aMedia,
CMPXMessageArray* aMessageArray)
{
MPX_FUNC("CMPXDbHandler::DoAddSongL");
if (!aMedia.IsSupported(KMPXMediaGeneralUri))
{
User::Leave(KErrArgument);
}
// add the song to the Music table
TDriveUnit drive(aMedia.ValueText(KMPXMediaGeneralUri));
TUint32 songId(iDbMusic->AddSongL(aMedia, drive,
iRefresh?NULL:aMessageArray));
// update the playlist tables
// make sure the song db flags are reset and not just updated
iDbPlaylist->UpdateSongL(aMedia, ETrue);
if(iMtpInUse)
{
++iOpOnDbCount;
}
return songId;
}
// ----------------------------------------------------------------------------
// Add playlist to collection
// ----------------------------------------------------------------------------
//
TUint32 CMPXDbHandler::DoAddPlaylistL(
const CMPXMedia& aMedia)
{
MPX_FUNC("CMPXDbHandler::DoAddPlaylistL");
CMPXMedia* media = CMPXMedia::NewL(aMedia);
CleanupStack::PushL(media);
const TDesC& playlistUri = media->ValueText(KMPXMediaGeneralUri);
//
// client has asked to create a virtual playlist if file name is not specified
// in the URI. In this case, generate URI for virtual playlist specified as
// follows:
// <dir path>\timestamp.vir
//
TParsePtrC parser(playlistUri);
if (!parser.NameOrExtPresent() ||
parser.IsNameWild() ||
parser.IsExtWild())
{
HBufC* newUri = HBufC::NewLC(parser.DriveAndPath().Length() + KMCMaxTextLen +
KMPXVirtualPlaylistExt().Length());
TPtr ptr = newUri->Des();
ptr.Append(parser.DriveAndPath());
TTime time;
time.HomeTime();
ptr.AppendNum(time.Int64());
ptr.Append(KMPXVirtualPlaylistExt);
// overwrite the old uri with the new one with full path and playlist
// playlist filename
media->SetTextValueL(KMPXMediaGeneralUri, *newUri);
CleanupStack::PopAndDestroy(newUri);
// set DbFlags to indicate that this is a virtual playlist
media->SetTObjectValueL<TUint>(KMPXMediaGeneralFlags,
KMPXMediaGeneralFlagsSetOrUnsetBit | KMPXMediaGeneralFlagsIsVirtual);
}
// complete the song attributes from the music table
UpdatePlaylistSongInfoL(*media);
// add playlist to the database
TUint32 playlistId = iDbPlaylist->AddPlaylistL(*media);
CleanupStack::PopAndDestroy(media);
return playlistId;
}
// ----------------------------------------------------------------------------
// Add song to playlist
// ----------------------------------------------------------------------------
//
TUint32 CMPXDbHandler::DoAddSongToPlaylistL(
const CMPXMedia& aMedia)
{
MPX_FUNC("CMPXDbHandler::DoAddSongToPlaylistL");
CMPXMedia* media = CMPXMedia::NewL(aMedia);
CleanupStack::PushL(media);
// complete the song attributes from the music table
UpdatePlaylistSongInfoL(*media);
// add the songs to the playlist
TUint32 playlistId((media->ValueTObjectL<TMPXItemId>(KMPXMediaGeneralId)).iId2);
CMPXMediaArray* ary( aMedia.Value<CMPXMediaArray>(KMPXMediaArrayContents) );
User::LeaveIfNull( ary );
iDbPlaylist->AddSongsL(playlistId,*ary);
CleanupStack::PopAndDestroy(media);
return playlistId;
}
// ----------------------------------------------------------------------------
// Update a song in the collection
// ----------------------------------------------------------------------------
//
CMPXDbActiveTask::TChangeVisibility CMPXDbHandler::DoUpdateSongL(
const CMPXMedia& aMedia,
CMPXMessageArray& aItemChangedMessages)
{
MPX_FUNC("CMPXDbHandler::DoUpdateSongL");
CMPXDbActiveTask::TChangeVisibility visibleChange(CMPXDbActiveTask::ENotVisibile);
TUint32 songId(0);
if (aMedia.IsSupported(KMPXMediaGeneralId))
{
songId = (aMedia.ValueTObjectL<TMPXItemId>(KMPXMediaGeneralId)).iId2;
}
if (aMedia.IsSupported(KMPXMediaGeneralUri))
{
const TDesC& uri = aMedia.ValueText(KMPXMediaGeneralUri);
songId = MPXDbCommonUtil::GenerateUniqueIdL(iFs, EMPXCollection, uri, EFalse);
}
if (!songId)
{
User::Leave(KErrNotSupported);
}
// Update the Music table
TRAPD(err, visibleChange = iDbMusic->UpdateSongL(songId, aMedia, aItemChangedMessages));
// do not leave if song is not found in Music table
// leave for other errors such as disk full
if(err != KErrNone && err != KErrNotFound)
{
User::Leave(err);
}
// Update the Playlist table
TBool visible = EFalse;
TRAP( err, visible = iDbPlaylist->UpdateSongL(aMedia, EFalse, &aItemChangedMessages));
// do not leave if song is not found in Playlist table
// leave for other errors such as disk full
if(err != KErrNone && err != KErrNotFound)
{
User::Leave(err);
}
// make it visible if either table is updated
if (visible)
{
visibleChange = CMPXDbActiveTask::EAllVisible;
}
return visibleChange;
}
// ----------------------------------------------------------------------------
// Update a playlist in the collection
// ----------------------------------------------------------------------------
//
void CMPXDbHandler::DoUpdatePlaylistL(
const CMPXMedia& aMedia,
CMPXMessageArray& aMessageArray)
{
MPX_FUNC("CMPXDbHandler::DoUpdatePlaylistL");
TUint32 playlistId(0);
TInt drive(0);
CMPXMedia* media = CMPXMedia::NewL(aMedia);
CleanupStack::PushL(media);
ProcessPlaylistMediaL(*media, playlistId, drive);
CMPXMessage* m1 = CMPXMessage::NewL();
CleanupStack::PushL(m1);
CMPXMessage* m2 = CMPXMessage::NewL();
CleanupStack::PushL(m2);
// send 2 messages to notify the playlist change & to refresh the display (update playlist name)
MPXDbCommonUtil::FillItemChangedMessageL(*m1, playlistId, EMPXItemModified,
EMPXPlaylist, KDBPluginUid);
MPXDbCommonUtil::FillItemChangedMessageL(*m2, EBrowsePlaylist, EMPXItemModified,
EMPXPlaylist, KDBPluginUid);
iDbPlaylist->UpdatePlaylistL(*media, *m1, drive);
aMessageArray.AppendL(*m1);
aMessageArray.AppendL(*m2);
CleanupStack::PopAndDestroy(m2);
CleanupStack::PopAndDestroy(m1);
CleanupStack::PopAndDestroy(media);
}
// ----------------------------------------------------------------------------
// Update a playlist in the collection
// ----------------------------------------------------------------------------
//
void CMPXDbHandler::DoUpdatePlaylistSongsL(
const CMPXMedia& aMedia,
CMPXMessage& aMessage)
{
MPX_FUNC("CMPXDbHandler::DoUpdatePlaylistSongsL");
CMPXMedia* media = CMPXMedia::NewL(aMedia);
CleanupStack::PushL(media);
TUint32 playlistId(0);
TInt drive(0);
// get the playlist ID and drive ID
ProcessPlaylistMediaL(*media, playlistId, drive);
MPXDbCommonUtil::FillItemChangedMessageL(aMessage, playlistId, EMPXItemModified,
EMPXPlaylist, KDBPluginUid);
// complete the song attributes from the Music table
UpdatePlaylistSongInfoL(*media);
// delete existing songs for the playlist first
iDbPlaylist->Songs().DeleteSongsL(playlistId, drive);
// add new songs to the playlist
CMPXMediaArray* ary( media->Value<CMPXMediaArray>(KMPXMediaArrayContents ) );
User::LeaveIfNull( ary );
iDbPlaylist->AddSongsL(playlistId, *ary);
CleanupStack::PopAndDestroy(media);
}
// ----------------------------------------------------------------------------
// Reorder a song in a playlist
// ----------------------------------------------------------------------------
//
void CMPXDbHandler::DoReorderPlaylistL(
const TMPXItemId& aPlaylistId,
const TMPXItemId& aSongId,
TUint aOriginalOrdinal,
TUint aNewOrdinal,
CMPXMessage& aMessage)
{
MPX_DEBUG1("-->CMPXDbHandler::DoReorderPlaylistL()");
if (aOriginalOrdinal != aNewOrdinal)
{
iDbPlaylist->Songs().ReorderSongL(aPlaylistId, aSongId, aOriginalOrdinal, aNewOrdinal);
MPXDbCommonUtil::FillItemChangedMessageL(aMessage, aPlaylistId.iId2, EMPXItemModified,
EMPXPlaylist, KDBPluginUid);
}
MPX_DEBUG1("<--CMPXDbHandler::DoReorderPlaylistL()");
}
// ----------------------------------------------------------------------------
// Delete a song from collection
// The function notifies collection model to perform deletion
// ----------------------------------------------------------------------------
//
void CMPXDbHandler::DoRemoveSongL(
TUint32 aSongId,
CDesCArray& aUriArray,
CMPXMessageArray& aItemChangedMessages,
TBool aDeleteRecord)
{
MPX_FUNC("CMPXDbHandler::DoRemoveSongL");
// Get the song drive
TUint32 artistID(0);
TUint32 albumID(0);
TUint32 genreID(0);
TUint32 composerID(0);
TInt drive(0);
// Get information from the Music table first
HBufC* uri = iDbMusic->GetSongInfoL(aSongId, artistID, albumID, genreID, composerID, drive);
// add the URI to the return array
CleanupStack::PushL(uri);
aUriArray.AppendL(*uri);
CleanupStack::PopAndDestroy(uri);
// Update the category records
TBool categoryExist( EFalse );
iDbArtist->DecrementSongsForCategoryL(artistID, drive, &aItemChangedMessages, categoryExist);
iDbAlbum->DecrementSongsForCategoryL(albumID, drive, &aItemChangedMessages, categoryExist, artistID);
iDbGenre->DecrementSongsForCategoryL(genreID, drive, &aItemChangedMessages, categoryExist);
iDbComposer->DecrementSongsForCategoryL(composerID, drive, &aItemChangedMessages, categoryExist);
// Update the music table
TBool deleteRecord(ETrue);
#if defined (__MTP_PROTOCOL_SUPPORT)
// Mark the song record as deleted if the following is true; otherwise, delete the
// song record.
//
// A client other than MTP has initiated this song deletion (aDeleteRecord is EFalse)
// and MTP has turned on its cenrep key to save deleted records and current number of
// saved deleted records has not exceeded its maximum, KMCMaxSavedDeletedRecords.
//
// Songs are marked as deleted in order to support auto-sync. MTP will delete these
// marked records at the end of each session via CleanupDeletedRecordsL.
//
// For performance consideration, if the number of saved records exceeds its maximum,
// song record will be deleted.
if (!aDeleteRecord && SaveDeletedSongs())
{
TUint32 savedDeletedRecordCount(iDbAuxiliary->SaveDeletedRecordCountL());
MPX_DEBUG2("Current number of saved deleted record count is %d", savedDeletedRecordCount);
if (savedDeletedRecordCount < KMCMaxSavedDeletedRecords)
{
deleteRecord = EFalse;
TUint32 savedDeletedDriveRecordCount(iDbAuxiliary->SaveDeletedRecordCountL(drive));
iDbAuxiliary->SetSaveDeletedRecordCountL(drive,++savedDeletedDriveRecordCount);
}
}
#endif
// delete the song from the Music table
iDbMusic->DeleteSongL(aSongId, drive, deleteRecord);
// add the item changed message
MPXDbCommonUtil::AddItemChangedMessageL(aItemChangedMessages, aSongId, EMPXItemDeleted,
EMPXSong, KDBPluginUid);
if(iMtpInUse)
{
++iOpOnDbCount;
}
}
// ----------------------------------------------------------------------------
// Delete a song from playlist tables
// ----------------------------------------------------------------------------
//
void CMPXDbHandler::DoRemoveSongFromPlaylistL(TUint32 aSongId,CMPXMessageArray& aItemChangedMessages)
{
MPX_FUNC("CMPXDbHandler::DoRemoveSongFromPlaylistL");
// delete song from the playlist tables on all drives
iDbPlaylist->DeleteSongL(aSongId, aItemChangedMessages);
}
// ----------------------------------------------------------------------------
// Removes a category of songs from the music collection,
// and its corresponding category in the lookup table
// ----------------------------------------------------------------------------
//
void CMPXDbHandler::DoRemoveSongsMatchingCategoryL(
TMPXGeneralCategory aCategory,
TUint32 aCategoryId,
CDesCArray& aUriArray,
CMPXMessageArray& aItemChangedMessages)
{
MPX_FUNC("CMPXDbHandler::DoRemoveSongsMatchingCategoryL");
// get the songs for the specified category
CMPXMediaArray* songs = CMPXMediaArray::NewL();
CleanupStack::PushL(songs);
RArray<TMPXAttribute> attributes;
CleanupClosePushL(attributes);
attributes.AppendL(KMPXMediaGeneralId);
switch (aCategory)
{
case EMPXArtist:
{
iDbMusic->GetSongsForArtistL(aCategoryId, attributes.Array(), *songs);
break;
}
case EMPXAlbum:
{
iDbMusic->GetSongsForAlbumL(aCategoryId, attributes.Array(), *songs);
break;
}
case EMPXGenre:
{
iDbMusic->GetSongsForGenreL(aCategoryId, attributes.Array(), *songs);
break;
}
case EMPXComposer:
{
iDbMusic->GetSongsForComposerL(aCategoryId, attributes.Array(), *songs);
break;
}
default:
User::Leave(KErrNotSupported);
}
CleanupStack::PopAndDestroy(&attributes);
// iterate the songs and remove them one by one
// so records in the category tables can also be updated
TInt count(songs->Count());
for (TInt index = 0; index < count; ++index)
{
CMPXMedia* song = (*songs)[index];
if (song->IsSupported(KMPXMediaGeneralId))
{
DoRemoveSongL((song->ValueTObjectL<TMPXItemId>(KMPXMediaGeneralId)).iId2,
aUriArray, aItemChangedMessages, EFalse);
DoRemoveSongFromPlaylistL((song->ValueTObjectL<TMPXItemId>(KMPXMediaGeneralId)).iId2,aItemChangedMessages);
}
}
CleanupStack::PopAndDestroy(songs);
}
// ----------------------------------------------------------------------------------------------------------
// Delete songs for the specified artist and album from collection
// ----------------------------------------------------------------------------------------------------------
//
void CMPXDbHandler::DoRemoveSongsMatchingArtistAndAlbumL(
TUint32 aArtistId,
TUint32 aAlbumId,
CDesCArray& aUriArray,
CMPXMessageArray& aItemChangedMessages)
{
MPX_FUNC("CMPXDbHandler::RemoveSongsMatchingArtistAndAlbumL");
// get the songs for the specified artist and album
CMPXMediaArray* songs = CMPXMediaArray::NewL();
CleanupStack::PushL(songs);
RArray<TMPXAttribute> attributes;
CleanupClosePushL (attributes);
attributes.AppendL(KMPXMediaGeneralId);
iDbMusic->GetSongsForArtistAndAlbumL(aArtistId, aAlbumId, attributes.Array(), *songs);
CleanupStack::PopAndDestroy(&attributes);
// iterate the songs and remove them one by one
// so records in the category tables can also be updated
TInt count(songs->Count());
for (TInt index = 0; index < count; ++index)
{
CMPXMedia* song = (*songs)[index];
if (song->IsSupported(KMPXMediaGeneralId))
{
DoRemoveSongL( song->ValueTObjectL<TMPXItemId>(KMPXMediaGeneralId),
aUriArray, aItemChangedMessages, EFalse);
DoRemoveSongFromPlaylistL(song->ValueTObjectL<TMPXItemId>(KMPXMediaGeneralId),aItemChangedMessages);
}
}
CleanupStack::PopAndDestroy(songs);
}
// ----------------------------------------------------------------------------
// Remove all playlists from collection
// ----------------------------------------------------------------------------
//
void CMPXDbHandler::DoRemoveAllPlaylistsL()
{
MPX_FUNC("CMPXDbHandler::DoRemoveAllPlaylistsL");
iDbPlaylist->DeleteAllPlaylistsL();
}
// ----------------------------------------------------------------------------
// Remove specified playlist
// ----------------------------------------------------------------------------
//
void CMPXDbHandler::DoRemovePlaylistL(
TUint32 aPlaylistId,
CDesCArray& aUriArray,
CMPXMessageArray& aItemChangedMessages)
{
MPX_FUNC("CMPXDbHandler::DoRemovePlaylistL");
HBufC* uri(iDbPlaylist->DeletePlaylistL(aPlaylistId));
if (uri)
{
CleanupStack::PushL(uri);
aUriArray.AppendL(*uri);
CleanupStack::PopAndDestroy(uri);
}
MPXDbCommonUtil::AddItemChangedMessageL(aItemChangedMessages, aPlaylistId, EMPXItemDeleted,
EMPXPlaylist, KDBPluginUid);
}
// ----------------------------------------------------------------------------
// Remove song from playlist songs table
// ----------------------------------------------------------------------------
//
void CMPXDbHandler::DoRemoveSongFromPlaylistL(
TUint32 aPlaylistId,
const TMPXItemId& aSongId,
TInt aOrdinal,
CMPXMessageArray& aItemChangedMessages)
{
MPX_FUNC("CMPXDbHandler::DoRemoveSongFromPlaylistL");
MPX_DEBUG5("CMPXDbHandler::DoRemoveSongFromPlaylistL(playlist 0x%x, songId [0x%x,0x%x], ordinal %d)",
aPlaylistId, aSongId.iId1, aSongId.iId2, aOrdinal);
// delete the song
iDbPlaylist->DeleteSongL(aPlaylistId, aSongId.iId2, aOrdinal);
// Send a playlist modified message
MPXDbCommonUtil::AddItemChangedMessageL(aItemChangedMessages, aPlaylistId, EMPXItemModified,
EMPXPlaylist, KDBPluginUid);
// Send a message on the song in the playlist that is deleted
MPXDbCommonUtil::AddItemChangedMessageL(aItemChangedMessages, aSongId, EMPXItemDeleted,
EMPXSong, KDBPluginUid);
}
// ----------------------------------------------------------------------------
// CMPXDbHandler::DoCleanupDeletedRecordsL
// ----------------------------------------------------------------------------
//
void CMPXDbHandler::DoCleanupDeletedRecordsL()
{
MPX_FUNC("CMPXDbHandler::DoCleanupDeletedRecordsL");
// delete all marked records from the Music table
iDbMusic->CleanupL();
// reset the count in the Auxiliary table
iDbAuxiliary->SetSaveDeletedRecordCountL(KDbManagerAllDrives,0);
}
// ----------------------------------------------------------------------------
// FindAllL
// ----------------------------------------------------------------------------
//
void CMPXDbHandler::FindAllL(
const CMPXMedia& aCriteria,
const TArray<TMPXAttribute>& aAttrs,
CMPXMediaArray* aMediaArray)
{
MPX_FUNC("CMPXDbHandler::FindAllL");
RArray<TMPXAttribute> attributes;
CleanupClosePushL(attributes);
MPXUser::MergeAttributeL(aAttrs, attributes);
TMPXGeneralCategory category = aCriteria.ValueTObjectL<TMPXGeneralCategory>(KMPXMediaGeneralCategory);
switch (category)
{
case EMPXPlaylist:
{
TUint32 playlistId(0);
if (aCriteria.IsSupported(KMPXMediaGeneralId))
{
playlistId = (aCriteria.ValueTObjectL<TMPXItemId>(KMPXMediaGeneralId)).iId2;
}
if (iAutoPlaylist->AutoPlaylistTypeL(playlistId) != EMPXNoAutoPlaylist)
{
CMPXMedia* media = CMPXMedia::NewL();
CleanupStack::PushL(media);
iAutoPlaylist->GetPlaylistL(playlistId, aAttrs, *media);
aMediaArray->AppendL(*media);
CleanupStack::PopAndDestroy(media);
}
else
{
iDbPlaylist->FindAllL(aCriteria, attributes.Array(), *aMediaArray);
}
break;
}
case EMPXSong:
{
FindSongL(aCriteria, attributes.Array(), *aMediaArray);
break;
}
default:
{
DbCategoryL(category)->FindAllL(aCriteria, attributes.Array(), *aMediaArray);
break;
}
}
CleanupStack::PopAndDestroy(&attributes);
}
// ----------------------------------------------------------------------------
// Get song(s) from the music table that match the given criteria
// ----------------------------------------------------------------------------
//
void CMPXDbHandler::FindSongL(
const CMPXMedia& aCriteria,
const TArray<TMPXAttribute>& aAttrs,
CMPXMediaArray& aMediaArray)
{
MPX_FUNC("CMPXDbCollection::FindSongL");
TMPXGeneralType type = aCriteria.ValueTObjectL<TMPXGeneralType>(KMPXMediaGeneralType);
TUint32 id(0);
if (aCriteria.IsSupported(KMPXMediaGeneralId))
{
id = (aCriteria.ValueTObjectL<TMPXItemId>(KMPXMediaGeneralId)).iId2;
}
TUint32 containerId(0);
if (aCriteria.IsSupported(KMPXMediaGeneralContainerId))
{
containerId = aCriteria.ValueTObjectL<TUint32>(KMPXMediaGeneralContainerId);
}
//////////////////////////////////////////////////////////////////////
// Find songs in the specified playlist
//////////////////////////////////////////////////////////////////////
TMPXGeneralCategory cat(MPX_ITEM_CATEGORY(id));
if (type == EMPXGroup &&
(cat == EMPXPlaylist ||
MPX_ITEM_CATEGORY(containerId) == EMPXPlaylist))
{
TUint32 playlistId = (cat == EMPXPlaylist) ?
id : (containerId & KMCCategoryMask);
GetPlaylistSongsL(playlistId, aAttrs, aMediaArray);
}
//////////////////////////////////////////////////////////////////////
// Find a particular song in the specified playlist. This fills the
// song with info from Playlist table first then overwrites it with
// info from Songs table if Songs table where this song is located
// is present in order to support the display of song titles in a
// playlist when memory card is removed if the playlist refers to
// songs on the memory card. Caller of this scenario is OpenL/MediaL.
// When user attempts to play a track in an auto-playlist, we will
// find the song from Songs table directly since auto-playlists are
// not stored in the Playlist table. Auto-playlists are query-based,
// therefore, when memory card is removed, songs on the memory card
// will not be shown in the auto-playlist; hence they do not exhibit
// the same challenge as user created playlists.
//////////////////////////////////////////////////////////////////////
else if (type == EMPXItem &&
cat == EMPXCollection &&
MPX_ITEM_CATEGORY(containerId) == EMPXPlaylist)
{
if (iAutoPlaylist->AutoPlaylistTypeL(containerId) != EMPXNoAutoPlaylist)
{
// auto playlist song, get the song details from the music table
iDbMusic->FindSongsL(id, 0, type, aCriteria, aAttrs, aMediaArray);
}
else
{
GetPlaylistSongL(id, containerId, aAttrs, aMediaArray);
}
}
//////////////////////////////////////////////////////////////////////
// Find all songs, all songs in a particular album and/or artist, or
// a particular song
//////////////////////////////////////////////////////////////////////
else
{
iDbMusic->FindSongsL(id, containerId, type, aCriteria, aAttrs, aMediaArray);
}
}
// ----------------------------------------------------------------------------
// Get song(s) in the specified playlist
// ----------------------------------------------------------------------------
//
void CMPXDbHandler::GetPlaylistSongsL(
TUint32 aPlaylistId,
const TArray<TMPXAttribute>& aAttrs,
CMPXMediaArray& aMediaArray)
{
MPX_FUNC("CMPXDbHandler::GetPlaylistSongsL");
MPX_DEBUG2("CMPXDbHandler::GetPlaylistSongsL(0x%x)", aPlaylistId);
// check the auto playlists first
if (aPlaylistId == iAutoPlaylist->AutoPlaylistIdL(EMPXRecentlyPlayedPlaylist))
{
iDbMusic->GetRecentlyPlayedSongsL(aAttrs, aMediaArray);
}
else if (aPlaylistId == iAutoPlaylist->AutoPlaylistIdL(EMPXMostPlayedPlaylist))
{
iDbMusic->GetMostPlayedSongsL(aAttrs, aMediaArray);
}
else if (aPlaylistId == iAutoPlaylist->AutoPlaylistIdL(EMPXRecentlyAddedPlaylist))
{
iDbMusic->GetRecentlyAddedSongsL(aAttrs, aMediaArray);
}
else
{
TInt attrCount(aAttrs.Count());
if ( attrCount > 1 || (attrCount == 1 && !(aAttrs[0] == KMPXMediaGeneralId)) )
{
TInt plDrive(iDbPlaylist->GetDriveIdL(aPlaylistId));
MPX_TRAPD(err, iDbMusic->GetAllSongsL(plDrive, aPlaylistId, aAttrs, aMediaArray));
// song not found in Music table
if (err == KErrNotFound)
{
//
// Leave with KErrNotFound if one of the following is true:
// 1) the requested song is in an auto playlist. Since auto-playlist isn't
// stored in playlist tables, we won't be able to retrieve info elsewhere
// 2) the requested song is in a user playlist but we cannot find the song
// info from playlist tables either
//
if (EMPXNoAutoPlaylist != iAutoPlaylist->AutoPlaylistTypeL(aPlaylistId) ||
!iDbPlaylist->Songs().GetSongsL(aPlaylistId, aAttrs, aMediaArray))
{
User::Leave(KErrNotFound);
}
}
else
{
// ignore the error if KErrNotFound
User::LeaveIfError(err);
}
}
else
{
// get ids of the songs in the playlist
iDbPlaylist->Songs().GetSongsL(aPlaylistId, aMediaArray);
}
}
}
// ----------------------------------------------------------------------------
// Find all albums or the albums for a specified artist
// ----------------------------------------------------------------------------
//
void CMPXDbHandler::FindAlbumL(
const CMPXMedia& aCriteria,
const TArray<TMPXAttribute>& aAttrs,
CMPXMediaArray& aMediaArray)
{
MPX_FUNC("CMPXDbHandler::FindAlbumL");
TMPXGeneralType type = aCriteria.ValueTObjectL<TMPXGeneralType>(KMPXMediaGeneralType);
TUint32 id(0);
if (aCriteria.IsSupported(KMPXMediaGeneralId))
{
id = aCriteria.ValueTObjectL<TMPXItemId>(KMPXMediaGeneralId);
}
if ((type == EMPXGroup) && (MPX_ITEM_CATEGORY(id) == EMPXArtist))
{
// get all the albums for the artist
GetAlbumsMatchingArtistL(id, aAttrs, aMediaArray);
}
else
{
// look up all albums from album table
iDbAlbum->FindAllL(aCriteria, aAttrs, aMediaArray);
}
}
// ----------------------------------------------------------------------------
// Extracts the playlist ID and drive ID from a playlist media instance
// ----------------------------------------------------------------------------
//
void CMPXDbHandler::ProcessPlaylistMediaL(
CMPXMedia& aMedia,
TUint32& aPlaylistId,
TInt& aPlaylistDriveId)
{
MPX_FUNC("CMPXDbHandler::ProcessPlaylistMediaL");
if (aMedia.IsSupported(KMPXMediaGeneralId))
{
aPlaylistId = aMedia.ValueTObjectL<TMPXItemId>(KMPXMediaGeneralId);
if (aMedia.IsSupported(KMPXMediaGeneralUri))
{
// find drive id of the playlist
aPlaylistDriveId = TDriveUnit(aMedia.ValueText(KMPXMediaGeneralUri));
}
else
{
// Find drive Id(s) of corresponding Playlist Id
aPlaylistDriveId = iDbPlaylist->GetDriveIdL(aPlaylistId);
}
}
else if (aMedia.IsSupported(KMPXMediaGeneralUri))
{
const TDesC& playlistUri = aMedia.ValueText(KMPXMediaGeneralUri);
// find drive id of the playlist
aPlaylistDriveId = TDriveUnit(playlistUri);
// aMedia does not have an ID, make sure the add it
aPlaylistId = GetPlaylistIdMatchingUriL(playlistUri);
aMedia.SetTObjectValueL<TMPXItemId>(KMPXMediaGeneralId, aPlaylistId);
}
else
{
User::Leave(KErrArgument);
}
}
// ----------------------------------------------------------------------------
// Makes sure that all songs in the specified playlist have the ID, title and URI attributes
// ----------------------------------------------------------------------------
//
void CMPXDbHandler::UpdatePlaylistSongInfoL(
CMPXMedia& aMedia)
{
MPX_FUNC("CMPXDbHandler::UpdatePlaylistSongInfoL");
CMPXMediaArray* mediaArray = aMedia.Value<CMPXMediaArray>(KMPXMediaArrayContents);
User::LeaveIfNull(mediaArray);
// make sure each song has Id, Uri, and Title before they can be added to playlist
TInt count(mediaArray->Count());
for (TInt i = 0; i < count; ++i)
{
CMPXMedia* element = mediaArray->AtL(i);
// copy each song to deal w/ global heap issues
CMPXMedia* entry = CMPXMedia::NewL(*element);
CleanupStack::PushL(entry);
// song has everything, go to next song
if (entry->IsSupported(KMPXMediaGeneralUri) &&
entry->IsSupported(KMPXMediaGeneralId) &&
entry->IsSupported(KMPXMediaGeneralTitle))
{
// pop entry to maintain CleanupStack
CleanupStack::PopAndDestroy(entry);
continue;
}
// songs must contain (at minimum) an Uri or an Id
if (!entry->IsSupported(KMPXMediaGeneralUri) &&
!entry->IsSupported(KMPXMediaGeneralId))
{
User::Leave(KErrArgument);
}
// get Id
if (!entry->IsSupported(KMPXMediaGeneralId))
{
// fill in the ID if not present
TParsePtrC parser(entry->ValueText(KMPXMediaGeneralUri));
entry->SetTObjectValueL<TMPXItemId>(KMPXMediaGeneralId,
MPXDbCommonUtil::GenerateUniqueIdL(iFs, EMPXCollection, parser.FullName(), EFalse));
}
CMPXMedia* song(NULL);
// update songs info
TInt error(iDbMusic->GetSongL(*entry, song));
TBool result (ETrue);
// error can only be KErrNone or KErrNotFound
// from CMPXDbMusic::GetSongL
// if not found in Music, get info from PlaylistSongs (PlaylistSongs & PlaylistSongInfo) DB
if (error == KErrNotFound)
{
RArray<TMPXAttribute> attributes;
CleanupClosePushL(attributes);
attributes.AppendL(TMPXAttribute(KMPXMediaIdGeneral,
EMPXMediaGeneralId | EMPXMediaGeneralTitle | EMPXMediaGeneralUri | EMPXMediaGeneralFlags));
// this song doesn't exist in Music table. This song is either a broken link or
// is of an unsupported song type that exists in the file system. Broken links
// have already been marked as such during playlist import.
result = iDbPlaylist->Songs().GetSongL(entry->ValueTObjectL<TMPXItemId>(KMPXMediaGeneralId), attributes.Array(), song);
if (!result)
{
// song is a broken link
//TUint flags = KMPXMediaGeneralFlagsSetOrUnsetBit;
//flags |= KMPXMediaGeneralFlagsIsInvalid; // set flag
//t->SetTObjectValueL<TUint>( KMPXMediaGeneralFlags, flags );
if (entry->IsSupported(KMPXMediaGeneralUri))
{
// no valid Id but has Uri, just verify Title is present
// this is the case if the song is a broken link or podcast
if (!entry->IsSupported(KMPXMediaGeneralTitle))
{
// does not have Title, make up the Title from file name
TParsePtrC parser(entry->ValueText(KMPXMediaGeneralUri));
entry->SetTextValueL(KMPXMediaGeneralTitle, parser.Name());
}
}
else
{
// no valid Id & no Uri, bad argument
User::Leave(KErrArgument);
}
}
CleanupStack::PopAndDestroy(&attributes);
}
// update attributes
CleanupStack::PushL(song);
// song not found in Music or Playlist DB, update entry
if(error == KErrNotFound && !result)
{
mediaArray->InsertL(*entry,i);
}
else // found in DB, replace entry
{
mediaArray->InsertL(*song,i);
}
// replace element in the array
CleanupStack::PopAndDestroy(song);
CleanupStack::PopAndDestroy(entry);
mediaArray->Remove(i+1);
}
}
// ----------------------------------------------------------------------------
// CMPXDbHandler::ProcessMusicFoldersL
// ----------------------------------------------------------------------------
//
void CMPXDbHandler::ProcessMusicFoldersL(
const CDesCArray& aFolders)
{
MPX_FUNC("CMPXDbHandler::ProcessMusicFoldersL");
TInt count(aFolders.MdcaCount());
for (TInt i = 0; i < count; ++i)
{
TPtrC16 folder = aFolders.MdcaPoint(i);
// check if disk is inserted and act accordingly
TDriveUnit driveUnit(folder);
if (!iFs.IsValidDrive(driveUnit))
{
User::Leave(KErrArgument);
}
// append the drive to the drive list
iDbDrives.AppendL(driveUnit);
// make sure the folder is created
TVolumeInfo info;
if (iFs.Volume(info, driveUnit) == KErrNone)
{
if (!BaflUtils::PathExists(iFs, folder))
{
// create music folder if necessary
TInt err(iFs.MkDirAll(folder));
MPX_DEBUG3("Try to create music folder %S return code %d", &folder, err);
if (err != KErrAlreadyExists)
{
User::LeaveIfError(err);
}
}
}
}
}
// ----------------------------------------------------------------------------
// CMPXDbHandler::DbCategoryL
// ----------------------------------------------------------------------------
//
CMPXDbCategory* CMPXDbHandler::DbCategoryL(
TMPXGeneralCategory aCategory) const
{
MPX_FUNC("CMPXDbHandler::DbCategoryL");
CMPXDbCategory* dbCategory(NULL);
switch (aCategory)
{
case EMPXArtist:
{
dbCategory = (CMPXDbCategory*)iDbArtist;
break;
}
case EMPXAlbum:
{
dbCategory = (CMPXDbCategory*)iDbAlbum;
break;
}
case EMPXGenre:
{
dbCategory = (CMPXDbCategory*)iDbGenre;
break;
}
case EMPXComposer:
{
dbCategory = (CMPXDbCategory*)iDbComposer;
break;
}
default:
User::Leave(KErrNotSupported);
}
return dbCategory;
}
// ----------------------------------------------------------------------------
// Verifies that the volume ID of the database matches the drive
// ----------------------------------------------------------------------------
//
void CMPXDbHandler::VerifyVolumeIdL()
{
MPX_DEBUG1("CMPXDbHandler::VerifyVolumeIdL <--");
TInt count( iDbDrives.Count() );
for( TInt i=0; i<count; ++i )
{
if( iDbManager->IsOpen( iDbDrives[i] ) )
{
TVolumeInfo volInfo;
iFs.Volume(volInfo, iDbDrives[i] );
TUint curId(volInfo.iUniqueID);
TInt volId = iDbAuxiliary->IdL( iDbDrives[i] );
// New database, no volume id set, mask out top bit because this is an uint
//
MPX_DEBUG3("CMPXDBHandler::VerifyVolumeIdL drive:%i db:%i", curId, volId);
if( volId == 0 )
{
MPX_DEBUG1("CMPXDbHandler::VerifyVolumeIdL -- New ID");
BeginTransactionL();
TRAPD( err, iDbAuxiliary->SetIdL( iDbDrives[i], curId&0x7FFFFFFF ) );
EndTransactionL( err );
// KSqlDbCorrupted indicates DB corrupted, need to recreate.
if ( err == KSqlDbCorrupted )
{
MPX_DEBUG1("CMPXPodcastDbHandler::VerifyVolumeIdL -- Corrupted DB");
iDbManager->RecreateDatabaseL(iDbDrives[i]);
BeginTransactionL();
TRAPD(err, iDbAuxiliary->SetDBCorruptedL( ETrue ) );
EndTransactionL( err );
}
}
// Unmatched volume id, mark db as corrupt and break
//
else if ( (curId&0x7FFFFFFF) != (volId&0x7FFFFFFFF) )
{
MPX_DEBUG1("CMPXDbHandler::VerifyVolumeIdL -- ID match FAILED");
iDbManager->RecreateDatabaseL(iDbDrives[i]);
BeginTransactionL();
TRAPD(err, iDbAuxiliary->SetDBCorruptedL( ETrue ) );
EndTransactionL( err );
}
}
}
MPX_DEBUG1("CMPXDbHandler::VerifyVolumeIdL -->");
}
// ----------------------------------------------------------------------------
// Checks if there is a drive that has a low disk space
// ----------------------------------------------------------------------------
//
void CMPXDbHandler::CheckDiskSpaceOnDrivesL()
{
MPX_DEBUG1("CMPXDbHandler::CheckDiskSpaceOnDrivesL <--");
TInt count( iDbDrives.Count() );
for( TInt index=0; index<count; ++index )
{
iDbManager->CheckDiskSpaceL(iDbDrives[index]);
}
MPX_DEBUG1("CMPXDbHandler::CheckDiskSpaceOnDrivesL -->");
}
#if defined (__MTP_PROTOCOL_SUPPORT)
// ----------------------------------------------------------------------------
// CMPXDbHandler::SaveDeletedSongs
// ----------------------------------------------------------------------------
//
TBool CMPXDbHandler::SaveDeletedSongs()
{
MPX_FUNC("CMPXDbHandler::SaveDeletedSongs");
TBool saveDeletedSongs(ETrue);
CRepository* cenrep(NULL);
MPX_TRAPD(error, cenrep = CRepository::NewL(KMPXMtpSettings));
if (!error)
{
cenrep->Get(KMPXMtpSaveDeletedRecordFlag, saveDeletedSongs);
delete cenrep;
MPX_DEBUG2("MTP indicated to save deleted songs? %d", saveDeletedSongs);
}
return saveDeletedSongs;
}
#endif
#ifdef RD_MULTIPLE_DRIVE
// ----------------------------------------------------------------------------------------------------------
// Retrieve all visible music folder locations
// ----------------------------------------------------------------------------------------------------------
//
CDesCArrayFlat* CMPXDbHandler::GetMusicFoldersL()
{
MPX_FUNC("CMPXDbHandler::GetMusicFoldersL()");
TDriveList driveList;
TInt driveCount(0);
User::LeaveIfError(DriveInfo::GetUserVisibleDrives(iFs, driveList, driveCount));
MPX_DEBUG2 ("CMPXDbHandler::GetMusicFoldersL() - driveCount = %d", driveCount);
CDesCArrayFlat* folders = new (ELeave) CDesCArrayFlat(1); // granularity
CleanupStack::PushL(folders);
for (TInt i = EDriveA; i <= EDriveZ; i++)
{
if ((driveList[i]) && (!IsRemoteDrive(static_cast<TDriveNumber>(i))))
{
if (i == EDriveC)
{
// Append the default phone memory path to the list
// of music folders
TPtrC rootPath(PathInfo::PhoneMemoryRootPath());
folders->AppendL(rootPath);
MPX_DEBUG2("CMPXDbHandler::GetMusicFoldersL() - adding...%S", &rootPath);
}
else
{
// Get drive letter
TChar driveChar;
User::LeaveIfError(iFs.DriveToChar(i, driveChar));
// Append visible drive to list of music folders
TBuf<2> drive;
drive.Append(driveChar);
drive.Append(_L(":"));
folders->AppendL(drive);
MPX_DEBUG2 ("CMPXDbHandler::GetMusicFoldersL() - adding...%S", &drive);
}
}
}
CleanupStack::Pop(folders);
return folders;
}
#endif // RD_MULTIPLE_DRIVE
// ----------------------------------------------------------------------------
// CMPXDbHandler::AddCategoryItemL
// ----------------------------------------------------------------------------
//
TUint32 CMPXDbHandler::AddCategoryItemL(
TMPXGeneralCategory aCategory,
const TDesC& aName,
TInt aDriveId,
CMPXMessageArray* aItemChangedMessages,
TBool& aItemExist)
{
MPX_FUNC("CMPXDbHandler::AddCategoryItemL()");
MPX_PERF_START(CMPXDbHandler_AddCategoryItemL);
TBool newRecord(EFalse);
TUint32 id(DbCategoryL(aCategory)->AddItemL(aName, aDriveId, newRecord, (aCategory != EMPXGenre)));
if (newRecord && aItemChangedMessages)
{
MPXDbCommonUtil::AddItemChangedMessageL(*aItemChangedMessages, id, EMPXItemInserted,
aCategory, KDBPluginUid);
}
// when the added item's category is Genre or Composer,
// and it is NOT a new record,
// we should send the item number changed message
else if ( ( aCategory == EMPXGenre || aCategory == EMPXComposer ) &&
!newRecord && aItemChangedMessages )
{
MPXDbCommonUtil::AddItemChangedMessageL(*aItemChangedMessages, id, EMPXItemModified,
aCategory, KDBPluginUid);
}
aItemExist = !newRecord;
MPX_PERF_END(CMPXDbHandler_AddCategoryItemL);
return id;
}
TUint32 CMPXDbHandler::AddCategoryItemL(
TMPXGeneralCategory aCategory,
const TDesC& aName,
TUint32 aArtist,
const TDesC& aArt,
TInt aDriveId,
CMPXMessageArray* aItemChangedMessages,
TBool& aItemExist)
{
MPX_FUNC("CMPXDbHandler::AddCategoryItemL()");
MPX_PERF_START(CMPXDbHandler_AddCategoryItemL);
TBool newRecord(EFalse);
TUint32 id = 0;
if ( aArtist )
{
id = iDbAlbum->AddItemL(aName, aArtist, aArt, aDriveId, newRecord, (aCategory != EMPXGenre));
}
else
{
id = iDbArtist->AddItemL(aName, aArt, aDriveId, newRecord, (aCategory != EMPXGenre));
}
if (newRecord && aItemChangedMessages)
{
MPXDbCommonUtil::AddItemChangedMessageL(*aItemChangedMessages, id, EMPXItemInserted,
aCategory, KDBPluginUid);
}
// when the added item's category is Artist, and it is NOT a new record,
// we should send the item number changed message
else if ( aCategory == EMPXArtist &&
!newRecord && aItemChangedMessages )
{
MPXDbCommonUtil::AddItemChangedMessageL(*aItemChangedMessages, id, EMPXItemModified,
aCategory, KDBPluginUid);
}
aItemExist = !newRecord;
MPX_PERF_END(CMPXDbHandler_AddCategoryItemL);
return id;
}
void CMPXDbHandler::UpdateCategoryItemL(
TMPXGeneralCategory aCategory,
TUint32 aCategoryId,
const CMPXMedia& aMedia,
TInt aDrive,
CMPXMessageArray* aItemChangedMessages)
{
switch(aCategory)
{
case EMPXAlbum:
iDbAlbum->UpdateItemL(aCategoryId, aMedia, aDrive, aItemChangedMessages);
break;
case EMPXArtist:
iDbArtist->UpdateItemL(aCategoryId, aMedia, aDrive, aItemChangedMessages);
break;
default:
DbCategoryL(aCategory)->UpdateItemL(aCategoryId, aMedia, aDrive, aItemChangedMessages);
break;
}
}
// ----------------------------------------------------------------------------
// CMPXDbHandler::DeleteSongForCategoryL
// ----------------------------------------------------------------------------
//
void CMPXDbHandler::DeleteSongForCategoryL(
TMPXGeneralCategory aCategory,
TUint32 aCategoryId,
TInt aDriveId,
CMPXMessageArray* aItemChangedMessages,
TBool& aItemExist)
{
MPX_FUNC("CMPXDbHandler::DeleteSongForCategoryL");
DbCategoryL(aCategory)->DecrementSongsForCategoryL(aCategoryId, aDriveId,
aItemChangedMessages, aItemExist);
}
// ----------------------------------------------------------------------------
// CMPXDbHandler::HandlePlayCountModifiedL
// ----------------------------------------------------------------------------
//
void CMPXDbHandler::HandlePlayCountModifiedL(
CMPXMessageArray& aItemChangedMessages)
{
MPX_FUNC("CMPXDbHandler::HandlePlayCountModifiedL");
TUint32 plId(iAutoPlaylist->AutoPlaylistIdL(EMPXMostPlayedPlaylist));
MPXDbCommonUtil::AddItemChangedMessageL(aItemChangedMessages, plId, EMPXItemModified,
EMPXSong, KDBPluginUid, plId);
// Force the deprecated ID attribute
aItemChangedMessages[aItemChangedMessages.Count() - 1]->
SetTObjectValueL<TMPXItemId>(KMPXMessageMediaDeprecatedId, plId);
}
// ----------------------------------------------------------------------------------------------------------
// CMPXDbHandler::HandlePlaybackTimeModifiedL
// ----------------------------------------------------------------------------------------------------------
//
void CMPXDbHandler::HandlePlaybackTimeModifiedL(
CMPXMessageArray& aItemChangedMessages)
{
MPX_FUNC("CMPXDbHandler::HandlePlaybackTimeModifiedL");
TUint32 plId(iAutoPlaylist->AutoPlaylistIdL(EMPXRecentlyPlayedPlaylist));
MPXDbCommonUtil::AddItemChangedMessageL(aItemChangedMessages, plId, EMPXItemModified,
EMPXSong, KDBPluginUid, plId);
// Force the deprecated ID attribute
aItemChangedMessages[aItemChangedMessages.Count() - 1]->
SetTObjectValueL<TMPXItemId>(KMPXMessageMediaDeprecatedId, plId);
}
// ---------------------------------------------------------------------------
// CMPXDbHandler::IsRemoteDrive
// ---------------------------------------------------------------------------
//
TBool CMPXDbHandler::IsRemoteDrive(TDriveNumber aDrive)
{
return iDbManager->IsRemoteDrive(aDrive);
}
TInt CMPXDbHandler::HandlePlaylistDurationL(TUint32 aPlaylistId)
{
return GetPlaylistDurationL(aPlaylistId);
}
TInt CMPXDbHandler::HandleGetAlbumsCountForArtistL(TUint32 aArtistId)
{
return iDbAlbum->GetAlbumsCountForArtistL(aArtistId);
}
TBool CMPXDbHandler::HandleIsUnknownArtistL(TUint32 aArtistId)
{
return iDbArtist->IsUnknownArtistL(aArtistId);
}
TUint32 CMPXDbHandler::HandleArtistForAlbumL(const TUint32 aAlbumId)
{
return iDbMusic->ArtistForAlbumL(aAlbumId);
}
// End of file