Removed the old Android client in preparation for the new one.

git-svn-id: https://zxing.googlecode.com/svn/trunk@624 59b500cc-1b3d-0410-9834-0bbf25fbcc57
This commit is contained in:
dswitkin 2008-10-18 13:31:08 +00:00
parent f142a9478c
commit f3123f432b
14 changed files with 0 additions and 2202 deletions

View file

@ -1,432 +0,0 @@
/*
* Copyright (C) 2007 The Android Open Source Project
*
* 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 com.android.barcodes;
import android.util.Log;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpException;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.HttpRequestInterceptor;
import org.apache.http.HttpResponse;
import org.apache.http.HttpMessage;
import org.apache.http.client.HttpClient;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.params.HttpClientParams;
import org.apache.http.client.protocol.ClientContext;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.entity.AbstractHttpEntity;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.client.RequestWrapper;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.BasicHttpProcessor;
import org.apache.http.protocol.HttpContext;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
/**
* <p>Subclass of the Apache {@link DefaultHttpClient} that is configured with
* reasonable default settings and registered schemes for Android, and
* also lets the user add {@link HttpRequestInterceptor} classes.
* Don't create this directly, use the {@link #newInstance} factory method.</p>
*
* <p>This client processes cookies but does not retain them by default.
* To retain cookies, simply add a cookie store to the HttpContext:
* <pre>context.setAttribute(ClientContext.COOKIE_STORE, cookieStore);</pre>
* </p>
*/
public final class AndroidHttpClient implements HttpClient {
// Gzip of data shorter than this probably won't be worthwhile
public static final long DEFAULT_SYNC_MIN_GZIP_BYTES = 256;
private static final String TAG = "AndroidHttpClient";
/**
* Set if HTTP requests are blocked from being executed on this thread
*/
private static final ThreadLocal<Boolean> sThreadBlocked =
new ThreadLocal<Boolean>();
/**
* Interceptor throws an exception if the executing thread is blocked
*/
private static final HttpRequestInterceptor sThreadCheckInterceptor =
new HttpRequestInterceptor() {
public void process(HttpRequest request, HttpContext context) {
if (sThreadBlocked.get() != null && sThreadBlocked.get()) {
throw new RuntimeException("This thread forbids HTTP requests");
}
}
};
/**
* Create a new HttpClient with reasonable defaults (which you can update).
*
* @param userAgent to report in your HTTP requests.
* @return AndroidHttpClient for you to use for all your requests.
*/
public static AndroidHttpClient newInstance(String userAgent) {
HttpParams params = new BasicHttpParams();
// Turn off stale checking. Our connections break all the time anyway,
// and it's not worth it to pay the penalty of checking every time.
HttpConnectionParams.setStaleCheckingEnabled(params, false);
// Default connection and socket timeout of 20 seconds. Tweak to taste.
HttpConnectionParams.setConnectionTimeout(params, 20 * 1000);
HttpConnectionParams.setSoTimeout(params, 20 * 1000);
HttpConnectionParams.setSocketBufferSize(params, 8192);
// Don't handle redirects -- return them to the caller. Our code
// often wants to re-POST after a redirect, which we must do ourselves.
HttpClientParams.setRedirecting(params, false);
// Set the specified user agent and register standard protocols.
HttpProtocolParams.setUserAgent(params, userAgent);
SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register(new Scheme("http",
PlainSocketFactory.getSocketFactory(), 80));
schemeRegistry.register(new Scheme("https",
SSLSocketFactory.getSocketFactory(), 443));
ClientConnectionManager manager =
new ThreadSafeClientConnManager(params, schemeRegistry);
// We use a factory method to modify superclass initialization
// parameters without the funny call-a-static-method dance.
return new AndroidHttpClient(manager, params);
}
private final HttpClient delegate;
private RuntimeException mLeakedException = new IllegalStateException(
"AndroidHttpClient created and never closed");
private AndroidHttpClient(ClientConnectionManager ccm, HttpParams params) {
this.delegate = new DefaultHttpClient(ccm, params) {
@Override
protected BasicHttpProcessor createHttpProcessor() {
// Add interceptor to prevent making requests from main thread.
BasicHttpProcessor processor = super.createHttpProcessor();
processor.addRequestInterceptor(sThreadCheckInterceptor);
processor.addRequestInterceptor(new CurlLogger());
return processor;
}
@Override
protected HttpContext createHttpContext() {
// Same as DefaultHttpClient.createHttpContext() minus the
// cookie store.
HttpContext context = new BasicHttpContext();
context.setAttribute(ClientContext.AUTHSCHEME_REGISTRY, getAuthSchemes());
context.setAttribute(ClientContext.COOKIESPEC_REGISTRY, getCookieSpecs());
context.setAttribute(ClientContext.CREDS_PROVIDER, getCredentialsProvider());
return context;
}
};
}
@Override
protected void finalize() throws Throwable {
super.finalize();
if (mLeakedException != null) {
Log.e(TAG, "Leak found", mLeakedException);
mLeakedException = null;
}
}
/**
* Block this thread from executing HTTP requests.
* Used to guard against HTTP requests blocking the main application thread.
*
* @param blocked if HTTP requests run on this thread should be denied
*/
public static void setThreadBlocked(boolean blocked) {
sThreadBlocked.set(blocked);
}
/**
* Modifies a request to indicate to the server that we would like a
* gzipped response. (Uses the "Accept-Encoding" HTTP header.)
*
* @param request the request to modify
* @see #getUngzippedContent
*/
public static void modifyRequestToAcceptGzipResponse(HttpMessage request) {
request.addHeader("Accept-Encoding", "gzip");
}
/**
* Gets the input stream from a response entity. If the entity is gzipped
* then this will get a stream over the uncompressed data.
*
* @param entity the entity whose content should be read
* @return the input stream to read from
* @throws IOException
*/
public static InputStream getUngzippedContent(HttpEntity entity) throws IOException {
InputStream responseStream = entity.getContent();
if (responseStream == null) {
return responseStream;
}
Header header = entity.getContentEncoding();
if (header == null) {
return responseStream;
}
String contentEncoding = header.getValue();
if (contentEncoding == null) {
return responseStream;
}
if (contentEncoding.contains("gzip")) responseStream = new GZIPInputStream(responseStream);
return responseStream;
}
/**
* Release resources associated with this client. You must call this,
* or significant resources (sockets and memory) may be leaked.
*/
public void close() {
if (mLeakedException != null) {
getConnectionManager().shutdown();
mLeakedException = null;
}
}
public HttpParams getParams() {
return delegate.getParams();
}
public ClientConnectionManager getConnectionManager() {
return delegate.getConnectionManager();
}
public HttpResponse execute(HttpUriRequest request) throws IOException {
return delegate.execute(request);
}
public HttpResponse execute(HttpUriRequest request, HttpContext context) throws IOException {
return delegate.execute(request, context);
}
public HttpResponse execute(HttpHost target, HttpRequest request) throws IOException {
return delegate.execute(target, request);
}
public HttpResponse execute(HttpHost target, HttpRequest request,
HttpContext context) throws IOException {
return delegate.execute(target, request, context);
}
public <T> T execute(HttpUriRequest request, ResponseHandler<? extends T> responseHandler) throws IOException {
return delegate.execute(request, responseHandler);
}
public <T> T execute(HttpUriRequest request, ResponseHandler<? extends T> responseHandler, HttpContext context)
throws IOException {
return delegate.execute(request, responseHandler, context);
}
public <T> T execute(HttpHost target, HttpRequest request, ResponseHandler<? extends T> responseHandler)
throws IOException {
return delegate.execute(target, request, responseHandler);
}
public <T> T execute(HttpHost target, HttpRequest request,
ResponseHandler<? extends T> responseHandler,
HttpContext context)
throws IOException {
return delegate.execute(target, request, responseHandler, context);
}
/**
* Compress data to send to server.
* Creates a Http Entity holding the gzipped data.
* The data will not be compressed if it is too short.
*
* @param data The bytes to compress
* @return Entity holding the data
*/
public static AbstractHttpEntity getCompressedEntity(byte data[]) throws IOException {
AbstractHttpEntity entity;
if (data.length < getMinGzipSize()) {
entity = new ByteArrayEntity(data);
} else {
ByteArrayOutputStream arr = new ByteArrayOutputStream();
OutputStream zipper = new GZIPOutputStream(arr);
zipper.write(data);
zipper.close();
entity = new ByteArrayEntity(arr.toByteArray());
entity.setContentEncoding("gzip");
}
return entity;
}
/**
* Retrieves the minimum size for compressing data.
* Shorter data will not be compressed.
*/
public static long getMinGzipSize() {
return DEFAULT_SYNC_MIN_GZIP_BYTES;
}
/* cURL logging support. */
/**
* Logging tag and level.
*/
private static class LoggingConfiguration {
private final String tag;
private final int level;
private LoggingConfiguration(String tag, int level) {
this.tag = tag;
this.level = level;
}
/**
* Returns true if logging is turned on for this configuration.
*/
private boolean isLoggable() {
return Log.isLoggable(tag, level);
}
/**
* Prints a message using this configuration.
*/
private void println(String message) {
Log.println(level, tag, message);
}
}
/**
* cURL logging configuration.
*/
private volatile LoggingConfiguration curlConfiguration;
/**
* Enables cURL request logging for this client.
*
* @param name to log messages with
* @param level at which to log messages (see {@link android.util.Log})
*/
public void enableCurlLogging(String name, int level) {
if (name == null) {
throw new NullPointerException("name");
}
if (level < Log.VERBOSE || level > Log.ASSERT) {
throw new IllegalArgumentException("Level is out of range ["
+ Log.VERBOSE + ".." + Log.ASSERT + "]");
}
curlConfiguration = new LoggingConfiguration(name, level);
}
/**
* Disables cURL logging for this client.
*/
public void disableCurlLogging() {
curlConfiguration = null;
}
/**
* Logs cURL commands equivalent to requests.
*/
private class CurlLogger implements HttpRequestInterceptor {
public void process(HttpRequest request, HttpContext context)
throws HttpException, IOException {
LoggingConfiguration configuration = curlConfiguration;
if (configuration != null
&& configuration.isLoggable()
&& request instanceof HttpUriRequest) {
configuration.println(toCurl((HttpUriRequest) request));
}
}
/**
* Generates a cURL command equivalent to the given request.
*/
private String toCurl(HttpUriRequest request) throws IOException {
StringBuilder builder = new StringBuilder();
builder.append("curl ");
for (Header header : request.getAllHeaders()) {
builder.append("--header \"");
builder.append(header.toString().trim());
builder.append("\" ");
}
URI uri = request.getURI();
// If this is a wrapped request, use the URI from the original
// request instead. getURI() on the wrapper seems to return a
// relative URI. We want an absolute URI.
if (request instanceof RequestWrapper) {
HttpRequest original = ((RequestWrapper) request).getOriginal();
if (original instanceof HttpUriRequest) {
uri = ((HttpUriRequest) original).getURI();
}
}
builder.append('"');
builder.append(uri);
builder.append('"');
if (request instanceof HttpEntityEnclosingRequest) {
HttpEntityEnclosingRequest entityRequest =
(HttpEntityEnclosingRequest) request;
HttpEntity entity = entityRequest.getEntity();
if (entity != null && entity.isRepeatable()) {
if (entity.getContentLength() < 1024) {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
entity.writeTo(stream);
String entityString = stream.toString();
// TODO: Check the content type, too.
builder.append(" --data-ascii \"").append(entityString).append('"');
} else {
builder.append(" [TOO MUCH DATA TO INCLUDE]");
}
}
}
return builder.toString();
}
}
}

View file

@ -1,57 +0,0 @@
/*
* Copyright 2008 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 com.android.barcodes;
import android.content.Intent;
import com.google.zxing.client.result.ParsedResult;
import com.google.zxing.client.result.ParsedResultType;
import java.net.URISyntaxException;
/**
* A {@link com.google.zxing.client.result.ParsedResult} derived from a URI that encodes an Android
* {@link Intent}, and which should presumably trigger that intent on Android.
*/
public final class AndroidIntentParsedResult extends ParsedResult {
private final Intent mIntent;
private AndroidIntentParsedResult(Intent intent) {
super(ParsedResultType.ANDROID_INTENT);
mIntent = intent;
}
public static AndroidIntentParsedResult parse(String rawText) {
try {
return new AndroidIntentParsedResult(Intent.getIntent(rawText));
} catch (URISyntaxException urise) {
return null;
} catch (IllegalArgumentException iae) {
return null;
}
}
public Intent getIntent() {
return mIntent;
}
@Override
public String getDisplayResult() {
return mIntent.toString();
}
}

View file

@ -1,315 +0,0 @@
/*
* Copyright (C) 2008 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 com.android.barcodes;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.AssetFileDescriptor;
import android.content.res.Configuration;
import android.media.MediaPlayer;
import android.media.AudioManager;
import android.media.MediaPlayer.OnCompletionListener;
import android.net.Uri;
import android.os.Bundle;
import android.os.Message;
import android.preference.PreferenceManager;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.TextView;
import com.google.zxing.Result;
import com.google.zxing.ResultPoint;
import com.google.zxing.client.result.ParsedResult;
import java.io.IOException;
/**
* The barcode reader activity itself. This is loosely based on the CameraPreview
* example included in the Android SDK.
*/
public final class BarcodesCaptureActivity extends Activity implements SurfaceHolder.Callback {
private static final int SETTINGS_ID = Menu.FIRST;
private static final int HELP_ID = Menu.FIRST + 1;
private static final int ABOUT_ID = Menu.FIRST + 2;
public BarcodesCaptureActivityHandler mHandler;
private ViewfinderView mViewfinderView;
private MediaPlayer mMediaPlayer;
private String mLastResult;
private boolean mPlayBeep;
private boolean mScanIntent;
private String mDecodeMode;
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
Window window = getWindow();
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
setContentView(R.layout.capture);
CameraManager.init(getApplication());
mViewfinderView = (ViewfinderView) findViewById(R.id.viewfinder_view);
mHandler = null;
SurfaceView surfaceView = (SurfaceView) findViewById(R.id.preview_view);
SurfaceHolder surfaceHolder = surfaceView.getHolder();
surfaceHolder.addCallback(this);
surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
@Override
protected void onResume() {
super.onResume();
resetStatusView();
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
mPlayBeep = prefs.getBoolean(BarcodesPreferenceActivity.KEY_PLAY_BEEP, true);
initBeepSound();
Intent intent = getIntent();
if (intent != null && intent.getAction().equals(Intents.Scan.ACTION)) {
mScanIntent = true;
mDecodeMode = intent.getStringExtra(Intents.Scan.MODE);
} else {
mScanIntent = false;
mDecodeMode = null;
}
}
@Override
protected void onPause() {
super.onPause();
if (mHandler != null) {
mHandler.quitSynchronously();
mHandler = null;
}
CameraManager.get().closeDriver();
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
if (mScanIntent) {
setResult(RESULT_CANCELED);
finish();
return true;
}
} else if (keyCode == KeyEvent.KEYCODE_FOCUS || keyCode == KeyEvent.KEYCODE_CAMERA) {
// Handle these events so they don't launch the Camera app
return true;
}
return super.onKeyDown(keyCode, event);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
menu.add(0, SETTINGS_ID, 0, R.string.menu_settings)
.setIcon(android.R.drawable.ic_menu_preferences);
menu.add(0, HELP_ID, 0, R.string.menu_help)
.setIcon(android.R.drawable.ic_menu_help);
menu.add(0, ABOUT_ID, 0, R.string.menu_about)
.setIcon(android.R.drawable.ic_menu_info_details);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case SETTINGS_ID: {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setClassName(this, BarcodesPreferenceActivity.class.getName());
startActivity(intent);
break;
}
case HELP_ID: {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(R.string.title_help);
builder.setMessage(R.string.msg_help);
builder.setPositiveButton(R.string.button_ok, null);
builder.show();
break;
}
case ABOUT_ID: {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(R.string.title_about);
builder.setMessage(getString(R.string.msg_about) + "\n\n" + getString(R.string.zxing_url));
builder.setIcon(R.drawable.zxing_icon);
builder.setPositiveButton(R.string.button_open_browser, mAboutListener);
builder.setNegativeButton(R.string.button_cancel, null);
builder.show();
break;
}
}
return super.onOptionsItemSelected(item);
}
@Override
public void onConfigurationChanged(Configuration config) {
// Do nothing, this is to prevent the activity from being restarted when the keyboard opens.
super.onConfigurationChanged(config);
}
private final DialogInterface.OnClickListener mAboutListener = new DialogInterface.OnClickListener() {
public void onClick(android.content.DialogInterface dialogInterface, int i) {
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.zxing_url)));
startActivity(intent);
}
};
public void surfaceCreated(SurfaceHolder holder) {
CameraManager.get().openDriver(holder);
if (mHandler == null) {
mHandler = new BarcodesCaptureActivityHandler(this, mDecodeMode);
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
}
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
/**
* A valid barcode has been found, so give an indication of success and show the results.
*
* @param rawResult The contents of the barcode.
* @param duration How long the decoding took in milliseconds.
*/
public void handleDecode(Result rawResult, int duration) {
if (!rawResult.toString().equals(mLastResult)) {
mLastResult = rawResult.toString();
playBeepSound();
ResultPoint[] points = rawResult.getResultPoints();
if (points != null && points.length > 0) {
mViewfinderView.drawResultPoints(points);
}
TextView textView = (TextView) findViewById(R.id.status_text_view);
ParsedResult result = ResultHandler.parseResult(rawResult);
String displayResult = result.getDisplayResult();
displayResult = displayResult.replace("\r", "");
textView.setText(displayResult);
if (!mScanIntent) {
Button actionButton = (Button) findViewById(R.id.status_action_button);
int buttonText = ResultHandler.getActionButtonText(result.getType());
if (buttonText != 0) {
actionButton.setVisibility(View.VISIBLE);
actionButton.setText(buttonText);
ResultHandler resultHandler = new ResultHandler(this, result);
actionButton.setOnClickListener(resultHandler);
actionButton.requestFocus();
} else {
actionButton.setVisibility(View.GONE);
}
}
View statusView = findViewById(R.id.status_view);
statusView.setBackgroundColor(getResources().getColor(R.color.result_points));
// Show the green finder patterns briefly, then either return the result or go back to
// continuous scanning.
if (mScanIntent) {
Intent intent = new Intent(Intents.Scan.ACTION);
intent.putExtra(Intents.Scan.RESULT, rawResult.toString());
intent.putExtra(Intents.Scan.RESULT_FORMAT, rawResult.getBarcodeFormat().toString());
Message message = Message.obtain(mHandler, R.id.return_scan_result);
message.obj = intent;
mHandler.sendMessageDelayed(message, 1000);
} else {
Message message = Message.obtain(mHandler, R.id.restart_preview);
mHandler.sendMessageDelayed(message, 2000);
}
} else if (mHandler != null) {
Message message = Message.obtain(mHandler, R.id.restart_preview);
message.sendToTarget();
}
}
/**
* Creates the beep MediaPlayer in advance so that the sound can be triggered with the least
* latency possible.
*/
private void initBeepSound() {
if (mPlayBeep && mMediaPlayer == null) {
mMediaPlayer = new MediaPlayer();
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_SYSTEM);
mMediaPlayer.setOnCompletionListener(mBeepListener);
AssetFileDescriptor file = getResources().openRawResourceFd(R.raw.beep);
try {
mMediaPlayer.setDataSource(file.getFileDescriptor(), file.getStartOffset(),
file.getLength());
file.close();
mMediaPlayer.setVolume(0.15f, 0.15f);
mMediaPlayer.prepare();
} catch (IOException e) {
mMediaPlayer = null;
}
}
}
private void playBeepSound() {
if (mPlayBeep && mMediaPlayer != null) {
mMediaPlayer.start();
}
}
/**
* When the beep has finished playing, rewind to queue up another one.
*/
private final OnCompletionListener mBeepListener = new OnCompletionListener() {
public void onCompletion(MediaPlayer mediaPlayer) {
mediaPlayer.seekTo(0);
}
};
private void resetStatusView() {
resetStatusViewColor();
TextView textView = (TextView) findViewById(R.id.status_text_view);
textView.setText(R.string.msg_default_status);
Button actionButton = (Button) findViewById(R.id.status_action_button);
actionButton.setVisibility(View.GONE);
mLastResult = "";
}
public void resetStatusViewColor() {
View statusView = findViewById(R.id.status_view);
statusView.setBackgroundColor(getResources().getColor(R.color.status_view));
}
public void drawViewfinder() {
mViewfinderView.drawViewfinder();
}
}

View file

@ -1,102 +0,0 @@
/*
* Copyright (C) 2008 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 com.android.barcodes;
import android.app.Activity;
import android.content.Intent;
import android.os.Handler;
import android.os.Message;
import com.google.zxing.Result;
/**
* This class handles all the messaging which comprises the state machine for capture.
*/
public class BarcodesCaptureActivityHandler extends Handler {
private final BarcodesCaptureActivity mActivity;
private final DecodeThread mDecodeThread;
private State mState;
private enum State {
PREVIEW,
SUCCESS,
DONE
}
BarcodesCaptureActivityHandler(BarcodesCaptureActivity activity, String decodeMode) {
mActivity = activity;
mDecodeThread = new DecodeThread(activity, decodeMode);
mDecodeThread.start();
mState = State.SUCCESS;
// Start ourselves capturing previews and decoding.
restartPreviewAndDecode();
}
public void handleMessage(Message message) {
switch (message.what) {
case R.id.auto_focus:
// When one auto focus pass finishes, start another. This is the closest thing to
// continuous AF. It does seem to hunt a bit, but I'm not sure what else to do.
CameraManager.get().requestAutoFocus(this, R.id.auto_focus);
break;
case R.id.restart_preview:
restartPreviewAndDecode();
break;
case R.id.decode_succeeded:
mState = State.SUCCESS;
int duration = message.arg1;
mActivity.handleDecode((Result) message.obj, duration);
break;
case R.id.decode_failed:
// We're decoding as fast as possible, so when one decode fails, start another.
mState = State.PREVIEW;
CameraManager.get().requestPreviewFrame(mDecodeThread.mHandler, R.id.decode);
break;
case R.id.return_scan_result:
mActivity.setResult(Activity.RESULT_OK, (Intent) message.obj);
mActivity.finish();
break;
}
}
public void quitSynchronously() {
mState = State.DONE;
CameraManager.get().stopPreview();
Message quit = Message.obtain(mDecodeThread.mHandler, R.id.quit);
quit.sendToTarget();
try {
mDecodeThread.join();
} catch (InterruptedException e) {
}
// Be absolutely sure we don't send any queued up messages
removeMessages(R.id.decode_succeeded);
removeMessages(R.id.decode_failed);
}
private void restartPreviewAndDecode() {
if (mState == State.SUCCESS) {
mState = State.PREVIEW;
CameraManager.get().startPreview();
CameraManager.get().requestPreviewFrame(mDecodeThread.mHandler, R.id.decode);
CameraManager.get().requestAutoFocus(this, R.id.auto_focus);
mActivity.resetStatusViewColor();
mActivity.drawViewfinder();
}
}
}

View file

@ -1,137 +0,0 @@
/*
* Copyright (C) 2008 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 com.android.barcodes;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.DialogInterface.OnCancelListener;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
/**
* This class encodes data from an Intent into a QR code, and then displays it full screen so that
* another person can scan it with their device.
*/
public class BarcodesEncodeActivity extends Activity {
private QRCodeEncoder mQRCodeEncoder;
private ProgressDialog mProgressDialog;
private boolean mFirstLayout;
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
Intent intent = getIntent();
if (intent == null || !intent.getAction().equals(Intents.Encode.ACTION)) {
finish();
} else {
setContentView(R.layout.encode);
}
}
@Override
protected void onResume() {
super.onResume();
LinearLayout layout = (LinearLayout) findViewById(R.id.encode_view);
layout.getViewTreeObserver().addOnGlobalLayoutListener(mLayoutListener);
mFirstLayout = true;
}
/**
* This needs to be delayed until after the first layout so that the view dimensions will be
* available.
*/
public OnGlobalLayoutListener mLayoutListener = new OnGlobalLayoutListener() {
public void onGlobalLayout() {
if (mFirstLayout) {
LinearLayout layout = (LinearLayout) findViewById(R.id.encode_view);
int width = layout.getWidth();
int height = layout.getHeight();
int smallerDimension = (width < height) ? width : height;
Intent intent = getIntent();
try {
mQRCodeEncoder = new QRCodeEncoder(BarcodesEncodeActivity.this, intent);
setTitle(getString(R.string.app_name) + " - " + mQRCodeEncoder.getTitle());
mQRCodeEncoder.requestBarcode(mHandler, smallerDimension);
mProgressDialog = ProgressDialog.show(BarcodesEncodeActivity.this, null,
getString(R.string.msg_encode_in_progress), true, true, mCancelListener);
} catch (IllegalArgumentException e) {
showErrorMessage(R.string.msg_encode_contents_failed);
}
mFirstLayout = false;
}
}
};
public Handler mHandler = new Handler() {
public void handleMessage(Message message) {
switch (message.what) {
case R.id.encode_succeeded:
mProgressDialog.dismiss();
mProgressDialog = null;
Bitmap image = (Bitmap)message.obj;
ImageView view = (ImageView) findViewById(R.id.image_view);
view.setImageBitmap(image);
TextView contents = (TextView) findViewById(R.id.contents_text_view);
contents.setText(mQRCodeEncoder.getDisplayContents());
mQRCodeEncoder = null;
break;
case R.id.encode_failed:
showErrorMessage(R.string.msg_encode_barcode_failed);
mQRCodeEncoder = null;
break;
}
}
};
private void showErrorMessage(int message) {
if (mProgressDialog != null) {
mProgressDialog.dismiss();
mProgressDialog = null;
}
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage(message);
builder.setPositiveButton(R.string.button_ok, mClickListener);
builder.show();
}
private OnClickListener mClickListener = new OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
finish();
}
};
private OnCancelListener mCancelListener = new OnCancelListener() {
public void onCancel(DialogInterface dialog) {
finish();
}
};
}

View file

@ -1,58 +0,0 @@
/*
* Copyright (C) 2008 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 com.android.barcodes;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.os.Bundle;
import android.preference.PreferenceScreen;
import android.preference.CheckBoxPreference;
public class BarcodesPreferenceActivity extends android.preference.PreferenceActivity
implements OnSharedPreferenceChangeListener {
static final String KEY_DECODE_1D = "preferences_decode_1D";
static final String KEY_DECODE_QR = "preferences_decode_QR";
static final String KEY_PLAY_BEEP = "preferences_play_beep";
CheckBoxPreference mDecode1D;
CheckBoxPreference mDecodeQR;
CheckBoxPreference mPlayBeep;
@Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
addPreferencesFromResource(R.xml.preferences);
PreferenceScreen preferences = getPreferenceScreen();
preferences.getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
mDecode1D = (CheckBoxPreference) preferences.findPreference(KEY_DECODE_1D);
mDecodeQR = (CheckBoxPreference) preferences.findPreference(KEY_DECODE_QR);
mPlayBeep = (CheckBoxPreference) preferences.findPreference(KEY_PLAY_BEEP);
}
// Prevent the user from turning off both decode options
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
if (key.equals(KEY_DECODE_1D)) {
mDecodeQR.setEnabled(mDecode1D.isChecked());
mDecodeQR.setChecked(true);
} else if (key.equals(KEY_DECODE_QR)) {
mDecode1D.setEnabled(mDecodeQR.isChecked());
mDecode1D.setChecked(true);
}
}
}

View file

@ -1,219 +0,0 @@
/*
* Copyright (C) 2008 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 com.android.barcodes;
import android.content.Context;
import android.graphics.Point;
import android.graphics.Rect;
import android.hardware.Camera;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.Display;
import android.view.WindowManager;
import android.view.SurfaceHolder;
import com.google.zxing.ResultPoint;
/**
* This object wraps the Camera service object and expects to be the only one talking to it. The
* implementation encapsulates the steps needed to take preview-sized images, which are used for
* both preview and decoding.
*/
final class CameraManager {
private static final String TAG = "CameraManager";
private static CameraManager mCameraManager;
private Camera mCamera;
private final Context mContext;
private Point mScreenResolution;
private Rect mFramingRect;
private Handler mPreviewHandler;
private int mPreviewMessage;
private Handler mAutoFocusHandler;
private int mAutoFocusMessage;
private boolean mInitialized;
private boolean mPreviewing;
public static void init(Context context) {
if (mCameraManager == null) {
mCameraManager = new CameraManager(context);
}
}
public static CameraManager get() {
return mCameraManager;
}
private CameraManager(Context context) {
mContext = context;
mCamera = null;
mInitialized = false;
mPreviewing = false;
}
public void openDriver(SurfaceHolder holder) {
if (mCamera == null) {
mCamera = Camera.open();
mCamera.setPreviewDisplay(holder);
if (!mInitialized) {
mInitialized = true;
getScreenResolution();
}
setCameraParameters();
}
}
public void closeDriver() {
if (mCamera != null) {
mCamera.release();
mCamera = null;
}
}
public void startPreview() {
if (mCamera != null && !mPreviewing) {
mCamera.startPreview();
mPreviewing = true;
}
}
public void stopPreview() {
if (mCamera != null && mPreviewing) {
mCamera.setPreviewCallback(null);
mCamera.stopPreview();
mPreviewHandler = null;
mAutoFocusHandler = null;
mPreviewing = false;
}
}
/**
* A single preview frame will be returned to the handler supplied. The data will arrive as byte[]
* in the message.obj field, with width and height encoded as message.arg1 and message.arg2,
* respectively.
*
* @param handler The handler to send the message to.
* @param message The what field of the message to be sent.
*/
public void requestPreviewFrame(Handler handler, int message) {
if (mCamera != null && mPreviewing) {
mPreviewHandler = handler;
mPreviewMessage = message;
mCamera.setPreviewCallback(previewCallback);
}
}
public void requestAutoFocus(Handler handler, int message) {
if (mCamera != null && mPreviewing) {
mAutoFocusHandler = handler;
mAutoFocusMessage = message;
mCamera.autoFocus(autoFocusCallback);
}
}
/**
* Calculates the framing rect which the UI should draw to show the user where to place the
* barcode. The actual captured image should be a bit larger than indicated because they might
* frame the shot too tightly. This target helps with alignment as well as forces the user to hold
* the device far enough away to ensure the image will be in focus.
*
* @return The rectangle to draw on screen in window coordinates.
*/
public Rect getFramingRect() {
if (mFramingRect == null) {
int size = ((mScreenResolution.x < mScreenResolution.y) ? mScreenResolution.x :
mScreenResolution.y) * 3 / 4;
int leftOffset = (mScreenResolution.x - size) / 2;
int topOffset = (mScreenResolution.y - size) / 2;
mFramingRect = new Rect(leftOffset, topOffset, leftOffset + size, topOffset + size);
Log.v(TAG, "Calculated framing rect: " + mFramingRect);
}
return mFramingRect;
}
/**
* Converts the result points from still resolution coordinates to screen coordinates.
*
* @param points The points returned by the Reader subclass through Result.getResultPoints().
* @return An array of Points scaled to the size of the framing rect and offset appropriately
* so they can be drawn in screen coordinates.
*/
public Point[] convertResultPoints(ResultPoint[] points) {
Rect frame = getFramingRect();
int count = points.length;
Point[] output = new Point[count];
for (int x = 0; x < count; x++) {
output[x] = new Point();
output[x].x = frame.left + (int) (points[x].getX() + 0.5f);
output[x].y = frame.top + (int) (points[x].getY() + 0.5f);
}
return output;
}
/**
* Preview frames are delivered here, which we pass on to the registered handler. Make sure to
* clear the handler so it will only receive one message.
*/
private final Camera.PreviewCallback previewCallback = new Camera.PreviewCallback() {
public void onPreviewFrame(byte[] data, Camera camera) {
camera.setPreviewCallback(null);
if (mPreviewHandler != null) {
Message message = mPreviewHandler.obtainMessage(mPreviewMessage, mScreenResolution.x,
mScreenResolution.y, data);
message.sendToTarget();
mPreviewHandler = null;
}
}
};
private final Camera.AutoFocusCallback autoFocusCallback = new Camera.AutoFocusCallback() {
public void onAutoFocus(boolean success, Camera camera) {
if (mAutoFocusHandler != null) {
Message message = mAutoFocusHandler.obtainMessage(mAutoFocusMessage, success);
// Simulate continuous autofocus by sending a focus request every second.
mAutoFocusHandler.sendMessageDelayed(message, 1000);
mAutoFocusHandler = null;
}
}
};
/**
* Sets the camera up to take preview images which are used for both preview and decoding. We're
* counting on the default YUV420 semi-planar data. If that changes in the future, we'll need to
* specify it explicitly with setPreviewFormat().
*/
private void setCameraParameters() {
Camera.Parameters parameters = mCamera.getParameters();
parameters.setPreviewSize(mScreenResolution.x, mScreenResolution.y);
mCamera.setParameters(parameters);
Log.v(TAG, "Setting params for preview: width " + mScreenResolution.x + " height " +
mScreenResolution.y);
}
private Point getScreenResolution() {
if (mScreenResolution == null) {
WindowManager manager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
Display display = manager.getDefaultDisplay();
mScreenResolution = new Point(display.getWidth(), display.getHeight());
}
return mScreenResolution;
}
}

View file

@ -1,82 +0,0 @@
/*
* Copyright (C) 2008 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 com.android.barcodes;
public final class Contents {
/**
* All the formats we know about.
*/
public static final class Format {
public static final String UPC_A = "UPC_A";
public static final String UPC_E = "UPC_E";
public static final String EAN_8 = "EAN_8";
public static final String EAN_13 = "EAN_13";
public static final String CODE_39 = "CODE_39";
public static final String CODE_128 = "CODE_128";
public static final String QR_CODE = "QR_CODE";
}
public static final class Type {
/**
* Plain text. Use Intent.putExtra(DATA, string). This can be used for URLs too, but string
* must include "http://" or "https://".
*/
public static final String TEXT = "TEXT_TYPE";
/**
* An email type. Use Intent.putExtra(DATA, string) where string is the email address.
*/
public static final String EMAIL = "EMAIL_TYPE";
/**
* Use Intent.putExtra(DATA, string) where string is the phone number to call.
*/
public static final String PHONE = "PHONE_TYPE";
/**
* An SMS type. Use Intent.putExtra(DATA, string) where string is the number to SMS.
*/
public static final String SMS = "SMS_TYPE";
/**
* A contact. Send a request to encode it as follows:
*
* import android.provider.Contacts;
*
* Intent intent = new Intent(Intents.Encode.ACTION);
* intent.putExtra(Intents.Encode.TYPE, CONTACT);
* Bundle bundle = new Bundle();
* bundle.putString(Contacts.Intents.Insert.NAME, "Jenny");
* bundle.putString(Contacts.Intents.Insert.PHONE, "8675309");
* bundle.putString(Contacts.Intents.Insert.EMAIL, "jenny@the80s.com");
* intent.putExtra(Intents.Encode.DATA, bundle);
*/
public static final String CONTACT = "CONTACT_TYPE";
/**
* A geographic location. Use as follows:
* Bundle bundle = new Bundle();
* bundle.putFloat("LAT", latitude);
* bundle.putFloat("LONG", longitude);
* intent.putExtra(Intents.Encode.DATA, bundle);
*/
public static final String LOCATION = "LOCATION_TYPE";
}
}

View file

@ -1,162 +0,0 @@
/*
* Copyright (C) 2008 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 com.android.barcodes;
import android.content.SharedPreferences;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.preference.PreferenceManager;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.DecodeHintType;
import com.google.zxing.MonochromeBitmapSource;
import com.google.zxing.MultiFormatReader;
import com.google.zxing.ReaderException;
import com.google.zxing.Result;
import java.util.Date;
import java.util.Hashtable;
import java.util.Vector;
/**
* This thread does all the heavy lifting of decoding the images.
*/
final class DecodeThread extends Thread {
public Handler mHandler;
private BarcodesCaptureActivity mActivity;
private MultiFormatReader mMultiFormatReader;
DecodeThread(BarcodesCaptureActivity activity, String mode) {
mActivity = activity;
mMultiFormatReader = new MultiFormatReader();
// The prefs can't change while the thread is running, so pick them up once here.
if (mode == null || mode.length() == 0) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
boolean decode1D = prefs.getBoolean(BarcodesPreferenceActivity.KEY_DECODE_1D, true);
boolean decodeQR = prefs.getBoolean(BarcodesPreferenceActivity.KEY_DECODE_QR, true);
if (decode1D && decodeQR) {
setDecodeAllMode();
} else if (decode1D) {
setDecode1DMode();
} else if (decodeQR) {
setDecodeQRMode();
}
} else {
if (mode.equals(Intents.Scan.PRODUCT_MODE)) {
setDecodeProductMode();
} else if (mode.equals(Intents.Scan.ONE_D_MODE)) {
setDecode1DMode();
} else if (mode.equals(Intents.Scan.QR_CODE_MODE)) {
setDecodeQRMode();
} else {
setDecodeAllMode();
}
}
}
@Override
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message message) {
switch (message.what) {
case R.id.decode:
decode((byte[]) message.obj, message.arg1, message.arg2);
break;
case R.id.quit:
Looper.myLooper().quit();
break;
}
}
};
Looper.loop();
}
private void setDecodeProductMode() {
Hashtable<DecodeHintType, Object> hints = new Hashtable<DecodeHintType, Object>(3);
Vector<BarcodeFormat> vector = new Vector<BarcodeFormat>();
vector.addElement(BarcodeFormat.UPC_A);
vector.addElement(BarcodeFormat.UPC_E);
vector.addElement(BarcodeFormat.EAN_13);
vector.addElement(BarcodeFormat.EAN_8);
hints.put(DecodeHintType.POSSIBLE_FORMATS, vector);
mMultiFormatReader.setHints(hints);
}
// TODO: This is fragile in case we add new formats. It would be better to have a new enum
// value which represented all 1D formats.
private void setDecode1DMode() {
Hashtable<DecodeHintType, Object> hints = new Hashtable<DecodeHintType, Object>(3);
Vector<BarcodeFormat> vector = new Vector<BarcodeFormat>();
vector.addElement(BarcodeFormat.UPC_A);
vector.addElement(BarcodeFormat.UPC_E);
vector.addElement(BarcodeFormat.EAN_13);
vector.addElement(BarcodeFormat.EAN_8);
vector.addElement(BarcodeFormat.CODE_39);
vector.addElement(BarcodeFormat.CODE_128);
hints.put(DecodeHintType.POSSIBLE_FORMATS, vector);
mMultiFormatReader.setHints(hints);
}
private void setDecodeQRMode() {
Hashtable<DecodeHintType, Object> hints = new Hashtable<DecodeHintType, Object>(3);
Vector<BarcodeFormat> vector = new Vector<BarcodeFormat>();
vector.addElement(BarcodeFormat.QR_CODE);
hints.put(DecodeHintType.POSSIBLE_FORMATS, vector);
mMultiFormatReader.setHints(hints);
}
private void setDecodeAllMode() {
mMultiFormatReader.setHints(null);
}
/**
* Decode the data within the viewfinder rectangle, and time how long it took. For efficiency,
* reuse the same reader objects from one decode to the next.
*
* @param data The YUV preview frame.
* @param width The width of the preview frame.
* @param height The height of the preview frame.
*/
private void decode(byte[] data, int width, int height) {
Date startDate = new Date();
boolean success;
Result rawResult = null;
try {
MonochromeBitmapSource source = new YUVMonochromeBitmapSource(data, width, height,
CameraManager.get().getFramingRect());
rawResult = mMultiFormatReader.decodeWithState(source);
success = true;
} catch (ReaderException e) {
success = false;
}
Date endDate = new Date();
if (success) {
Message message = Message.obtain(mActivity.mHandler, R.id.decode_succeeded, rawResult);
message.arg1 = (int) (endDate.getTime() - startDate.getTime());
message.sendToTarget();
} else {
Message message = Message.obtain(mActivity.mHandler, R.id.decode_failed);
message.arg1 = (int) (endDate.getTime() - startDate.getTime());
message.sendToTarget();
}
}
}

View file

@ -1,86 +0,0 @@
/*
* Copyright (C) 2008 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 com.android.barcodes;
public final class Intents {
public static final class Scan {
/**
* Send this intent to open the Barcodes app in scanning mode, find a barcode, and return
* the results.
*/
public static final String ACTION = "com.android.barcodes.SCAN";
/**
* By default, sending Scan.ACTION will decode all barcodes that we understand. However it
* may be useful to limit scanning to certain formats. Use Intent.putExtra(MODE, value) with
* one of the values below (optional).
*/
public static final String MODE = "SCAN_MODE";
/**
* Decode only UPC and EAN barcodes. This is the right choice for shopping apps which get
* prices, reviews, etc. for products.
*/
public static final String PRODUCT_MODE = "PRODUCT_MODE";
/**
* Decode only 1D barcodes (currently UPC, EAN, Code 39, and Code 128).
*/
public static final String ONE_D_MODE = "ONE_D_MODE";
/**
* Decode only QR codes.
*/
public static final String QR_CODE_MODE = "QR_CODE_MODE";
/**
* If a barcode is found, Barcodes returns RESULT_OK to onActivityResult() of the app which
* requested the scan via startSubActivity(). The barcodes contents can be retrieved with
* intent.getStringExtra(RESULT). If the user presses Back, the result code will be
* RESULT_CANCELED.
*/
public static final String RESULT = "SCAN_RESULT";
/**
* Call intent.getStringExtra(RESULT_FORMAT) to determine which barcode format was found.
* See Contents.Format for possible values.
*/
public static final String RESULT_FORMAT = "SCAN_RESULT_FORMAT";
}
public static final class Encode {
/**
* Send this intent to encode a piece of data as a QR code and display it full screen, so
* that another person can scan the barcode from your screen.
*/
public static final String ACTION = "com.android.barcodes.ENCODE";
/**
* The data to encode. Use Intent.putExtra(DATA, data) where data is either a String or a
* Bundle, depending on the type specified. See Contents for details.
*/
public static final String DATA = "ENCODE_DATA";
/**
* The type of data being supplied. Use Intent.putExtra(TYPE, type) with one of
* Contents.Type.
*/
public static final String TYPE = "ENCODE_TYPE";
}
}

View file

@ -1,180 +0,0 @@
/*
* Copyright (C) 2008 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 com.android.barcodes;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.provider.Contacts;
import android.util.Log;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import java.net.URI;
public class QRCodeEncoder {
private static final String TAG = "QRCodeEncoder";
private static final String CHART_SERVER_URL = "//chart.apis.google.com/chart?cht=qr&chs=";
private Activity mActivity;
private String mContents;
private String mDisplayContents;
private String mTitle;
private NetworkThread mNetworkThread;
public QRCodeEncoder(Activity activity, Intent intent) {
mActivity = activity;
if (!encodeContents(intent)) {
throw new IllegalArgumentException("No valid data to encode.");
}
}
// Once the core ZXing library supports encoding, we'll be able to generate the bitmap
// synchronously. For now, it's a network request, so it's handled on a thread.
public void requestBarcode(Handler handler, int pixelResolution) {
mNetworkThread = new NetworkThread(mContents, handler, pixelResolution);
mNetworkThread.start();
}
public String getContents() {
return mContents;
}
public String getDisplayContents() {
return mDisplayContents;
}
public String getTitle() {
return mTitle;
}
// Perhaps the string encoding should live in the core ZXing library too.
private boolean encodeContents(Intent intent) {
if (intent == null) return false;
String type = intent.getStringExtra(Intents.Encode.TYPE);
if (type == null || type.length() == 0) return false;
if (type.equals(Contents.Type.TEXT)) {
String string = intent.getStringExtra(Intents.Encode.DATA);
if (string != null && string.length() > 0) {
mContents = string;
mDisplayContents = string;
mTitle = mActivity.getString(R.string.contents_text);
}
} else if (type.equals(Contents.Type.EMAIL)) {
String string = intent.getStringExtra(Intents.Encode.DATA);
if (string != null && string.length() > 0) {
mContents = "mailto:" + string;
mDisplayContents = string;
mTitle = mActivity.getString(R.string.contents_email);
}
} else if (type.equals(Contents.Type.PHONE)) {
String string = intent.getStringExtra(Intents.Encode.DATA);
if (string != null && string.length() > 0) {
mContents = "tel:" + string;
mDisplayContents = string;
mTitle = mActivity.getString(R.string.contents_phone);
}
} else if (type.equals(Contents.Type.SMS)) {
String string = intent.getStringExtra(Intents.Encode.DATA);
if (string != null && string.length() > 0) {
mContents = "sms:" + string;
mDisplayContents = string;
mTitle = mActivity.getString(R.string.contents_sms);
}
} else if (type.equals(Contents.Type.CONTACT)) {
Bundle bundle = intent.getBundleExtra(Intents.Encode.DATA);
if (bundle != null) {
String name = bundle.getString(Contacts.Intents.Insert.NAME);
if (name != null && !name.equals("")) {
mContents = "MECARD:N:" + name + ";";
mDisplayContents = name;
String phone = bundle.getString(Contacts.Intents.Insert.PHONE);
if (phone != null && !phone.equals("")) {
mContents += "TEL:" + phone + ";";
mDisplayContents += "\n" + phone;
}
String email = bundle.getString(Contacts.Intents.Insert.EMAIL);
if (email != null && !email.equals("")) {
mContents += "EMAIL:" + email + ";";
mDisplayContents += "\n" + email;
}
mContents += ";";
mTitle = mActivity.getString(R.string.contents_contact);
}
}
} else if (type.equals(Contents.Type.LOCATION)) {
Bundle bundle = intent.getBundleExtra(Intents.Encode.DATA);
if (bundle != null) {
float latitude = bundle.getFloat("LAT", Float.MAX_VALUE);
float longitude = bundle.getFloat("LONG", Float.MAX_VALUE);
if (latitude != Float.MAX_VALUE && longitude != Float.MAX_VALUE) {
mContents = "geo:" + latitude + "," + longitude;
mDisplayContents = latitude + "," + longitude;
mTitle = mActivity.getString(R.string.contents_location);
}
}
}
return mContents != null && mContents.length() > 0;
}
private class NetworkThread extends Thread {
private String mContents;
private Handler mHandler;
private int mPixelResolution;
public NetworkThread(String contents, Handler handler, int pixelResolution) {
mContents = contents;
mHandler = handler;
mPixelResolution = pixelResolution;
}
public void run() {
String url = CHART_SERVER_URL + mPixelResolution + "x" + mPixelResolution + "&chl=" +
mContents;
try {
URI uri = new URI("http", url, null);
HttpGet get = new HttpGet(uri);
AndroidHttpClient client = AndroidHttpClient.newInstance("Android-Barcodes/0.1");
HttpResponse response = client.execute(get);
HttpEntity entity = response.getEntity();
Bitmap image = BitmapFactory.decodeStream(entity.getContent());
if (image != null) {
Message message = Message.obtain(mHandler, R.id.encode_succeeded);
message.obj = image;
message.sendToTarget();
} else {
Log.e(TAG, "Could not decode png from the network");
Message message = Message.obtain(mHandler, R.id.encode_failed);
message.sendToTarget();
}
} catch (Exception e) {
Log.e(TAG, e.toString());
Message message = Message.obtain(mHandler, R.id.encode_failed);
message.sendToTarget();
}
}
}
}

View file

@ -1,162 +0,0 @@
/*
* Copyright (C) 2008 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 com.android.barcodes;
import android.content.Intent;
import android.net.Uri;
import android.provider.Contacts;
import android.view.View;
import android.widget.Button;
import com.google.zxing.Result;
import com.google.zxing.client.result.AddressBookParsedResult;
import com.google.zxing.client.result.EmailAddressParsedResult;
import com.google.zxing.client.result.GeoParsedResult;
import com.google.zxing.client.result.ISBNParsedResult;
import com.google.zxing.client.result.ParsedResult;
import com.google.zxing.client.result.ParsedResultType;
import com.google.zxing.client.result.ResultParser;
import com.google.zxing.client.result.SMSParsedResult;
import com.google.zxing.client.result.TelParsedResult;
import com.google.zxing.client.result.UPCParsedResult;
import com.google.zxing.client.result.URIParsedResult;
/**
* Handles the result of barcode decoding in the context of the Android platform, by dispatching the
* proper intents to open other activities like GMail, Maps, etc.
*/
final class ResultHandler implements Button.OnClickListener {
private static final String TAG = "ResultHandler";
private final Intent mIntent;
private final BarcodesCaptureActivity mCaptureActivity;
ResultHandler(BarcodesCaptureActivity captureActivity, ParsedResult result) {
mCaptureActivity = captureActivity;
mIntent = resultToIntent(result);
}
public void onClick(View view) {
if (mIntent != null) {
mCaptureActivity.startActivity(mIntent);
}
}
public Intent getIntent() {
return mIntent;
}
public static ParsedResult parseResult(Result rawResult) {
ParsedResult result = ResultParser.parseResult(rawResult);
if (result.getType().equals(ParsedResultType.TEXT)) {
String rawText = rawResult.getText();
AndroidIntentParsedResult androidResult = AndroidIntentParsedResult.parse(rawText);
if (androidResult != null) {
Intent intent = androidResult.getIntent();
if (!Intent.ACTION_VIEW.equals(intent.getAction())) {
// For now, don't take anything that just parses as a View action. A lot
// of things are accepted as a View action by default.
result = androidResult;
}
}
}
return result;
}
public static int getActionButtonText(ParsedResultType type) {
int buttonText;
if (type.equals(ParsedResultType.ADDRESSBOOK)) {
buttonText = R.string.button_add_contact;
} else if (type.equals(ParsedResultType.URI)) {
buttonText = R.string.button_open_browser;
} else if (type.equals(ParsedResultType.EMAIL_ADDRESS)) {
buttonText = R.string.button_email;
} else if (type.equals(ParsedResultType.SMS)) {
buttonText = R.string.button_sms;
} else if (type.equals(ParsedResultType.UPC)) {
buttonText = R.string.button_lookup_product;
} else if (type.equals(ParsedResultType.TEL)) {
buttonText = R.string.button_dial;
} else if (type.equals(ParsedResultType.GEO)) {
buttonText = R.string.button_show_map;
} else if (type.equals(ParsedResultType.ISBN)) {
buttonText = R.string.button_lookup_book;
} else {
buttonText = 0;
}
return buttonText;
}
private static Intent resultToIntent(ParsedResult result) {
Intent intent = null;
ParsedResultType type = result.getType();
if (type.equals(ParsedResultType.ADDRESSBOOK)) {
AddressBookParsedResult addressResult = (AddressBookParsedResult) result;
intent = new Intent(Contacts.Intents.Insert.ACTION, Contacts.People.CONTENT_URI);
putExtra(intent, Contacts.Intents.Insert.NAME, addressResult.getNames());
putExtra(intent, Contacts.Intents.Insert.PHONE, addressResult.getPhoneNumbers());
putExtra(intent, Contacts.Intents.Insert.EMAIL, addressResult.getEmails());
putExtra(intent, Contacts.Intents.Insert.NOTES, addressResult.getNote());
putExtra(intent, Contacts.Intents.Insert.POSTAL, addressResult.getAddress());
putExtra(intent, Contacts.Intents.Insert.COMPANY, addressResult.getOrg());
putExtra(intent, Contacts.Intents.Insert.JOB_TITLE, addressResult.getTitle());
} else if (type.equals(ParsedResultType.EMAIL_ADDRESS)) {
EmailAddressParsedResult emailResult = (EmailAddressParsedResult) result;
intent = new Intent(Intent.ACTION_SENDTO, Uri.parse(emailResult.getMailtoURI()));
putExtra(intent, "subject", emailResult.getSubject());
putExtra(intent, "body", emailResult.getBody());
} else if (type.equals(ParsedResultType.SMS)) {
SMSParsedResult smsResult = (SMSParsedResult) result;
intent = new Intent(Intent.ACTION_SENDTO, Uri.parse(smsResult.getSMSURI()));
putExtra(intent, "subject", smsResult.getSubject());
putExtra(intent, "body", smsResult.getBody());
} else if (type.equals(ParsedResultType.TEL)) {
TelParsedResult telResult = (TelParsedResult) result;
intent = new Intent(Intent.ACTION_DIAL, Uri.parse(telResult.getTelURI()));
} else if (type.equals(ParsedResultType.GEO)) {
GeoParsedResult geoResult = (GeoParsedResult) result;
intent = new Intent(Intent.ACTION_VIEW, Uri.parse(geoResult.getGeoURI()));
} else if (type.equals(ParsedResultType.UPC)) {
UPCParsedResult upcResult = (UPCParsedResult) result;
Uri uri = Uri.parse("http://www.google.com/products?q=" + upcResult.getUPC());
intent = new Intent(Intent.ACTION_VIEW, uri);
} else if (type.equals(ParsedResultType.ISBN)) {
ISBNParsedResult isbnResult = (ISBNParsedResult) result;
Uri uri = Uri.parse("http://www.google.com/products?q=" + isbnResult.getISBN());
intent = new Intent(Intent.ACTION_VIEW, uri);
} else if (type.equals(ParsedResultType.URI)) {
URIParsedResult uriResult = (URIParsedResult) result;
intent = new Intent(Intent.ACTION_VIEW, Uri.parse(uriResult.getURI()));
} else if (type.equals(ParsedResultType.ANDROID_INTENT)) {
intent = ((AndroidIntentParsedResult) result).getIntent();
}
return intent;
}
private static void putExtra(Intent intent, String key, String value) {
if (value != null && value.length() > 0) {
intent.putExtra(key, value);
}
}
private static void putExtra(Intent intent, String key, String[] value) {
if (value != null && value.length > 0) {
putExtra(intent, key, value[0]);
}
}
}

View file

@ -1,136 +0,0 @@
/*
* Copyright (C) 2008 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 com.android.barcodes;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.View;
import com.google.zxing.ResultPoint;
/**
* This view is overlaid on top of the camera preview. It adds the viewfinder rectangle and partial
* transparency outside it, as well as the laser scanner animation and result points.
*/
public class ViewfinderView extends View {
private static final int[] SCANNER_ALPHA = {0, 64, 128, 192, 255, 192, 128, 64};
private static final int ANIMATION_DELAY = 100;
private Paint mPaint;
private Rect mBox;
private Point[] mResultPoints;
private int mMaskColor;
private int mFrameColor;
private int mPointsColor;
private int mLaserColor;
private int mScannerAlpha;
// This constructor is used when the class is built from an XML resource.
public ViewfinderView(Context context, AttributeSet attrs) {
super(context, attrs);
// Initialize these once for performance rather than calling them every time in onDraw().
mPaint = new Paint();
mBox = new Rect();
Resources resources = getResources();
mMaskColor = resources.getColor(R.color.viewfinder_mask);
mFrameColor = resources.getColor(R.color.viewfinder_frame);
mPointsColor = resources.getColor(R.color.result_points);
mLaserColor = resources.getColor(R.color.viewfinder_laser);
mScannerAlpha = 0;
}
@Override
public void onDraw(Canvas canvas) {
Rect frame = CameraManager.get().getFramingRect();
int width = canvas.getWidth();
int height = canvas.getHeight();
// Draw the exterior (i.e. outside the framing rect) darkened
mPaint.setColor(mMaskColor);
mBox.set(0, 0, width, frame.top);
canvas.drawRect(mBox, mPaint);
mBox.set(0, frame.top, frame.left, frame.bottom + 1);
canvas.drawRect(mBox, mPaint);
mBox.set(frame.right + 1, frame.top, width, frame.bottom + 1);
canvas.drawRect(mBox, mPaint);
mBox.set(0, frame.bottom + 1, width, height);
canvas.drawRect(mBox, mPaint);
// Draw a two pixel solid black border inside the framing rect
mPaint.setColor(mFrameColor);
mBox.set(frame.left, frame.top, frame.right + 1, frame.top + 2);
canvas.drawRect(mBox, mPaint);
mBox.set(frame.left, frame.top + 2, frame.left + 2, frame.bottom - 1);
canvas.drawRect(mBox, mPaint);
mBox.set(frame.right - 1, frame.top, frame.right + 1, frame.bottom - 1);
canvas.drawRect(mBox, mPaint);
mBox.set(frame.left, frame.bottom - 1, frame.right + 1, frame.bottom + 1);
canvas.drawRect(mBox, mPaint);
if (mResultPoints != null) {
// Superimpose a line for 1D or dots for 2D to highlight the key features of the barcode
mPaint.setColor(mPointsColor);
if (mResultPoints.length == 2) {
mPaint.setStrokeWidth(4);
canvas.drawLine(mResultPoints[0].x, mResultPoints[0].y, mResultPoints[1].x,
mResultPoints[1].y, mPaint);
} else {
mPaint.setStrokeWidth(10);
for (int x = 0; x < mResultPoints.length; x++) {
canvas.drawPoint(mResultPoints[x].x, mResultPoints[x].y, mPaint);
}
}
} else {
// Draw a red "laser scanner" line through the middle to show decoding is active
mPaint.setColor(mLaserColor);
mPaint.setAlpha(SCANNER_ALPHA[mScannerAlpha]);
mScannerAlpha = (mScannerAlpha + 1) % SCANNER_ALPHA.length;
int middle = frame.height() / 2 + frame.top;
mBox.set(frame.left + 2, middle - 1, frame.right - 1, middle + 2);
canvas.drawRect(mBox, mPaint);
// Request another update at the animation interval, but only repaint the laser line,
// not the entire viewfinder mask.
postInvalidateDelayed(ANIMATION_DELAY, mBox.left, mBox.top, mBox.right, mBox.bottom);
}
}
public void drawViewfinder() {
mResultPoints = null;
invalidate();
}
/**
* Draw a line for 1D barcodes (which return two points) or otherwise a set of points returned
* from the decoder to indicate what we found. For efficiency, convert these to drawable
* coordinates once here.
*
* @param resultPoints An array of points from the decoder, whose coordinates are expressed
* relative to the still image from the camera.
*/
public void drawResultPoints(ResultPoint[] resultPoints) {
mResultPoints = CameraManager.get().convertResultPoints(resultPoints);
invalidate();
}
}

View file

@ -1,74 +0,0 @@
/*
* Copyright (C) 2008 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 com.android.barcodes;
import android.graphics.Rect;
import com.google.zxing.common.BaseMonochromeBitmapSource;
/**
* This object implements MonochromeBitmapSource around an array of YUV data, giving you the option
* to crop to a rectangle within the full data. This can be used to exclude superfluous pixels
* around the perimeter and speed up decoding.
*/
final class YUVMonochromeBitmapSource extends BaseMonochromeBitmapSource {
private final byte[] mYUVData;
private final int mDataWidth;
private final Rect mCrop;
/**
* Builds an object around a YUV buffer from the camera.
*
* @param yuvData A byte array of planar Y data, followed by interleaved U and V
* @param dataWidth The width of the Y data
* @param dataHeight The height of the Y data
* @param crop The rectangle within the yuvData to expose to MonochromeBitmapSource users
*/
YUVMonochromeBitmapSource(byte[] yuvData, int dataWidth, int dataHeight, Rect crop) {
mYUVData = yuvData;
mDataWidth = dataWidth;
mCrop = crop;
assert (crop.width() <= dataWidth);
assert (crop.height() <= dataHeight);
}
public int getHeight() {
return mCrop.height();
}
public int getWidth() {
return mCrop.width();
}
/**
* The Y channel is stored as planar data at the head of the array, so we just ignore the
* interleavd U and V which follow it.
*
* @param x The x coordinate to fetch within crop
* @param y The y coordinate to fetch within crop
* @return The luminance as an int, from 0-255
*/
public int getLuminance(int x, int y) {
return mYUVData[(y + mCrop.top) * mDataWidth + x + mCrop.left] & 0xff;
}
// Nothing to do, since we have direct access to the mYUVData array.
public void cacheRowForLuminance(int y) {
}
}