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