View Javadoc

1   /***
2    *     Ambient - A music player for the Android platform
3    Copyright (C) 2007 Martin Vysny
4    
5    This program is free software: you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation, either version 3 of the License, or
8    (at your option) any later version.
9    
10   This program is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   GNU General Public License for more details.
14  
15   You should have received a copy of the GNU General Public License
16   along with this program.  If not, see <http://www.gnu.org/licenses/>.
17   */
18  
19  package sk.baka.ambient.collection.local;
20  
21  import java.util.ArrayList;
22  import java.util.Collection;
23  import java.util.EnumMap;
24  import java.util.List;
25  import java.util.Map;
26  
27  import sk.baka.ambient.AmbientApplication;
28  import sk.baka.ambient.R;
29  import sk.baka.ambient.collection.CategoryEnum;
30  import sk.baka.ambient.collection.CategoryItem;
31  import sk.baka.ambient.collection.CollectionUtils;
32  import sk.baka.ambient.collection.ICollection;
33  import sk.baka.ambient.collection.IDynamicPlaylistTrackProvider;
34  import sk.baka.ambient.collection.Statistics;
35  import sk.baka.ambient.collection.TrackMetadataBean;
36  import sk.baka.ambient.collection.TrackOriginEnum;
37  import sk.baka.ambient.commons.MiscUtils;
38  import sk.baka.ambient.library.DBStrategy;
39  import sk.baka.ambient.library.Library;
40  import sk.baka.ambient.library.LibraryUtils;
41  import sk.baka.ambient.playlist.Random;
42  import android.database.Cursor;
43  
44  /***
45   * Collection strategy which uses local database (the {@link Library}).
46   * 
47   * @author Martin Vysny
48   */
49  public final class LibraryCollection implements ICollection {
50  	private final DBStrategy library;
51  
52  	/***
53  	 * Creates new collection wrapper.
54  	 * 
55  	 * @param l
56  	 *            the library to wrap.
57  	 */
58  	public LibraryCollection(final Library l) {
59  		library = l.getBackend();
60  	}
61  
62  	@SuppressWarnings("unchecked")
63  	public List<CategoryItem> getCategoryList(final CategoryEnum request,
64  			final CategoryItem context, final String substring,
65  			final boolean sortByYear) throws InterruptedException {
66  		final EnumMap<CategoryEnum, String> currentSearchCriteria = new EnumMap<CategoryEnum, String>(
67  				CategoryEnum.class);
68  		if (context != null) {
69  			currentSearchCriteria
70  					.putAll((EnumMap<CategoryEnum, String>) context.id);
71  			currentSearchCriteria.put(context.category, context.name);
72  		}
73  		if (originFilter != null) {
74  			currentSearchCriteria.put(CategoryEnum.Origin, originFilter
75  					.toDBString());
76  		}
77  		final CategoryEnum[] criterii;
78  		if (request == CategoryEnum.Album) {
79  			if (sortByYear) {
80  				criterii = new CategoryEnum[] { CategoryEnum.YearReleased,
81  						CategoryEnum.Album };
82  			} else {
83  				criterii = new CategoryEnum[] { CategoryEnum.Album,
84  						CategoryEnum.YearReleased };
85  			}
86  		} else {
87  			criterii = new CategoryEnum[] { request };
88  		}
89  		final Cursor c = library.getCriteriaList(criterii,
90  				currentSearchCriteria);
91  		final CategoryItem.Builder b = new CategoryItem.Builder();
92  		final List<CategoryItem> result = new ArrayList<CategoryItem>();
93  		if (!c.moveToFirst()) {
94  			c.close();
95  			return result;
96  		}
97  		try {
98  			do {
99  				if (Thread.currentThread().isInterrupted()) {
100 					throw new InterruptedException();
101 				}
102 				if (request == CategoryEnum.Album) {
103 					b.name = c.getString(sortByYear ? 1 : 0);
104 					b.year = c.getString(sortByYear ? 0 : 1);
105 				} else {
106 					b.name = c.getString(0);
107 				}
108 				b.id = currentSearchCriteria;
109 				b.category = request;
110 				result.add(b.build());
111 			} while (c.moveToNext());
112 		} finally {
113 			c.close();
114 		}
115 		// finally, sort the result
116 		if ((request == CategoryEnum.Album) && sortByYear) {
117 			CollectionUtils.sortByYearKey(result);
118 		} else {
119 			CollectionUtils.sortByKey(result);
120 		}
121 		return result;
122 	}
123 
124 	@SuppressWarnings("unchecked")
125 	public List<TrackMetadataBean> getTracks(CategoryItem context)
126 			throws InterruptedException {
127 		final EnumMap<CategoryEnum, String> crit = new EnumMap<CategoryEnum, String>(
128 				CategoryEnum.class);
129 		crit.putAll((EnumMap<CategoryEnum, String>) context.id);
130 		crit.put(context.category, context.name);
131 		if (originFilter != null) {
132 			crit.put(CategoryEnum.Origin, originFilter.toDBString());
133 		}
134 		final Cursor c = library.findByCriteria(crit, false, null);
135 		if (Thread.currentThread().isInterrupted()) {
136 			throw new InterruptedException();
137 		}
138 		return LibraryUtils.pollTracks(c);
139 	}
140 
141 	public List<TrackMetadataBean> findTracks(String substring)
142 			throws InterruptedException {
143 		String where;
144 		final String[] selArgs;
145 		if (substring != null) {
146 			where = "(title LIKE ? or artist LIKE ? or album LIKE ? or genre LIKE ?)";
147 			final String substr = "%" + substring + "%";
148 			selArgs = new String[] { substr, substr, substr, substr };
149 			if (originFilter != null) {
150 				where += " and origin='" + originFilter.toDBString() + "'";
151 			}
152 		} else {
153 			where = null;
154 			selArgs = null;
155 		}
156 		final Cursor c = library.rawTrackQuery(where, selArgs);
157 		if (Thread.currentThread().isInterrupted()) {
158 			throw new InterruptedException();
159 		}
160 		return LibraryUtils.pollTracks(c);
161 	}
162 
163 	public boolean isLocal() {
164 		return true;
165 	}
166 
167 	public String getName() {
168 		return AmbientApplication.getInstance().getString(
169 				R.string.localCollection);
170 	}
171 
172 	/***
173 	 * the origin or <code>null</code> if tracks will be shown regardless of
174 	 * their origin.
175 	 */
176 	private TrackOriginEnum originFilter = null;
177 
178 	/***
179 	 * Show tracks only with given origin.
180 	 * 
181 	 * @param origin
182 	 *            the origin or <code>null</code> if tracks will be shown
183 	 *            regardless of their origin.
184 	 */
185 	public void filterOrigin(final TrackOriginEnum origin) {
186 		originFilter = origin;
187 	}
188 
189 	public Statistics getStatistics() {
190 		final Library lib = AmbientApplication.getInstance().getLibrary();
191 		if (originFilter != null) {
192 			return lib.getStatistics(originFilter);
193 		}
194 		final Statistics magnatune = lib
195 				.getStatistics(TrackOriginEnum.Magnatune);
196 		return magnatune;
197 	}
198 
199 	public CategoryItem deserializeItem(String id) {
200 		return (CategoryItem) MiscUtils.deserialize(MiscUtils.fromHexa(id));
201 	}
202 
203 	public String serializeItem(CategoryItem item) {
204 		final byte[] serialized = MiscUtils.serializeToBytes(item);
205 		return MiscUtils.toHexa(serialized);
206 	}
207 
208 	public IDynamicPlaylistTrackProvider newTrackProvider(final Random random) {
209 		return new LibraryTrackProvider(random);
210 	}
211 
212 	public List<TrackMetadataBean> findTracks(Map<CategoryEnum, String> criteria) {
213 		final Cursor c = library.findByCriteria(criteria, true, null);
214 		return LibraryUtils.pollTracks(c);
215 	}
216 
217 	public Map<String, String> fixLocations(Collection<String> locations) {
218 		throw new UnsupportedOperationException();
219 	}
220 
221 	public boolean supportsLocationFix() {
222 		return false;
223 	}
224 }