Changeset View
Changeset View
Standalone View
Standalone View
src/org/kde/kdeconnect/Plugins/MprisPlugin/AlbumArtCache.java
Show First 20 Lines • Show All 72 Lines • ▼ Show 20 Line(s) | 49 | public final class AlbumArtCache { | |||
---|---|---|---|---|---|
73 | 73 | | |||
74 | /** | 74 | /** | ||
75 | * A list of plugins to notify on fetched album art | 75 | * A list of plugins to notify on fetched album art | ||
76 | */ | 76 | */ | ||
77 | private static ArrayList<MprisPlugin> registeredPlugins = new ArrayList<>(); | 77 | private static ArrayList<MprisPlugin> registeredPlugins = new ArrayList<>(); | ||
78 | 78 | | |||
79 | /** | 79 | /** | ||
80 | * Initializes the disk cache. Needs to be called at least once before trying to use the cache | 80 | * Initializes the disk cache. Needs to be called at least once before trying to use the cache | ||
81 | * | ||||
81 | * @param context The context | 82 | * @param context The context | ||
82 | */ | 83 | */ | ||
83 | public static void initializeDiskCache(Context context) { | 84 | public static void initializeDiskCache(Context context) { | ||
84 | if (diskCache != null) return; | 85 | if (diskCache != null) return; | ||
85 | 86 | | |||
86 | File cacheDir = new File(context.getCacheDir(), "album_art"); | 87 | File cacheDir = new File(context.getCacheDir(), "album_art"); | ||
87 | int versionCode; | 88 | int versionCode; | ||
88 | try { | 89 | try { | ||
89 | PackageInfo info = context.getPackageManager().getPackageInfo(context.getPackageName(), 0); | 90 | PackageInfo info = context.getPackageManager().getPackageInfo(context.getPackageName(), 0); | ||
90 | versionCode = info.versionCode; | 91 | versionCode = info.versionCode; | ||
91 | //Initialize the disk cache with a limit of 5 MB storage (fits ~830 images, taking Spotify as reference) | 92 | //Initialize the disk cache with a limit of 5 MB storage (fits ~830 images, taking Spotify as reference) | ||
92 | diskCache = DiskLruCache.open(cacheDir, versionCode, 1, 1000 * 1000 * 5); | 93 | diskCache = DiskLruCache.open(cacheDir, versionCode, 1, 1000 * 1000 * 5); | ||
93 | } catch (PackageManager.NameNotFoundException e) { | 94 | } catch (PackageManager.NameNotFoundException e) { | ||
94 | throw new AssertionError(e); | 95 | throw new AssertionError(e); | ||
95 | } catch (IOException e) { | 96 | } catch (IOException e) { | ||
96 | Log.e("KDE/Mpris/AlbumArtCache", "Could not open the album art disk cache!", e); | 97 | Log.e("KDE/Mpris/AlbumArtCache", "Could not open the album art disk cache!", e); | ||
97 | } | 98 | } | ||
98 | } | 99 | } | ||
99 | 100 | | |||
100 | /** | 101 | /** | ||
101 | * Registers a mpris plugin, such that it gets notified of fetched album art | 102 | * Registers a mpris plugin, such that it gets notified of fetched album art | ||
103 | * | ||||
102 | * @param mpris The mpris plugin | 104 | * @param mpris The mpris plugin | ||
103 | */ | 105 | */ | ||
104 | public static void registerPlugin(MprisPlugin mpris) { | 106 | public static void registerPlugin(MprisPlugin mpris) { | ||
105 | registeredPlugins.add(mpris); | 107 | registeredPlugins.add(mpris); | ||
106 | } | 108 | } | ||
107 | 109 | | |||
108 | /** | 110 | /** | ||
109 | * Deregister a mpris plugin | 111 | * Deregister a mpris plugin | ||
112 | * | ||||
110 | * @param mpris The mpris plugin | 113 | * @param mpris The mpris plugin | ||
111 | */ | 114 | */ | ||
112 | public static void deregisterPlugin(MprisPlugin mpris) { | 115 | public static void deregisterPlugin(MprisPlugin mpris) { | ||
113 | registeredPlugins.remove(mpris); | 116 | registeredPlugins.remove(mpris); | ||
114 | } | 117 | } | ||
115 | 118 | | |||
116 | /** | 119 | /** | ||
117 | * Get the album art for the given url. Currently only handles http(s) urls. | 120 | * Get the album art for the given url. Currently only handles http(s) urls. | ||
▲ Show 20 Lines • Show All 69 Lines • ▼ Show 20 Line(s) | 126 | public static Bitmap getAlbumArt(String albumUrl) { | |||
187 | /* If not found, we have not tried fetching it (recently), or a fetch is in-progress. | 190 | /* If not found, we have not tried fetching it (recently), or a fetch is in-progress. | ||
188 | Either way, just add it to the fetch queue and starting fetching it if no fetch is running. */ | 191 | Either way, just add it to the fetch queue and starting fetching it if no fetch is running. */ | ||
189 | fetchUrl(url); | 192 | fetchUrl(url); | ||
190 | return null; | 193 | return null; | ||
191 | } | 194 | } | ||
192 | 195 | | |||
193 | /** | 196 | /** | ||
194 | * Fetches an album art url and puts it in the cache | 197 | * Fetches an album art url and puts it in the cache | ||
198 | * | ||||
195 | * @param url The url | 199 | * @param url The url | ||
196 | */ | 200 | */ | ||
197 | private static void fetchUrl(URL url) { | 201 | private static void fetchUrl(URL url) { | ||
198 | //We need the disk cache for this | 202 | //We need the disk cache for this | ||
199 | if (diskCache == null) { | 203 | if (diskCache == null) { | ||
200 | Log.e("KDE/Mpris/AlbumArtCache", "The disk cache is not intialized!"); | 204 | Log.e("KDE/Mpris/AlbumArtCache", "The disk cache is not intialized!"); | ||
201 | return; | 205 | return; | ||
202 | } | 206 | } | ||
Show All 11 Lines | 217 | private static final class FetchURLTask extends AsyncTask<Void, Void, Boolean> { | |||
214 | private URL url; | 218 | private URL url; | ||
215 | private InputStream input; | 219 | private InputStream input; | ||
216 | private DiskLruCache.Editor cacheItem; | 220 | private DiskLruCache.Editor cacheItem; | ||
217 | private OutputStream output; | 221 | private OutputStream output; | ||
218 | 222 | | |||
219 | /** | 223 | /** | ||
220 | * Initialize an url fetch | 224 | * Initialize an url fetch | ||
221 | * | 225 | * | ||
222 | * @param url The url being fetched | 226 | * @param url The url being fetched | ||
223 | * @param payloadInput A payload input stream (if from the connected device). null if fetched from http(s) | 227 | * @param payloadInput A payload input stream (if from the connected device). null if fetched from http(s) | ||
224 | * @param cacheItem The disk cache item to edit | 228 | * @param cacheItem The disk cache item to edit | ||
225 | * @throws IOException | 229 | * @throws IOException | ||
226 | */ | 230 | */ | ||
227 | FetchURLTask(URL url, InputStream payloadInput, DiskLruCache.Editor cacheItem) throws IOException { | 231 | FetchURLTask(URL url, InputStream payloadInput, DiskLruCache.Editor cacheItem) throws IOException { | ||
228 | this.url = url; | 232 | this.url = url; | ||
229 | this.input = payloadInput; | 233 | this.input = payloadInput; | ||
230 | this.cacheItem = cacheItem; | 234 | this.cacheItem = cacheItem; | ||
231 | output = cacheItem.newOutputStream(0); | 235 | output = cacheItem.newOutputStream(0); | ||
232 | } | 236 | } | ||
233 | 237 | | |||
234 | /** | 238 | /** | ||
235 | * Opens the http(s) connection | 239 | * Opens the http(s) connection | ||
240 | * | ||||
236 | * @return True if succeeded | 241 | * @return True if succeeded | ||
237 | * @throws IOException | 242 | * @throws IOException | ||
238 | */ | 243 | */ | ||
239 | private boolean openHttp() throws IOException { | 244 | private boolean openHttp() throws IOException { | ||
240 | //Default android behaviour does not follow https -> http urls, so do this manually | 245 | //Default android behaviour does not follow https -> http urls, so do this manually | ||
241 | URL currentUrl = url; | 246 | URL currentUrl = url; | ||
242 | HttpURLConnection connection; | 247 | HttpURLConnection connection; | ||
243 | for (int i = 0; i<5; ++i) { | 248 | for (int i = 0; i < 5; ++i) { | ||
244 | connection = (HttpURLConnection) currentUrl.openConnection(); | 249 | connection = (HttpURLConnection) currentUrl.openConnection(); | ||
245 | connection.setConnectTimeout(10000); | 250 | connection.setConnectTimeout(10000); | ||
246 | connection.setReadTimeout(10000); | 251 | connection.setReadTimeout(10000); | ||
247 | connection.setInstanceFollowRedirects(false); | 252 | connection.setInstanceFollowRedirects(false); | ||
248 | 253 | | |||
249 | switch (connection.getResponseCode()) { | 254 | switch (connection.getResponseCode()) { | ||
250 | case HttpURLConnection.HTTP_MOVED_PERM: | 255 | case HttpURLConnection.HTTP_MOVED_PERM: | ||
251 | case HttpURLConnection.HTTP_MOVED_TEMP: | 256 | case HttpURLConnection.HTTP_MOVED_TEMP: | ||
▲ Show 20 Lines • Show All 67 Lines • ▼ Show 20 Line(s) | 300 | protected void onPostExecute(Boolean success) { | |||
319 | } | 324 | } | ||
320 | 325 | | |||
321 | //Remove the url from the to-fetch list | 326 | //Remove the url from the to-fetch list | ||
322 | fetchUrlList.remove(url); | 327 | fetchUrlList.remove(url); | ||
323 | //Fetch the next url (if any) | 328 | //Fetch the next url (if any) | ||
324 | --numFetching; | 329 | --numFetching; | ||
325 | initiateFetch(); | 330 | initiateFetch(); | ||
326 | } | 331 | } | ||
327 | }; | 332 | } | ||
333 | | ||||
334 | ; | ||||
328 | 335 | | |||
329 | /** | 336 | /** | ||
330 | * Does the actual fetching and makes sure only not too many fetches are running at the same time | 337 | * Does the actual fetching and makes sure only not too many fetches are running at the same time | ||
331 | */ | 338 | */ | ||
332 | private static void initiateFetch() { | 339 | private static void initiateFetch() { | ||
333 | if (numFetching >= 2) return; | 340 | if (numFetching >= 2) return; | ||
334 | if (fetchUrlList.isEmpty()) return; | 341 | if (fetchUrlList.isEmpty()) return; | ||
335 | 342 | | |||
Show All 16 Lines | 358 | } catch (IOException e) { | |||
352 | Log.e("KDE/Mpris/AlbumArtCache", "Problems with the disk cache", e); | 359 | Log.e("KDE/Mpris/AlbumArtCache", "Problems with the disk cache", e); | ||
353 | --numFetching; | 360 | --numFetching; | ||
354 | } | 361 | } | ||
355 | } | 362 | } | ||
356 | 363 | | |||
357 | /** | 364 | /** | ||
358 | * The disk cache requires mostly alphanumeric characters, and at most 64 characters. | 365 | * The disk cache requires mostly alphanumeric characters, and at most 64 characters. | ||
359 | * So hash the url to get a valid key | 366 | * So hash the url to get a valid key | ||
367 | * | ||||
360 | * @param url The url | 368 | * @param url The url | ||
361 | * @return A valid disk cache key | 369 | * @return A valid disk cache key | ||
362 | */ | 370 | */ | ||
363 | private static String urlToDiskCacheKey(String url) { | 371 | private static String urlToDiskCacheKey(String url) { | ||
364 | MessageDigest hasher; | 372 | MessageDigest hasher; | ||
365 | try { | 373 | try { | ||
366 | hasher = MessageDigest.getInstance("MD5"); | 374 | hasher = MessageDigest.getInstance("MD5"); | ||
367 | } catch (NoSuchAlgorithmException e) { | 375 | } catch (NoSuchAlgorithmException e) { | ||
368 | //Should always be available | 376 | //Should always be available | ||
369 | throw new AssertionError(e); | 377 | throw new AssertionError(e); | ||
370 | } | 378 | } | ||
371 | 379 | | |||
372 | StringBuilder builder = new StringBuilder(); | 380 | StringBuilder builder = new StringBuilder(); | ||
373 | for (byte singleByte : hasher.digest(url.getBytes())) { | 381 | for (byte singleByte : hasher.digest(url.getBytes())) { | ||
374 | builder.append(String.format("%02x", singleByte)); | 382 | builder.append(String.format("%02x", singleByte)); | ||
375 | } | 383 | } | ||
376 | return builder.toString(); | 384 | return builder.toString(); | ||
377 | } | 385 | } | ||
378 | 386 | | |||
379 | /** | 387 | /** | ||
380 | * Transfer an asked-for album art payload to the disk cache. | 388 | * Transfer an asked-for album art payload to the disk cache. | ||
389 | * | ||||
381 | * @param albumUrl The url of the album art (should be a file:// url) | 390 | * @param albumUrl The url of the album art (should be a file:// url) | ||
382 | * @param payload The payload input stream | 391 | * @param payload The payload input stream | ||
383 | */ | 392 | */ | ||
384 | public static void payloadToDiskCache(String albumUrl, InputStream payload) { | 393 | public static void payloadToDiskCache(String albumUrl, InputStream payload) { | ||
385 | //We need the disk cache for this | 394 | //We need the disk cache for this | ||
386 | if (diskCache == null) { | 395 | if (diskCache == null) { | ||
387 | Log.e("KDE/Mpris/AlbumArtCache", "The disk cache is not intialized!"); | 396 | Log.e("KDE/Mpris/AlbumArtCache", "The disk cache is not intialized!"); | ||
388 | return; | 397 | return; | ||
389 | } | 398 | } | ||
390 | 399 | | |||
Show All 38 Lines |