mirror of
https://github.com/zxing/zxing.git
synced 2025-02-02 05:41:08 -08:00
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:
parent
f142a9478c
commit
f3123f432b
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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";
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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";
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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]);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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) {
|
||||
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue