2 * Copyright (C) 2008 ZXing authors
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package com.google.zxing.client.android.encode;
19 import com.google.zxing.BarcodeFormat;
20 import com.google.zxing.MultiFormatWriter;
21 import com.google.zxing.WriterException;
22 import com.google.zxing.client.android.Intents;
23 import com.google.zxing.client.android.Contents;
24 import com.google.zxing.client.android.R;
25 import com.google.zxing.common.ByteMatrix;
27 import android.app.Activity;
28 import android.content.Intent;
29 import android.graphics.Bitmap;
30 import android.os.Bundle;
31 import android.os.Handler;
32 import android.os.Message;
33 import android.provider.Contacts;
34 import android.telephony.PhoneNumberUtils;
35 import android.util.Log;
38 * This class does the work of decoding the user's request and extracting all the data
39 * to be encoded in a QR Code.
41 * @author dswitkin@google.com (Daniel Switkin)
43 final class QRCodeEncoder {
44 private final Activity activity;
45 private String contents;
46 private String displayContents;
48 private BarcodeFormat format;
50 public QRCodeEncoder(Activity activity, Intent intent) {
51 this.activity = activity;
52 if (!encodeContents(intent)) {
53 throw new IllegalArgumentException("No valid data to encode.");
57 public void requestBarcode(Handler handler, int pixelResolution) {
58 Thread encodeThread = new EncodeThread(contents, handler, pixelResolution,
63 public String getContents() {
67 public String getDisplayContents() {
68 return displayContents;
71 public String getTitle() {
75 public String getFormat() {
76 return format.toString();
79 // It would be nice if the string encoding lived in the core ZXing library,
80 // but we use platform specific code like PhoneNumberUtils, so it can't.
81 private boolean encodeContents(Intent intent) {
86 // default to QR_CODE if no format given
87 String format = intent.getStringExtra(Intents.Encode.FORMAT);
88 if (format == null || format.length() == 0 ||
89 format.equals(Contents.Format.QR_CODE)) {
90 String type = intent.getStringExtra(Intents.Encode.TYPE);
91 if (type == null || type.length() == 0) {
94 this.format = BarcodeFormat.QR_CODE;
95 encodeQRCodeContents(intent, type);
97 String data = intent.getStringExtra(Intents.Encode.DATA);
98 if (data != null && data.length() != 0) {
100 displayContents = data;
101 title = activity.getString(R.string.contents_text);
102 if (format.equals(Contents.Format.CODE_128)) {
103 this.format = BarcodeFormat.CODE_128;
104 } else if (format.equals(Contents.Format.CODE_39)) {
105 this.format = BarcodeFormat.CODE_39;
106 } else if (format.equals(Contents.Format.EAN_8)) {
107 this.format = BarcodeFormat.EAN_8;
108 } else if (format.equals(Contents.Format.EAN_13)) {
109 this.format = BarcodeFormat.EAN_13;
110 } else if (format.equals(Contents.Format.UPC_A)) {
111 this.format = BarcodeFormat.UPC_A;
112 } else if (format.equals(Contents.Format.UPC_E)) {
113 this.format = BarcodeFormat.UPC_E;
117 return contents != null && contents.length() > 0;
120 private void encodeQRCodeContents(Intent intent, String type) {
121 if (type.equals(Contents.Type.TEXT)) {
122 String data = intent.getStringExtra(Intents.Encode.DATA);
123 if (data != null && data.length() > 0) {
125 displayContents = data;
126 title = activity.getString(R.string.contents_text);
128 } else if (type.equals(Contents.Type.EMAIL)) {
129 String data = intent.getStringExtra(Intents.Encode.DATA);
130 if (data != null && data.length() > 0) {
131 contents = "mailto:" + data;
132 displayContents = data;
133 title = activity.getString(R.string.contents_email);
135 } else if (type.equals(Contents.Type.PHONE)) {
136 String data = intent.getStringExtra(Intents.Encode.DATA);
137 if (data != null && data.length() > 0) {
138 contents = "tel:" + data;
139 displayContents = PhoneNumberUtils.formatNumber(data);
140 title = activity.getString(R.string.contents_phone);
142 } else if (type.equals(Contents.Type.SMS)) {
143 String data = intent.getStringExtra(Intents.Encode.DATA);
144 if (data != null && data.length() > 0) {
145 contents = "sms:" + data;
146 displayContents = PhoneNumberUtils.formatNumber(data);
147 title = activity.getString(R.string.contents_sms);
149 } else if (type.equals(Contents.Type.CONTACT)) {
150 Bundle bundle = intent.getBundleExtra(Intents.Encode.DATA);
151 if (bundle != null) {
152 StringBuilder newContents = new StringBuilder();
153 StringBuilder newDisplayContents = new StringBuilder();
154 newContents.append("MECARD:");
155 String name = bundle.getString(Contacts.Intents.Insert.NAME);
156 if (name != null && name.length() > 0) {
157 newContents.append("N:").append(name).append(';');
158 newDisplayContents.append(name);
160 String address = bundle.getString(Contacts.Intents.Insert.POSTAL);
161 if (address != null && address.length() > 0) {
162 newContents.append("ADR:").append(address).append(';');
163 newDisplayContents.append('\n').append(address);
165 for (int x = 0; x < Contents.PHONE_KEYS.length; x++) {
166 String phone = bundle.getString(Contents.PHONE_KEYS[x]);
167 if (phone != null && phone.length() > 0) {
168 newContents.append("TEL:").append(phone).append(';');
169 newDisplayContents.append('\n').append(PhoneNumberUtils.formatNumber(phone));
172 for (int x = 0; x < Contents.EMAIL_KEYS.length; x++) {
173 String email = bundle.getString(Contents.EMAIL_KEYS[x]);
174 if (email != null && email.length() > 0) {
175 newContents.append("EMAIL:").append(email).append(';');
176 newDisplayContents.append('\n').append(email);
179 // Make sure we've encoded at least one field.
180 if (newDisplayContents.length() > 0) {
181 newContents.append(';');
182 contents = newContents.toString();
183 displayContents = newDisplayContents.toString();
184 title = activity.getString(R.string.contents_contact);
187 displayContents = null;
190 } else if (type.equals(Contents.Type.LOCATION)) {
191 Bundle bundle = intent.getBundleExtra(Intents.Encode.DATA);
192 if (bundle != null) {
193 // These must use Bundle.getFloat(), not getDouble(), it's part of the API.
194 float latitude = bundle.getFloat("LAT", Float.MAX_VALUE);
195 float longitude = bundle.getFloat("LONG", Float.MAX_VALUE);
196 if (latitude != Float.MAX_VALUE && longitude != Float.MAX_VALUE) {
197 contents = "geo:" + latitude + ',' + longitude;
198 displayContents = latitude + "," + longitude;
199 title = activity.getString(R.string.contents_location);
205 private static final class EncodeThread extends Thread {
206 private static final String TAG = "EncodeThread";
208 private final String contents;
209 private final Handler handler;
210 private final int pixelResolution;
211 private final BarcodeFormat format;
213 EncodeThread(String contents, Handler handler, int pixelResolution,
214 BarcodeFormat format) {
215 this.contents = contents;
216 this.handler = handler;
217 this.pixelResolution = pixelResolution;
218 this.format = format;
224 ByteMatrix result = new MultiFormatWriter().encode(contents, format,
225 pixelResolution, pixelResolution);
226 int width = result.getWidth();
227 int height = result.getHeight();
228 byte[][] array = result.getArray();
229 int[] pixels = new int[width * height];
230 for (int y = 0; y < height; y++) {
231 for (int x = 0; x < width; x++) {
232 int grey = array[y][x] & 0xff;
233 // pixels[y * width + x] = (0xff << 24) | (grey << 16) | (grey << 8) | grey;
234 pixels[y * width + x] = 0xff000000 | (0x00010101 * grey);
238 Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
239 bitmap.setPixels(pixels, 0, width, 0, 0, width, height);
240 Message message = Message.obtain(handler, R.id.encode_succeeded);
241 message.obj = bitmap;
242 message.sendToTarget();
243 } catch (WriterException e) {
244 Log.e(TAG, e.toString());
245 Message message = Message.obtain(handler, R.id.encode_failed);
246 message.sendToTarget();
247 } catch (IllegalArgumentException e) {
248 Log.e(TAG, e.toString());
249 Message message = Message.obtain(handler, R.id.encode_failed);
250 message.sendToTarget();