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.share;
19 import android.app.Activity;
20 import android.content.ContentResolver;
21 import android.content.Intent;
22 import android.database.Cursor;
23 import android.net.Uri;
24 import android.os.Bundle;
25 import android.provider.Browser;
26 import android.provider.Contacts;
27 import android.provider.BaseColumns;
28 import android.text.ClipboardManager;
29 import android.util.Log;
30 import android.view.View;
31 import android.widget.Button;
32 import com.google.zxing.BarcodeFormat;
33 import com.google.zxing.client.android.Intents;
34 import com.google.zxing.client.android.Contents;
35 import com.google.zxing.client.android.R;
38 * Barcode Scanner can share data like contacts and bookmarks by displaying a QR Code on screen,
39 * such that another user can scan the barcode with their phone.
41 * @author dswitkin@google.com (Daniel Switkin)
43 public final class ShareActivity extends Activity {
45 private static final String TAG = ShareActivity.class.getSimpleName();
47 private static final int PICK_BOOKMARK = 0;
48 private static final int PICK_CONTACT = 1;
49 private static final int PICK_APP = 2;
51 //private static final int METHODS_ID_COLUMN = 0;
52 private static final int METHODS_KIND_COLUMN = 1;
53 private static final int METHODS_DATA_COLUMN = 2;
55 private static final String[] METHODS_PROJECTION = {
57 Contacts.ContactMethodsColumns.KIND, // 1
58 Contacts.ContactMethodsColumns.DATA, // 2
61 private static final int PHONES_NUMBER_COLUMN = 1;
63 private static final String[] PHONES_PROJECTION = {
65 Contacts.PhonesColumns.NUMBER // 1
68 private Button clipboardButton;
70 private final Button.OnClickListener contactListener = new Button.OnClickListener() {
71 public void onClick(View v) {
72 Intent intent = new Intent(Intent.ACTION_PICK, Contacts.People.CONTENT_URI);
73 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
74 startActivityForResult(intent, PICK_CONTACT);
78 private final Button.OnClickListener bookmarkListener = new Button.OnClickListener() {
79 public void onClick(View v) {
80 Intent intent = new Intent(Intent.ACTION_PICK);
81 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
82 intent.setClassName(ShareActivity.this, BookmarkPickerActivity.class.getName());
83 startActivityForResult(intent, PICK_BOOKMARK);
87 private final Button.OnClickListener appListener = new Button.OnClickListener() {
88 public void onClick(View v) {
89 Intent intent = new Intent(Intent.ACTION_PICK);
90 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
91 intent.setClassName(ShareActivity.this, AppPickerActivity.class.getName());
92 startActivityForResult(intent, PICK_APP);
96 private final Button.OnClickListener clipboardListener = new Button.OnClickListener() {
97 public void onClick(View v) {
98 ClipboardManager clipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
99 // Should always be true, because we grey out the clipboard button in onResume() if it's empty
100 if (clipboard.hasText()) {
101 Intent intent = new Intent(Intents.Encode.ACTION);
102 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
103 intent.putExtra(Intents.Encode.TYPE, Contents.Type.TEXT);
104 intent.putExtra(Intents.Encode.DATA, clipboard.getText().toString());
105 intent.putExtra(Intents.Encode.FORMAT, BarcodeFormat.QR_CODE.toString());
106 startActivity(intent);
112 public void onCreate(Bundle icicle) {
113 super.onCreate(icicle);
114 setContentView(R.layout.share);
116 findViewById(R.id.contact_button).setOnClickListener(contactListener);
117 findViewById(R.id.bookmark_button).setOnClickListener(bookmarkListener);
118 findViewById(R.id.app_button).setOnClickListener(appListener);
119 clipboardButton = (Button) findViewById(R.id.clipboard_button);
120 clipboardButton.setOnClickListener(clipboardListener);
124 protected void onResume() {
127 ClipboardManager clipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
128 if (clipboard.hasText()) {
129 clipboardButton.setEnabled(true);
130 clipboardButton.setText(R.string.button_share_clipboard);
132 clipboardButton.setEnabled(false);
133 clipboardButton.setText(R.string.button_clipboard_empty);
138 public void onActivityResult(int requestCode, int resultCode, Intent intent) {
139 if (resultCode == RESULT_OK) {
140 switch (requestCode) {
143 showTextAsBarcode(intent.getStringExtra(Browser.BookmarkColumns.URL));
146 // Data field is content://contacts/people/984
147 showContactAsBarcode(intent.getData());
153 private void showTextAsBarcode(String text) {
154 Log.i(TAG, "Showing text as barcode: " + text);
156 return; // Show error?
158 Intent intent = new Intent(Intents.Encode.ACTION);
159 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
160 intent.putExtra(Intents.Encode.TYPE, Contents.Type.TEXT);
161 intent.putExtra(Intents.Encode.DATA, text);
162 intent.putExtra(Intents.Encode.FORMAT, BarcodeFormat.QR_CODE.toString());
163 startActivity(intent);
167 * Takes a contact Uri and does the necessary database lookups to retrieve that person's info,
168 * then sends an Encode intent to render it as a QR Code.
170 * @param contactUri A Uri of the form content://contacts/people/17
172 private void showContactAsBarcode(Uri contactUri) {
173 Log.i(TAG, "Showing contact URI as barcode: " + contactUri);
174 if (contactUri == null) {
175 return; // Show error?
177 ContentResolver resolver = getContentResolver();
178 Cursor contactCursor = resolver.query(contactUri, null, null, null, null);
179 Bundle bundle = new Bundle();
180 if (contactCursor != null && contactCursor.moveToFirst()) {
181 int nameColumn = contactCursor.getColumnIndex(Contacts.PeopleColumns.NAME);
182 String name = contactCursor.getString(nameColumn);
184 // Don't require a name to be present, this contact might be just a phone number.
185 if (name != null && name.length() > 0) {
186 bundle.putString(Contacts.Intents.Insert.NAME, massageContactData(name));
188 contactCursor.close();
190 Uri phonesUri = Uri.withAppendedPath(contactUri, Contacts.People.Phones.CONTENT_DIRECTORY);
191 Cursor phonesCursor = resolver.query(phonesUri, PHONES_PROJECTION, null, null, null);
192 if (phonesCursor != null) {
194 while (phonesCursor.moveToNext()) {
195 String number = phonesCursor.getString(PHONES_NUMBER_COLUMN);
196 if (foundPhone < Contents.PHONE_KEYS.length) {
197 bundle.putString(Contents.PHONE_KEYS[foundPhone], massageContactData(number));
201 phonesCursor.close();
204 Uri methodsUri = Uri.withAppendedPath(contactUri,
205 Contacts.People.ContactMethods.CONTENT_DIRECTORY);
206 Cursor methodsCursor = resolver.query(methodsUri, METHODS_PROJECTION, null, null, null);
207 if (methodsCursor != null) {
209 boolean foundPostal = false;
210 while (methodsCursor.moveToNext()) {
211 int kind = methodsCursor.getInt(METHODS_KIND_COLUMN);
212 String data = methodsCursor.getString(METHODS_DATA_COLUMN);
214 case Contacts.KIND_EMAIL:
215 if (foundEmail < Contents.EMAIL_KEYS.length) {
216 bundle.putString(Contents.EMAIL_KEYS[foundEmail], massageContactData(data));
220 case Contacts.KIND_POSTAL:
222 bundle.putString(Contacts.Intents.Insert.POSTAL, massageContactData(data));
228 methodsCursor.close();
231 Intent intent = new Intent(Intents.Encode.ACTION);
232 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
233 intent.putExtra(Intents.Encode.TYPE, Contents.Type.CONTACT);
234 intent.putExtra(Intents.Encode.DATA, bundle);
235 intent.putExtra(Intents.Encode.FORMAT, BarcodeFormat.QR_CODE.toString());
237 Log.i(TAG, "Sending bundle for encoding: " + bundle);
238 startActivity(intent);
242 private static String massageContactData(String data) {
243 // For now -- make sure we don't put newlines in shared contact data. It messes up
244 // any known encoding of contact data. Replace with space.
245 if (data.indexOf('\n') >= 0) {
246 data = data.replace("\n", " ");
248 if (data.indexOf('\r') >= 0) {
249 data = data.replace("\r", " ");