Java tutorial
/* * * Copyright (C) 2013 www.yaacc.de * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 3 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ package de.yaacc.upnp.server; import android.content.Context; import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.net.Uri; import android.provider.MediaStore; import android.util.Log; import org.apache.http.ConnectionReuseStrategy; import org.apache.http.HttpEntity; import org.apache.http.HttpException; import org.apache.http.HttpRequest; import org.apache.http.HttpResponse; import org.apache.http.HttpResponseFactory; import org.apache.http.HttpStatus; import org.apache.http.MethodNotSupportedException; import org.apache.http.entity.ByteArrayEntity; import org.apache.http.entity.FileEntity; import org.apache.http.entity.StringEntity; import org.apache.http.message.BasicHeader; import org.apache.http.protocol.HttpContext; import org.apache.http.protocol.HttpProcessor; import org.apache.http.protocol.HttpService; import org.seamless.util.MimeType; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.util.Locale; import de.yaacc.R; /** * A http service to retrieve media content by an id. * * @author Tobias Schoene (openbit) */ public class YaaccHttpService extends HttpService { private Context context; public YaaccHttpService(HttpProcessor proc, ConnectionReuseStrategy connStrategy, HttpResponseFactory responseFactory, Context context) { super(proc, connStrategy, responseFactory); this.context = context; } /* * (non-Javadoc) * * @see * org.apache.http.protocol.HttpService#doService(org.apache.http.HttpRequest * , org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext) */ @Override protected void doService(HttpRequest request, HttpResponse response, HttpContext context) throws HttpException, IOException { Log.d(getClass().getName(), "Processing HTTP request: " + request.getRequestLine().toString()); // Extract what we need from the HTTP httpRequest String requestMethod = request.getRequestLine().getMethod().toUpperCase(Locale.ENGLISH); // Only accept HTTP-GET if (!requestMethod.equals("GET") && !requestMethod.equals("HEAD")) { Log.d(getClass().getName(), "HTTP request isn't GET or HEAD stop! Method was: " + requestMethod); throw new MethodNotSupportedException(requestMethod + " method not supported"); } Uri requestUri = Uri.parse(request.getRequestLine().getUri()); String contentId = requestUri.getQueryParameter("id"); contentId = contentId == null ? "" : contentId; String albumId = requestUri.getQueryParameter("album"); albumId = albumId == null ? "" : albumId; String thumbId = requestUri.getQueryParameter("thumb"); thumbId = thumbId == null ? "" : thumbId; if (contentId.equals("") && albumId.equals("") && thumbId.equals("")) { response.setStatusCode(HttpStatus.SC_FORBIDDEN); StringEntity entity = new StringEntity("<html><body><h1>Access denied</h1></body></html>", "UTF-8"); response.setEntity(entity); Log.d(getClass().getName(), "end doService: Access denied"); return; } ContentHolder contentHolder = null; if (!contentId.equals("")) { contentHolder = lookupContent(contentId); } else if (!albumId.equals("")) { contentHolder = lookupAlbumArt(albumId); } else if (!thumbId.equals("")) { contentHolder = lookupThumbnail(thumbId); } if (contentHolder == null) { // tricky but works Log.d(getClass().getName(), "Resource with id " + contentId + albumId + thumbId + " not found"); response.setStatusCode(HttpStatus.SC_NOT_FOUND); StringEntity entity = new StringEntity("<html><body><h1>Resource with id " + contentId + albumId + thumbId + " not found</h1></body></html>", "UTF-8"); response.setEntity(entity); } else { response.setStatusCode(HttpStatus.SC_OK); response.setEntity(contentHolder.getHttpEntity()); } Log.d(getClass().getName(), "end doService: "); } private Context getContext() { return context; } /** * Lookup content in the mediastore * * @param contentId the id of the content * @return the content description */ private ContentHolder lookupContent(String contentId) { ContentHolder result = null; if (contentId == null) { return null; } Log.d(getClass().getName(), "System media store lookup: " + contentId); String[] projection = { MediaStore.Files.FileColumns._ID, MediaStore.Files.FileColumns.MIME_TYPE, MediaStore.Files.FileColumns.DATA }; String selection = MediaStore.Files.FileColumns._ID + "=?"; String[] selectionArgs = { contentId }; Cursor mFilesCursor = getContext().getContentResolver().query(MediaStore.Files.getContentUri("external"), projection, selection, selectionArgs, null); if (mFilesCursor != null) { mFilesCursor.moveToFirst(); while (!mFilesCursor.isAfterLast()) { String dataUri = mFilesCursor .getString(mFilesCursor.getColumnIndex(MediaStore.Files.FileColumns.DATA)); String mimeTypeStr = mFilesCursor .getString(mFilesCursor.getColumnIndex(MediaStore.Files.FileColumns.MIME_TYPE)); MimeType mimeType = MimeType.valueOf("*/*"); if (mimeTypeStr != null) { mimeType = MimeType.valueOf(mimeTypeStr); } Log.d(getClass().getName(), "Content found: " + mimeType + " Uri: " + dataUri); result = new ContentHolder(mimeType, dataUri); mFilesCursor.moveToNext(); } } else { Log.d(getClass().getName(), "System media store is empty."); } mFilesCursor.close(); return result; } /** * Lookup content in the mediastore * * @param albumId the id of the album * @return the content description */ private ContentHolder lookupAlbumArt(String albumId) { ContentHolder result = new ContentHolder(MimeType.valueOf("image/png"), getDefaultIcon()); if (albumId == null) { return null; } Log.d(getClass().getName(), "System media store lookup album: " + albumId); String[] projection = { MediaStore.Audio.Albums._ID, // FIXME what is the right mime type? // MediaStore.Audio.Albums.MIME_TYPE, MediaStore.Audio.Albums.ALBUM_ART }; String selection = MediaStore.Audio.Albums._ID + "=?"; String[] selectionArgs = { albumId }; Cursor cursor = getContext().getContentResolver().query(MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI, projection, selection, selectionArgs, null); if (cursor != null) { cursor.moveToFirst(); while (!cursor.isAfterLast()) { String dataUri = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Albums.ALBUM_ART)); // String mimeTypeStr = null; // FIXME mime type resolving cursor // .getString(cursor // .getColumnIndex(MediaStore.Files.FileColumns.MIME_TYPE)); MimeType mimeType = MimeType.valueOf("image/png"); // if (mimeTypeStr != null) { // mimeType = MimeType.valueOf(mimeTypeStr); // } if (dataUri != null) { Log.d(getClass().getName(), "Content found: " + mimeType + " Uri: " + dataUri); result = new ContentHolder(mimeType, dataUri); } cursor.moveToNext(); } } else { Log.d(getClass().getName(), "System media store is empty."); } cursor.close(); return result; } /** * Lookup a thumbnail content in the mediastore * * @param idStr the id of the thumbnail * @return the content description */ private ContentHolder lookupThumbnail(String idStr) { ContentHolder result = new ContentHolder(MimeType.valueOf("image/png"), getDefaultIcon()); if (idStr == null) { return null; } Long id = null; try { id = Long.valueOf(idStr); } catch (NumberFormatException nfe) { Log.d(getClass().getName(), "ParsingError of id: " + idStr, nfe); return null; } Log.d(getClass().getName(), "System media store lookup thumbnail: " + idStr); Bitmap bitmap = MediaStore.Images.Thumbnails.getThumbnail(getContext().getContentResolver(), id, MediaStore.Images.Thumbnails.MINI_KIND, null); if (bitmap != null) { ByteArrayOutputStream stream = new ByteArrayOutputStream(); bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream); byte[] byteArray = stream.toByteArray(); MimeType mimeType = MimeType.valueOf("image/png"); result = new ContentHolder(mimeType, byteArray); } else { Log.d(getClass().getName(), "System media store is empty."); } return result; } private byte[] getDefaultIcon() { Drawable drawable = getContext().getResources().getDrawable(R.drawable.yaacc192_32); byte[] result = null; if (drawable != null) { Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap(); ByteArrayOutputStream stream = new ByteArrayOutputStream(); bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream); result = stream.toByteArray(); } return result; } /** * ValueHolder for media content. */ static class ContentHolder { private String uri; private MimeType mimeType; private byte[] content; public ContentHolder(MimeType mimeType, String uri) { this.uri = uri; this.mimeType = mimeType; } public ContentHolder(MimeType mimeType, byte[] content) { this.content = content; this.mimeType = mimeType; } /** * @return the uri */ public String getUri() { return uri; } /** * @return the mimeType */ public MimeType getMimeType() { return mimeType; } public HttpEntity getHttpEntity() { HttpEntity result = null; if (getUri() != null && !getUri().equals("")) { File file = new File(getUri()); result = new FileEntity(file, getMimeType().toString()); Log.d(getClass().getName(), "Return file-Uri: " + getUri() + "Mimetype: " + getMimeType()); } else if (content != null) { result = new ByteArrayEntity(content); ((ByteArrayEntity) result) .setContentType(new BasicHeader("Content-Type", getMimeType().toString())); } return result; } } }