// Copyright 2010 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package org.npr.android.test;
import android.content.Context;
import android.content.res.AssetFileDescriptor;
import android.util.Log;
import java.io.IOException;
import java.io.InputStream;
// TODO: This is a test framework piece and therefore needs a unit-test.
/**
* A single-connection HTTP server that will respond to requests
* for files and pull them from the application's res/raw folder.
*
* Here's a simple example of how to use it. Assume that there is
* a file in the package called res/raw/image.jpg
* <code>
* HttpRawResourceServer server = new HttpRawResourceServer(getContext());
* try {
* server.init()
* server.start();
*
* String url = "http://127.0.0.1:" + server.getPort() + "/image";
* // Send a request to the URL, perhaps with HttpClient
* // or with File.open(url);
* } finally {
* server.stop();
* }
* </code>
*/
public class HttpRawResourceServer extends HttpServer {
private static final String TAG = HttpRawResourceServer.class.getName();
private Context resourceContext;
/**
* Creates a new HttpRawResourceServer instance. This server accepts HTTP
* request and returns files in the res/raw folder of the the application.
*
* When using with Android unit tests, note that AndroidTestCase.getContext
* returns the context of the <i>application under test</a>, not the test test
* itself, so this would look in the application's res/raw/ folder.
*
* To get access to the test package's res/raw/ folder files, you need to
* derive your test from InstrumentationTestCase and then use
* getInstrumentation().getContext().
*
* @param context
* The Android application context. Used to access resources.
* @param streaming
* Whether the server will continuously stream the content.
*/
public HttpRawResourceServer(Context context, boolean streaming) {
if (context == null) {
throw new IllegalArgumentException(
"Context for accessing resources cannot be null");
}
setSimulateStream(streaming);
resourceContext = context;
}
/**
* Creates a RawResourceDataSource object for the request.
* @return A <code>DataSource</code> subclass for the raw resource request.
*/
@Override
protected DataSource getData(String request) {
// Remove initial '/' in path
String path = request.substring(1);
// TODO: remove any extensions
Log.d(TAG, "GET request: " + request + " -> " + path);
return new RawResourceDataSource(path);
}
protected class RawResourceDataSource extends DataSource {
private AssetFileDescriptor fd;
private final int resourceId;
public RawResourceDataSource(String resourceName) {
String resPath = String.format("%3$s:%2$s/%1$s", resourceName, "raw",
resourceContext.getPackageName());
Log.d(TAG, "Resource: " + resPath);
resourceId = resourceContext.getResources().getIdentifier(resPath, null, null);
}
@Override
public InputStream createInputStream() throws IOException {
// NB: Because createInputStream can only be called once per asset
// we always create a new file descriptor here.
getFileDescriptor();
return fd.createInputStream();
}
@Override
public String getContentType() {
// TODO: Support other media if we need to
return "audio/mp3";
}
@Override
public long getContentLength() {
if( isSimulatingStream() ) {
super.getContentLength();
}
if (fd == null) {
getFileDescriptor();
}
return fd.getLength();
}
private void getFileDescriptor() {
Log.d(TAG, "getting file");
fd = resourceContext.getResources().openRawResourceFd(resourceId);
}
}
}