e6a92d4554046b88461778b99dcce88040aeb6a7
[zxing.git] / android / src / com / google / zxing / client / android / QRCodeEncoder.java
1 /*
2  * Copyright (C) 2008 ZXing authors
3  *
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
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 package com.google.zxing.client.android;
18
19 import android.app.Activity;
20 import android.content.Intent;
21 import android.graphics.Bitmap;
22 import android.os.Bundle;
23 import android.os.Handler;
24 import android.os.Message;
25 import android.provider.Contacts;
26 import android.util.Log;
27 import android.telephony.PhoneNumberUtils;
28 import com.google.zxing.BarcodeFormat;
29 import com.google.zxing.MultiFormatWriter;
30 import com.google.zxing.WriterException;
31 import com.google.zxing.common.ByteMatrix;
32
33 public final class QRCodeEncoder {
34
35   private static final String TAG = "QRCodeEncoder";
36
37   private final Activity mActivity;
38   private String mContents;
39   private String mDisplayContents;
40   private String mTitle;
41
42   public QRCodeEncoder(Activity activity, Intent intent) {
43     mActivity = activity;
44     if (!encodeContents(intent)) {
45       throw new IllegalArgumentException("No valid data to encode.");
46     }
47   }
48
49   public void requestBarcode(Handler handler, int pixelResolution) {
50     Thread encodeThread = new EncodeThread(mContents, handler, pixelResolution);
51     encodeThread.start();
52   }
53
54   public String getContents() {
55     return mContents;
56   }
57
58   public String getDisplayContents() {
59     return mDisplayContents;
60   }
61
62   public String getTitle() {
63     return mTitle;
64   }
65
66   // TODO: The string encoding should live in the core ZXing library.
67   private boolean encodeContents(Intent intent) {
68     if (intent == null) return false;
69     String type = intent.getStringExtra(Intents.Encode.TYPE);
70     if (type == null || type.length() == 0) return false;
71
72     if (type.equals(Contents.Type.TEXT)) {
73       String string = intent.getStringExtra(Intents.Encode.DATA);
74       if (string != null && string.length() > 0) {
75         mContents = string;
76         mDisplayContents = string;
77         mTitle = mActivity.getString(R.string.contents_text);
78       }
79     } else if (type.equals(Contents.Type.EMAIL)) {
80       String string = intent.getStringExtra(Intents.Encode.DATA);
81       if (string != null && string.length() > 0) {
82         mContents = "mailto:" + string;
83         mDisplayContents = string;
84         mTitle = mActivity.getString(R.string.contents_email);
85       }
86     } else if (type.equals(Contents.Type.PHONE)) {
87       String string = intent.getStringExtra(Intents.Encode.DATA);
88       if (string != null && string.length() > 0) {
89         mContents = "tel:" + string;
90         mDisplayContents = PhoneNumberUtils.formatNumber(string);
91         mTitle = mActivity.getString(R.string.contents_phone);
92       }
93     } else if (type.equals(Contents.Type.SMS)) {
94       String string = intent.getStringExtra(Intents.Encode.DATA);
95       if (string != null && string.length() > 0) {
96         mContents = "sms:" + string;
97         mDisplayContents = PhoneNumberUtils.formatNumber(string);
98         mTitle = mActivity.getString(R.string.contents_sms);
99       }
100     } else if (type.equals(Contents.Type.CONTACT)) {
101       Bundle bundle = intent.getBundleExtra(Intents.Encode.DATA);
102       if (bundle != null) {
103         String name = bundle.getString(Contacts.Intents.Insert.NAME);
104         if (name != null && name.length() > 0) {
105           mContents = "MECARD:N:" + name + ";";
106           mDisplayContents = name;
107           String address = bundle.getString(Contacts.Intents.Insert.POSTAL);
108           if (address != null && address.length() > 0) {
109             mContents += "ADR:" + address + ";";
110             mDisplayContents += "\n" + address;
111           }
112           for (int x = 0; x < Contents.PHONE_KEYS.length; x++) {
113             String phone = bundle.getString(Contents.PHONE_KEYS[x]);
114             if (phone != null && phone.length() > 0) {
115               mContents += "TEL:" + phone + ";";
116               mDisplayContents += "\n" + PhoneNumberUtils.formatNumber(phone);
117             }
118           }
119           for (int x = 0; x < Contents.EMAIL_KEYS.length; x++) {
120             String email = bundle.getString(Contents.EMAIL_KEYS[x]);
121             if (email != null && email.length() > 0) {
122               mContents += "EMAIL:" + email + ";";
123               mDisplayContents += "\n" + email;
124             }
125           }
126           mContents += ";";
127           mTitle = mActivity.getString(R.string.contents_contact);
128         }
129       }
130     } else if (type.equals(Contents.Type.LOCATION)) {
131       Bundle bundle = intent.getBundleExtra(Intents.Encode.DATA);
132       if (bundle != null) {
133         float latitude = bundle.getFloat("LAT", Float.MAX_VALUE);
134         float longitude = bundle.getFloat("LONG", Float.MAX_VALUE);
135         if (latitude != Float.MAX_VALUE && longitude != Float.MAX_VALUE) {
136           mContents = "geo:" + latitude + "," + longitude;
137           mDisplayContents = latitude + "," + longitude;
138           mTitle = mActivity.getString(R.string.contents_location);
139         }
140       }
141     }
142     return mContents != null && mContents.length() > 0;
143   }
144
145   private final static class EncodeThread extends Thread {
146
147     private final String mContents;
148     private final Handler mHandler;
149     private final int mPixelResolution;
150
151     public EncodeThread(String contents, Handler handler, int pixelResolution) {
152       mContents = contents;
153       mHandler = handler;
154       mPixelResolution = pixelResolution;
155     }
156
157     public final void run() {
158       try {
159         ByteMatrix result = new MultiFormatWriter().encode(mContents, BarcodeFormat.QR_CODE,
160              mPixelResolution, mPixelResolution);
161         int width = result.width();
162         int height = result.height();
163         byte[][] array = result.getArray();
164         int[] pixels = new int[width * height];
165         for (int y = 0; y < height; y++) {
166           for (int x = 0; x < width; x++) {
167             int grey = array[y][x] & 0xff;
168             pixels[y * width + x] = (0xff << 24) | (grey << 16) | (grey << 8) | grey;
169           }
170         }
171
172         Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
173         bitmap.setPixels(pixels, 0, width, 0, 0, width, height);
174         Message message = Message.obtain(mHandler, R.id.encode_succeeded);
175         message.obj = bitmap;
176         message.sendToTarget();
177       } catch (WriterException e) {
178         Log.e(TAG, e.toString());
179         Message message = Message.obtain(mHandler, R.id.encode_failed);
180         message.sendToTarget();
181       } catch (IllegalArgumentException e) {
182         Log.e(TAG, e.toString());
183         Message message = Message.obtain(mHandler, R.id.encode_failed);
184         message.sendToTarget();
185       }
186     }
187   }
188
189 }