<string name="menu_about">詳細</string>
<string name="menu_help">ヘルプ</string>
<string name="menu_settings">設定</string>
+ <string name="menu_history">歴史</string>
<string name="menu_share">共有</string>
<string name="msg_about">オープンソースのバーコード ライブラリ、ZXing を使用しています</string>
<string name="result_text">テキストデータがヒットしました</string>
<string name="result_uri">URL がヒットしました</string>
+ <string name="history_title">歴史</string>
+ <string name="history_clear_text">削除履歴</string>
+
<string name="sbc_name">Google ブックス</string>
<string name="share_name">バーコードで共有する</string>
<string name="menu_about">关于</string>\r
<string name="menu_help">帮助</string>\r
<string name="menu_settings">设置</string>\r
+ <string name="menu_history">历史</string> \r
<string name="menu_share">分享</string>\r
<string name="msg_about">以ZXing的开源条码库为基础</string>\r
<string name="msg_default_contents">内容</string>\r
<string name="result_tel">找到电话号码</string>\r
<string name="result_text">找到纯文本</string>\r
<string name="result_uri">找到URL</string>\r
+ <string name="history_title">历史</string>\r
+ <string name="history_clear_text">删除历史</string>\r
<string name="sbc_name">Google图书搜索</string>\r
<string name="share_name">通过条码分享</string>\r
<string name="title_about">条码扫描器</string>\r
<string name="menu_about">關于</string>\r
<string name="menu_help">幫助</string>\r
<string name="menu_settings">設置</string>\r
+ <string name="menu_history">歷史</string> \r
<string name="menu_share">分享</string>\r
<string name="msg_about">以ZXing的開源條碼庫為基礎</string>\r
<string name="msg_default_contents">內容</string>\r
<string name="result_tel">找到電話號碼</string>\r
<string name="result_text">找到純文本</string>\r
<string name="result_uri">找到URL</string>\r
+ <string name="history_title">歷史</string>\r
+ <string name="history_clear_text">刪除歷史</string>\r
<string name="sbc_name">Google圖書搜索</string>\r
<string name="share_name">通過條碼分享</string>\r
<string name="title_about">條碼掃描器</string>\r
<string name="menu_about">About</string>
<string name="menu_help">Help</string>
<string name="menu_settings">Settings</string>
+ <string name="menu_history">History</string>
<string name="menu_share">Share</string>
<string name="msg_about">Based on the open source ZXing Barcode Library</string>
<string name="result_text">Found plain text</string>
<string name="result_uri">Found URL</string>
+ <string name="history_title">History</string>
+ <string name="history_clear_text">Clear history</string>
+
<string name="sbc_name">Google Book Search</string>
<string name="share_name">Share via barcode</string>
* @author dswitkin@google.com (Daniel Switkin)
*/
public abstract class BaseLuminanceSource extends LuminanceSource {
- public BaseLuminanceSource(int width, int height) {
+
+ BaseLuminanceSource(int width, int height) {
super(width, height);
}
+++ /dev/null
-/*
- * Copyright (C) 2008 ZXing authors
- *
- * 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.google.zxing.client.android;
-
-import android.app.ListActivity;
-import android.content.Intent;
-import android.database.Cursor;
-import android.os.Bundle;
-import android.provider.Browser;
-import android.view.View;
-import android.widget.ListAdapter;
-import android.widget.ListView;
-import android.widget.SimpleCursorAdapter;
-
-/**
- * This class is only needed because I can't successfully send an ACTION_PICK intent to
- * com.android.browser.BrowserBookmarksPage. It can go away if that starts working in the future.
- *
- * @author dswitkin@google.com (Daniel Switkin)
- */
-public final class BookmarkPickerActivity extends ListActivity {
- private static final String[] BOOKMARK_PROJECTION = {
- Browser.BookmarkColumns.TITLE,
- Browser.BookmarkColumns.URL
- };
-
- private static final int[] TWO_LINE_VIEW_IDS = {
- R.id.bookmark_title,
- R.id.bookmark_url
- };
-
- private static final int TITLE_COLUMN = 0;
- private static final int URL_COLUMN = 1;
-
- // Without this selection, we'd get all the history entries too
- private static final String BOOKMARK_SELECTION = "bookmark = 1";
-
- private Cursor cursor;
-
- @Override
- protected void onCreate(Bundle icicle) {
- super.onCreate(icicle);
-
- cursor = getContentResolver().query(Browser.BOOKMARKS_URI, BOOKMARK_PROJECTION,
- BOOKMARK_SELECTION, null, null);
- startManagingCursor(cursor);
-
- ListAdapter adapter = new SimpleCursorAdapter(this, R.layout.bookmark_picker_list_item,
- cursor, BOOKMARK_PROJECTION, TWO_LINE_VIEW_IDS);
- setListAdapter(adapter);
- }
-
- @Override
- protected void onListItemClick(ListView l, View view, int position, long id) {
- if (cursor.moveToPosition(position)) {
- Intent intent = new Intent();
- intent.putExtra(Browser.BookmarkColumns.TITLE, cursor.getString(TITLE_COLUMN));
- intent.putExtra(Browser.BookmarkColumns.URL, cursor.getString(URL_COLUMN));
- setResult(RESULT_OK, intent);
- } else {
- setResult(RESULT_CANCELED);
- }
- finish();
- }
-}
import com.google.zxing.client.android.result.ResultButtonListener;
import com.google.zxing.client.android.result.ResultHandler;
import com.google.zxing.client.android.result.ResultHandlerFactory;
+import com.google.zxing.client.android.history.HistoryManager;
+import com.google.zxing.client.android.share.ShareActivity;
import android.app.Activity;
import android.app.AlertDialog;
import android.os.Bundle;
import android.os.Message;
import android.os.Vibrator;
+import android.os.Handler;
import android.preference.PreferenceManager;
import android.text.ClipboardManager;
import android.text.SpannableStringBuilder;
private static final String TAG = "CaptureActivity";
private static final int SHARE_ID = Menu.FIRST;
- private static final int SETTINGS_ID = Menu.FIRST + 1;
- private static final int HELP_ID = Menu.FIRST + 2;
- private static final int ABOUT_ID = Menu.FIRST + 3;
+ private static final int HISTORY_ID = Menu.FIRST + 1;
+ private static final int SETTINGS_ID = Menu.FIRST + 2;
+ private static final int HELP_ID = Menu.FIRST + 3;
+ private static final int ABOUT_ID = Menu.FIRST + 4;
private static final int MAX_RESULT_IMAGE_SIZE = 150;
private static final long INTENT_RESULT_DURATION = 1500L;
NONE
}
- public CaptureActivityHandler handler;
+ private CaptureActivityHandler handler;
private ViewfinderView viewfinderView;
private View statusView;
private String sourceUrl;
private String decodeMode;
private String versionName;
+ private HistoryManager historyManager;
private final OnCompletionListener beepListener = new BeepListener();
}
};
+ public Handler getHandler() {
+ return handler;
+ }
+
@Override
public void onCreate(Bundle icicle) {
Log.i(TAG, "Creating CaptureActivity");
handler = null;
lastResult = null;
hasSurface = false;
+ historyManager = new HistoryManager(this);
showHelpOnFirstLaunch();
}
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
menu.add(0, SHARE_ID, 0, R.string.menu_share).setIcon(R.drawable.share_menu_item);
+ menu.add(0, HISTORY_ID, 0, R.string.menu_history).setIcon(android.R.drawable.ic_menu_recent_history);
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)
startActivity(intent);
break;
}
+ case HISTORY_ID: {
+ AlertDialog historyAlert = historyManager.buildAlert();
+ historyAlert.show();
+ break;
+ }
case SETTINGS_ID: {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setClassName(this, PreferencesActivity.class.getName());
*/
public void handleDecode(Result rawResult, Bitmap barcode) {
lastResult = rawResult;
- playBeepSoundAndVibrate();
- drawResultPoints(barcode, rawResult);
-
- switch (source) {
- case NATIVE_APP_INTENT:
- case PRODUCT_SEARCH_LINK:
- handleDecodeExternally(rawResult, barcode);
- break;
- case ZXING_LINK:
- case NONE:
- handleDecodeInternally(rawResult, barcode);
- break;
+ historyManager.addHistoryItem(rawResult.getText());
+ if (barcode != null) {
+ playBeepSoundAndVibrate();
+ drawResultPoints(barcode, rawResult);
+ switch (source) {
+ case NATIVE_APP_INTENT:
+ case PRODUCT_SEARCH_LINK:
+ handleDecodeExternally(rawResult, barcode);
+ break;
+ case ZXING_LINK:
+ case NONE:
+ handleDecodeInternally(rawResult, barcode);
+ break;
+ }
+ } else {
+ handleDecodeInternally(rawResult, null);
}
}
resultView.setVisibility(View.VISIBLE);
ImageView barcodeImageView = (ImageView) findViewById(R.id.barcode_image_view);
- barcodeImageView.setMaxWidth(MAX_RESULT_IMAGE_SIZE);
- barcodeImageView.setMaxHeight(MAX_RESULT_IMAGE_SIZE);
- barcodeImageView.setImageBitmap(barcode);
+ if (barcode == null) {
+ barcodeImageView.setVisibility(View.GONE);
+ } else {
+ barcodeImageView.setVisibility(View.VISIBLE);
+ barcodeImageView.setMaxWidth(MAX_RESULT_IMAGE_SIZE);
+ barcodeImageView.setMaxHeight(MAX_RESULT_IMAGE_SIZE);
+ barcodeImageView.setImageBitmap(barcode);
+ }
TextView formatTextView = (TextView) findViewById(R.id.format_text_view);
- formatTextView.setText(getString(R.string.msg_default_format) + ": " +
- rawResult.getBarcodeFormat().toString());
+ if (rawResult.getBarcodeFormat() == null) {
+ formatTextView.setVisibility(View.GONE);
+ } else {
+ formatTextView.setVisibility(View.VISIBLE);
+ formatTextView.setText(getString(R.string.msg_default_format) + ": " +
+ rawResult.getBarcodeFormat().toString());
+ }
ResultHandler resultHandler = ResultHandlerFactory.makeResultHandler(this, rawResult);
TextView typeTextView = (TextView) findViewById(R.id.type_text_view);
case R.id.decode_succeeded:
state = State.SUCCESS;
Bundle bundle = message.getData();
- Bitmap barcode = bundle.getParcelable(DecodeThread.BARCODE_BITMAP);
+ Bitmap barcode = bundle == null ? null : (Bitmap) bundle.getParcelable(DecodeThread.BARCODE_BITMAP);
activity.handleDecode((Result) message.obj, barcode);
break;
case R.id.decode_failed:
// We're decoding as fast as possible, so when one decode fails, start another.
state = State.PREVIEW;
- CameraManager.get().requestPreviewFrame(decodeThread.handler, R.id.decode);
+ CameraManager.get().requestPreviewFrame(decodeThread.getHandler(), R.id.decode);
break;
case R.id.return_scan_result:
activity.setResult(Activity.RESULT_OK, (Intent) message.obj);
public void quitSynchronously() {
state = State.DONE;
CameraManager.get().stopPreview();
- Message quit = Message.obtain(decodeThread.handler, R.id.quit);
+ Message quit = Message.obtain(decodeThread.getHandler(), R.id.quit);
quit.sendToTarget();
try {
decodeThread.join();
private void restartPreviewAndDecode() {
if (state == State.SUCCESS) {
state = State.PREVIEW;
- CameraManager.get().requestPreviewFrame(decodeThread.handler, R.id.decode);
+ CameraManager.get().requestPreviewFrame(decodeThread.getHandler(), R.id.decode);
CameraManager.get().requestAutoFocus(this, R.id.auto_focus);
activity.drawViewfinder();
}
public static final String BARCODE_BITMAP = "barcode_bitmap";
private static final String TAG = "DecodeThread";
- public Handler handler;
+ private Handler handler;
private final CaptureActivity activity;
private final MultiFormatReader multiFormatReader;
}
}
+ Handler getHandler() {
+ return handler;
+ }
+
@Override
public void run() {
Looper.prepare();
if (success) {
Log.v(TAG, "Found barcode (" + (end - start) + " ms):\n" + rawResult.toString());
- Message message = Message.obtain(activity.handler, R.id.decode_succeeded, rawResult);
+ Message message = Message.obtain(activity.getHandler(), R.id.decode_succeeded, rawResult);
Bundle bundle = new Bundle();
bundle.putParcelable(BARCODE_BITMAP, source.renderCroppedGreyscaleBitmap());
message.setData(bundle);
message.sendToTarget();
} else {
- Message message = Message.obtain(activity.handler, R.id.decode_failed);
+ Message message = Message.obtain(activity.getHandler(), R.id.decode_failed);
message.sendToTarget();
}
}
+++ /dev/null
-/*
- * Copyright (C) 2008 ZXing authors
- *
- * 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.google.zxing.client.android;
-
-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.View;
-import android.view.ViewTreeObserver.OnGlobalLayoutListener;
-import android.widget.ImageView;
-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.
- *
- * @author dswitkin@google.com (Daniel Switkin)
- */
-public final class EncodeActivity extends Activity {
- private QRCodeEncoder qrCodeEncoder;
- private ProgressDialog progressDialog;
- private boolean firstLayout;
-
- /**
- * This needs to be delayed until after the first layout so that the view dimensions will be
- * available.
- */
- public final OnGlobalLayoutListener layoutListener = new OnGlobalLayoutListener() {
- public void onGlobalLayout() {
- if (firstLayout) {
- View layout = findViewById(R.id.encode_view);
- int width = layout.getWidth();
- int height = layout.getHeight();
- int smallerDimension = width < height ? width : height;
- smallerDimension = smallerDimension * 7 / 8;
-
- Intent intent = getIntent();
- try {
- qrCodeEncoder = new QRCodeEncoder(EncodeActivity.this, intent);
- setTitle(getString(R.string.app_name) + " - " + qrCodeEncoder.getTitle());
- qrCodeEncoder.requestBarcode(handler, smallerDimension);
- progressDialog = ProgressDialog.show(EncodeActivity.this, null,
- getString(R.string.msg_encode_in_progress), true, true, cancelListener);
- } catch (IllegalArgumentException e) {
- showErrorMessage(R.string.msg_encode_contents_failed);
- }
- firstLayout = false;
- }
- }
- };
-
- public final Handler handler = new Handler() {
- @Override
- public void handleMessage(Message message) {
- switch (message.what) {
- case R.id.encode_succeeded:
- progressDialog.dismiss();
- progressDialog = 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(qrCodeEncoder.getDisplayContents());
- qrCodeEncoder = null;
- break;
- case R.id.encode_failed:
- showErrorMessage(R.string.msg_encode_barcode_failed);
- qrCodeEncoder = null;
- break;
- }
- }
- };
-
- private final OnClickListener clickListener = new OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- finish();
- }
- };
-
- private final OnCancelListener cancelListener = new OnCancelListener() {
- public void onCancel(DialogInterface dialog) {
- finish();
- }
- };
-
- @Override
- public void onCreate(Bundle icicle) {
- super.onCreate(icicle);
-
- Intent intent = getIntent();
- if (intent != null && (intent.getAction().equals(Intents.Encode.ACTION))) {
- setContentView(R.layout.encode);
- } else {
- finish();
- }
- }
-
- @Override
- protected void onResume() {
- super.onResume();
-
- View layout = findViewById(R.id.encode_view);
- layout.getViewTreeObserver().addOnGlobalLayoutListener(layoutListener);
- firstLayout = true;
- }
-
- private void showErrorMessage(int message) {
- if (progressDialog != null) {
- progressDialog.dismiss();
- progressDialog = null;
- }
- AlertDialog.Builder builder = new AlertDialog.Builder(this);
- builder.setMessage(message);
- builder.setPositiveButton(R.string.button_ok, clickListener);
- builder.show();
- }
-}
+++ /dev/null
-/*
- * Copyright (C) 2008 ZXing authors
- *
- * 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.google.zxing.client.android;
-
-import com.google.zxing.BarcodeFormat;
-import com.google.zxing.MultiFormatWriter;
-import com.google.zxing.WriterException;
-import com.google.zxing.common.ByteMatrix;
-
-import android.app.Activity;
-import android.content.Intent;
-import android.graphics.Bitmap;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
-import android.provider.Contacts;
-import android.telephony.PhoneNumberUtils;
-import android.util.Log;
-
-/**
- * This class does the work of decoding the user's request and extracting all the data
- * to be encoded in a QR Code.
- *
- * @author dswitkin@google.com (Daniel Switkin)
- */
-public final class QRCodeEncoder {
- private final Activity activity;
- private String contents;
- private String displayContents;
- private String title;
- private BarcodeFormat format;
-
- public QRCodeEncoder(Activity activity, Intent intent) {
- this.activity = activity;
- if (!encodeContents(intent)) {
- throw new IllegalArgumentException("No valid data to encode.");
- }
- }
-
- public void requestBarcode(Handler handler, int pixelResolution) {
- Thread encodeThread = new EncodeThread(contents, handler, pixelResolution,
- format);
- encodeThread.start();
- }
-
- public String getContents() {
- return contents;
- }
-
- public String getDisplayContents() {
- return displayContents;
- }
-
- public String getTitle() {
- return title;
- }
-
- public String getFormat() {
- return format.toString();
- }
-
- // It would be nice if the string encoding lived in the core ZXing library,
- // but we use platform specific code like PhoneNumberUtils, so it can't.
- private boolean encodeContents(Intent intent) {
- if (intent == null) {
- return false;
- }
-
- // default to QR_CODE if no format given
- String format = intent.getStringExtra(Intents.Encode.FORMAT);
- if (format == null || format.length() == 0 ||
- format.equals(Contents.Format.QR_CODE)) {
- String type = intent.getStringExtra(Intents.Encode.TYPE);
- if (type == null || type.length() == 0) {
- return false;
- }
- this.format = BarcodeFormat.QR_CODE;
- encodeQRCodeContents(intent, type);
- } else {
- String data = intent.getStringExtra(Intents.Encode.DATA);
- if (data != null && data.length() != 0) {
- contents = data;
- displayContents = data;
- title = activity.getString(R.string.contents_text);
- if (format.equals(Contents.Format.CODE_128))
- this.format = BarcodeFormat.CODE_128;
- else if (format.equals(Contents.Format.CODE_39))
- this.format = BarcodeFormat.CODE_39;
- else if (format.equals(Contents.Format.EAN_8))
- this.format = BarcodeFormat.EAN_8;
- else if (format.equals(Contents.Format.EAN_13))
- this.format = BarcodeFormat.EAN_13;
- else if (format.equals(Contents.Format.UPC_A))
- this.format = BarcodeFormat.UPC_A;
- else if (format.equals(Contents.Format.UPC_E))
- this.format = BarcodeFormat.UPC_E;
- }
- }
- return contents != null && contents.length() > 0;
- }
-
- private void encodeQRCodeContents(Intent intent, String type) {
- if (type.equals(Contents.Type.TEXT)) {
- String data = intent.getStringExtra(Intents.Encode.DATA);
- if (data != null && data.length() > 0) {
- contents = data;
- displayContents = data;
- title = activity.getString(R.string.contents_text);
- }
- } else if (type.equals(Contents.Type.EMAIL)) {
- String data = intent.getStringExtra(Intents.Encode.DATA);
- if (data != null && data.length() > 0) {
- contents = "mailto:" + data;
- displayContents = data;
- title = activity.getString(R.string.contents_email);
- }
- } else if (type.equals(Contents.Type.PHONE)) {
- String data = intent.getStringExtra(Intents.Encode.DATA);
- if (data != null && data.length() > 0) {
- contents = "tel:" + data;
- displayContents = PhoneNumberUtils.formatNumber(data);
- title = activity.getString(R.string.contents_phone);
- }
- } else if (type.equals(Contents.Type.SMS)) {
- String data = intent.getStringExtra(Intents.Encode.DATA);
- if (data != null && data.length() > 0) {
- contents = "sms:" + data;
- displayContents = PhoneNumberUtils.formatNumber(data);
- title = activity.getString(R.string.contents_sms);
- }
- } else if (type.equals(Contents.Type.CONTACT)) {
- Bundle bundle = intent.getBundleExtra(Intents.Encode.DATA);
- if (bundle != null) {
- StringBuilder newContents = new StringBuilder();
- StringBuilder newDisplayContents = new StringBuilder();
- newContents.append("MECARD:");
- String name = bundle.getString(Contacts.Intents.Insert.NAME);
- if (name != null && name.length() > 0) {
- newContents.append("N:").append(name).append(';');
- newDisplayContents.append(name);
- }
- String address = bundle.getString(Contacts.Intents.Insert.POSTAL);
- if (address != null && address.length() > 0) {
- newContents.append("ADR:").append(address).append(';');
- newDisplayContents.append('\n').append(address);
- }
- for (int x = 0; x < Contents.PHONE_KEYS.length; x++) {
- String phone = bundle.getString(Contents.PHONE_KEYS[x]);
- if (phone != null && phone.length() > 0) {
- newContents.append("TEL:").append(phone).append(';');
- newDisplayContents.append('\n').append(PhoneNumberUtils.formatNumber(phone));
- }
- }
- for (int x = 0; x < Contents.EMAIL_KEYS.length; x++) {
- String email = bundle.getString(Contents.EMAIL_KEYS[x]);
- if (email != null && email.length() > 0) {
- newContents.append("EMAIL:").append(email).append(';');
- newDisplayContents.append('\n').append(email);
- }
- }
- // Make sure we've encoded at least one field.
- if (newDisplayContents.length() > 0) {
- newContents.append(';');
- contents = newContents.toString();
- displayContents = newDisplayContents.toString();
- title = activity.getString(R.string.contents_contact);
- } else {
- contents = null;
- displayContents = null;
- }
- }
- } else if (type.equals(Contents.Type.LOCATION)) {
- Bundle bundle = intent.getBundleExtra(Intents.Encode.DATA);
- if (bundle != null) {
- // These must use Bundle.getFloat(), not getDouble(), it's part of the API.
- 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) {
- contents = "geo:" + latitude + ',' + longitude;
- displayContents = latitude + "," + longitude;
- title = activity.getString(R.string.contents_location);
- }
- }
- }
- }
-
- private static final class EncodeThread extends Thread {
- private static final String TAG = "EncodeThread";
-
- private final String contents;
- private final Handler handler;
- private final int pixelResolution;
- private final BarcodeFormat format;
-
- EncodeThread(String contents, Handler handler, int pixelResolution,
- BarcodeFormat format) {
- this.contents = contents;
- this.handler = handler;
- this.pixelResolution = pixelResolution;
- this.format = format;
- }
-
- @Override
- public void run() {
- try {
- ByteMatrix result = new MultiFormatWriter().encode(contents, format,
- pixelResolution, pixelResolution);
- int width = result.getWidth();
- int height = result.getHeight();
- byte[][] array = result.getArray();
- int[] pixels = new int[width * height];
- for (int y = 0; y < height; y++) {
- for (int x = 0; x < width; x++) {
- int grey = array[y][x] & 0xff;
- // pixels[y * width + x] = (0xff << 24) | (grey << 16) | (grey << 8) | grey;
- pixels[y * width + x] = 0xff000000 | (0x00010101 * grey);
- }
- }
-
- Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
- bitmap.setPixels(pixels, 0, width, 0, 0, width, height);
- Message message = Message.obtain(handler, R.id.encode_succeeded);
- message.obj = bitmap;
- message.sendToTarget();
- } catch (WriterException e) {
- Log.e(TAG, e.toString());
- Message message = Message.obtain(handler, R.id.encode_failed);
- message.sendToTarget();
- } catch (IllegalArgumentException e) {
- Log.e(TAG, e.toString());
- Message message = Message.obtain(handler, R.id.encode_failed);
- message.sendToTarget();
- }
- }
- }
-}
+++ /dev/null
-/*
- * Copyright (C) 2008 ZXing authors
- *
- * 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.google.zxing.client.android;
-
-import android.app.Activity;
-import android.content.Intent;
-import android.content.res.Configuration;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
-import android.util.Log;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.webkit.CookieManager;
-import android.webkit.CookieSyncManager;
-import android.widget.Button;
-import android.widget.EditText;
-import android.widget.ListView;
-import android.widget.TextView;
-import org.apache.http.Header;
-import org.apache.http.HttpEntity;
-import org.apache.http.HttpResponse;
-import org.apache.http.client.methods.HttpGet;
-import org.apache.http.client.methods.HttpHead;
-import org.apache.http.client.methods.HttpUriRequest;
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.net.URI;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Uses Google Book Search to find a word or phrase in the requested book.
- *
- * @author dswitkin@google.com (Daniel Switkin)
- */
-public final class SearchBookContentsActivity extends Activity {
- private static final String TAG = "SearchBookContents";
- private static final String USER_AGENT = "ZXing (Android)";
-
- private NetworkThread networkThread;
- private String isbn;
- private EditText queryTextView;
- private Button queryButton;
- private ListView resultListView;
- private TextView headerView;
-
- public final Handler handler = new Handler() {
- @Override
- public void handleMessage(Message message) {
- switch (message.what) {
- case R.id.search_book_contents_succeeded:
- handleSearchResults((JSONObject) message.obj);
- resetForNewQuery();
- break;
- case R.id.search_book_contents_failed:
- resetForNewQuery();
- headerView.setText(R.string.msg_sbc_failed);
- break;
- }
- }
- };
-
- private final Button.OnClickListener buttonListener = new Button.OnClickListener() {
- public void onClick(View view) {
- launchSearch();
- }
- };
-
- private final View.OnKeyListener keyListener = new View.OnKeyListener() {
- public boolean onKey(View view, int keyCode, KeyEvent event) {
- if (keyCode == KeyEvent.KEYCODE_ENTER) {
- launchSearch();
- return true;
- }
- return false;
- }
- };
-
- @Override
- public void onCreate(Bundle icicle) {
- super.onCreate(icicle);
-
- // Make sure that expired cookies are removed on launch.
- CookieSyncManager.createInstance(this);
- CookieManager.getInstance().removeExpiredCookie();
-
- Intent intent = getIntent();
- if (intent == null || (!intent.getAction().equals(Intents.SearchBookContents.ACTION))) {
- finish();
- return;
- }
-
- isbn = intent.getStringExtra(Intents.SearchBookContents.ISBN);
- setTitle(getString(R.string.sbc_name) + ": ISBN " + isbn);
-
- setContentView(R.layout.search_book_contents);
- queryTextView = (EditText) findViewById(R.id.query_text_view);
-
- String initialQuery = intent.getStringExtra(Intents.SearchBookContents.QUERY);
- if (initialQuery != null && initialQuery.length() > 0) {
- // Populate the search box but don't trigger the search
- queryTextView.setText(initialQuery);
- }
- queryTextView.setOnKeyListener(keyListener);
-
- queryButton = (Button) findViewById(R.id.query_button);
- queryButton.setOnClickListener(buttonListener);
-
- resultListView = (ListView) findViewById(R.id.result_list_view);
- LayoutInflater factory = LayoutInflater.from(this);
- headerView = (TextView) factory.inflate(R.layout.search_book_contents_header,
- resultListView, false);
- resultListView.addHeaderView(headerView);
- }
-
- @Override
- protected void onResume() {
- super.onResume();
- queryTextView.selectAll();
- }
-
- @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 void resetForNewQuery() {
- networkThread = null;
- queryTextView.setEnabled(true);
- queryTextView.selectAll();
- queryButton.setEnabled(true);
- }
-
- private void launchSearch() {
- if (networkThread == null) {
- String query = queryTextView.getText().toString();
- if (query != null && query.length() > 0) {
- networkThread = new NetworkThread(isbn, query, handler);
- networkThread.start();
- headerView.setText(R.string.msg_sbc_searching_book);
- resultListView.setAdapter(null);
- queryTextView.setEnabled(false);
- queryButton.setEnabled(false);
- }
- }
- }
-
- // Currently there is no way to distinguish between a query which had no results and a book
- // which is not searchable - both return zero results.
- private void handleSearchResults(JSONObject json) {
- try {
- int count = json.getInt("number_of_results");
- headerView.setText("Found " + (count == 1 ? "1 result" : count + " results"));
- if (count > 0) {
- JSONArray results = json.getJSONArray("search_results");
- SearchBookContentsResult.setQuery(queryTextView.getText().toString());
- List<SearchBookContentsResult> items = new ArrayList<SearchBookContentsResult>(count);
- for (int x = 0; x < count; x++) {
- items.add(parseResult(results.getJSONObject(x)));
- }
- resultListView.setAdapter(new SearchBookContentsAdapter(this, items));
- } else {
- String searchable = json.optString("searchable");
- if ("false".equals(searchable)) {
- headerView.setText(R.string.msg_sbc_book_not_searchable);
- }
- resultListView.setAdapter(null);
- }
- } catch (JSONException e) {
- Log.e(TAG, e.toString());
- resultListView.setAdapter(null);
- headerView.setText(R.string.msg_sbc_failed);
- }
- }
-
- // Available fields: page_number, page_id, page_url, snippet_text
- private SearchBookContentsResult parseResult(JSONObject json) {
- try {
- String pageNumber = json.getString("page_number");
- if (pageNumber.length() > 0) {
- pageNumber = getString(R.string.msg_sbc_page) + ' ' + pageNumber;
- } else {
- // This can happen for text on the jacket, and possibly other reasons.
- pageNumber = getString(R.string.msg_sbc_unknown_page);
- }
-
- // Remove all HTML tags and encoded characters. Ideally the server would do this.
- String snippet = json.optString("snippet_text");
- boolean valid = true;
- if (snippet.length() > 0) {
- snippet = snippet.replaceAll("\\<.*?\\>", "");
- snippet = snippet.replaceAll("<", "<");
- snippet = snippet.replaceAll(">", ">");
- snippet = snippet.replaceAll("'", "'");
- snippet = snippet.replaceAll(""", "\"");
- } else {
- snippet = '(' + getString(R.string.msg_sbc_snippet_unavailable) + ')';
- valid = false;
- }
- return new SearchBookContentsResult(pageNumber, snippet, valid);
- } catch (JSONException e) {
- // Never seen in the wild, just being complete.
- return new SearchBookContentsResult(getString(R.string.msg_sbc_no_page_returned), "", false);
- }
- }
-
- private static final class NetworkThread extends Thread {
- private final String isbn;
- private final String query;
- private final Handler handler;
-
- NetworkThread(String isbn, String query, Handler handler) {
- this.isbn = isbn;
- this.query = query;
- this.handler = handler;
- }
-
- @Override
- public void run() {
- AndroidHttpClient client = null;
- try {
- // These return a JSON result which describes if and where the query was found. This API may
- // break or disappear at any time in the future. Since this is an API call rather than a
- // website, we don't use LocaleManager to change the TLD.
- URI uri = new URI("http", null, "www.google.com", -1, "/books", "vid=isbn" + isbn +
- "&jscmd=SearchWithinVolume2&q=" + query, null);
- HttpUriRequest get = new HttpGet(uri);
- get.setHeader("cookie", getCookie(uri.toString()));
- client = AndroidHttpClient.newInstance(USER_AGENT);
- HttpResponse response = client.execute(get);
- if (response.getStatusLine().getStatusCode() == 200) {
- HttpEntity entity = response.getEntity();
- ByteArrayOutputStream jsonHolder = new ByteArrayOutputStream();
- entity.writeTo(jsonHolder);
- jsonHolder.flush();
- JSONObject json = new JSONObject(jsonHolder.toString(getEncoding(entity)));
- jsonHolder.close();
-
- Message message = Message.obtain(handler, R.id.search_book_contents_succeeded);
- message.obj = json;
- message.sendToTarget();
- } else {
- Log.e(TAG, "HTTP returned " + response.getStatusLine().getStatusCode() + " for " + uri);
- Message message = Message.obtain(handler, R.id.search_book_contents_failed);
- message.sendToTarget();
- }
- } catch (Exception e) {
- Log.e(TAG, e.toString());
- Message message = Message.obtain(handler, R.id.search_book_contents_failed);
- message.sendToTarget();
- } finally {
- if (client != null) {
- client.close();
- }
- }
- }
-
- // Book Search requires a cookie to work, which we store persistently. If the cookie does
- // not exist, this could be the first search or it has expired. Either way, do a quick HEAD
- // request to fetch it, save it via the CookieSyncManager to flash, then return it.
- private String getCookie(String url) {
- String cookie = CookieManager.getInstance().getCookie(url);
- if (cookie == null || cookie.length() == 0) {
- Log.v(TAG, "Book Search cookie was missing or expired");
- HttpUriRequest head = new HttpHead(url);
- AndroidHttpClient client = AndroidHttpClient.newInstance(USER_AGENT);
- try {
- HttpResponse response = client.execute(head);
- if (response.getStatusLine().getStatusCode() == 200) {
- Header[] cookies = response.getHeaders("set-cookie");
- for (Header theCookie : cookies) {
- CookieManager.getInstance().setCookie(url, theCookie.getValue());
- }
- CookieSyncManager.getInstance().sync();
- cookie = CookieManager.getInstance().getCookie(url);
- }
- } catch (IOException e) {
- Log.e(TAG, e.toString());
- }
- client.close();
- }
- return cookie;
- }
-
- private static String getEncoding(HttpEntity entity) {
- // FIXME: The server is returning ISO-8859-1 but the content is actually windows-1252.
- // Once Jeff fixes the HTTP response, remove this hardcoded value and go back to getting
- // the encoding dynamically.
- return "windows-1252";
-// HeaderElement[] elements = entity.getContentType().getElements();
-// if (elements != null && elements.length > 0) {
-// String encoding = elements[0].getParameterByName("charset").getValue();
-// if (encoding != null && encoding.length() > 0) {
-// return encoding;
-// }
-// }
-// return "UTF-8";
- }
- }
-}
+++ /dev/null
-/*
- * Copyright (C) 2008 ZXing authors
- *
- * 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.google.zxing.client.android;
-
-import android.content.Context;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ArrayAdapter;
-
-import java.util.List;
-
-/**
- * Manufactures list items which represent SBC results.
- *
- * @author dswitkin@google.com (Daniel Switkin)
- */
-public final class SearchBookContentsAdapter extends ArrayAdapter<SearchBookContentsResult> {
- public SearchBookContentsAdapter(Context context, List<SearchBookContentsResult> items) {
- super(context, R.layout.search_book_contents_list_item, 0, items);
- }
-
- @Override
- public View getView(int position, View view, ViewGroup viewGroup) {
- SearchBookContentsListItem listItem;
-
- if (view == null) {
- LayoutInflater factory = LayoutInflater.from(getContext());
- listItem = (SearchBookContentsListItem) factory.inflate(
- R.layout.search_book_contents_list_item, viewGroup, false);
- } else {
- if (view instanceof SearchBookContentsListItem) {
- listItem = (SearchBookContentsListItem) view;
- } else {
- return view;
- }
- }
-
- SearchBookContentsResult result = getItem(position);
- listItem.set(result);
- return listItem;
- }
-}
+++ /dev/null
-/*
- * Copyright (C) 2008 ZXing authors
- *
- * 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.google.zxing.client.android;
-
-import android.content.Context;
-import android.graphics.Typeface;
-import android.text.SpannableString;
-import android.text.Spannable;
-import android.text.style.StyleSpan;
-import android.util.AttributeSet;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-/**
- * A list item which displays the page number and snippet of this search result.
- *
- * @author dswitkin@google.com (Daniel Switkin)
- */
-public final class SearchBookContentsListItem extends LinearLayout {
- private TextView pageNumberView;
- private TextView snippetView;
-
- SearchBookContentsListItem(Context context) {
- super(context);
- }
-
- public SearchBookContentsListItem(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- @Override
- protected void onFinishInflate() {
- super.onFinishInflate();
- pageNumberView = (TextView) findViewById(R.id.page_number_view);
- snippetView = (TextView) findViewById(R.id.snippet_view);
- }
-
- public void set(SearchBookContentsResult result) {
- pageNumberView.setText(result.getPageNumber());
- String snippet = result.getSnippet();
- if (snippet.length() > 0) {
- if (result.getValidSnippet()) {
- String lowerQuery = SearchBookContentsResult.getQuery().toLowerCase();
- String lowerSnippet = snippet.toLowerCase();
- Spannable styledSnippet = new SpannableString(snippet);
- StyleSpan boldSpan = new StyleSpan(Typeface.BOLD);
- int queryLength = lowerQuery.length();
- int offset = 0;
- while (true) {
- int pos = lowerSnippet.indexOf(lowerQuery, offset);
- if (pos < 0) {
- break;
- }
- styledSnippet.setSpan(boldSpan, pos, pos + queryLength, 0);
- offset = pos + queryLength;
- }
- snippetView.setText(styledSnippet);
- } else {
- // This may be an error message, so don't try to bold the query terms within it
- snippetView.setText(snippet);
- }
- } else {
- snippetView.setText("");
- }
- }
-}
+++ /dev/null
-/*
- * Copyright (C) 2008 ZXing authors
- *
- * 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.google.zxing.client.android;
-
-/**
- * The underlying data for a SBC result.
- *
- * @author dswitkin@google.com (Daniel Switkin)
- */
-public final class SearchBookContentsResult {
- private static String query;
-
- private final String pageNumber;
- private final String snippet;
- private final boolean validSnippet;
-
- public SearchBookContentsResult(String pageNumber, String snippet, boolean validSnippet) {
- this.pageNumber = pageNumber;
- this.snippet = snippet;
- this.validSnippet = validSnippet;
- }
-
- public static void setQuery(String query) {
- SearchBookContentsResult.query = query;
- }
-
- public String getPageNumber() {
- return pageNumber;
- }
-
- public String getSnippet() {
- return snippet;
- }
-
- public boolean getValidSnippet() {
- return validSnippet;
- }
-
- public static String getQuery() {
- return query;
- }
-}
+++ /dev/null
-/*
- * Copyright (C) 2008 ZXing authors
- *
- * 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.google.zxing.client.android;
-
-import android.app.Activity;
-import android.content.ContentResolver;
-import android.content.Intent;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.Bundle;
-import android.provider.Browser;
-import android.provider.Contacts;
-import android.provider.BaseColumns;
-import android.text.ClipboardManager;
-import android.view.View;
-import android.widget.Button;
-
-/**
- * Barcode Scanner can share data like contacts and bookmarks by displaying a QR Code on screen,
- * such that another user can scan the barcode with their phone.
- *
- * @author dswitkin@google.com (Daniel Switkin)
- */
-public final class ShareActivity extends Activity {
- private static final int PICK_BOOKMARK = 0;
- private static final int PICK_CONTACT = 1;
-
- //private static final int METHODS_ID_COLUMN = 0;
- private static final int METHODS_KIND_COLUMN = 1;
- private static final int METHODS_DATA_COLUMN = 2;
-
- private static final String[] METHODS_PROJECTION = {
- BaseColumns._ID, // 0
- Contacts.ContactMethodsColumns.KIND, // 1
- Contacts.ContactMethodsColumns.DATA, // 2
- };
-
- private static final int PHONES_NUMBER_COLUMN = 1;
-
- private static final String[] PHONES_PROJECTION = {
- BaseColumns._ID, // 0
- Contacts.PhonesColumns.NUMBER // 1
- };
-
- private Button clipboardButton;
-
- private final Button.OnClickListener contactListener = new Button.OnClickListener() {
- public void onClick(View v) {
- startActivityForResult(new Intent(Intent.ACTION_PICK, Contacts.People.CONTENT_URI),
- PICK_CONTACT);
- }
- };
-
- private final Button.OnClickListener bookmarkListener = new Button.OnClickListener() {
- public void onClick(View v) {
- Intent intent = new Intent(Intent.ACTION_PICK);
- intent.setClassName(ShareActivity.this, BookmarkPickerActivity.class.getName());
- startActivityForResult(intent, PICK_BOOKMARK);
- }
- };
-
- private final Button.OnClickListener clipboardListener = new Button.OnClickListener() {
- public void onClick(View v) {
- ClipboardManager clipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
- // Should always be true, because we grey out the clipboard button in onResume() if it's empty
- if (clipboard.hasText()) {
- Intent intent = new Intent(Intents.Encode.ACTION);
- intent.putExtra(Intents.Encode.TYPE, Contents.Type.TEXT);
- intent.putExtra(Intents.Encode.DATA, clipboard.getText());
- intent.putExtra(Intents.Encode.FORMAT, Contents.Format.QR_CODE);
- startActivity(intent);
- }
- }
- };
-
- @Override
- public void onCreate(Bundle icicle) {
- super.onCreate(icicle);
- setContentView(R.layout.share);
-
- Button mContactButton = (Button) findViewById(R.id.contact_button);
- mContactButton.setOnClickListener(contactListener);
- Button mBookmarkButton = (Button) findViewById(R.id.bookmark_button);
- mBookmarkButton.setOnClickListener(bookmarkListener);
- clipboardButton = (Button) findViewById(R.id.clipboard_button);
- clipboardButton.setOnClickListener(clipboardListener);
- }
-
- @Override
- protected void onResume() {
- super.onResume();
-
- ClipboardManager clipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
- if (clipboard.hasText()) {
- clipboardButton.setEnabled(true);
- clipboardButton.setText(R.string.button_share_clipboard);
- } else {
- clipboardButton.setEnabled(false);
- clipboardButton.setText(R.string.button_clipboard_empty);
- }
- }
-
- @Override
- public void onActivityResult(int requestCode, int resultCode, Intent intent) {
- if (resultCode == RESULT_OK) {
- switch (requestCode) {
- case PICK_BOOKMARK:
- showTextAsBarcode(intent.getStringExtra(Browser.BookmarkColumns.URL));
- break;
- case PICK_CONTACT:
- // Data field is content://contacts/people/984
- showContactAsBarcode(intent.getData());
- break;
- }
- }
- }
-
- private void showTextAsBarcode(String text) {
- Intent intent = new Intent(Intents.Encode.ACTION);
- intent.putExtra(Intents.Encode.TYPE, Contents.Type.TEXT);
- intent.putExtra(Intents.Encode.DATA, text);
- intent.putExtra(Intents.Encode.FORMAT, Contents.Format.QR_CODE);
- startActivity(intent);
- }
-
- /**
- * Takes a contact Uri and does the necessary database lookups to retrieve that person's info,
- * then sends an Encode intent to render it as a QR Code.
- *
- * @param contactUri A Uri of the form content://contacts/people/17
- */
- private void showContactAsBarcode(Uri contactUri) {
- ContentResolver resolver = getContentResolver();
- Cursor contactCursor = resolver.query(contactUri, null, null, null, null);
- Bundle bundle = new Bundle();
- if (contactCursor != null && contactCursor.moveToFirst()) {
- int nameColumn = contactCursor.getColumnIndex(Contacts.PeopleColumns.NAME);
- String name = contactCursor.getString(nameColumn);
-
- // Don't require a name to be present, this contact might be just a phone number.
- if (name != null && name.length() > 0) {
- bundle.putString(Contacts.Intents.Insert.NAME, massageContactData(name));
- }
- contactCursor.close();
-
- Uri phonesUri = Uri.withAppendedPath(contactUri, Contacts.People.Phones.CONTENT_DIRECTORY);
- Cursor phonesCursor = resolver.query(phonesUri, PHONES_PROJECTION, null, null, null);
- if (phonesCursor != null) {
- int foundPhone = 0;
- while (phonesCursor.moveToNext()) {
- String number = phonesCursor.getString(PHONES_NUMBER_COLUMN);
- if (foundPhone < Contents.PHONE_KEYS.length) {
- bundle.putString(Contents.PHONE_KEYS[foundPhone], massageContactData(number));
- foundPhone++;
- }
- }
- phonesCursor.close();
- }
-
- Uri methodsUri = Uri.withAppendedPath(contactUri,
- Contacts.People.ContactMethods.CONTENT_DIRECTORY);
- Cursor methodsCursor = resolver.query(methodsUri, METHODS_PROJECTION, null, null, null);
- if (methodsCursor != null) {
- int foundEmail = 0;
- boolean foundPostal = false;
- while (methodsCursor.moveToNext()) {
- int kind = methodsCursor.getInt(METHODS_KIND_COLUMN);
- String data = methodsCursor.getString(METHODS_DATA_COLUMN);
- switch (kind) {
- case Contacts.KIND_EMAIL:
- if (foundEmail < Contents.EMAIL_KEYS.length) {
- bundle.putString(Contents.EMAIL_KEYS[foundEmail], massageContactData(data));
- foundEmail++;
- }
- break;
- case Contacts.KIND_POSTAL:
- if (!foundPostal) {
- bundle.putString(Contacts.Intents.Insert.POSTAL, massageContactData(data));
- foundPostal = true;
- }
- break;
- }
- }
- methodsCursor.close();
- }
-
- Intent intent = new Intent(Intents.Encode.ACTION);
- intent.putExtra(Intents.Encode.TYPE, Contents.Type.CONTACT);
- intent.putExtra(Intents.Encode.DATA, bundle);
- intent.putExtra(Intents.Encode.FORMAT, Contents.Format.QR_CODE);
-
- startActivity(intent);
- }
- }
-
- private static String massageContactData(String data) {
- // For now -- make sure we don't put newlines in shared contact data. It messes up
- // any known encoding of contact data. Replace with space.
- if (data.indexOf('\n') >= 0) {
- data = data.replace("\n", " ");
- }
- if (data.indexOf('\r') >= 0) {
- data = data.replace("\r", " ");
- }
- return data;
- }
-}
--- /dev/null
+/*
+ * Copyright (C) 2008 ZXing authors
+ *
+ * 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.google.zxing.client.android.book;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.content.res.Configuration;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.webkit.CookieManager;
+import android.webkit.CookieSyncManager;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.ListView;
+import android.widget.TextView;
+import org.apache.http.Header;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpHead;
+import org.apache.http.client.methods.HttpUriRequest;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Pattern;
+
+import com.google.zxing.client.android.R;
+import com.google.zxing.client.android.Intents;
+import com.google.zxing.client.android.AndroidHttpClient;
+
+/**
+ * Uses Google Book Search to find a word or phrase in the requested book.
+ *
+ * @author dswitkin@google.com (Daniel Switkin)
+ */
+public final class SearchBookContentsActivity extends Activity {
+ private static final String TAG = "SearchBookContents";
+ private static final String USER_AGENT = "ZXing (Android)";
+
+ private NetworkThread networkThread;
+ private String isbn;
+ private EditText queryTextView;
+ private Button queryButton;
+ private ListView resultListView;
+ private TextView headerView;
+
+ private final Handler handler = new Handler() {
+ @Override
+ public void handleMessage(Message message) {
+ switch (message.what) {
+ case R.id.search_book_contents_succeeded:
+ handleSearchResults((JSONObject) message.obj);
+ resetForNewQuery();
+ break;
+ case R.id.search_book_contents_failed:
+ resetForNewQuery();
+ headerView.setText(R.string.msg_sbc_failed);
+ break;
+ }
+ }
+ };
+
+ private final Button.OnClickListener buttonListener = new Button.OnClickListener() {
+ public void onClick(View view) {
+ launchSearch();
+ }
+ };
+
+ private final View.OnKeyListener keyListener = new View.OnKeyListener() {
+ public boolean onKey(View view, int keyCode, KeyEvent event) {
+ if (keyCode == KeyEvent.KEYCODE_ENTER) {
+ launchSearch();
+ return true;
+ }
+ return false;
+ }
+ };
+ private static final Pattern TAG_PATTERN = Pattern.compile("\\<.*?\\>");
+ private static final Pattern LT_ENTITY_PATTERN = Pattern.compile("<");
+ private static final Pattern GT_ENTITY_PATTERN = Pattern.compile(">");
+ private static final Pattern QUOTE_ENTITY_PATTERN = Pattern.compile("'");
+ private static final Pattern QUOT_ENTITY_PATTERN = Pattern.compile(""");
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ // Make sure that expired cookies are removed on launch.
+ CookieSyncManager.createInstance(this);
+ CookieManager.getInstance().removeExpiredCookie();
+
+ Intent intent = getIntent();
+ if (intent == null || (!intent.getAction().equals(Intents.SearchBookContents.ACTION))) {
+ finish();
+ return;
+ }
+
+ isbn = intent.getStringExtra(Intents.SearchBookContents.ISBN);
+ setTitle(getString(R.string.sbc_name) + ": ISBN " + isbn);
+
+ setContentView(R.layout.search_book_contents);
+ queryTextView = (EditText) findViewById(R.id.query_text_view);
+
+ String initialQuery = intent.getStringExtra(Intents.SearchBookContents.QUERY);
+ if (initialQuery != null && initialQuery.length() > 0) {
+ // Populate the search box but don't trigger the search
+ queryTextView.setText(initialQuery);
+ }
+ queryTextView.setOnKeyListener(keyListener);
+
+ queryButton = (Button) findViewById(R.id.query_button);
+ queryButton.setOnClickListener(buttonListener);
+
+ resultListView = (ListView) findViewById(R.id.result_list_view);
+ LayoutInflater factory = LayoutInflater.from(this);
+ headerView = (TextView) factory.inflate(R.layout.search_book_contents_header,
+ resultListView, false);
+ resultListView.addHeaderView(headerView);
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ queryTextView.selectAll();
+ }
+
+ @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 void resetForNewQuery() {
+ networkThread = null;
+ queryTextView.setEnabled(true);
+ queryTextView.selectAll();
+ queryButton.setEnabled(true);
+ }
+
+ private void launchSearch() {
+ if (networkThread == null) {
+ String query = queryTextView.getText().toString();
+ if (query != null && query.length() > 0) {
+ networkThread = new NetworkThread(isbn, query, handler);
+ networkThread.start();
+ headerView.setText(R.string.msg_sbc_searching_book);
+ resultListView.setAdapter(null);
+ queryTextView.setEnabled(false);
+ queryButton.setEnabled(false);
+ }
+ }
+ }
+
+ // Currently there is no way to distinguish between a query which had no results and a book
+ // which is not searchable - both return zero results.
+ private void handleSearchResults(JSONObject json) {
+ try {
+ int count = json.getInt("number_of_results");
+ headerView.setText("Found " + (count == 1 ? "1 result" : count + " results"));
+ if (count > 0) {
+ JSONArray results = json.getJSONArray("search_results");
+ SearchBookContentsResult.setQuery(queryTextView.getText().toString());
+ List<SearchBookContentsResult> items = new ArrayList<SearchBookContentsResult>(count);
+ for (int x = 0; x < count; x++) {
+ items.add(parseResult(results.getJSONObject(x)));
+ }
+ resultListView.setAdapter(new SearchBookContentsAdapter(this, items));
+ } else {
+ String searchable = json.optString("searchable");
+ if ("false".equals(searchable)) {
+ headerView.setText(R.string.msg_sbc_book_not_searchable);
+ }
+ resultListView.setAdapter(null);
+ }
+ } catch (JSONException e) {
+ Log.e(TAG, e.toString());
+ resultListView.setAdapter(null);
+ headerView.setText(R.string.msg_sbc_failed);
+ }
+ }
+
+ // Available fields: page_number, page_id, page_url, snippet_text
+ private SearchBookContentsResult parseResult(JSONObject json) {
+ try {
+ String pageNumber = json.getString("page_number");
+ if (pageNumber.length() > 0) {
+ pageNumber = getString(R.string.msg_sbc_page) + ' ' + pageNumber;
+ } else {
+ // This can happen for text on the jacket, and possibly other reasons.
+ pageNumber = getString(R.string.msg_sbc_unknown_page);
+ }
+
+ // Remove all HTML tags and encoded characters. Ideally the server would do this.
+ String snippet = json.optString("snippet_text");
+ boolean valid = true;
+ if (snippet.length() > 0) {
+ snippet = TAG_PATTERN.matcher(snippet).replaceAll("");
+ snippet = LT_ENTITY_PATTERN.matcher(snippet).replaceAll("<");
+ snippet = GT_ENTITY_PATTERN.matcher(snippet).replaceAll(">");
+ snippet = QUOTE_ENTITY_PATTERN.matcher(snippet).replaceAll("'");
+ snippet = QUOT_ENTITY_PATTERN.matcher(snippet).replaceAll("\"");
+ } else {
+ snippet = '(' + getString(R.string.msg_sbc_snippet_unavailable) + ')';
+ valid = false;
+ }
+ return new SearchBookContentsResult(pageNumber, snippet, valid);
+ } catch (JSONException e) {
+ // Never seen in the wild, just being complete.
+ return new SearchBookContentsResult(getString(R.string.msg_sbc_no_page_returned), "", false);
+ }
+ }
+
+ private static final class NetworkThread extends Thread {
+ private final String isbn;
+ private final String query;
+ private final Handler handler;
+
+ NetworkThread(String isbn, String query, Handler handler) {
+ this.isbn = isbn;
+ this.query = query;
+ this.handler = handler;
+ }
+
+ @Override
+ public void run() {
+ AndroidHttpClient client = null;
+ try {
+ // These return a JSON result which describes if and where the query was found. This API may
+ // break or disappear at any time in the future. Since this is an API call rather than a
+ // website, we don't use LocaleManager to change the TLD.
+ URI uri = new URI("http", null, "www.google.com", -1, "/books", "vid=isbn" + isbn +
+ "&jscmd=SearchWithinVolume2&q=" + query, null);
+ HttpUriRequest get = new HttpGet(uri);
+ get.setHeader("cookie", getCookie(uri.toString()));
+ client = AndroidHttpClient.newInstance(USER_AGENT);
+ HttpResponse response = client.execute(get);
+ if (response.getStatusLine().getStatusCode() == 200) {
+ HttpEntity entity = response.getEntity();
+ ByteArrayOutputStream jsonHolder = new ByteArrayOutputStream();
+ entity.writeTo(jsonHolder);
+ jsonHolder.flush();
+ JSONObject json = new JSONObject(jsonHolder.toString(getEncoding(entity)));
+ jsonHolder.close();
+
+ Message message = Message.obtain(handler, R.id.search_book_contents_succeeded);
+ message.obj = json;
+ message.sendToTarget();
+ } else {
+ Log.e(TAG, "HTTP returned " + response.getStatusLine().getStatusCode() + " for " + uri);
+ Message message = Message.obtain(handler, R.id.search_book_contents_failed);
+ message.sendToTarget();
+ }
+ } catch (Exception e) {
+ Log.e(TAG, e.toString());
+ Message message = Message.obtain(handler, R.id.search_book_contents_failed);
+ message.sendToTarget();
+ } finally {
+ if (client != null) {
+ client.close();
+ }
+ }
+ }
+
+ // Book Search requires a cookie to work, which we store persistently. If the cookie does
+ // not exist, this could be the first search or it has expired. Either way, do a quick HEAD
+ // request to fetch it, save it via the CookieSyncManager to flash, then return it.
+ private static String getCookie(String url) {
+ String cookie = CookieManager.getInstance().getCookie(url);
+ if (cookie == null || cookie.length() == 0) {
+ Log.v(TAG, "Book Search cookie was missing or expired");
+ HttpUriRequest head = new HttpHead(url);
+ AndroidHttpClient client = AndroidHttpClient.newInstance(USER_AGENT);
+ try {
+ HttpResponse response = client.execute(head);
+ if (response.getStatusLine().getStatusCode() == 200) {
+ Header[] cookies = response.getHeaders("set-cookie");
+ for (Header theCookie : cookies) {
+ CookieManager.getInstance().setCookie(url, theCookie.getValue());
+ }
+ CookieSyncManager.getInstance().sync();
+ cookie = CookieManager.getInstance().getCookie(url);
+ }
+ } catch (IOException e) {
+ Log.e(TAG, e.toString());
+ }
+ client.close();
+ }
+ return cookie;
+ }
+
+ private static String getEncoding(HttpEntity entity) {
+ // FIXME: The server is returning ISO-8859-1 but the content is actually windows-1252.
+ // Once Jeff fixes the HTTP response, remove this hardcoded value and go back to getting
+ // the encoding dynamically.
+ return "windows-1252";
+// HeaderElement[] elements = entity.getContentType().getElements();
+// if (elements != null && elements.length > 0) {
+// String encoding = elements[0].getParameterByName("charset").getValue();
+// if (encoding != null && encoding.length() > 0) {
+// return encoding;
+// }
+// }
+// return "UTF-8";
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright (C) 2008 ZXing authors
+ *
+ * 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.google.zxing.client.android.book;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+
+import java.util.List;
+
+import com.google.zxing.client.android.R;
+
+/**
+ * Manufactures list items which represent SBC results.
+ *
+ * @author dswitkin@google.com (Daniel Switkin)
+ */
+final class SearchBookContentsAdapter extends ArrayAdapter<SearchBookContentsResult> {
+ public SearchBookContentsAdapter(Context context, List<SearchBookContentsResult> items) {
+ super(context, R.layout.search_book_contents_list_item, 0, items);
+ }
+
+ @Override
+ public View getView(int position, View view, ViewGroup viewGroup) {
+ SearchBookContentsListItem listItem;
+
+ if (view == null) {
+ LayoutInflater factory = LayoutInflater.from(getContext());
+ listItem = (SearchBookContentsListItem) factory.inflate(
+ R.layout.search_book_contents_list_item, viewGroup, false);
+ } else {
+ if (view instanceof SearchBookContentsListItem) {
+ listItem = (SearchBookContentsListItem) view;
+ } else {
+ return view;
+ }
+ }
+
+ SearchBookContentsResult result = getItem(position);
+ listItem.set(result);
+ return listItem;
+ }
+}
--- /dev/null
+/*
+ * Copyright (C) 2008 ZXing authors
+ *
+ * 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.google.zxing.client.android.book;
+
+import android.content.Context;
+import android.graphics.Typeface;
+import android.text.SpannableString;
+import android.text.Spannable;
+import android.text.style.StyleSpan;
+import android.util.AttributeSet;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+import com.google.zxing.client.android.R;
+
+/**
+ * A list item which displays the page number and snippet of this search result.
+ *
+ * @author dswitkin@google.com (Daniel Switkin)
+ */
+final class SearchBookContentsListItem extends LinearLayout {
+ private TextView pageNumberView;
+ private TextView snippetView;
+
+ SearchBookContentsListItem(Context context) {
+ super(context);
+ }
+
+ public SearchBookContentsListItem(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ pageNumberView = (TextView) findViewById(R.id.page_number_view);
+ snippetView = (TextView) findViewById(R.id.snippet_view);
+ }
+
+ public void set(SearchBookContentsResult result) {
+ pageNumberView.setText(result.getPageNumber());
+ String snippet = result.getSnippet();
+ if (snippet.length() > 0) {
+ if (result.getValidSnippet()) {
+ String lowerQuery = SearchBookContentsResult.getQuery().toLowerCase();
+ String lowerSnippet = snippet.toLowerCase();
+ Spannable styledSnippet = new SpannableString(snippet);
+ StyleSpan boldSpan = new StyleSpan(Typeface.BOLD);
+ int queryLength = lowerQuery.length();
+ int offset = 0;
+ while (true) {
+ int pos = lowerSnippet.indexOf(lowerQuery, offset);
+ if (pos < 0) {
+ break;
+ }
+ styledSnippet.setSpan(boldSpan, pos, pos + queryLength, 0);
+ offset = pos + queryLength;
+ }
+ snippetView.setText(styledSnippet);
+ } else {
+ // This may be an error message, so don't try to bold the query terms within it
+ snippetView.setText(snippet);
+ }
+ } else {
+ snippetView.setText("");
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright (C) 2008 ZXing authors
+ *
+ * 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.google.zxing.client.android.book;
+
+/**
+ * The underlying data for a SBC result.
+ *
+ * @author dswitkin@google.com (Daniel Switkin)
+ */
+final class SearchBookContentsResult {
+ private static String query;
+
+ private final String pageNumber;
+ private final String snippet;
+ private final boolean validSnippet;
+
+ SearchBookContentsResult(String pageNumber, String snippet, boolean validSnippet) {
+ this.pageNumber = pageNumber;
+ this.snippet = snippet;
+ this.validSnippet = validSnippet;
+ }
+
+ public static void setQuery(String query) {
+ SearchBookContentsResult.query = query;
+ }
+
+ public String getPageNumber() {
+ return pageNumber;
+ }
+
+ public String getSnippet() {
+ return snippet;
+ }
+
+ public boolean getValidSnippet() {
+ return validSnippet;
+ }
+
+ public static String getQuery() {
+ return query;
+ }
+}
--- /dev/null
+/*
+ * Copyright (C) 2008 ZXing authors
+ *
+ * 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.google.zxing.client.android.encode;
+
+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.View;
+import android.view.ViewTreeObserver.OnGlobalLayoutListener;
+import android.widget.ImageView;
+import android.widget.TextView;
+import com.google.zxing.client.android.R;
+import com.google.zxing.client.android.Intents;
+
+/**
+ * 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.
+ *
+ * @author dswitkin@google.com (Daniel Switkin)
+ */
+final class EncodeActivity extends Activity {
+ private QRCodeEncoder qrCodeEncoder;
+ private ProgressDialog progressDialog;
+ private boolean firstLayout;
+
+ /**
+ * This needs to be delayed until after the first layout so that the view dimensions will be
+ * available.
+ */
+ private final OnGlobalLayoutListener layoutListener = new OnGlobalLayoutListener() {
+ public void onGlobalLayout() {
+ if (firstLayout) {
+ View layout = findViewById(R.id.encode_view);
+ int width = layout.getWidth();
+ int height = layout.getHeight();
+ int smallerDimension = width < height ? width : height;
+ smallerDimension = smallerDimension * 7 / 8;
+
+ Intent intent = getIntent();
+ try {
+ qrCodeEncoder = new QRCodeEncoder(EncodeActivity.this, intent);
+ setTitle(getString(R.string.app_name) + " - " + qrCodeEncoder.getTitle());
+ qrCodeEncoder.requestBarcode(handler, smallerDimension);
+ progressDialog = ProgressDialog.show(EncodeActivity.this, null,
+ getString(R.string.msg_encode_in_progress), true, true, cancelListener);
+ } catch (IllegalArgumentException e) {
+ showErrorMessage(R.string.msg_encode_contents_failed);
+ }
+ firstLayout = false;
+ }
+ }
+ };
+
+ private final Handler handler = new Handler() {
+ @Override
+ public void handleMessage(Message message) {
+ switch (message.what) {
+ case R.id.encode_succeeded:
+ progressDialog.dismiss();
+ progressDialog = 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(qrCodeEncoder.getDisplayContents());
+ qrCodeEncoder = null;
+ break;
+ case R.id.encode_failed:
+ showErrorMessage(R.string.msg_encode_barcode_failed);
+ qrCodeEncoder = null;
+ break;
+ }
+ }
+ };
+
+ private final OnClickListener clickListener = new OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ finish();
+ }
+ };
+
+ private final OnCancelListener cancelListener = new OnCancelListener() {
+ public void onCancel(DialogInterface dialog) {
+ finish();
+ }
+ };
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ Intent intent = getIntent();
+ if (intent != null && (intent.getAction().equals(Intents.Encode.ACTION))) {
+ setContentView(R.layout.encode);
+ } else {
+ finish();
+ }
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+
+ View layout = findViewById(R.id.encode_view);
+ layout.getViewTreeObserver().addOnGlobalLayoutListener(layoutListener);
+ firstLayout = true;
+ }
+
+ private void showErrorMessage(int message) {
+ if (progressDialog != null) {
+ progressDialog.dismiss();
+ progressDialog = null;
+ }
+ AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ builder.setMessage(message);
+ builder.setPositiveButton(R.string.button_ok, clickListener);
+ builder.show();
+ }
+}
--- /dev/null
+/*
+ * Copyright (C) 2008 ZXing authors
+ *
+ * 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.google.zxing.client.android.encode;
+
+import com.google.zxing.BarcodeFormat;
+import com.google.zxing.MultiFormatWriter;
+import com.google.zxing.WriterException;
+import com.google.zxing.client.android.Intents;
+import com.google.zxing.client.android.Contents;
+import com.google.zxing.client.android.R;
+import com.google.zxing.common.ByteMatrix;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.provider.Contacts;
+import android.telephony.PhoneNumberUtils;
+import android.util.Log;
+
+/**
+ * This class does the work of decoding the user's request and extracting all the data
+ * to be encoded in a QR Code.
+ *
+ * @author dswitkin@google.com (Daniel Switkin)
+ */
+final class QRCodeEncoder {
+ private final Activity activity;
+ private String contents;
+ private String displayContents;
+ private String title;
+ private BarcodeFormat format;
+
+ public QRCodeEncoder(Activity activity, Intent intent) {
+ this.activity = activity;
+ if (!encodeContents(intent)) {
+ throw new IllegalArgumentException("No valid data to encode.");
+ }
+ }
+
+ public void requestBarcode(Handler handler, int pixelResolution) {
+ Thread encodeThread = new EncodeThread(contents, handler, pixelResolution,
+ format);
+ encodeThread.start();
+ }
+
+ public String getContents() {
+ return contents;
+ }
+
+ public String getDisplayContents() {
+ return displayContents;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public String getFormat() {
+ return format.toString();
+ }
+
+ // It would be nice if the string encoding lived in the core ZXing library,
+ // but we use platform specific code like PhoneNumberUtils, so it can't.
+ private boolean encodeContents(Intent intent) {
+ if (intent == null) {
+ return false;
+ }
+
+ // default to QR_CODE if no format given
+ String format = intent.getStringExtra(Intents.Encode.FORMAT);
+ if (format == null || format.length() == 0 ||
+ format.equals(Contents.Format.QR_CODE)) {
+ String type = intent.getStringExtra(Intents.Encode.TYPE);
+ if (type == null || type.length() == 0) {
+ return false;
+ }
+ this.format = BarcodeFormat.QR_CODE;
+ encodeQRCodeContents(intent, type);
+ } else {
+ String data = intent.getStringExtra(Intents.Encode.DATA);
+ if (data != null && data.length() != 0) {
+ contents = data;
+ displayContents = data;
+ title = activity.getString(R.string.contents_text);
+ if (format.equals(Contents.Format.CODE_128)) {
+ this.format = BarcodeFormat.CODE_128;
+ } else if (format.equals(Contents.Format.CODE_39)) {
+ this.format = BarcodeFormat.CODE_39;
+ } else if (format.equals(Contents.Format.EAN_8)) {
+ this.format = BarcodeFormat.EAN_8;
+ } else if (format.equals(Contents.Format.EAN_13)) {
+ this.format = BarcodeFormat.EAN_13;
+ } else if (format.equals(Contents.Format.UPC_A)) {
+ this.format = BarcodeFormat.UPC_A;
+ } else if (format.equals(Contents.Format.UPC_E)) {
+ this.format = BarcodeFormat.UPC_E;
+ }
+ }
+ }
+ return contents != null && contents.length() > 0;
+ }
+
+ private void encodeQRCodeContents(Intent intent, String type) {
+ if (type.equals(Contents.Type.TEXT)) {
+ String data = intent.getStringExtra(Intents.Encode.DATA);
+ if (data != null && data.length() > 0) {
+ contents = data;
+ displayContents = data;
+ title = activity.getString(R.string.contents_text);
+ }
+ } else if (type.equals(Contents.Type.EMAIL)) {
+ String data = intent.getStringExtra(Intents.Encode.DATA);
+ if (data != null && data.length() > 0) {
+ contents = "mailto:" + data;
+ displayContents = data;
+ title = activity.getString(R.string.contents_email);
+ }
+ } else if (type.equals(Contents.Type.PHONE)) {
+ String data = intent.getStringExtra(Intents.Encode.DATA);
+ if (data != null && data.length() > 0) {
+ contents = "tel:" + data;
+ displayContents = PhoneNumberUtils.formatNumber(data);
+ title = activity.getString(R.string.contents_phone);
+ }
+ } else if (type.equals(Contents.Type.SMS)) {
+ String data = intent.getStringExtra(Intents.Encode.DATA);
+ if (data != null && data.length() > 0) {
+ contents = "sms:" + data;
+ displayContents = PhoneNumberUtils.formatNumber(data);
+ title = activity.getString(R.string.contents_sms);
+ }
+ } else if (type.equals(Contents.Type.CONTACT)) {
+ Bundle bundle = intent.getBundleExtra(Intents.Encode.DATA);
+ if (bundle != null) {
+ StringBuilder newContents = new StringBuilder();
+ StringBuilder newDisplayContents = new StringBuilder();
+ newContents.append("MECARD:");
+ String name = bundle.getString(Contacts.Intents.Insert.NAME);
+ if (name != null && name.length() > 0) {
+ newContents.append("N:").append(name).append(';');
+ newDisplayContents.append(name);
+ }
+ String address = bundle.getString(Contacts.Intents.Insert.POSTAL);
+ if (address != null && address.length() > 0) {
+ newContents.append("ADR:").append(address).append(';');
+ newDisplayContents.append('\n').append(address);
+ }
+ for (int x = 0; x < Contents.PHONE_KEYS.length; x++) {
+ String phone = bundle.getString(Contents.PHONE_KEYS[x]);
+ if (phone != null && phone.length() > 0) {
+ newContents.append("TEL:").append(phone).append(';');
+ newDisplayContents.append('\n').append(PhoneNumberUtils.formatNumber(phone));
+ }
+ }
+ for (int x = 0; x < Contents.EMAIL_KEYS.length; x++) {
+ String email = bundle.getString(Contents.EMAIL_KEYS[x]);
+ if (email != null && email.length() > 0) {
+ newContents.append("EMAIL:").append(email).append(';');
+ newDisplayContents.append('\n').append(email);
+ }
+ }
+ // Make sure we've encoded at least one field.
+ if (newDisplayContents.length() > 0) {
+ newContents.append(';');
+ contents = newContents.toString();
+ displayContents = newDisplayContents.toString();
+ title = activity.getString(R.string.contents_contact);
+ } else {
+ contents = null;
+ displayContents = null;
+ }
+ }
+ } else if (type.equals(Contents.Type.LOCATION)) {
+ Bundle bundle = intent.getBundleExtra(Intents.Encode.DATA);
+ if (bundle != null) {
+ // These must use Bundle.getFloat(), not getDouble(), it's part of the API.
+ 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) {
+ contents = "geo:" + latitude + ',' + longitude;
+ displayContents = latitude + "," + longitude;
+ title = activity.getString(R.string.contents_location);
+ }
+ }
+ }
+ }
+
+ private static final class EncodeThread extends Thread {
+ private static final String TAG = "EncodeThread";
+
+ private final String contents;
+ private final Handler handler;
+ private final int pixelResolution;
+ private final BarcodeFormat format;
+
+ EncodeThread(String contents, Handler handler, int pixelResolution,
+ BarcodeFormat format) {
+ this.contents = contents;
+ this.handler = handler;
+ this.pixelResolution = pixelResolution;
+ this.format = format;
+ }
+
+ @Override
+ public void run() {
+ try {
+ ByteMatrix result = new MultiFormatWriter().encode(contents, format,
+ pixelResolution, pixelResolution);
+ int width = result.getWidth();
+ int height = result.getHeight();
+ byte[][] array = result.getArray();
+ int[] pixels = new int[width * height];
+ for (int y = 0; y < height; y++) {
+ for (int x = 0; x < width; x++) {
+ int grey = array[y][x] & 0xff;
+ // pixels[y * width + x] = (0xff << 24) | (grey << 16) | (grey << 8) | grey;
+ pixels[y * width + x] = 0xff000000 | (0x00010101 * grey);
+ }
+ }
+
+ Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+ bitmap.setPixels(pixels, 0, width, 0, 0, width, height);
+ Message message = Message.obtain(handler, R.id.encode_succeeded);
+ message.obj = bitmap;
+ message.sendToTarget();
+ } catch (WriterException e) {
+ Log.e(TAG, e.toString());
+ Message message = Message.obtain(handler, R.id.encode_failed);
+ message.sendToTarget();
+ } catch (IllegalArgumentException e) {
+ Log.e(TAG, e.toString());
+ Message message = Message.obtain(handler, R.id.encode_failed);
+ message.sendToTarget();
+ }
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright (C) 2009 ZXing authors
+ *
+ * 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.google.zxing.client.android.history;
+
+import android.database.sqlite.SQLiteOpenHelper;
+import android.database.sqlite.SQLiteDatabase;
+import android.content.Context;
+
+/**
+ * @author Sean Owen
+ */
+final class DBHelper extends SQLiteOpenHelper {
+
+ private static final int DB_VERSION = 1;
+ private static final String DB_NAME = "barcode_scanner_history.db";
+ static final String TABLE_NAME = "history";
+ private static final String ID_COL = "id";
+ static final String TEXT_COL = "text";
+ static final String TIMESTAMP_COL = "timestamp";
+
+ DBHelper(Context context) {
+ super(context, DB_NAME, null, DB_VERSION);
+ }
+
+ @Override
+ public void onCreate(SQLiteDatabase sqLiteDatabase) {
+ sqLiteDatabase.execSQL(
+ "CREATE TABLE " + TABLE_NAME + " (" +
+ ID_COL + " INTEGER PRIMARY KEY, " +
+ TEXT_COL + " TEXT, " +
+ TIMESTAMP_COL + " INTEGER" +
+ ");");
+ }
+
+ @Override
+ public void onUpgrade(SQLiteDatabase sqLiteDatabase, int oldVersion, int newVersion) {
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2009 ZXing authors
+ *
+ * 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.google.zxing.client.android.history;
+
+import android.app.AlertDialog;
+import android.content.ContentValues;
+import android.content.DialogInterface;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+import android.database.Cursor;
+import android.os.Message;
+
+import java.util.List;
+import java.util.ArrayList;
+
+import com.google.zxing.client.android.R;
+import com.google.zxing.client.android.CaptureActivity;
+import com.google.zxing.Result;
+
+/**
+ * @author Sean Owen
+ */
+public final class HistoryManager {
+
+ private final CaptureActivity activity;
+
+ public HistoryManager(CaptureActivity activity) {
+ this.activity = activity;
+ }
+
+ List<String> getHistoryItems() {
+
+ SQLiteOpenHelper helper = new DBHelper(activity);
+ SQLiteDatabase db = helper.getReadableDatabase();
+ List<String> items = new ArrayList<String>();
+ try {
+ Cursor cursor = db.query(DBHelper.TABLE_NAME,
+ new String[] {DBHelper.TEXT_COL},
+ null, null, null, null,
+ DBHelper.TIMESTAMP_COL + " DESC");
+ while (cursor.moveToNext()) {
+ items.add(cursor.getString(0));
+ }
+ } finally {
+ db.close();
+ }
+ return items;
+ }
+
+ public AlertDialog buildAlert() {
+ List<String> items = getHistoryItems();
+ final String[] dialogItems = new String[items.size() + 1];
+ for (int i = 0; i < items.size(); i++) {
+ dialogItems[i] = items.get(i);
+ }
+ dialogItems[dialogItems.length - 1] = activity.getResources().getString(R.string.history_clear_text);
+ DialogInterface.OnClickListener clickListener = new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialogInterface, int i) {
+ if (i == dialogItems.length - 1) {
+ clearHistory();
+ } else {
+ Result result = new Result(dialogItems[i], null, null, null);
+ Message message = Message.obtain(activity.getHandler(), R.id.decode_succeeded, result);
+ message.sendToTarget();
+ }
+ }
+ };
+ AlertDialog.Builder builder = new AlertDialog.Builder(activity);
+ builder.setTitle(R.string.history_title);
+ builder.setItems(dialogItems, clickListener);
+ return builder.create();
+ }
+
+ public void addHistoryItem(String text) {
+
+ if (getHistoryItems().contains(text)) {
+ return;
+ }
+
+ SQLiteOpenHelper helper = new DBHelper(activity);
+ SQLiteDatabase db = helper.getWritableDatabase();
+ try {
+ ContentValues values = new ContentValues();
+ values.put(DBHelper.TEXT_COL, text);
+ values.put(DBHelper.TIMESTAMP_COL, System.currentTimeMillis());
+ db.insert(DBHelper.TABLE_NAME, DBHelper.TIMESTAMP_COL, values);
+ } finally {
+ db.close();
+ }
+ }
+
+ void clearHistory() {
+ SQLiteOpenHelper helper = new DBHelper(activity);
+ SQLiteDatabase db = helper.getWritableDatabase();
+ try {
+ db.delete(DBHelper.TABLE_NAME, null, null);
+ } finally {
+ db.close();
+ }
+ }
+
+}
@Override
public void handleButtonPress(int index) {
- AddressBookParsedResult addressResult = (AddressBookParsedResult) result;
+ AddressBookParsedResult addressResult = (AddressBookParsedResult) getResult();
int action = mapIndexToAction(index);
switch (action) {
case 0:
// Overriden so we can hyphenate phone numbers, format birthdays, and bold the name.
@Override
public CharSequence getDisplayContents() {
- AddressBookParsedResult result = (AddressBookParsedResult) this.result;
+ AddressBookParsedResult result = (AddressBookParsedResult) getResult();
StringBuffer contents = new StringBuffer();
ParsedResult.maybeAppend(result.getNames(), contents);
int namesLength = contents.length();
@Override
public void handleButtonPress(int index) {
- CalendarParsedResult calendarResult = (CalendarParsedResult) result;
+ CalendarParsedResult calendarResult = (CalendarParsedResult) getResult();
switch (index) {
case 0:
addCalendarEvent(calendarResult.getSummary(), calendarResult.getStart(),
@Override
public CharSequence getDisplayContents() {
- CalendarParsedResult calResult = (CalendarParsedResult) result;
+ CalendarParsedResult calResult = (CalendarParsedResult) getResult();
StringBuffer result = new StringBuffer();
ParsedResult.maybeAppend(calResult.getSummary(), result);
appendTime(calResult.getStart(), result);
@Override
public void handleButtonPress(int index) {
- EmailAddressParsedResult emailResult = (EmailAddressParsedResult) result;
+ EmailAddressParsedResult emailResult = (EmailAddressParsedResult) getResult();
switch (index) {
case 0:
sendEmailFromUri(emailResult.getMailtoURI(), null, null);
@Override
public void handleButtonPress(int index) {
- GeoParsedResult geoResult = (GeoParsedResult) result;
+ GeoParsedResult geoResult = (GeoParsedResult) getResult();
switch (index) {
case 0:
openMap(geoResult.getGeoURI());
@Override
public void handleButtonPress(int index) {
- ISBNParsedResult isbnResult = (ISBNParsedResult) result;
+ ISBNParsedResult isbnResult = (ISBNParsedResult) getResult();
switch (index) {
case 0:
openProductSearch(isbnResult.getISBN());
@Override
public void handleButtonPress(int index) {
- ProductParsedResult productResult = (ProductParsedResult) result;
+ ProductParsedResult productResult = (ProductParsedResult) getResult();
switch (index) {
case 0:
openProductSearch(productResult.getNormalizedProductID());
* @author dswitkin@google.com (Daniel Switkin)
*/
public final class ResultButtonListener implements Button.OnClickListener {
- final ResultHandler resultHandler;
- final int index;
+ private final ResultHandler resultHandler;
+ private final int index;
public ResultButtonListener(ResultHandler resultHandler, int index) {
this.resultHandler = resultHandler;
import com.google.zxing.client.android.Intents;
import com.google.zxing.client.android.LocaleManager;
import com.google.zxing.client.android.R;
-import com.google.zxing.client.android.SearchBookContentsActivity;
+import com.google.zxing.client.android.book.SearchBookContentsActivity;
import com.google.zxing.client.result.ParsedResult;
import com.google.zxing.client.result.ParsedResultType;
public static final int MAX_BUTTON_COUNT = 4;
- protected final ParsedResult result;
+ private final ParsedResult result;
private final Activity activity;
- protected ResultHandler(Activity activity, ParsedResult result) {
+ ResultHandler(Activity activity, ParsedResult result) {
this.result = result;
this.activity = activity;
}
+ ParsedResult getResult() {
+ return result;
+ }
+
/**
* Indicates how many buttons the derived class wants shown.
*
* @param start The start time as yyyyMMdd or yyyyMMdd'T'HHmmss or yyyyMMdd'T'HHmmss'Z'
* @param end The end time as yyyyMMdd or yyyyMMdd'T'HHmmss or yyyyMMdd'T'HHmmss'Z'
*/
- public final void addCalendarEvent(String summary, String start, String end) {
+ final void addCalendarEvent(String summary, String start, String end) {
Intent intent = new Intent(Intent.ACTION_EDIT);
intent.setType("vnd.android.cursor.item/event");
intent.putExtra("beginTime", calculateMilliseconds(start));
}
}
- public final void addContact(String[] names, String[] phoneNumbers, String[] emails, String note,
+ final void addContact(String[] names, String[] phoneNumbers, String[] emails, String note,
String address, String org, String title) {
// Only use the first name in the array, if present.
launchIntent(intent);
}
- public final void shareByEmail(String contents) {
+ final void shareByEmail(String contents) {
sendEmailFromUri("mailto:", activity.getString(R.string.msg_share_subject_line), contents);
}
- public final void sendEmail(String address, String subject, String body) {
+ final void sendEmail(String address, String subject, String body) {
sendEmailFromUri("mailto:" + address, subject, body);
}
// Use public Intent fields rather than private GMail app fields to specify subject and body.
- public final void sendEmailFromUri(String uri, String subject, String body) {
+ final void sendEmailFromUri(String uri, String subject, String body) {
Intent intent = new Intent(Intent.ACTION_SEND, Uri.parse(uri));
putExtra(intent, Intent.EXTRA_SUBJECT, subject);
putExtra(intent, Intent.EXTRA_TEXT, body);
launchIntent(intent);
}
- public final void shareBySMS(String contents) {
+ final void shareBySMS(String contents) {
sendSMSFromUri("smsto:", activity.getString(R.string.msg_share_subject_line) + ":\n" +
contents);
}
- public final void sendSMS(String phoneNumber, String body) {
+ final void sendSMS(String phoneNumber, String body) {
sendSMSFromUri("smsto:" + phoneNumber, body);
}
- public final void sendSMSFromUri(String uri, String body) {
+ final void sendSMSFromUri(String uri, String body) {
Intent intent = new Intent(Intent.ACTION_SENDTO, Uri.parse(uri));
putExtra(intent, "sms_body", body);
// Exit the app once the SMS is sent
launchIntent(intent);
}
- public final void sendMMS(String phoneNumber, String subject, String body) {
+ final void sendMMS(String phoneNumber, String subject, String body) {
sendMMSFromUri("mmsto:" + phoneNumber, subject, body);
}
- public final void sendMMSFromUri(String uri, String subject, String body) {
+ final void sendMMSFromUri(String uri, String subject, String body) {
Intent intent = new Intent(Intent.ACTION_SENDTO, Uri.parse(uri));
// The Messaging app needs to see a valid subject or else it will treat this an an SMS.
if (subject == null || subject.length() == 0) {
launchIntent(intent);
}
- public final void dialPhone(String phoneNumber) {
+ final void dialPhone(String phoneNumber) {
launchIntent(new Intent(Intent.ACTION_DIAL, Uri.parse("tel:" + phoneNumber)));
}
- public final void dialPhoneFromUri(String uri) {
+ final void dialPhoneFromUri(String uri) {
launchIntent(new Intent(Intent.ACTION_DIAL, Uri.parse(uri)));
}
- public final void openMap(String geoURI) {
+ final void openMap(String geoURI) {
launchIntent(new Intent(Intent.ACTION_VIEW, Uri.parse(geoURI)));
}
* @param address The address to find
* @param title An optional title, e.g. the name of the business at this address
*/
- public final void searchMap(String address, String title) {
+ final void searchMap(String address, String title) {
String query = address;
if (title != null && title.length() > 0) {
query = query + " (" + title + ')';
launchIntent(new Intent(Intent.ACTION_VIEW, Uri.parse("geo:0,0?q=" + Uri.encode(query))));
}
- public final void getDirections(double latitude, double longitude) {
+ final void getDirections(double latitude, double longitude) {
launchIntent(new Intent(Intent.ACTION_VIEW, Uri.parse("http://maps.google." +
LocaleManager.getCountryTLD() + "/maps?f=d&daddr=" + latitude + ',' + longitude)));
}
// Uses the mobile-specific version of Product Search, which is formatted for small screens.
- public final void openProductSearch(String upc) {
+ final void openProductSearch(String upc) {
Uri uri = Uri.parse("http://www.google." + LocaleManager.getProductSearchCountryTLD() +
"/m/products?q=" + upc + "&source=zxing");
launchIntent(new Intent(Intent.ACTION_VIEW, uri));
}
- public final void openBookSearch(String isbn) {
+ final void openBookSearch(String isbn) {
Uri uri = Uri.parse("http://books.google." + LocaleManager.getBookSearchCountryTLD() +
"/books?vid=isbn" + isbn);
launchIntent(new Intent(Intent.ACTION_VIEW, uri));
}
- public final void searchBookContents(String isbn) {
+ final void searchBookContents(String isbn) {
Intent intent = new Intent(Intents.SearchBookContents.ACTION);
intent.setClassName(activity, SearchBookContentsActivity.class.getName());
putExtra(intent, Intents.SearchBookContents.ISBN, isbn);
launchIntent(intent);
}
- public final void openURL(String url) {
+ final void openURL(String url) {
launchIntent(new Intent(Intent.ACTION_VIEW, Uri.parse(url)));
}
- public final void webSearch(String query) {
+ final void webSearch(String query) {
Intent intent = new Intent(Intent.ACTION_WEB_SEARCH);
intent.putExtra("query", query);
launchIntent(intent);
}
- private void launchIntent(Intent intent) {
+ void launchIntent(Intent intent) {
if (intent != null) {
try {
activity.startActivity(intent);
@Override
public void handleButtonPress(int index) {
- SMSParsedResult smsResult = (SMSParsedResult) result;
+ SMSParsedResult smsResult = (SMSParsedResult) getResult();
switch (index) {
case 0:
sendSMS(smsResult.getNumber(), smsResult.getBody());
@Override
public CharSequence getDisplayContents() {
- SMSParsedResult smsResult = (SMSParsedResult) result;
+ SMSParsedResult smsResult = (SMSParsedResult) getResult();
StringBuffer contents = new StringBuffer();
ParsedResult.maybeAppend(PhoneNumberUtils.formatNumber(smsResult.getNumber()), contents);
ParsedResult.maybeAppend(smsResult.getVia(), contents);
@Override
public void handleButtonPress(int index) {
- TelParsedResult telResult = (TelParsedResult) result;
+ TelParsedResult telResult = (TelParsedResult) getResult();
switch (index) {
case 0:
dialPhoneFromUri(telResult.getTelURI());
// Overriden so we can take advantage of Android's phone number hyphenation routines.
@Override
public CharSequence getDisplayContents() {
- String contents = result.getDisplayResult();
+ String contents = getResult().getDisplayResult();
contents = contents.replace("\r", "");
return PhoneNumberUtils.formatNumber(contents);
}
@Override
public void handleButtonPress(int index) {
- String text = result.getDisplayResult();
+ String text = getResult().getDisplayResult();
switch (index) {
case 0:
webSearch(text);
@Override
public void handleButtonPress(int index) {
- URIParsedResult uriResult = (URIParsedResult) result;
+ URIParsedResult uriResult = (URIParsedResult) getResult();
switch (index) {
case 0:
openURL(uriResult.getURI());
--- /dev/null
+/*
+ * Copyright (C) 2008 ZXing authors
+ *
+ * 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.google.zxing.client.android.share;
+
+import android.app.ListActivity;
+import android.content.Intent;
+import android.database.Cursor;
+import android.os.Bundle;
+import android.provider.Browser;
+import android.view.View;
+import android.widget.ListAdapter;
+import android.widget.ListView;
+import android.widget.SimpleCursorAdapter;
+import com.google.zxing.client.android.R;
+
+/**
+ * This class is only needed because I can't successfully send an ACTION_PICK intent to
+ * com.android.browser.BrowserBookmarksPage. It can go away if that starts working in the future.
+ *
+ * @author dswitkin@google.com (Daniel Switkin)
+ */
+final class BookmarkPickerActivity extends ListActivity {
+ private static final String[] BOOKMARK_PROJECTION = {
+ Browser.BookmarkColumns.TITLE,
+ Browser.BookmarkColumns.URL
+ };
+
+ private static final int[] TWO_LINE_VIEW_IDS = {
+ R.id.bookmark_title,
+ R.id.bookmark_url
+ };
+
+ private static final int TITLE_COLUMN = 0;
+ private static final int URL_COLUMN = 1;
+
+ // Without this selection, we'd get all the history entries too
+ private static final String BOOKMARK_SELECTION = "bookmark = 1";
+
+ private Cursor cursor;
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ cursor = getContentResolver().query(Browser.BOOKMARKS_URI, BOOKMARK_PROJECTION,
+ BOOKMARK_SELECTION, null, null);
+ startManagingCursor(cursor);
+
+ ListAdapter adapter = new SimpleCursorAdapter(this, R.layout.bookmark_picker_list_item,
+ cursor, BOOKMARK_PROJECTION, TWO_LINE_VIEW_IDS);
+ setListAdapter(adapter);
+ }
+
+ @Override
+ protected void onListItemClick(ListView l, View view, int position, long id) {
+ if (cursor.moveToPosition(position)) {
+ Intent intent = new Intent();
+ intent.putExtra(Browser.BookmarkColumns.TITLE, cursor.getString(TITLE_COLUMN));
+ intent.putExtra(Browser.BookmarkColumns.URL, cursor.getString(URL_COLUMN));
+ setResult(RESULT_OK, intent);
+ } else {
+ setResult(RESULT_CANCELED);
+ }
+ finish();
+ }
+}
--- /dev/null
+/*
+ * Copyright (C) 2008 ZXing authors
+ *
+ * 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.google.zxing.client.android.share;
+
+import android.app.Activity;
+import android.content.ContentResolver;
+import android.content.Intent;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Bundle;
+import android.provider.Browser;
+import android.provider.Contacts;
+import android.provider.BaseColumns;
+import android.text.ClipboardManager;
+import android.view.View;
+import android.widget.Button;
+import com.google.zxing.client.android.Intents;
+import com.google.zxing.client.android.Contents;
+import com.google.zxing.client.android.R;
+
+/**
+ * Barcode Scanner can share data like contacts and bookmarks by displaying a QR Code on screen,
+ * such that another user can scan the barcode with their phone.
+ *
+ * @author dswitkin@google.com (Daniel Switkin)
+ */
+public final class ShareActivity extends Activity {
+ private static final int PICK_BOOKMARK = 0;
+ private static final int PICK_CONTACT = 1;
+
+ //private static final int METHODS_ID_COLUMN = 0;
+ private static final int METHODS_KIND_COLUMN = 1;
+ private static final int METHODS_DATA_COLUMN = 2;
+
+ private static final String[] METHODS_PROJECTION = {
+ BaseColumns._ID, // 0
+ Contacts.ContactMethodsColumns.KIND, // 1
+ Contacts.ContactMethodsColumns.DATA, // 2
+ };
+
+ private static final int PHONES_NUMBER_COLUMN = 1;
+
+ private static final String[] PHONES_PROJECTION = {
+ BaseColumns._ID, // 0
+ Contacts.PhonesColumns.NUMBER // 1
+ };
+
+ private Button clipboardButton;
+
+ private final Button.OnClickListener contactListener = new Button.OnClickListener() {
+ public void onClick(View v) {
+ startActivityForResult(new Intent(Intent.ACTION_PICK, Contacts.People.CONTENT_URI),
+ PICK_CONTACT);
+ }
+ };
+
+ private final Button.OnClickListener bookmarkListener = new Button.OnClickListener() {
+ public void onClick(View v) {
+ Intent intent = new Intent(Intent.ACTION_PICK);
+ intent.setClassName(ShareActivity.this, BookmarkPickerActivity.class.getName());
+ startActivityForResult(intent, PICK_BOOKMARK);
+ }
+ };
+
+ private final Button.OnClickListener clipboardListener = new Button.OnClickListener() {
+ public void onClick(View v) {
+ ClipboardManager clipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
+ // Should always be true, because we grey out the clipboard button in onResume() if it's empty
+ if (clipboard.hasText()) {
+ Intent intent = new Intent(Intents.Encode.ACTION);
+ intent.putExtra(Intents.Encode.TYPE, Contents.Type.TEXT);
+ intent.putExtra(Intents.Encode.DATA, clipboard.getText());
+ intent.putExtra(Intents.Encode.FORMAT, Contents.Format.QR_CODE);
+ startActivity(intent);
+ }
+ }
+ };
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ setContentView(R.layout.share);
+
+ Button mContactButton = (Button) findViewById(R.id.contact_button);
+ mContactButton.setOnClickListener(contactListener);
+ Button mBookmarkButton = (Button) findViewById(R.id.bookmark_button);
+ mBookmarkButton.setOnClickListener(bookmarkListener);
+ clipboardButton = (Button) findViewById(R.id.clipboard_button);
+ clipboardButton.setOnClickListener(clipboardListener);
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+
+ ClipboardManager clipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
+ if (clipboard.hasText()) {
+ clipboardButton.setEnabled(true);
+ clipboardButton.setText(R.string.button_share_clipboard);
+ } else {
+ clipboardButton.setEnabled(false);
+ clipboardButton.setText(R.string.button_clipboard_empty);
+ }
+ }
+
+ @Override
+ public void onActivityResult(int requestCode, int resultCode, Intent intent) {
+ if (resultCode == RESULT_OK) {
+ switch (requestCode) {
+ case PICK_BOOKMARK:
+ showTextAsBarcode(intent.getStringExtra(Browser.BookmarkColumns.URL));
+ break;
+ case PICK_CONTACT:
+ // Data field is content://contacts/people/984
+ showContactAsBarcode(intent.getData());
+ break;
+ }
+ }
+ }
+
+ private void showTextAsBarcode(String text) {
+ Intent intent = new Intent(Intents.Encode.ACTION);
+ intent.putExtra(Intents.Encode.TYPE, Contents.Type.TEXT);
+ intent.putExtra(Intents.Encode.DATA, text);
+ intent.putExtra(Intents.Encode.FORMAT, Contents.Format.QR_CODE);
+ startActivity(intent);
+ }
+
+ /**
+ * Takes a contact Uri and does the necessary database lookups to retrieve that person's info,
+ * then sends an Encode intent to render it as a QR Code.
+ *
+ * @param contactUri A Uri of the form content://contacts/people/17
+ */
+ private void showContactAsBarcode(Uri contactUri) {
+ ContentResolver resolver = getContentResolver();
+ Cursor contactCursor = resolver.query(contactUri, null, null, null, null);
+ Bundle bundle = new Bundle();
+ if (contactCursor != null && contactCursor.moveToFirst()) {
+ int nameColumn = contactCursor.getColumnIndex(Contacts.PeopleColumns.NAME);
+ String name = contactCursor.getString(nameColumn);
+
+ // Don't require a name to be present, this contact might be just a phone number.
+ if (name != null && name.length() > 0) {
+ bundle.putString(Contacts.Intents.Insert.NAME, massageContactData(name));
+ }
+ contactCursor.close();
+
+ Uri phonesUri = Uri.withAppendedPath(contactUri, Contacts.People.Phones.CONTENT_DIRECTORY);
+ Cursor phonesCursor = resolver.query(phonesUri, PHONES_PROJECTION, null, null, null);
+ if (phonesCursor != null) {
+ int foundPhone = 0;
+ while (phonesCursor.moveToNext()) {
+ String number = phonesCursor.getString(PHONES_NUMBER_COLUMN);
+ if (foundPhone < Contents.PHONE_KEYS.length) {
+ bundle.putString(Contents.PHONE_KEYS[foundPhone], massageContactData(number));
+ foundPhone++;
+ }
+ }
+ phonesCursor.close();
+ }
+
+ Uri methodsUri = Uri.withAppendedPath(contactUri,
+ Contacts.People.ContactMethods.CONTENT_DIRECTORY);
+ Cursor methodsCursor = resolver.query(methodsUri, METHODS_PROJECTION, null, null, null);
+ if (methodsCursor != null) {
+ int foundEmail = 0;
+ boolean foundPostal = false;
+ while (methodsCursor.moveToNext()) {
+ int kind = methodsCursor.getInt(METHODS_KIND_COLUMN);
+ String data = methodsCursor.getString(METHODS_DATA_COLUMN);
+ switch (kind) {
+ case Contacts.KIND_EMAIL:
+ if (foundEmail < Contents.EMAIL_KEYS.length) {
+ bundle.putString(Contents.EMAIL_KEYS[foundEmail], massageContactData(data));
+ foundEmail++;
+ }
+ break;
+ case Contacts.KIND_POSTAL:
+ if (!foundPostal) {
+ bundle.putString(Contacts.Intents.Insert.POSTAL, massageContactData(data));
+ foundPostal = true;
+ }
+ break;
+ }
+ }
+ methodsCursor.close();
+ }
+
+ Intent intent = new Intent(Intents.Encode.ACTION);
+ intent.putExtra(Intents.Encode.TYPE, Contents.Type.CONTACT);
+ intent.putExtra(Intents.Encode.DATA, bundle);
+ intent.putExtra(Intents.Encode.FORMAT, Contents.Format.QR_CODE);
+
+ startActivity(intent);
+ }
+ }
+
+ private static String massageContactData(String data) {
+ // For now -- make sure we don't put newlines in shared contact data. It messes up
+ // any known encoding of contact data. Replace with space.
+ if (data.indexOf('\n') >= 0) {
+ data = data.replace("\n", " ");
+ }
+ if (data.indexOf('\r') >= 0) {
+ data = data.replace("\r", " ");
+ }
+ return data;
+ }
+}