2 * Copyright (C) 2009 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.history;
19 import android.app.AlertDialog;
20 import android.content.ContentValues;
21 import android.content.DialogInterface;
22 import android.content.SharedPreferences;
23 import android.content.res.Resources;
24 import android.database.sqlite.SQLiteDatabase;
25 import android.database.sqlite.SQLiteOpenHelper;
26 import android.database.Cursor;
27 import android.net.Uri;
28 import android.os.Environment;
31 import java.io.FileOutputStream;
32 import java.io.IOException;
33 import java.io.OutputStreamWriter;
34 import java.nio.charset.Charset;
35 import java.text.DateFormat;
36 import java.util.Date;
37 import java.util.List;
38 import java.util.ArrayList;
40 import android.preference.PreferenceManager;
41 import android.util.Log;
42 import com.google.zxing.BarcodeFormat;
43 import com.google.zxing.client.android.Intents;
44 import com.google.zxing.client.android.PreferencesActivity;
45 import com.google.zxing.client.android.R;
46 import com.google.zxing.client.android.CaptureActivity;
47 import com.google.zxing.Result;
50 * <p>Manages functionality related to scan history.</p>
54 public final class HistoryManager {
56 private static final String TAG = HistoryManager.class.getSimpleName();
58 private static final int MAX_ITEMS = 50;
59 //private static final String[] TEXT_COL_PROJECTION = { DBHelper.TEXT_COL };
60 private static final String[] GET_ITEM_COL_PROJECTION = {
63 DBHelper.TIMESTAMP_COL,
65 private static final String[] EXPORT_COL_PROJECTION = {
69 DBHelper.TIMESTAMP_COL,
71 private static final String[] ID_COL_PROJECTION = { DBHelper.ID_COL };
72 private static final DateFormat EXPORT_DATE_TIME_FORMAT = DateFormat.getDateTimeInstance();
74 private final CaptureActivity activity;
76 public HistoryManager(CaptureActivity activity) {
77 this.activity = activity;
80 List<Result> getHistoryItems() {
81 SQLiteOpenHelper helper = new DBHelper(activity);
82 List<Result> items = new ArrayList<Result>();
83 SQLiteDatabase db = helper.getReadableDatabase();
86 cursor = db.query(DBHelper.TABLE_NAME,
87 GET_ITEM_COL_PROJECTION,
88 null, null, null, null,
89 DBHelper.TIMESTAMP_COL + " DESC");
90 while (cursor.moveToNext()) {
91 Result result = new Result(cursor.getString(0),
94 BarcodeFormat.valueOf(cursor.getString(1)),
107 public AlertDialog buildAlert() {
108 List<Result> items = getHistoryItems();
109 int size = items.size();
110 String[] dialogItems = new String[size + 2];
111 for (int i = 0; i < size; i++) {
112 dialogItems[i] = items.get(i).getText();
114 Resources res = activity.getResources();
115 dialogItems[dialogItems.length - 2] = res.getString(R.string.history_send);
116 dialogItems[dialogItems.length - 1] = res.getString(R.string.history_clear_text);
117 DialogInterface.OnClickListener clickListener = new HistoryClickListener(this, activity, dialogItems, items);
118 AlertDialog.Builder builder = new AlertDialog.Builder(activity);
119 builder.setTitle(R.string.history_title);
120 builder.setItems(dialogItems, clickListener);
121 return builder.create();
124 public void addHistoryItem(Result result) {
126 if (!activity.getIntent().getBooleanExtra(Intents.Scan.SAVE_HISTORY, true)) {
127 return; // Do not save this item to the history.
130 SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
131 boolean rememberDuplicates = prefs.getBoolean(PreferencesActivity.KEY_REMEMBER_DUPLICATES, false);
133 if (!rememberDuplicates) {
134 deletePrevious(result.getText());
137 SQLiteOpenHelper helper = new DBHelper(activity);
138 SQLiteDatabase db = helper.getWritableDatabase();
141 ContentValues values = new ContentValues();
142 values.put(DBHelper.TEXT_COL, result.getText());
143 values.put(DBHelper.FORMAT_COL, result.getBarcodeFormat().toString());
144 values.put(DBHelper.DISPLAY_COL, result.getText()); // TODO use parsed result display value?
145 values.put(DBHelper.TIMESTAMP_COL, System.currentTimeMillis());
146 db.insert(DBHelper.TABLE_NAME, DBHelper.TIMESTAMP_COL, values);
152 private void deletePrevious(String text) {
153 SQLiteOpenHelper helper = new DBHelper(activity);
154 SQLiteDatabase db = helper.getWritableDatabase();
156 db.delete(DBHelper.TABLE_NAME, DBHelper.TEXT_COL + "=?", new String[] { text });
162 public void trimHistory() {
163 SQLiteOpenHelper helper = new DBHelper(activity);
164 SQLiteDatabase db = helper.getWritableDatabase();
165 Cursor cursor = null;
167 cursor = db.query(DBHelper.TABLE_NAME,
169 null, null, null, null,
170 DBHelper.TIMESTAMP_COL + " DESC");
172 while (count < MAX_ITEMS && cursor.moveToNext()) {
175 while (cursor.moveToNext()) {
176 db.delete(DBHelper.TABLE_NAME, DBHelper.ID_COL + '=' + cursor.getString(0), null);
179 if (cursor != null) {
187 * <p>Builds a text representation of the scanning history. Each scan is encoded on one
188 * line, terminated by a line break (\r\n). The values in each line are comma-separated,
189 * and double-quoted. Double-quotes within values are escaped with a sequence of two
190 * double-quotes. The fields output are:</p>
194 * <li>Display text</li>
195 * <li>Format (e.g. QR_CODE)</li>
197 * <li>Formatted version of timestamp</li>
200 CharSequence buildHistory() {
201 StringBuilder historyText = new StringBuilder(1000);
202 SQLiteOpenHelper helper = new DBHelper(activity);
203 SQLiteDatabase db = helper.getReadableDatabase();
204 Cursor cursor = null;
206 cursor = db.query(DBHelper.TABLE_NAME,
207 EXPORT_COL_PROJECTION,
208 null, null, null, null,
209 DBHelper.TIMESTAMP_COL + " DESC");
210 while (cursor.moveToNext()) {
211 for (int col = 0; col < EXPORT_COL_PROJECTION.length; col++) {
212 historyText.append('"').append(massageHistoryField(cursor.getString(col))).append("\",");
214 // Add timestamp again, formatted
215 long timestamp = cursor.getLong(EXPORT_COL_PROJECTION.length - 1);
216 historyText.append('"').append(massageHistoryField(
217 EXPORT_DATE_TIME_FORMAT.format(new Date(timestamp)))).append("\"\r\n");
220 if (cursor != null) {
228 static Uri saveHistory(String history) {
229 File bsRoot = new File(Environment.getExternalStorageDirectory(), "BarcodeScanner");
230 File historyRoot = new File(bsRoot, "History");
231 if (!historyRoot.exists() && !historyRoot.mkdirs()) {
232 Log.w(TAG, "Couldn't make dir " + historyRoot);
235 File historyFile = new File(historyRoot, "history-" + System.currentTimeMillis() + ".csv");
236 OutputStreamWriter out = null;
238 out = new OutputStreamWriter(new FileOutputStream(historyFile), Charset.forName("UTF-8"));
240 return Uri.parse("file://" + historyFile.getAbsolutePath());
241 } catch (IOException ioe) {
242 Log.w(TAG, "Couldn't access file " + historyFile + " due to " + ioe);
248 } catch (IOException ioe) {
255 private static String massageHistoryField(String value) {
256 return value.replace("\"","\"\"");
259 void clearHistory() {
260 SQLiteOpenHelper helper = new DBHelper(activity);
261 SQLiteDatabase db = helper.getWritableDatabase();
263 db.delete(DBHelper.TABLE_NAME, null, null);