Commit ecb1f5eb by 倪力烽

1. 完成调度功能框架的搭建

2. 完成调度界面的编写
3. 提交功能逻辑尚未编写
4. 需要结合接口进行测试
5. 二维码框架搭建完成
parent 465504c7
......@@ -48,4 +48,5 @@ dependencies {
compile 'com.android.support:design:25.3.1'
compile files('/Users/ni/Documents/lierda/lierda_project/EBike-Administrer-Tool/libs/android-async-http-1.4.6.jar')
compile files('/Users/ni/Documents/lierda/lierda_project/EBike-Administrer-Tool/libs/org.apache.http.legacy.jar')
compile files('/Users/ni/Documents/lierda/lierda_project/EBike-Administrer-Tool/libs/zixing-core-3.2.0.jar')
}
......@@ -5,6 +5,15 @@
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.FLASHLIGHT" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<uses-feature
android:name="android.hardware.camera.front" android:required="false" />
<uses-feature
android:name="android.hardware.camera.flash"
android:required="false" />
<application
android:name=".MyApplication"
android:allowBackup="true"
......@@ -28,6 +37,18 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="com.google.zxing.client.android.CaptureActivity"
android:screenOrientation="portrait"
android:clearTaskOnLaunch="true"
android:stateNotNeeded="true"
android:theme="@android:style/Theme.NoTitleBar" >
<intent-filter>
<action android:name="com.google.zxing.client.android.SCAN" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
</application>
</manifest>
\ No newline at end of file
/*
* Copyright (C) 2012 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.zxing.client.android;
import android.content.Context;
import android.content.SharedPreferences;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.preference.PreferenceManager;
import com.google.zxing.client.android.camera.CameraManager;
import com.google.zxing.client.android.camera.FrontLightMode;
/**
* Detects ambient light and switches on the front light when very dark, and off again when sufficiently light.
*
* @author Sean Owen
* @author Nikolaus Huber
*/
final class AmbientLightManager implements SensorEventListener {
private static final float TOO_DARK_LUX = 45.0f;
private static final float BRIGHT_ENOUGH_LUX = 450.0f;
private final Context context;
private CameraManager cameraManager;
private Sensor lightSensor;
AmbientLightManager(Context context) {
this.context = context;
}
void start(CameraManager cameraManager) {
this.cameraManager = cameraManager;
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context);
if (FrontLightMode.readPref(sharedPrefs) == FrontLightMode.AUTO) {
SensorManager sensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
lightSensor = sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
if (lightSensor != null) {
sensorManager.registerListener(this, lightSensor, SensorManager.SENSOR_DELAY_NORMAL);
}
}
}
void stop() {
if (lightSensor != null) {
SensorManager sensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
sensorManager.unregisterListener(this);
cameraManager = null;
lightSensor = null;
}
}
@Override
public void onSensorChanged(SensorEvent sensorEvent) {
float ambientLightLux = sensorEvent.values[0];
if (cameraManager != null) {
if (ambientLightLux <= TOO_DARK_LUX) {
cameraManager.setTorch(true);
} else if (ambientLightLux >= BRIGHT_ENOUGH_LUX) {
cameraManager.setTorch(false);
}
}
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// do nothing
}
}
/*
* Copyright (C) 2010 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.zxing.client.android;
import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.AssetFileDescriptor;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.os.Vibrator;
import android.preference.PreferenceManager;
import android.util.Log;
import com.senthink.ebike_administrer_tool.R;
import java.io.Closeable;
import java.io.IOException;
/**
* Manages beeps and vibrations for {@link CaptureActivity}.
*/
final class BeepManager implements MediaPlayer.OnErrorListener, Closeable {
private static final String TAG = BeepManager.class.getSimpleName();
private static final float BEEP_VOLUME = 0.10f;
private static final long VIBRATE_DURATION = 200L;
private final Activity activity;
private MediaPlayer mediaPlayer;
private boolean playBeep;
private boolean vibrate;
BeepManager(Activity activity) {
this.activity = activity;
this.mediaPlayer = null;
updatePrefs();
}
synchronized void updatePrefs() {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
playBeep = shouldBeep(prefs, activity);
vibrate = prefs.getBoolean(PreferencesActivity.KEY_VIBRATE, false);
if (playBeep && mediaPlayer == null) {
// The volume on STREAM_SYSTEM is not adjustable, and users found it too loud,
// so we now play on the music stream.
activity.setVolumeControlStream(AudioManager.STREAM_MUSIC);
mediaPlayer = buildMediaPlayer(activity);
}
}
synchronized void playBeepSoundAndVibrate() {
if (playBeep && mediaPlayer != null) {
mediaPlayer.start();
}
if (vibrate) {
Vibrator vibrator = (Vibrator) activity.getSystemService(Context.VIBRATOR_SERVICE);
vibrator.vibrate(VIBRATE_DURATION);
}
}
private static boolean shouldBeep(SharedPreferences prefs, Context activity) {
boolean shouldPlayBeep = prefs.getBoolean(PreferencesActivity.KEY_PLAY_BEEP, true);
if (shouldPlayBeep) {
// See if sound settings overrides this
AudioManager audioService = (AudioManager) activity.getSystemService(Context.AUDIO_SERVICE);
if (audioService.getRingerMode() != AudioManager.RINGER_MODE_NORMAL) {
shouldPlayBeep = false;
}
}
return shouldPlayBeep;
}
private MediaPlayer buildMediaPlayer(Context activity) {
MediaPlayer mediaPlayer = new MediaPlayer();
try {
AssetFileDescriptor file = activity.getResources().openRawResourceFd(R.raw.beep);
try {
mediaPlayer.setDataSource(file.getFileDescriptor(), file.getStartOffset(), file.getLength());
} finally {
file.close();
}
mediaPlayer.setOnErrorListener(this);
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.setLooping(false);
mediaPlayer.setVolume(BEEP_VOLUME, BEEP_VOLUME);
mediaPlayer.prepare();
return mediaPlayer;
} catch (IOException ioe) {
Log.w(TAG, ioe);
mediaPlayer.release();
return null;
}
}
@Override
public synchronized boolean onError(MediaPlayer mp, int what, int extra) {
if (what == MediaPlayer.MEDIA_ERROR_SERVER_DIED) {
// we are finished, so put up an appropriate error toast if required and finish
activity.finish();
} else {
// possibly media player error, so release and recreate
close();
updatePrefs();
}
return true;
}
@Override
public synchronized void close() {
if (mediaPlayer != null) {
mediaPlayer.release();
mediaPlayer = null;
}
}
}
/*
* Copyright (C) 2008 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.zxing.client.android;
import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.provider.Browser;
import android.util.Log;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.DecodeHintType;
import com.google.zxing.Result;
import com.google.zxing.client.android.camera.CameraManager;
import com.senthink.ebike_administrer_tool.R;
import java.util.Collection;
import java.util.Map;
/**
* This class handles all the messaging which comprises the state machine for capture.
*
* @author dswitkin@google.com (Daniel Switkin)
*/
public final class CaptureActivityHandler extends Handler {
private static final String TAG = CaptureActivityHandler.class.getSimpleName();
private final CaptureActivity activity;
private final DecodeThread decodeThread;
private State state;
private final CameraManager cameraManager;
private enum State {
PREVIEW,
SUCCESS,
DONE
}
CaptureActivityHandler(CaptureActivity activity,
Collection<BarcodeFormat> decodeFormats,
Map<DecodeHintType,?> baseHints,
String characterSet,
CameraManager cameraManager) {
this.activity = activity;
decodeThread = new DecodeThread(activity, decodeFormats, baseHints, characterSet,
new ViewfinderResultPointCallback(activity.getViewfinderView()));
decodeThread.start();
state = State.SUCCESS;
// Start ourselves capturing previews and decoding.
this.cameraManager = cameraManager;
cameraManager.startPreview();
restartPreviewAndDecode();
}
@Override
public void handleMessage(Message message) {
switch (message.what) {
case R.id.restart_preview:
restartPreviewAndDecode();
break;
case R.id.decode_succeeded:
state = State.SUCCESS;
Bundle bundle = message.getData();
Bitmap barcode = null;
float scaleFactor = 1.0f;
if (bundle != null) {
byte[] compressedBitmap = bundle.getByteArray(DecodeThread.BARCODE_BITMAP);
if (compressedBitmap != null) {
barcode = BitmapFactory.decodeByteArray(compressedBitmap, 0, compressedBitmap.length, null);
// Mutable copy:
barcode = barcode.copy(Bitmap.Config.ARGB_8888, true);
}
scaleFactor = bundle.getFloat(DecodeThread.BARCODE_SCALED_FACTOR);
}
activity.handleDecode((Result) message.obj, barcode, scaleFactor);
break;
case R.id.decode_failed:
// We're decoding as fast as possible, so when one decode fails, start another.
state = State.PREVIEW;
cameraManager.requestPreviewFrame(decodeThread.getHandler(), R.id.decode);
break;
case R.id.return_scan_result:
activity.setResult(Activity.RESULT_OK, (Intent) message.obj);
activity.finish();
break;
case R.id.launch_product_query:
String url = (String) message.obj;
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
intent.setData(Uri.parse(url));
ResolveInfo resolveInfo =
activity.getPackageManager().resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);
String browserPackageName = null;
if (resolveInfo != null && resolveInfo.activityInfo != null) {
browserPackageName = resolveInfo.activityInfo.packageName;
Log.d(TAG, "Using browser in package " + browserPackageName);
}
// Needed for default Android browser / Chrome only apparently
if ("com.android.browser".equals(browserPackageName) || "com.android.chrome".equals(browserPackageName)) {
intent.setPackage(browserPackageName);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra(Browser.EXTRA_APPLICATION_ID, browserPackageName);
}
try {
activity.startActivity(intent);
} catch (ActivityNotFoundException ignored) {
Log.w(TAG, "Can't find anything to handle VIEW of URI " + url);
}
break;
}
}
public void quitSynchronously() {
state = State.DONE;
cameraManager.stopPreview();
Message quit = Message.obtain(decodeThread.getHandler(), R.id.quit);
quit.sendToTarget();
try {
// Wait at most half a second; should be enough time, and onPause() will timeout quickly
decodeThread.join(500L);
} catch (InterruptedException e) {
// continue
}
// Be absolutely sure we don't send any queued up messages
removeMessages(R.id.decode_succeeded);
removeMessages(R.id.decode_failed);
}
private void restartPreviewAndDecode() {
if (state == State.SUCCESS) {
state = State.PREVIEW;
cameraManager.requestPreviewFrame(decodeThread.getHandler(), R.id.decode);
activity.drawViewfinder();
}
}
}
/*
* Copyright (C) 2008 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.zxing.client.android;
import android.provider.ContactsContract;
/**
* The set of constants to use when sending Barcode Scanner an Intent which requests a barcode
* to be encoded.
*
* @author dswitkin@google.com (Daniel Switkin)
*/
public final class Contents {
private Contents() {
}
public static final class Type {
/**
* Plain text. Use Intent.putExtra(DATA, string). This can be used for URLs too, but string
* must include "http://" or "https://".
*/
public static final String TEXT = "TEXT_TYPE";
/**
* An email type. Use Intent.putExtra(DATA, string) where string is the email address.
*/
public static final String EMAIL = "EMAIL_TYPE";
/**
* Use Intent.putExtra(DATA, string) where string is the phone number to call.
*/
public static final String PHONE = "PHONE_TYPE";
/**
* An SMS type. Use Intent.putExtra(DATA, string) where string is the number to SMS.
*/
public static final String SMS = "SMS_TYPE";
/**
* A contact. Send a request to encode it as follows:
* {@code
* import android.provider.Contacts;
*
* Intent intent = new Intent(Intents.Encode.ACTION);
* intent.putExtra(Intents.Encode.TYPE, CONTACT);
* Bundle bundle = new Bundle();
* bundle.putString(ContactsContract.Intents.Insert.NAME, "Jenny");
* bundle.putString(ContactsContract.Intents.Insert.PHONE, "8675309");
* bundle.putString(ContactsContract.Intents.Insert.EMAIL, "jenny@the80s.com");
* bundle.putString(ContactsContract.Intents.Insert.POSTAL, "123 Fake St. San Francisco, CA 94102");
* intent.putExtra(Intents.Encode.DATA, bundle);
* }
*/
public static final String CONTACT = "CONTACT_TYPE";
/**
* A geographic location. Use as follows:
* Bundle bundle = new Bundle();
* bundle.putFloat("LAT", latitude);
* bundle.putFloat("LONG", longitude);
* intent.putExtra(Intents.Encode.DATA, bundle);
*/
public static final String LOCATION = "LOCATION_TYPE";
private Type() {
}
}
public static final String URL_KEY = "URL_KEY";
public static final String NOTE_KEY = "NOTE_KEY";
/**
* When using Type.CONTACT, these arrays provide the keys for adding or retrieving multiple
* phone numbers and addresses.
*/
public static final String[] PHONE_KEYS = {
ContactsContract.Intents.Insert.PHONE,
ContactsContract.Intents.Insert.SECONDARY_PHONE,
ContactsContract.Intents.Insert.TERTIARY_PHONE
};
public static final String[] PHONE_TYPE_KEYS = {
ContactsContract.Intents.Insert.PHONE_TYPE,
ContactsContract.Intents.Insert.SECONDARY_PHONE_TYPE,
ContactsContract.Intents.Insert.TERTIARY_PHONE_TYPE
};
public static final String[] EMAIL_KEYS = {
ContactsContract.Intents.Insert.EMAIL,
ContactsContract.Intents.Insert.SECONDARY_EMAIL,
ContactsContract.Intents.Insert.TERTIARY_EMAIL
};
public static final String[] EMAIL_TYPE_KEYS = {
ContactsContract.Intents.Insert.EMAIL_TYPE,
ContactsContract.Intents.Insert.SECONDARY_EMAIL_TYPE,
ContactsContract.Intents.Insert.TERTIARY_EMAIL_TYPE
};
}
/*
* Copyright (C) 2010 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.zxing.client.android;
import android.content.Intent;
import android.net.Uri;
import com.google.zxing.BarcodeFormat;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;
final class DecodeFormatManager {
private static final Pattern COMMA_PATTERN = Pattern.compile(",");
static final Set<BarcodeFormat> PRODUCT_FORMATS;
static final Set<BarcodeFormat> INDUSTRIAL_FORMATS;
private static final Set<BarcodeFormat> ONE_D_FORMATS;
static final Set<BarcodeFormat> QR_CODE_FORMATS = EnumSet.of(BarcodeFormat.QR_CODE);
static final Set<BarcodeFormat> DATA_MATRIX_FORMATS = EnumSet.of(BarcodeFormat.DATA_MATRIX);
static final Set<BarcodeFormat> AZTEC_FORMATS = EnumSet.of(BarcodeFormat.AZTEC);
static final Set<BarcodeFormat> PDF417_FORMATS = EnumSet.of(BarcodeFormat.PDF_417);
static {
PRODUCT_FORMATS = EnumSet.of(BarcodeFormat.UPC_A,
BarcodeFormat.UPC_E,
BarcodeFormat.EAN_13,
BarcodeFormat.EAN_8,
BarcodeFormat.RSS_14,
BarcodeFormat.RSS_EXPANDED);
INDUSTRIAL_FORMATS = EnumSet.of(BarcodeFormat.CODE_39,
BarcodeFormat.CODE_93,
BarcodeFormat.CODE_128,
BarcodeFormat.ITF,
BarcodeFormat.CODABAR);
ONE_D_FORMATS = EnumSet.copyOf(PRODUCT_FORMATS);
ONE_D_FORMATS.addAll(INDUSTRIAL_FORMATS);
}
private static final Map<String,Set<BarcodeFormat>> FORMATS_FOR_MODE;
static {
FORMATS_FOR_MODE = new HashMap<String, Set<BarcodeFormat>>();
FORMATS_FOR_MODE.put(Intents.Scan.ONE_D_MODE, ONE_D_FORMATS);
FORMATS_FOR_MODE.put(Intents.Scan.PRODUCT_MODE, PRODUCT_FORMATS);
FORMATS_FOR_MODE.put(Intents.Scan.QR_CODE_MODE, QR_CODE_FORMATS);
FORMATS_FOR_MODE.put(Intents.Scan.DATA_MATRIX_MODE, DATA_MATRIX_FORMATS);
FORMATS_FOR_MODE.put(Intents.Scan.AZTEC_MODE, AZTEC_FORMATS);
FORMATS_FOR_MODE.put(Intents.Scan.PDF417_MODE, PDF417_FORMATS);
}
private DecodeFormatManager() {}
static Set<BarcodeFormat> parseDecodeFormats(Intent intent) {
Iterable<String> scanFormats = null;
CharSequence scanFormatsString = intent.getStringExtra(Intents.Scan.FORMATS);
if (scanFormatsString != null) {
scanFormats = Arrays.asList(COMMA_PATTERN.split(scanFormatsString));
}
return parseDecodeFormats(scanFormats, intent.getStringExtra(Intents.Scan.MODE));
}
static Set<BarcodeFormat> parseDecodeFormats(Uri inputUri) {
List<String> formats = inputUri.getQueryParameters(Intents.Scan.FORMATS);
if (formats != null && formats.size() == 1 && formats.get(0) != null){
formats = Arrays.asList(COMMA_PATTERN.split(formats.get(0)));
}
return parseDecodeFormats(formats, inputUri.getQueryParameter(Intents.Scan.MODE));
}
private static Set<BarcodeFormat> parseDecodeFormats(Iterable<String> scanFormats, String decodeMode) {
if (scanFormats != null) {
Set<BarcodeFormat> formats = EnumSet.noneOf(BarcodeFormat.class);
try {
for (String format : scanFormats) {
formats.add(BarcodeFormat.valueOf(format));
}
return formats;
} catch (IllegalArgumentException iae) {
// ignore it then
}
}
if (decodeMode != null) {
return FORMATS_FOR_MODE.get(decodeMode);
}
return null;
}
}
/*
* Copyright (C) 2010 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.zxing.client.android;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.DecodeHintType;
import com.google.zxing.MultiFormatReader;
import com.google.zxing.PlanarYUVLuminanceSource;
import com.google.zxing.ReaderException;
import com.google.zxing.Result;
import com.google.zxing.common.HybridBinarizer;
import com.senthink.ebike_administrer_tool.R;
import java.io.ByteArrayOutputStream;
import java.util.Map;
final class DecodeHandler extends Handler {
private static final String TAG = DecodeHandler.class.getSimpleName();
private final CaptureActivity activity;
private final MultiFormatReader multiFormatReader;
private boolean running = true;
DecodeHandler(CaptureActivity activity, Map<DecodeHintType,Object> hints) {
multiFormatReader = new MultiFormatReader();
multiFormatReader.setHints(hints);
this.activity = activity;
}
@Override
public void handleMessage(Message message) {
if (!running) {
return;
}
switch (message.what) {
case R.id.decode:
decode((byte[]) message.obj, message.arg1, message.arg2);
break;
case R.id.quit:
running = false;
Looper.myLooper().quit();
break;
}
}
/**
* Decode the data within the viewfinder rectangle, and time how long it took. For efficiency,
* reuse the same reader objects from one decode to the next.
*
* @param data The YUV preview frame.
* @param width The width of the preview frame.
* @param height The height of the preview frame.
*/
private void decode(byte[] data, int width, int height) {
long start = System.currentTimeMillis();
Result rawResult = null;
// PlanarYUVLuminanceSource source = activity.getCameraManager().buildLuminanceSource(data, width, height);
byte[] rotatedData = new byte[data.length];
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++)
rotatedData[x * height + height - y - 1] = data[x + y * width];
}
int tmp = width;
width = height;
height = tmp;
PlanarYUVLuminanceSource source = activity.getCameraManager().buildLuminanceSource(rotatedData, width, height);
if (source != null) {
BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
try {
rawResult = multiFormatReader.decodeWithState(bitmap);
} catch (ReaderException re) {
// continue
} finally {
multiFormatReader.reset();
}
}
Handler handler = activity.getHandler();
if (rawResult != null) {
// Don't log the barcode contents for security.
long end = System.currentTimeMillis();
Log.d(TAG, "Found barcode in " + (end - start) + " ms");
if (handler != null) {
Message message = Message.obtain(handler, R.id.decode_succeeded, rawResult);
Bundle bundle = new Bundle();
bundleThumbnail(source, bundle);
message.setData(bundle);
message.sendToTarget();
}
} else {
if (handler != null) {
Message message = Message.obtain(handler, R.id.decode_failed);
message.sendToTarget();
}
}
}
private static void bundleThumbnail(PlanarYUVLuminanceSource source, Bundle bundle) {
int[] pixels = source.renderThumbnail();
int width = source.getThumbnailWidth();
int height = source.getThumbnailHeight();
Bitmap bitmap = Bitmap.createBitmap(pixels, 0, width, width, height, Bitmap.Config.ARGB_8888);
ByteArrayOutputStream out = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 50, out);
bundle.putByteArray(DecodeThread.BARCODE_BITMAP, out.toByteArray());
bundle.putFloat(DecodeThread.BARCODE_SCALED_FACTOR, (float) width / source.getWidth());
}
}
/*
* Copyright (C) 2013 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.zxing.client.android;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import com.google.zxing.DecodeHintType;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Pattern;
/**
* @author Lachezar Dobrev
*/
final class DecodeHintManager {
private static final String TAG = DecodeHintManager.class.getSimpleName();
// This pattern is used in decoding integer arrays.
private static final Pattern COMMA = Pattern.compile(",");
private DecodeHintManager() {}
/**
* <p>Split a query string into a list of name-value pairs.</p>
*
* <p>This is an alternative to the {@link Uri#getQueryParameterNames()} and
* {@link Uri#getQueryParameters(String)}, which are quirky and not suitable
* for exist-only Uri parameters.</p>
*
* <p>This method ignores multiple parameters with the same name and returns the
* first one only. This is technically incorrect, but should be acceptable due
* to the method of processing Hints: no multiple values for a hint.</p>
*
* @param query query to split
* @return name-value pairs
*/
private static Map<String,String> splitQuery(String query) {
Map<String,String> map = new HashMap<String, String>();
int pos = 0;
while (pos < query.length()) {
if (query.charAt(pos) == '&') {
// Skip consecutive ampersand separators.
pos ++;
continue;
}
int amp = query.indexOf('&', pos);
int equ = query.indexOf('=', pos);
if (amp < 0) {
// This is the last element in the query, no more ampersand elements.
String name;
String text;
if (equ < 0) {
// No equal sign
name = query.substring(pos);
name = name.replace('+', ' '); // Preemptively decode +
name = Uri.decode(name);
text = "";
} else {
// Split name and text.
name = query.substring(pos, equ);
name = name.replace('+', ' '); // Preemptively decode +
name = Uri.decode(name);
text = query.substring(equ + 1);
text = text.replace('+', ' '); // Preemptively decode +
text = Uri.decode(text);
}
if (!map.containsKey(name)) {
map.put(name, text);
}
break;
}
if (equ < 0 || equ > amp) {
// No equal sign until the &: this is a simple parameter with no value.
String name = query.substring(pos, amp);
name = name.replace('+', ' '); // Preemptively decode +
name = Uri.decode(name);
if (!map.containsKey(name)) {
map.put(name, "");
}
pos = amp + 1;
continue;
}
String name = query.substring(pos, equ);
name = name.replace('+', ' '); // Preemptively decode +
name = Uri.decode(name);
String text = query.substring(equ+1, amp);
text = text.replace('+', ' '); // Preemptively decode +
text = Uri.decode(text);
if (!map.containsKey(name)) {
map.put(name, text);
}
pos = amp + 1;
}
return map;
}
static Map<DecodeHintType,?> parseDecodeHints(Uri inputUri) {
String query = inputUri.getEncodedQuery();
if (query == null || query.isEmpty()) {
return null;
}
// Extract parameters
Map<String, String> parameters = splitQuery(query);
Map<DecodeHintType, Object> hints = new EnumMap<DecodeHintType, Object>(DecodeHintType.class);
for (DecodeHintType hintType: DecodeHintType.values()) {
if (hintType == DecodeHintType.CHARACTER_SET ||
hintType == DecodeHintType.NEED_RESULT_POINT_CALLBACK ||
hintType == DecodeHintType.POSSIBLE_FORMATS) {
continue; // This hint is specified in another way
}
String parameterName = hintType.name();
String parameterText = parameters.get(parameterName);
if (parameterText == null) {
continue;
}
if (hintType.getValueType().equals(Object.class)) {
// This is an unspecified type of hint content. Use the value as is.
// TODO: Can we make a different assumption on this?
hints.put(hintType, parameterText);
continue;
}
if (hintType.getValueType().equals(Void.class)) {
// Void hints are just flags: use the constant specified by DecodeHintType
hints.put(hintType, Boolean.TRUE);
continue;
}
if (hintType.getValueType().equals(String.class)) {
// A string hint: use the decoded value.
hints.put(hintType, parameterText);
continue;
}
if (hintType.getValueType().equals(Boolean.class)) {
// A boolean hint: a few values for false, everything else is true.
// An empty parameter is simply a flag-style parameter, assuming true
if (parameterText.isEmpty()) {
hints.put(hintType, Boolean.TRUE);
} else if ("0".equals(parameterText) ||
"false".equalsIgnoreCase(parameterText) ||
"no".equalsIgnoreCase(parameterText)) {
hints.put(hintType, Boolean.FALSE);
} else {
hints.put(hintType, Boolean.TRUE);
}
continue;
}
if (hintType.getValueType().equals(int[].class)) {
// An integer array. Used to specify valid lengths.
// Strip a trailing comma as in Java style array initialisers.
if (!parameterText.isEmpty() && parameterText.charAt(parameterText.length() - 1) == ',') {
parameterText = parameterText.substring(0, parameterText.length() - 1);
}
String[] values = COMMA.split(parameterText);
int[] array = new int[values.length];
for (int i = 0; i < values.length; i++) {
try {
array[i] = Integer.parseInt(values[i]);
} catch (NumberFormatException ignored) {
Log.w(TAG, "Skipping array of integers hint " + hintType + " due to invalid numeric value: '" + values[i] + '\'');
array = null;
break;
}
}
if (array != null) {
hints.put(hintType, array);
}
continue;
}
Log.w(TAG, "Unsupported hint type '" + hintType + "' of type " + hintType.getValueType());
}
Log.i(TAG, "Hints from the URI: " + hints);
return hints;
}
static Map<DecodeHintType, Object> parseDecodeHints(Intent intent) {
Bundle extras = intent.getExtras();
if (extras == null || extras.isEmpty()) {
return null;
}
Map<DecodeHintType,Object> hints = new EnumMap<DecodeHintType, Object>(DecodeHintType.class);
for (DecodeHintType hintType: DecodeHintType.values()) {
if (hintType == DecodeHintType.CHARACTER_SET ||
hintType == DecodeHintType.NEED_RESULT_POINT_CALLBACK ||
hintType == DecodeHintType.POSSIBLE_FORMATS) {
continue; // This hint is specified in another way
}
String hintName = hintType.name();
if (extras.containsKey(hintName)) {
if (hintType.getValueType().equals(Void.class)) {
// Void hints are just flags: use the constant specified by the DecodeHintType
hints.put(hintType, Boolean.TRUE);
} else {
Object hintData = extras.get(hintName);
if (hintType.getValueType().isInstance(hintData)) {
hints.put(hintType, hintData);
} else {
Log.w(TAG, "Ignoring hint " + hintType + " because it is not assignable from " + hintData);
}
}
}
}
Log.i(TAG, "Hints from the Intent: " + hints);
return hints;
}
}
/*
* Copyright (C) 2008 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.zxing.client.android;
import android.content.SharedPreferences;
import android.os.Handler;
import android.os.Looper;
import android.preference.PreferenceManager;
import android.util.Log;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.DecodeHintType;
import com.google.zxing.ResultPointCallback;
import java.util.Collection;
import java.util.EnumMap;
import java.util.EnumSet;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
/**
* This thread does all the heavy lifting of decoding the images.
*
* @author dswitkin@google.com (Daniel Switkin)
*/
final class DecodeThread extends Thread {
public static final String BARCODE_BITMAP = "barcode_bitmap";
public static final String BARCODE_SCALED_FACTOR = "barcode_scaled_factor";
private final CaptureActivity activity;
private final Map<DecodeHintType,Object> hints;
private Handler handler;
private final CountDownLatch handlerInitLatch;
DecodeThread(CaptureActivity activity,
Collection<BarcodeFormat> decodeFormats,
Map<DecodeHintType,?> baseHints,
String characterSet,
ResultPointCallback resultPointCallback) {
this.activity = activity;
handlerInitLatch = new CountDownLatch(1);
hints = new EnumMap<DecodeHintType, Object>(DecodeHintType.class);
if (baseHints != null) {
hints.putAll(baseHints);
}
// The prefs can't change while the thread is running, so pick them up once here.
if (decodeFormats == null || decodeFormats.isEmpty()) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
decodeFormats = EnumSet.noneOf(BarcodeFormat.class);
if (prefs.getBoolean(PreferencesActivity.KEY_DECODE_1D_PRODUCT, true)) {
decodeFormats.addAll(DecodeFormatManager.PRODUCT_FORMATS);
}
if (prefs.getBoolean(PreferencesActivity.KEY_DECODE_1D_INDUSTRIAL, true)) {
decodeFormats.addAll(DecodeFormatManager.INDUSTRIAL_FORMATS);
}
if (prefs.getBoolean(PreferencesActivity.KEY_DECODE_QR, true)) {
decodeFormats.addAll(DecodeFormatManager.QR_CODE_FORMATS);
}
if (prefs.getBoolean(PreferencesActivity.KEY_DECODE_DATA_MATRIX, true)) {
decodeFormats.addAll(DecodeFormatManager.DATA_MATRIX_FORMATS);
}
if (prefs.getBoolean(PreferencesActivity.KEY_DECODE_AZTEC, false)) {
decodeFormats.addAll(DecodeFormatManager.AZTEC_FORMATS);
}
if (prefs.getBoolean(PreferencesActivity.KEY_DECODE_PDF417, false)) {
decodeFormats.addAll(DecodeFormatManager.PDF417_FORMATS);
}
}
hints.put(DecodeHintType.POSSIBLE_FORMATS, decodeFormats);
if (characterSet != null) {
hints.put(DecodeHintType.CHARACTER_SET, characterSet);
}
hints.put(DecodeHintType.NEED_RESULT_POINT_CALLBACK, resultPointCallback);
Log.i("DecodeThread", "Hints: " + hints);
}
Handler getHandler() {
try {
handlerInitLatch.await();
} catch (InterruptedException ie) {
// continue?
}
return handler;
}
@Override
public void run() {
Looper.prepare();
handler = new DecodeHandler(activity, hints);
handlerInitLatch.countDown();
Looper.loop();
}
}
/*
* Copyright (C) 2010 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.zxing.client.android;
import android.app.Activity;
import android.content.DialogInterface;
/**
* Simple listener used to exit the app in a few cases.
*
* @author Sean Owen
*/
public final class FinishListener implements DialogInterface.OnClickListener, DialogInterface.OnCancelListener {
private final Activity activityToFinish;
public FinishListener(Activity activityToFinish) {
this.activityToFinish = activityToFinish;
}
@Override
public void onCancel(DialogInterface dialogInterface) {
run();
}
@Override
public void onClick(DialogInterface dialogInterface, int i) {
run();
}
private void run() {
activityToFinish.finish();
}
}
/*
* Copyright 2011 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.zxing.client.android;
import android.util.Log;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLConnection;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
/**
* Utility methods for retrieving content over HTTP using the more-supported {@code java.net} classes
* in Android.
*/
public final class HttpHelper {
private static final String TAG = HttpHelper.class.getSimpleName();
private static final Collection<String> REDIRECTOR_DOMAINS = new HashSet<String>(Arrays.asList(
"amzn.to", "bit.ly", "bitly.com", "fb.me", "goo.gl", "is.gd", "j.mp", "lnkd.in", "ow.ly",
"R.BEETAGG.COM", "r.beetagg.com", "SCN.BY", "su.pr", "t.co", "tinyurl.com", "tr.im"
));
private HttpHelper() {
}
public enum ContentType {
/** HTML-like content type, including HTML, XHTML, etc. */
HTML,
/** JSON content */
JSON,
/** XML */
XML,
/** Plain text content */
TEXT,
}
/**
* Downloads the entire resource instead of part.
*
* @param uri URI to retrieve
* @param type expected text-like MIME type of that content
* @return content as a {@code String}
* @throws IOException if the content can't be retrieved because of a bad URI, network problem, etc.
* @see #downloadViaHttp(String, HttpHelper.ContentType, int)
*/
public static CharSequence downloadViaHttp(String uri, ContentType type) throws IOException {
return downloadViaHttp(uri, type, Integer.MAX_VALUE);
}
/**
* @param uri URI to retrieve
* @param type expected text-like MIME type of that content
* @param maxChars approximate maximum characters to read from the source
* @return content as a {@code String}
* @throws IOException if the content can't be retrieved because of a bad URI, network problem, etc.
*/
public static CharSequence downloadViaHttp(String uri, ContentType type, int maxChars) throws IOException {
String contentTypes;
switch (type) {
case HTML:
contentTypes = "application/xhtml+xml,text/html,text/*,*/*";
break;
case JSON:
contentTypes = "application/json,text/*,*/*";
break;
case XML:
contentTypes = "application/xml,text/*,*/*";
break;
case TEXT:
default:
contentTypes = "text/*,*/*";
}
return downloadViaHttp(uri, contentTypes, maxChars);
}
private static CharSequence downloadViaHttp(String uri, String contentTypes, int maxChars) throws IOException {
int redirects = 0;
while (redirects < 5) {
URL url = new URL(uri);
HttpURLConnection connection = safelyOpenConnection(url);
connection.setInstanceFollowRedirects(true); // Won't work HTTP -> HTTPS or vice versa
connection.setRequestProperty("Accept", contentTypes);
connection.setRequestProperty("Accept-Charset", "utf-8,*");
connection.setRequestProperty("User-Agent", "ZXing (Android)");
try {
int responseCode = safelyConnect(connection);
switch (responseCode) {
case HttpURLConnection.HTTP_OK:
return consume(connection, maxChars);
case HttpURLConnection.HTTP_MOVED_TEMP:
String location = connection.getHeaderField("Location");
if (location != null) {
uri = location;
redirects++;
continue;
}
throw new IOException("No Location");
default:
throw new IOException("Bad HTTP response: " + responseCode);
}
} finally {
connection.disconnect();
}
}
throw new IOException("Too many redirects");
}
private static String getEncoding(URLConnection connection) {
String contentTypeHeader = connection.getHeaderField("Content-Type");
if (contentTypeHeader != null) {
int charsetStart = contentTypeHeader.indexOf("charset=");
if (charsetStart >= 0) {
return contentTypeHeader.substring(charsetStart + "charset=".length());
}
}
return "UTF-8";
}
private static CharSequence consume(URLConnection connection, int maxChars) throws IOException {
String encoding = getEncoding(connection);
StringBuilder out = new StringBuilder();
Reader in = null;
try {
in = new InputStreamReader(connection.getInputStream(), encoding);
char[] buffer = new char[1024];
int charsRead;
while (out.length() < maxChars && (charsRead = in.read(buffer)) > 0) {
out.append(buffer, 0, charsRead);
}
} finally {
if (in != null) {
try {
in.close();
} catch (IOException ioe) {
// continue
}catch (NullPointerException ioe) {
// continue
}
}
}
return out;
}
public static URI unredirect(URI uri) throws IOException {
if (!REDIRECTOR_DOMAINS.contains(uri.getHost())) {
return uri;
}
URL url = uri.toURL();
HttpURLConnection connection = safelyOpenConnection(url);
connection.setInstanceFollowRedirects(false);
connection.setDoInput(false);
connection.setRequestMethod("HEAD");
connection.setRequestProperty("User-Agent", "ZXing (Android)");
try {
int responseCode = safelyConnect(connection);
switch (responseCode) {
case HttpURLConnection.HTTP_MULT_CHOICE:
case HttpURLConnection.HTTP_MOVED_PERM:
case HttpURLConnection.HTTP_MOVED_TEMP:
case HttpURLConnection.HTTP_SEE_OTHER:
case 307: // No constant for 307 Temporary Redirect ?
String location = connection.getHeaderField("Location");
if (location != null) {
try {
return new URI(location);
} catch (URISyntaxException e) {
// nevermind
}
}
}
return uri;
} finally {
connection.disconnect();
}
}
private static HttpURLConnection safelyOpenConnection(URL url) throws IOException {
URLConnection conn;
try {
conn = url.openConnection();
} catch (NullPointerException npe) {
// Another strange bug in Android?
Log.w(TAG, "Bad URI? " + url);
throw new IOException(npe);
}
if (!(conn instanceof HttpURLConnection)) {
throw new IOException();
}
return (HttpURLConnection) conn;
}
private static int safelyConnect(HttpURLConnection connection) throws IOException {
try {
connection.connect();
} catch (NullPointerException e) {
// this is an Android bug: http://code.google.com/p/android/issues/detail?id=16895
throw new IOException(e);
}catch(IllegalArgumentException e) {
// this is an Android bug: http://code.google.com/p/android/issues/detail?id=16895
throw new IOException(e);
}catch(IndexOutOfBoundsException e) {
// this is an Android bug: http://code.google.com/p/android/issues/detail?id=16895
throw new IOException(e);
}catch(SecurityException e) {
// this is an Android bug: http://code.google.com/p/android/issues/detail?id=16895
throw new IOException(e);
}
try {
return connection.getResponseCode();
} catch (NullPointerException e) {
// this is maybe this Android bug: http://code.google.com/p/android/issues/detail?id=15554
throw new IOException(e);
}catch (StringIndexOutOfBoundsException e) {
// this is maybe this Android bug: http://code.google.com/p/android/issues/detail?id=15554
throw new IOException(e);
}catch (IllegalArgumentException e) {
// this is maybe this Android bug: http://code.google.com/p/android/issues/detail?id=15554
throw new IOException(e);
}
}
}
/*
* Copyright (C) 2010 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.zxing.client.android;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.AsyncTask;
import android.os.BatteryManager;
import android.util.Log;
/**
* Finishes an activity after a period of inactivity if the device is on battery power.
*/
final class InactivityTimer {
private static final String TAG = InactivityTimer.class.getSimpleName();
private static final long INACTIVITY_DELAY_MS = 5 * 60 * 1000L;
private final Activity activity;
private final BroadcastReceiver powerStatusReceiver;
private boolean registered;
private AsyncTask<Object,Object,Object> inactivityTask;
InactivityTimer(Activity activity) {
this.activity = activity;
powerStatusReceiver = new PowerStatusReceiver();
registered = false;
onActivity();
}
synchronized void onActivity() {
cancel();
inactivityTask = new InactivityAsyncTask();
inactivityTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
public synchronized void onPause() {
cancel();
if (registered) {
activity.unregisterReceiver(powerStatusReceiver);
registered = false;
} else {
Log.w(TAG, "PowerStatusReceiver was never registered?");
}
}
public synchronized void onResume() {
if (registered) {
Log.w(TAG, "PowerStatusReceiver was already registered?");
} else {
activity.registerReceiver(powerStatusReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
registered = true;
}
onActivity();
}
private synchronized void cancel() {
AsyncTask<?,?,?> task = inactivityTask;
if (task != null) {
task.cancel(true);
inactivityTask = null;
}
}
void shutdown() {
cancel();
}
private final class PowerStatusReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent){
if (Intent.ACTION_BATTERY_CHANGED.equals(intent.getAction())) {
// 0 indicates that we're on battery
boolean onBatteryNow = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1) <= 0;
if (onBatteryNow) {
InactivityTimer.this.onActivity();
} else {
InactivityTimer.this.cancel();
}
}
}
}
private final class InactivityAsyncTask extends AsyncTask<Object,Object,Object> {
@Override
protected Object doInBackground(Object... objects) {
try {
Thread.sleep(INACTIVITY_DELAY_MS);
Log.i(TAG, "Finishing activity due to inactivity");
activity.finish();
} catch (InterruptedException e) {
// continue without killing
}
return null;
}
}
}
/*
* Copyright (C) 2011 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.zxing.client.android;
enum IntentSource {
NATIVE_APP_INTENT,
PRODUCT_SEARCH_LINK,
ZXING_LINK,
NONE
}
/*
* Copyright (C) 2008 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.zxing.client.android;
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
/**
* Handles any locale-specific logic for the client.
*
* @author Sean Owen
*/
public final class LocaleManager {
private static final String DEFAULT_TLD = "com";
private static final String DEFAULT_COUNTRY = "US";
private static final String DEFAULT_LANGUAGE = "en";
/**
* Locales (well, countries) where Google web search is available.
* These should be kept in sync with our translations.
*/
private static final Map<String,String> GOOGLE_COUNTRY_TLD;
static {
GOOGLE_COUNTRY_TLD = new HashMap<String, String>();
GOOGLE_COUNTRY_TLD.put("AR", "com.ar"); // ARGENTINA
GOOGLE_COUNTRY_TLD.put("AU", "com.au"); // AUSTRALIA
GOOGLE_COUNTRY_TLD.put("BR", "com.br"); // BRAZIL
GOOGLE_COUNTRY_TLD.put("BG", "bg"); // BULGARIA
GOOGLE_COUNTRY_TLD.put(Locale.CANADA.getCountry(), "ca");
GOOGLE_COUNTRY_TLD.put(Locale.CHINA.getCountry(), "cn");
GOOGLE_COUNTRY_TLD.put("CZ", "cz"); // CZECH REPUBLIC
GOOGLE_COUNTRY_TLD.put("DK", "dk"); // DENMARK
GOOGLE_COUNTRY_TLD.put("FI", "fi"); // FINLAND
GOOGLE_COUNTRY_TLD.put(Locale.FRANCE.getCountry(), "fr");
GOOGLE_COUNTRY_TLD.put(Locale.GERMANY.getCountry(), "de");
GOOGLE_COUNTRY_TLD.put("GR", "gr"); // GREECE
GOOGLE_COUNTRY_TLD.put("HU", "hu"); // HUNGARY
GOOGLE_COUNTRY_TLD.put("ID", "co.id"); // INDONESIA
GOOGLE_COUNTRY_TLD.put("IL", "co.il"); // ISRAEL
GOOGLE_COUNTRY_TLD.put(Locale.ITALY.getCountry(), "it");
GOOGLE_COUNTRY_TLD.put(Locale.JAPAN.getCountry(), "co.jp");
GOOGLE_COUNTRY_TLD.put(Locale.KOREA.getCountry(), "co.kr");
GOOGLE_COUNTRY_TLD.put("NL", "nl"); // NETHERLANDS
GOOGLE_COUNTRY_TLD.put("PL", "pl"); // POLAND
GOOGLE_COUNTRY_TLD.put("PT", "pt"); // PORTUGAL
GOOGLE_COUNTRY_TLD.put("RO", "ro"); // ROMANIA
GOOGLE_COUNTRY_TLD.put("RU", "ru"); // RUSSIA
GOOGLE_COUNTRY_TLD.put("SK", "sk"); // SLOVAK REPUBLIC
GOOGLE_COUNTRY_TLD.put("SI", "si"); // SLOVENIA
GOOGLE_COUNTRY_TLD.put("ES", "es"); // SPAIN
GOOGLE_COUNTRY_TLD.put("SE", "se"); // SWEDEN
GOOGLE_COUNTRY_TLD.put("CH", "ch"); // SWITZERLAND
GOOGLE_COUNTRY_TLD.put(Locale.TAIWAN.getCountry(), "tw");
GOOGLE_COUNTRY_TLD.put("TR", "com.tr"); // TURKEY
GOOGLE_COUNTRY_TLD.put("UA", "com.ua"); // UKRAINE
GOOGLE_COUNTRY_TLD.put(Locale.UK.getCountry(), "co.uk");
GOOGLE_COUNTRY_TLD.put(Locale.US.getCountry(), "com");
}
/**
* Google Product Search for mobile is available in fewer countries than web search. See here:
* http://support.google.com/merchants/bin/answer.py?hl=en-GB&answer=160619
*/
private static final Map<String,String> GOOGLE_PRODUCT_SEARCH_COUNTRY_TLD;
static {
GOOGLE_PRODUCT_SEARCH_COUNTRY_TLD = new HashMap<String, String>();
GOOGLE_PRODUCT_SEARCH_COUNTRY_TLD.put("AU", "com.au"); // AUSTRALIA
//GOOGLE_PRODUCT_SEARCH_COUNTRY_TLD.put(Locale.CHINA.getCountry(), "cn");
GOOGLE_PRODUCT_SEARCH_COUNTRY_TLD.put(Locale.FRANCE.getCountry(), "fr");
GOOGLE_PRODUCT_SEARCH_COUNTRY_TLD.put(Locale.GERMANY.getCountry(), "de");
GOOGLE_PRODUCT_SEARCH_COUNTRY_TLD.put(Locale.ITALY.getCountry(), "it");
GOOGLE_PRODUCT_SEARCH_COUNTRY_TLD.put(Locale.JAPAN.getCountry(), "co.jp");
GOOGLE_PRODUCT_SEARCH_COUNTRY_TLD.put("NL", "nl"); // NETHERLANDS
GOOGLE_PRODUCT_SEARCH_COUNTRY_TLD.put("ES", "es"); // SPAIN
GOOGLE_PRODUCT_SEARCH_COUNTRY_TLD.put("CH", "ch"); // SWITZERLAND
GOOGLE_PRODUCT_SEARCH_COUNTRY_TLD.put(Locale.UK.getCountry(), "co.uk");
GOOGLE_PRODUCT_SEARCH_COUNTRY_TLD.put(Locale.US.getCountry(), "com");
}
/**
* Book search is offered everywhere that web search is available.
*/
private static final Map<String,String> GOOGLE_BOOK_SEARCH_COUNTRY_TLD = GOOGLE_COUNTRY_TLD;
private static final Collection<String> TRANSLATED_HELP_ASSET_LANGUAGES =
Arrays.asList("de", "en", "es", "fr", "it", "ja", "ko", "nl", "pt", "ru", "uk", "zh-rCN", "zh-rTW", "zh-rHK");
private LocaleManager() {}
/**
* @param context application's {@link Context}
* @return country-specific TLD suffix appropriate for the current default locale
* (e.g. "co.uk" for the United Kingdom)
*/
public static String getCountryTLD(Context context) {
return doGetTLD(GOOGLE_COUNTRY_TLD, context);
}
/**
* The same as above, but specifically for Google Product Search.
*
* @param context application's {@link Context}
* @return The top-level domain to use.
*/
public static String getProductSearchCountryTLD(Context context) {
return doGetTLD(GOOGLE_PRODUCT_SEARCH_COUNTRY_TLD, context);
}
/**
* The same as above, but specifically for Google Book Search.
*
* @param context application's {@link Context}
* @return The top-level domain to use.
*/
public static String getBookSearchCountryTLD(Context context) {
return doGetTLD(GOOGLE_BOOK_SEARCH_COUNTRY_TLD, context);
}
/**
* Does a given URL point to Google Book Search, regardless of domain.
*
* @param url The address to check.
* @return True if this is a Book Search URL.
*/
public static boolean isBookSearchUrl(String url) {
return url.startsWith("http://google.com/books") || url.startsWith("http://books.google.");
}
private static String getSystemCountry() {
Locale locale = Locale.getDefault();
return locale == null ? DEFAULT_COUNTRY : locale.getCountry();
}
private static String getSystemLanguage() {
Locale locale = Locale.getDefault();
if (locale == null) {
return DEFAULT_LANGUAGE;
}
String language = locale.getLanguage();
// Special case Chinese
if (Locale.SIMPLIFIED_CHINESE.getLanguage().equals(language)) {
return language + "-r" + getSystemCountry();
}
return language;
}
public static String getTranslatedAssetLanguage() {
String language = getSystemLanguage();
return TRANSLATED_HELP_ASSET_LANGUAGES.contains(language) ? language : DEFAULT_LANGUAGE;
}
private static String doGetTLD(Map<String,String> map, Context context) {
String tld = map.get(getCountry(context));
return tld == null ? DEFAULT_TLD : tld;
}
public static String getCountry(Context context) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
String countryOverride = prefs.getString(PreferencesActivity.KEY_SEARCH_COUNTRY, "-");
if (countryOverride != null && !countryOverride.isEmpty() && !"-".equals(countryOverride)) {
return countryOverride;
}
return getSystemCountry();
}
}
/*
* Copyright (C) 2008 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.zxing.client.android;
import android.app.Activity;
import android.os.Bundle;
/**
* The main settings activity.
*
* @author dswitkin@google.com (Daniel Switkin)
* @author Sean Owen
*/
public final class PreferencesActivity extends Activity {
public static final String KEY_DECODE_1D_PRODUCT = "preferences_decode_1D_product";
public static final String KEY_DECODE_1D_INDUSTRIAL = "preferences_decode_1D_industrial";
public static final String KEY_DECODE_QR = "preferences_decode_QR";
public static final String KEY_DECODE_DATA_MATRIX = "preferences_decode_Data_Matrix";
public static final String KEY_DECODE_AZTEC = "preferences_decode_Aztec";
public static final String KEY_DECODE_PDF417 = "preferences_decode_PDF417";
public static final String KEY_CUSTOM_PRODUCT_SEARCH = "preferences_custom_product_search";
public static final String KEY_PLAY_BEEP = "preferences_play_beep";
public static final String KEY_VIBRATE = "preferences_vibrate";
public static final String KEY_COPY_TO_CLIPBOARD = "preferences_copy_to_clipboard";
public static final String KEY_FRONT_LIGHT_MODE = "preferences_front_light_mode";
public static final String KEY_BULK_MODE = "preferences_bulk_mode";
public static final String KEY_REMEMBER_DUPLICATES = "preferences_remember_duplicates";
public static final String KEY_ENABLE_HISTORY = "preferences_history";
public static final String KEY_SUPPLEMENTAL = "preferences_supplemental";
public static final String KEY_AUTO_FOCUS = "preferences_auto_focus";
public static final String KEY_INVERT_SCAN = "preferences_invert_scan";
public static final String KEY_SEARCH_COUNTRY = "preferences_search_country";
public static final String KEY_DISABLE_AUTO_ORIENTATION = "preferences_orientation";
public static final String KEY_DISABLE_CONTINUOUS_FOCUS = "preferences_disable_continuous_focus";
public static final String KEY_DISABLE_EXPOSURE = "preferences_disable_exposure";
public static final String KEY_DISABLE_METERING = "preferences_disable_metering";
public static final String KEY_DISABLE_BARCODE_SCENE_MODE = "preferences_disable_barcode_scene_mode";
public static final String KEY_AUTO_OPEN_WEB = "preferences_auto_open_web";
@Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
getFragmentManager().beginTransaction().replace(android.R.id.content, new PreferencesFragment()).commit();
}
// Apparently this will be necessary when targeting API 19+:
/*
@Override
protected boolean isValidFragment(String fragmentName) {
return true;
}
*/
}
/*
* Copyright (C) 2013 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.zxing.client.android;
import android.app.AlertDialog;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.CheckBoxPreference;
import android.preference.EditTextPreference;
import android.preference.Preference;
import android.preference.PreferenceFragment;
import android.preference.PreferenceScreen;
import com.senthink.ebike_administrer_tool.R;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collection;
public final class PreferencesFragment
extends PreferenceFragment
implements SharedPreferences.OnSharedPreferenceChangeListener {
private CheckBoxPreference[] checkBoxPrefs;
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
addPreferencesFromResource(R.xml.preferences);
PreferenceScreen preferences = getPreferenceScreen();
preferences.getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
checkBoxPrefs = findDecodePrefs(preferences,
PreferencesActivity.KEY_DECODE_1D_PRODUCT,
PreferencesActivity.KEY_DECODE_1D_INDUSTRIAL,
PreferencesActivity.KEY_DECODE_QR,
PreferencesActivity.KEY_DECODE_DATA_MATRIX,
PreferencesActivity.KEY_DECODE_AZTEC,
PreferencesActivity.KEY_DECODE_PDF417);
disableLastCheckedPref();
EditTextPreference customProductSearch = (EditTextPreference)
preferences.findPreference(PreferencesActivity.KEY_CUSTOM_PRODUCT_SEARCH);
customProductSearch.setOnPreferenceChangeListener(new CustomSearchURLValidator());
}
private static CheckBoxPreference[] findDecodePrefs(PreferenceScreen preferences, String... keys) {
CheckBoxPreference[] prefs = new CheckBoxPreference[keys.length];
for (int i = 0; i < keys.length; i++) {
prefs[i] = (CheckBoxPreference) preferences.findPreference(keys[i]);
}
return prefs;
}
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
disableLastCheckedPref();
}
private void disableLastCheckedPref() {
Collection<CheckBoxPreference> checked = new ArrayList<CheckBoxPreference>(checkBoxPrefs.length);
for (CheckBoxPreference pref : checkBoxPrefs) {
if (pref.isChecked()) {
checked.add(pref);
}
}
boolean disable = checked.size() <= 1;
for (CheckBoxPreference pref : checkBoxPrefs) {
pref.setEnabled(!(disable && checked.contains(pref)));
}
}
private class CustomSearchURLValidator implements Preference.OnPreferenceChangeListener {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
if (!isValid(newValue)) {
AlertDialog.Builder builder =
new AlertDialog.Builder(PreferencesFragment.this.getActivity());
builder.setTitle("错误");
builder.setMessage("值无效");
builder.setCancelable(true);
builder.show();
return false;
}
return true;
}
private boolean isValid(Object newValue) {
// Allow empty/null value
if (newValue == null) {
return true;
}
String valueString = newValue.toString();
if (valueString.isEmpty()) {
return true;
}
// Before validating, remove custom placeholders, which will not
// be considered valid parts of the URL in some locations:
// Blank %t and %s:
valueString = valueString.replaceAll("%[st]", "");
// Blank %f but not if followed by digit or a-f as it may be a hex sequence
valueString = valueString.replaceAll("%f(?![0-9a-f])", "");
// Require a scheme otherwise:
try {
URI uri = new URI(valueString);
return uri.getScheme() != null;
} catch (URISyntaxException use) {
return false;
}
}
}
}
/*
* Copyright (C) 2012 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.zxing.client.android;
import android.net.Uri;
import com.google.zxing.Result;
import com.google.zxing.client.android.result.ResultHandler;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
/**
* Manages functionality related to responding to requests to scan from an HTTP link in a web page.
* See <a href="http://github.com/zxing/zxing/wiki/ScanningFromWebPages">ScanningFromWebPages</a>.
*
* @author Sean Owen
*/
final class ScanFromWebPageManager {
private static final CharSequence CODE_PLACEHOLDER = "{CODE}";
private static final CharSequence RAW_CODE_PLACEHOLDER = "{RAWCODE}";
private static final CharSequence META_PLACEHOLDER = "{META}";
private static final CharSequence FORMAT_PLACEHOLDER = "{FORMAT}";
private static final CharSequence TYPE_PLACEHOLDER = "{TYPE}";
private static final String RETURN_URL_PARAM = "ret";
private static final String RAW_PARAM = "raw";
private final String returnUrlTemplate;
private final boolean returnRaw;
ScanFromWebPageManager(Uri inputUri) {
returnUrlTemplate = inputUri.getQueryParameter(RETURN_URL_PARAM);
returnRaw = inputUri.getQueryParameter(RAW_PARAM) != null;
}
boolean isScanFromWebPage() {
return returnUrlTemplate != null;
}
String buildReplyURL(Result rawResult, ResultHandler resultHandler) {
String result = returnUrlTemplate;
result = replace(CODE_PLACEHOLDER,
returnRaw ? rawResult.getText() : resultHandler.getDisplayContents(), result);
result = replace(RAW_CODE_PLACEHOLDER, rawResult.getText(), result);
result = replace(FORMAT_PLACEHOLDER, rawResult.getBarcodeFormat().toString(), result);
result = replace(TYPE_PLACEHOLDER, resultHandler.getType().toString(), result);
result = replace(META_PLACEHOLDER, String.valueOf(rawResult.getResultMetadata()), result);
return result;
}
private static String replace(CharSequence placeholder, CharSequence with, String pattern) {
CharSequence escapedWith = with == null ? "" : with;
try {
escapedWith = URLEncoder.encode(escapedWith.toString(), "UTF-8");
} catch (UnsupportedEncodingException e) {
// can't happen; UTF-8 is always supported. Continue, I guess, without encoding
}
return pattern.replace(placeholder, escapedWith);
}
}
/*
* Copyright (C) 2009 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.zxing.client.android;
import com.google.zxing.ResultPoint;
import com.google.zxing.ResultPointCallback;
final class ViewfinderResultPointCallback implements ResultPointCallback {
private final ViewfinderView viewfinderView;
ViewfinderResultPointCallback(ViewfinderView viewfinderView) {
this.viewfinderView = viewfinderView;
}
@Override
public void foundPossibleResultPoint(ResultPoint point) {
viewfinderView.addPossibleResultPoint(point);
}
}
/*
* Copyright (C) 2008 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.zxing.client.android;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.View;
import com.google.zxing.ResultPoint;
import com.senthink.ebike_administrer_tool.R;
import com.google.zxing.client.android.camera.CameraManager;
import java.util.ArrayList;
import java.util.List;
/**
* This view is overlaid on top of the camera preview. It adds the viewfinder rectangle and partial
* transparency outside it, as well as the laser scanner animation and result points.
*
* @author dswitkin@google.com (Daniel Switkin)
*/
public final class ViewfinderView extends View {
private static final int[] SCANNER_ALPHA = {0, 64, 128, 192, 255, 192, 128, 64};
private static final long ANIMATION_DELAY = 80L;
private static final int CURRENT_POINT_OPACITY = 0xA0;
private static final int MAX_RESULT_POINTS = 20;
private static final int POINT_SIZE = 6;
private CameraManager cameraManager;
private final Paint paint;
private Bitmap resultBitmap;
private final int maskColor;
private final int resultColor;
private final int laserColor;
private final int resultPointColor;
private int scannerAlpha;
private List<ResultPoint> possibleResultPoints;
private List<ResultPoint> lastPossibleResultPoints;
// This constructor is used when the class is built from an XML resource.
public ViewfinderView(Context context, AttributeSet attrs) {
super(context, attrs);
// Initialize these once for performance rather than calling them every time in onDraw().
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
Resources resources = getResources();
maskColor = resources.getColor(R.color.viewfinder_mask);
resultColor = resources.getColor(R.color.result_view);
laserColor = resources.getColor(R.color.viewfinder_laser);
resultPointColor = resources.getColor(R.color.possible_result_points);
scannerAlpha = 0;
possibleResultPoints = new ArrayList<ResultPoint>(5);
lastPossibleResultPoints = null;
}
public void setCameraManager(CameraManager cameraManager) {
this.cameraManager = cameraManager;
}
@SuppressLint("DrawAllocation")
@Override
public void onDraw(Canvas canvas) {
if (cameraManager == null) {
return; // not ready yet, early draw before done configuring
}
Rect frame = cameraManager.getFramingRect();
Rect previewFrame = cameraManager.getFramingRectInPreview();
if (frame == null || previewFrame == null) {
return;
}
int width = canvas.getWidth();
int height = canvas.getHeight();
// Draw the exterior (i.e. outside the framing rect) darkened
paint.setColor(resultBitmap != null ? resultColor : maskColor);
canvas.drawRect(0, 0, width, frame.top, paint);
canvas.drawRect(0, frame.top, frame.left, frame.bottom + 1, paint);
canvas.drawRect(frame.right + 1, frame.top, width, frame.bottom + 1, paint);
canvas.drawRect(0, frame.bottom + 1, width, height, paint);
if (resultBitmap != null) {
// Draw the opaque result bitmap over the scanning rectangle
paint.setAlpha(CURRENT_POINT_OPACITY);
canvas.drawBitmap(resultBitmap, null, frame, paint);
} else {
drawFrameBounds(canvas, frame);
// Draw a red "laser scanner" line through the middle to show decoding is active
paint.setColor(laserColor);
paint.setAlpha(SCANNER_ALPHA[scannerAlpha]);
scannerAlpha = (scannerAlpha + 1) % SCANNER_ALPHA.length;
int middle = frame.height() / 2 + frame.top;
canvas.drawRect(frame.left + 2, middle - 1, frame.right - 1, middle + 2, paint);
float scaleX = frame.width() / (float) previewFrame.width();
float scaleY = frame.height() / (float) previewFrame.height();
List<ResultPoint> currentPossible = possibleResultPoints;
List<ResultPoint> currentLast = lastPossibleResultPoints;
int frameLeft = frame.left;
int frameTop = frame.top;
if (currentPossible.isEmpty()) {
lastPossibleResultPoints = null;
} else {
possibleResultPoints = new ArrayList<ResultPoint>(5);
lastPossibleResultPoints = currentPossible;
paint.setAlpha(CURRENT_POINT_OPACITY);
paint.setColor(resultPointColor);
synchronized (currentPossible) {
for (ResultPoint point : currentPossible) {
canvas.drawCircle(frameLeft + (int) (point.getX() * scaleX),
frameTop + (int) (point.getY() * scaleY),
POINT_SIZE, paint);
}
}
}
if (currentLast != null) {
paint.setAlpha(CURRENT_POINT_OPACITY / 2);
paint.setColor(resultPointColor);
synchronized (currentLast) {
float radius = POINT_SIZE / 2.0f;
for (ResultPoint point : currentLast) {
canvas.drawCircle(frameLeft + (int) (point.getX() * scaleX),
frameTop + (int) (point.getY() * scaleY),
radius, paint);
}
}
}
// Request another update at the animation interval, but only repaint the laser line,
// not the entire viewfinder mask.
postInvalidateDelayed(ANIMATION_DELAY,
frame.left - POINT_SIZE,
frame.top - POINT_SIZE,
frame.right + POINT_SIZE,
frame.bottom + POINT_SIZE);
}
}
public void drawViewfinder() {
Bitmap resultBitmap = this.resultBitmap;
this.resultBitmap = null;
if (resultBitmap != null) {
resultBitmap.recycle();
}
invalidate();
}
/**
* Draw a bitmap with the result points highlighted instead of the live scanning display.
*
* @param barcode An image of the decoded barcode.
*/
public void drawResultBitmap(Bitmap barcode) {
resultBitmap = barcode;
invalidate();
}
public void addPossibleResultPoint(ResultPoint point) {
List<ResultPoint> points = possibleResultPoints;
synchronized (points) {
points.add(point);
int size = points.size();
if (size > MAX_RESULT_POINTS) {
// trim it
points.subList(0, size - MAX_RESULT_POINTS / 2).clear();
}
}
}
/**
* 绘制取景框边框
*
* @param canvas
* @param frame
*/
private void drawFrameBounds(Canvas canvas, Rect frame) {
paint.setColor(Color.WHITE);
paint.setStrokeWidth(2);
paint.setStyle(Paint.Style.STROKE);
canvas.drawRect(frame, paint);
paint.setColor(Color.BLUE);
paint.setStyle(Paint.Style.FILL);
int corWidth = 15;
int corLength = 45;
// 左上角
canvas.drawRect(frame.left - corWidth, frame.top, frame.left, frame.top
+ corLength, paint);
canvas.drawRect(frame.left - corWidth, frame.top - corWidth, frame.left
+ corLength, frame.top, paint);
// 右上角
canvas.drawRect(frame.right, frame.top, frame.right + corWidth,
frame.top + corLength, paint);
canvas.drawRect(frame.right - corLength, frame.top - corWidth,
frame.right + corWidth, frame.top, paint);
// 左下角
canvas.drawRect(frame.left - corWidth, frame.bottom - corLength,
frame.left, frame.bottom, paint);
canvas.drawRect(frame.left - corWidth, frame.bottom, frame.left
+ corLength, frame.bottom + corWidth, paint);
// 右下角
canvas.drawRect(frame.right, frame.bottom - corLength, frame.right
+ corWidth, frame.bottom, paint);
canvas.drawRect(frame.right - corLength, frame.bottom, frame.right
+ corWidth, frame.bottom + corWidth, paint);
}
}
/*
* Copyright (C) 2012 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.zxing.client.android.camera;
import android.content.Context;
import android.content.SharedPreferences;
import android.hardware.Camera;
import android.os.AsyncTask;
import android.preference.PreferenceManager;
import android.util.Log;
import com.google.zxing.client.android.PreferencesActivity;
import java.util.ArrayList;
import java.util.Collection;
import java.util.concurrent.RejectedExecutionException;
final class AutoFocusManager implements Camera.AutoFocusCallback {
private static final String TAG = AutoFocusManager.class.getSimpleName();
private static final long AUTO_FOCUS_INTERVAL_MS = 1000L;
private static final Collection<String> FOCUS_MODES_CALLING_AF;
static {
FOCUS_MODES_CALLING_AF = new ArrayList<String>(2);
FOCUS_MODES_CALLING_AF.add(Camera.Parameters.FOCUS_MODE_AUTO);
FOCUS_MODES_CALLING_AF.add(Camera.Parameters.FOCUS_MODE_MACRO);
}
private boolean stopped;
private boolean focusing;
private final boolean useAutoFocus;
private final Camera camera;
private AsyncTask<?,?,?> outstandingTask;
AutoFocusManager(Context context, Camera camera) {
this.camera = camera;
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context);
String currentFocusMode = camera.getParameters().getFocusMode();
useAutoFocus =
sharedPrefs.getBoolean(PreferencesActivity.KEY_AUTO_FOCUS, true) &&
FOCUS_MODES_CALLING_AF.contains(currentFocusMode);
Log.i(TAG, "Current focus mode '" + currentFocusMode + "'; use auto focus? " + useAutoFocus);
start();
}
@Override
public synchronized void onAutoFocus(boolean success, Camera theCamera) {
focusing = false;
autoFocusAgainLater();
}
private synchronized void autoFocusAgainLater() {
if (!stopped && outstandingTask == null) {
AutoFocusTask newTask = new AutoFocusTask();
try {
newTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
outstandingTask = newTask;
} catch (RejectedExecutionException ree) {
Log.w(TAG, "Could not request auto focus", ree);
}
}
}
synchronized void start() {
if (useAutoFocus) {
outstandingTask = null;
if (!stopped && !focusing) {
try {
camera.autoFocus(this);
focusing = true;
} catch (RuntimeException re) {
// Have heard RuntimeException reported in Android 4.0.x+; continue?
Log.w(TAG, "Unexpected exception while focusing", re);
// Try again later to keep cycle going
autoFocusAgainLater();
}
}
}
}
private synchronized void cancelOutstandingTask() {
if (outstandingTask != null) {
if (outstandingTask.getStatus() != AsyncTask.Status.FINISHED) {
outstandingTask.cancel(true);
}
outstandingTask = null;
}
}
synchronized void stop() {
stopped = true;
if (useAutoFocus) {
cancelOutstandingTask();
// Doesn't hurt to call this even if not focusing
try {
camera.cancelAutoFocus();
} catch (RuntimeException re) {
// Have heard RuntimeException reported in Android 4.0.x+; continue?
Log.w(TAG, "Unexpected exception while cancelling focusing", re);
}
}
}
private final class AutoFocusTask extends AsyncTask<Object,Object,Object> {
@Override
protected Object doInBackground(Object... voids) {
try {
Thread.sleep(AUTO_FOCUS_INTERVAL_MS);
} catch (InterruptedException e) {
// continue
}
start();
return null;
}
}
}
/*
* Copyright (C) 2010 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.zxing.client.android.camera;
import android.content.Context;
import android.content.SharedPreferences;
import android.graphics.Point;
import android.hardware.Camera;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.Display;
import android.view.Surface;
import android.view.WindowManager;
import com.google.zxing.client.android.PreferencesActivity;
import com.google.zxing.client.android.camera.open.CameraFacing;
import com.google.zxing.client.android.camera.open.OpenCamera;
/**
* A class which deals with reading, parsing, and setting the camera parameters which are used to
* configure the camera hardware.
*/
final class CameraConfigurationManager {
private static final String TAG = "CameraConfiguration";
private final Context context;
private int cwNeededRotation;
private int cwRotationFromDisplayToCamera;
private Point screenResolution;
private Point cameraResolution;
private Point bestPreviewSize;
private Point previewSizeOnScreen;
CameraConfigurationManager(Context context) {
this.context = context;
}
/**
* Reads, one time, values from the camera that are needed by the app.
*/
void initFromCameraParameters(OpenCamera camera) {
Camera.Parameters parameters = camera.getCamera().getParameters();
WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = manager.getDefaultDisplay();
int displayRotation = display.getRotation();
int cwRotationFromNaturalToDisplay;
switch (displayRotation) {
// 各个角度的二维码
case Surface.ROTATION_0:
cwRotationFromNaturalToDisplay = 0;
break;
case Surface.ROTATION_90:
cwRotationFromNaturalToDisplay = 90;
break;
case Surface.ROTATION_180:
cwRotationFromNaturalToDisplay = 180;
break;
case Surface.ROTATION_270:
cwRotationFromNaturalToDisplay = 270;
break;
default:
// Have seen this return incorrect values like -90
if (displayRotation % 90 == 0) {
cwRotationFromNaturalToDisplay = (360 + displayRotation) % 360;
} else {
throw new IllegalArgumentException("Bad rotation: " + displayRotation);
}
}
Log.i(TAG, "Display at: " + cwRotationFromNaturalToDisplay);
int cwRotationFromNaturalToCamera = camera.getOrientation();
Log.i(TAG, "Camera at: " + cwRotationFromNaturalToCamera);
// Still not 100% sure about this. But acts like we need to flip this:
if (camera.getFacing() == CameraFacing.FRONT) {
cwRotationFromNaturalToCamera = (360 - cwRotationFromNaturalToCamera) % 360;
Log.i(TAG, "Front camera overriden to: " + cwRotationFromNaturalToCamera);
}
/*
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
String overrideRotationString;
if (camera.getFacing() == CameraFacing.FRONT) {
overrideRotationString = prefs.getString(PreferencesActivity.KEY_FORCE_CAMERA_ORIENTATION_FRONT, null);
} else {
overrideRotationString = prefs.getString(PreferencesActivity.KEY_FORCE_CAMERA_ORIENTATION, null);
}
if (overrideRotationString != null && !"-".equals(overrideRotationString)) {
Log.i(TAG, "Overriding camera manually to " + overrideRotationString);
cwRotationFromNaturalToCamera = Integer.parseInt(overrideRotationString);
}
*/
cwRotationFromDisplayToCamera =
(360 + cwRotationFromNaturalToCamera - cwRotationFromNaturalToDisplay) % 360;
Log.i(TAG, "Final display orientation: " + cwRotationFromDisplayToCamera);
if (camera.getFacing() == CameraFacing.FRONT) {
Log.i(TAG, "Compensating rotation for front camera");
cwNeededRotation = (360 - cwRotationFromDisplayToCamera) % 360;
} else {
cwNeededRotation = cwRotationFromDisplayToCamera;
}
Log.i(TAG, "Clockwise rotation from display to camera: " + cwNeededRotation);
Point theScreenResolution = new Point();
display.getSize(theScreenResolution);
screenResolution = theScreenResolution;
Log.i(TAG, "Screen resolution in current orientation: " + screenResolution);
cameraResolution = CameraConfigurationUtils.findBestPreviewSizeValue(parameters, screenResolution);
Log.i(TAG, "Camera resolution: " + cameraResolution);
bestPreviewSize = CameraConfigurationUtils.findBestPreviewSizeValue(parameters, screenResolution);
Log.i(TAG, "Best available preview size: " + bestPreviewSize);
boolean isScreenPortrait = screenResolution.x < screenResolution.y;
boolean isPreviewSizePortrait = bestPreviewSize.x < bestPreviewSize.y;
if (isScreenPortrait == isPreviewSizePortrait) {
previewSizeOnScreen = bestPreviewSize;
} else {
previewSizeOnScreen = new Point(bestPreviewSize.y, bestPreviewSize.x);
}
Log.i(TAG, "Preview size on screen: " + previewSizeOnScreen);
}
void setDesiredCameraParameters(OpenCamera camera, boolean safeMode) {
Camera theCamera = camera.getCamera();
Camera.Parameters parameters = theCamera.getParameters();
if (parameters == null) {
Log.w(TAG, "Device error: no camera parameters are available. Proceeding without configuration.");
return;
}
Log.i(TAG, "Initial camera parameters: " + parameters.flatten());
if (safeMode) {
Log.w(TAG, "In camera config safe mode -- most settings will not be honored");
}
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
initializeTorch(parameters, prefs, safeMode);
CameraConfigurationUtils.setFocus(
parameters,
prefs.getBoolean(PreferencesActivity.KEY_AUTO_FOCUS, true),
prefs.getBoolean(PreferencesActivity.KEY_DISABLE_CONTINUOUS_FOCUS, true),
safeMode);
if (!safeMode) {
if (prefs.getBoolean(PreferencesActivity.KEY_INVERT_SCAN, false)) {
CameraConfigurationUtils.setInvertColor(parameters);
}
if (!prefs.getBoolean(PreferencesActivity.KEY_DISABLE_BARCODE_SCENE_MODE, true)) {
CameraConfigurationUtils.setBarcodeSceneMode(parameters);
}
if (!prefs.getBoolean(PreferencesActivity.KEY_DISABLE_METERING, true)) {
CameraConfigurationUtils.setVideoStabilization(parameters);
CameraConfigurationUtils.setFocusArea(parameters);
CameraConfigurationUtils.setMetering(parameters);
}
}
parameters.setPreviewSize(bestPreviewSize.x, bestPreviewSize.y);
theCamera.setDisplayOrientation(90);
theCamera.setParameters(parameters);
theCamera.setDisplayOrientation(cwRotationFromDisplayToCamera);
Camera.Parameters afterParameters = theCamera.getParameters();
Camera.Size afterSize = afterParameters.getPreviewSize();
if (afterSize != null && (bestPreviewSize.x != afterSize.width || bestPreviewSize.y != afterSize.height)) {
Log.w(TAG, "Camera said it supported preview size " + bestPreviewSize.x + 'x' + bestPreviewSize.y +
", but after setting it, preview size is " + afterSize.width + 'x' + afterSize.height);
bestPreviewSize.x = afterSize.width;
bestPreviewSize.y = afterSize.height;
}
}
Point getBestPreviewSize() {
return bestPreviewSize;
}
Point getPreviewSizeOnScreen() {
return previewSizeOnScreen;
}
Point getCameraResolution() {
return cameraResolution;
}
Point getScreenResolution() {
return screenResolution;
}
int getCWNeededRotation() {
return cwNeededRotation;
}
boolean getTorchState(Camera camera) {
if (camera != null) {
Camera.Parameters parameters = camera.getParameters();
if (parameters != null) {
String flashMode = camera.getParameters().getFlashMode();
return flashMode != null &&
(Camera.Parameters.FLASH_MODE_ON.equals(flashMode) ||
Camera.Parameters.FLASH_MODE_TORCH.equals(flashMode));
}
}
return false;
}
void setTorch(Camera camera, boolean newSetting) {
Camera.Parameters parameters = camera.getParameters();
doSetTorch(parameters, newSetting, false);
camera.setParameters(parameters);
}
private void initializeTorch(Camera.Parameters parameters, SharedPreferences prefs, boolean safeMode) {
boolean currentSetting = FrontLightMode.readPref(prefs) == FrontLightMode.ON;
doSetTorch(parameters, currentSetting, safeMode);
}
private void doSetTorch(Camera.Parameters parameters, boolean newSetting, boolean safeMode) {
CameraConfigurationUtils.setTorch(parameters, newSetting);
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
if (!safeMode && !prefs.getBoolean(PreferencesActivity.KEY_DISABLE_EXPOSURE, true)) {
CameraConfigurationUtils.setBestExposure(parameters, newSetting);
}
}
}
/*
* Copyright (C) 2012 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.zxing.client.android.camera;
import android.content.SharedPreferences;
import com.google.zxing.client.android.PreferencesActivity;
/**
* Enumerates settings of the preference controlling the front light.
*/
public enum FrontLightMode {
/** Always on. */
ON,
/** On only when ambient light is low. */
AUTO,
/** Always off. */
OFF;
private static FrontLightMode parse(String modeString) {
return modeString == null ? OFF : valueOf(modeString);
}
public static FrontLightMode readPref(SharedPreferences sharedPrefs) {
return parse(sharedPrefs.getString(PreferencesActivity.KEY_FRONT_LIGHT_MODE, OFF.toString()));
}
}
/*
* Copyright (C) 2010 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.zxing.client.android.camera;
import android.graphics.Point;
import android.hardware.Camera;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
final class PreviewCallback implements Camera.PreviewCallback {
private static final String TAG = PreviewCallback.class.getSimpleName();
private final CameraConfigurationManager configManager;
private Handler previewHandler;
private int previewMessage;
PreviewCallback(CameraConfigurationManager configManager) {
this.configManager = configManager;
}
void setHandler(Handler previewHandler, int previewMessage) {
this.previewHandler = previewHandler;
this.previewMessage = previewMessage;
}
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
Point cameraResolution = configManager.getCameraResolution();
Handler thePreviewHandler = previewHandler;
if (cameraResolution != null && thePreviewHandler != null) {
Message message = thePreviewHandler.obtainMessage(previewMessage, cameraResolution.x,
cameraResolution.y, data);
message.sendToTarget();
previewHandler = null;
} else {
Log.d(TAG, "Got preview callback, but no handler or resolution available");
}
}
}
/*
* Copyright (C) 2015 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.zxing.client.android.camera.open;
public enum CameraFacing {
BACK, // must be value 0!
FRONT, // must be value 1!
}
/*
* Copyright (C) 2015 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.zxing.client.android.camera.open;
import android.hardware.Camera;
public final class OpenCamera {
private final int index;
private final Camera camera;
private final CameraFacing facing;
private final int orientation;
public OpenCamera(int index, Camera camera, CameraFacing facing, int orientation) {
this.index = index;
this.camera = camera;
this.facing = facing;
this.orientation = orientation;
}
public Camera getCamera() {
return camera;
}
public CameraFacing getFacing() {
return facing;
}
public int getOrientation() {
return orientation;
}
@Override
public String toString() {
return "Camera #" + index + " : " + facing + ',' + orientation;
}
}
/*
* Copyright (C) 2012 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.zxing.client.android.camera.open;
import android.hardware.Camera;
import android.util.Log;
public final class OpenCameraInterface {
private static final String TAG = OpenCameraInterface.class.getName();
private OpenCameraInterface() {
}
/** For {@link #open(int)}, means no preference for which camera to open. */
public static final int NO_REQUESTED_CAMERA = -1;
/**
* Opens the requested camera with {@link Camera#open(int)}, if one exists.
*
* @param cameraId camera ID of the camera to use. A negative value
* or {@link #NO_REQUESTED_CAMERA} means "no preference", in which case a rear-facing
* camera is returned if possible or else any camera
* @return handle to {@link OpenCamera} that was opened
*/
public static OpenCamera open(int cameraId) {
int numCameras = Camera.getNumberOfCameras();
if (numCameras == 0) {
Log.w(TAG, "No cameras!");
return null;
}
boolean explicitRequest = cameraId >= 0;
Camera.CameraInfo selectedCameraInfo = null;
int index;
if (explicitRequest) {
index = cameraId;
selectedCameraInfo = new Camera.CameraInfo();
Camera.getCameraInfo(index, selectedCameraInfo);
} else {
index = 0;
while (index < numCameras) {
Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
Camera.getCameraInfo(index, cameraInfo);
CameraFacing reportedFacing = CameraFacing.values()[cameraInfo.facing];
if (reportedFacing == CameraFacing.BACK) {
selectedCameraInfo = cameraInfo;
break;
}
index++;
}
}
Camera camera;
if (index < numCameras) {
Log.i(TAG, "Opening camera #" + index);
camera = Camera.open(index);
} else {
if (explicitRequest) {
Log.w(TAG, "Requested camera does not exist: " + cameraId);
camera = null;
} else {
Log.i(TAG, "No camera facing " + CameraFacing.BACK + "; returning camera #0");
camera = Camera.open(0);
selectedCameraInfo = new Camera.CameraInfo();
Camera.getCameraInfo(0, selectedCameraInfo);
}
}
if (camera == null) {
return null;
}
return new OpenCamera(index,
camera,
CameraFacing.values()[selectedCameraInfo.facing],
selectedCameraInfo.orientation);
}
}
/*
* Copyright (C) 2011 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.zxing.client.android.encode;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
/**
* Implementations encode according to some scheme for encoding contact information, like VCard or
* MECARD.
*
* @author Sean Owen
*/
abstract class ContactEncoder {
/**
* @return first, the best effort encoding of all data in the appropriate format; second, a
* display-appropriate version of the contact information
*/
abstract String[] encode(List<String> names,
String organization,
List<String> addresses,
List<String> phones,
List<String> phoneTypes,
List<String> emails,
List<String> urls,
String note);
/**
* @return null if s is null or empty, or result of s.trim() otherwise
*/
static String trim(String s) {
if (s == null) {
return null;
}
String result = s.trim();
return result.isEmpty() ? null : result;
}
static void append(StringBuilder newContents,
StringBuilder newDisplayContents,
String prefix,
String value,
Formatter fieldFormatter,
char terminator) {
String trimmed = trim(value);
if (trimmed != null) {
newContents.append(prefix).append(fieldFormatter.format(trimmed, 0)).append(terminator);
newDisplayContents.append(trimmed).append('\n');
}
}
static void appendUpToUnique(StringBuilder newContents,
StringBuilder newDisplayContents,
String prefix,
List<String> values,
int max,
Formatter displayFormatter,
Formatter fieldFormatter,
char terminator) {
if (values == null) {
return;
}
int count = 0;
Collection<String> uniques = new HashSet<String>(2);
for (int i = 0; i < values.size(); i++) {
String value = values.get(i);
String trimmed = trim(value);
if (trimmed != null && !trimmed.isEmpty() && !uniques.contains(trimmed)) {
newContents.append(prefix).append(fieldFormatter.format(trimmed, i)).append(terminator);
CharSequence display = displayFormatter == null ? trimmed : displayFormatter.format(trimmed, i);
newDisplayContents.append(display).append('\n');
if (++count == max) {
break;
}
uniques.add(trimmed);
}
}
}
}
/*
* Copyright (C) 2011 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.zxing.client.android.encode;
/**
* Encapsulates some simple formatting logic, to aid refactoring in {@link ContactEncoder}.
*
* @author Sean Owen
*/
interface Formatter {
/**
* @param value value to format
* @param index index of value in a list of values to be formatted
* @return formatted value
*/
CharSequence format(CharSequence value, int index);
}
/*
* Copyright (C) 2011 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.zxing.client.android.encode;
import android.telephony.PhoneNumberUtils;
import java.util.List;
import java.util.regex.Pattern;
/**
* Encodes contact information according to the MECARD format.
*
* @author Sean Owen
*/
final class MECARDContactEncoder extends ContactEncoder {
private static final char TERMINATOR = ';';
@Override
public String[] encode(List<String> names,
String organization,
List<String> addresses,
List<String> phones,
List<String> phoneTypes,
List<String> emails,
List<String> urls,
String note) {
StringBuilder newContents = new StringBuilder(100);
newContents.append("MECARD:");
StringBuilder newDisplayContents = new StringBuilder(100);
Formatter fieldFormatter = new MECARDFieldFormatter();
appendUpToUnique(newContents, newDisplayContents, "N", names, 1, new
MECARDNameDisplayFormatter(), fieldFormatter, TERMINATOR);
append(newContents, newDisplayContents, "ORG", organization, fieldFormatter, TERMINATOR);
appendUpToUnique(newContents, newDisplayContents, "ADR", addresses, 1, null, fieldFormatter, TERMINATOR);
appendUpToUnique(newContents, newDisplayContents, "TEL", phones, Integer.MAX_VALUE,
new MECARDTelDisplayFormatter(), fieldFormatter, TERMINATOR);
appendUpToUnique(newContents, newDisplayContents, "EMAIL", emails, Integer.MAX_VALUE, null,
fieldFormatter, TERMINATOR);
appendUpToUnique(newContents, newDisplayContents, "URL", urls, Integer.MAX_VALUE, null,
fieldFormatter, TERMINATOR);
append(newContents, newDisplayContents, "NOTE", note, fieldFormatter, TERMINATOR);
newContents.append(';');
return new String[] { newContents.toString(), newDisplayContents.toString() };
}
private static class MECARDFieldFormatter implements Formatter {
private static final Pattern RESERVED_MECARD_CHARS = Pattern.compile("([\\\\:;])");
private static final Pattern NEWLINE = Pattern.compile("\\n");
@Override
public CharSequence format(CharSequence value, int index) {
return ':' + NEWLINE.matcher(RESERVED_MECARD_CHARS.matcher(value).replaceAll("\\\\$1")).replaceAll("");
}
}
private static class MECARDTelDisplayFormatter implements Formatter {
private static final Pattern NOT_DIGITS = Pattern.compile("[^0-9]+");
@Override
public CharSequence format(CharSequence value, int index) {
return NOT_DIGITS.matcher(PhoneNumberUtils.formatNumber(value.toString())).replaceAll("");
}
}
private static class MECARDNameDisplayFormatter implements Formatter {
private static final Pattern COMMA = Pattern.compile(",");
@Override
public CharSequence format(CharSequence value, int index) {
return COMMA.matcher(value).replaceAll("");
}
}
}
/*
* Copyright (C) 2011 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.zxing.client.android.encode;
import android.provider.ContactsContract;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Encodes contact information according to the vCard format.
*
* @author Sean Owen
*/
final class VCardContactEncoder extends ContactEncoder {
private static final char TERMINATOR = '\n';
@Override
public String[] encode(List<String> names,
String organization,
List<String> addresses,
List<String> phones,
List<String> phoneTypes,
List<String> emails,
List<String> urls,
String note) {
StringBuilder newContents = new StringBuilder(100);
newContents.append("BEGIN:VCARD").append(TERMINATOR);
newContents.append("VERSION:3.0").append(TERMINATOR);
StringBuilder newDisplayContents = new StringBuilder(100);
Formatter fieldFormatter = new VCardFieldFormatter();
appendUpToUnique(newContents, newDisplayContents, "N", names, 1, null, fieldFormatter, TERMINATOR);
append(newContents, newDisplayContents, "ORG", organization, fieldFormatter, TERMINATOR);
appendUpToUnique(newContents, newDisplayContents, "ADR", addresses, 1, null, fieldFormatter, TERMINATOR);
List<Map<String,Set<String>>> phoneMetadata = buildPhoneMetadata(phones, phoneTypes);
appendUpToUnique(newContents, newDisplayContents, "TEL", phones, Integer.MAX_VALUE,
new VCardTelDisplayFormatter(phoneMetadata),
new VCardFieldFormatter(phoneMetadata), TERMINATOR);
appendUpToUnique(newContents, newDisplayContents, "EMAIL", emails, Integer.MAX_VALUE, null,
fieldFormatter, TERMINATOR);
appendUpToUnique(newContents, newDisplayContents, "URL", urls, Integer.MAX_VALUE, null,
fieldFormatter, TERMINATOR);
append(newContents, newDisplayContents, "NOTE", note, fieldFormatter, TERMINATOR);
newContents.append("END:VCARD").append(TERMINATOR);
return new String[] { newContents.toString(), newDisplayContents.toString() };
}
static List<Map<String,Set<String>>> buildPhoneMetadata(Collection<String> phones, List<String> phoneTypes) {
if (phoneTypes == null || phoneTypes.isEmpty()) {
return null;
}
List<Map<String,Set<String>>> metadataForIndex = new ArrayList<Map<String, Set<String>>>();
for (int i = 0; i < phones.size(); i++) {
if (phoneTypes.size() <= i) {
metadataForIndex.add(null);
} else {
Map<String,Set<String>> metadata = new HashMap<String, Set<String>>();
metadataForIndex.add(metadata);
Set<String> typeTokens = new HashSet<String>();
metadata.put("TYPE", typeTokens);
String typeString = phoneTypes.get(i);
Integer androidType = maybeIntValue(typeString);
if (androidType == null) {
typeTokens.add(typeString);
} else {
String purpose = vCardPurposeLabelForAndroidType(androidType);
String context = vCardContextLabelForAndroidType(androidType);
if (purpose != null) {
typeTokens.add(purpose);
}
if (context != null) {
typeTokens.add(context);
}
}
}
}
return metadataForIndex;
}
private static Integer maybeIntValue(String value) {
try {
return Integer.valueOf(value);
} catch (NumberFormatException nfe) {
return null;
}
}
private static String vCardPurposeLabelForAndroidType(int androidType) {
switch (androidType) {
case ContactsContract.CommonDataKinds.Phone.TYPE_FAX_HOME:
case ContactsContract.CommonDataKinds.Phone.TYPE_FAX_WORK:
case ContactsContract.CommonDataKinds.Phone.TYPE_OTHER_FAX:
return "fax";
case ContactsContract.CommonDataKinds.Phone.TYPE_PAGER:
case ContactsContract.CommonDataKinds.Phone.TYPE_WORK_PAGER:
return "pager";
case ContactsContract.CommonDataKinds.Phone.TYPE_TTY_TDD:
return "textphone";
case ContactsContract.CommonDataKinds.Phone.TYPE_MMS:
return "text";
default:
return null;
}
}
private static String vCardContextLabelForAndroidType(int androidType) {
switch (androidType) {
case ContactsContract.CommonDataKinds.Phone.TYPE_HOME:
case ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE:
case ContactsContract.CommonDataKinds.Phone.TYPE_FAX_HOME:
case ContactsContract.CommonDataKinds.Phone.TYPE_PAGER:
return "home";
case ContactsContract.CommonDataKinds.Phone.TYPE_COMPANY_MAIN:
case ContactsContract.CommonDataKinds.Phone.TYPE_WORK:
case ContactsContract.CommonDataKinds.Phone.TYPE_WORK_MOBILE:
case ContactsContract.CommonDataKinds.Phone.TYPE_FAX_WORK:
case ContactsContract.CommonDataKinds.Phone.TYPE_WORK_PAGER:
return "work";
default:
return null;
}
}
}
/*
* Copyright (C) 2014 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.zxing.client.android.encode;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;
/**
* @author Sean Owen
*/
final class VCardFieldFormatter implements Formatter {
private static final Pattern RESERVED_VCARD_CHARS = Pattern.compile("([\\\\,;])");
private static final Pattern NEWLINE = Pattern.compile("\\n");
private final List<Map<String,Set<String>>> metadataForIndex;
VCardFieldFormatter() {
this(null);
}
VCardFieldFormatter(List<Map<String,Set<String>>> metadataForIndex) {
this.metadataForIndex = metadataForIndex;
}
@Override
public CharSequence format(CharSequence value, int index) {
value = RESERVED_VCARD_CHARS.matcher(value).replaceAll("\\\\$1");
value = NEWLINE.matcher(value).replaceAll("");
Map<String,Set<String>> metadata =
metadataForIndex == null || metadataForIndex.size() <= index ? null : metadataForIndex.get(index);
value = formatMetadata(value, metadata);
return value;
}
private static CharSequence formatMetadata(CharSequence value, Map<String,Set<String>> metadata) {
StringBuilder withMetadata = new StringBuilder();
if (metadata != null) {
for (Map.Entry<String,Set<String>> metadatum : metadata.entrySet()) {
Set<String> values = metadatum.getValue();
if (values == null || values.isEmpty()) {
continue;
}
withMetadata.append(';').append(metadatum.getKey()).append('=');
if (values.size() > 1) {
withMetadata.append('"');
}
Iterator<String> valuesIt = values.iterator();
withMetadata.append(valuesIt.next());
while (valuesIt.hasNext()) {
withMetadata.append(',').append(valuesIt.next());
}
if (values.size() > 1) {
withMetadata.append('"');
}
}
}
withMetadata.append(':').append(value);
return withMetadata;
}
}
/*
* Copyright (C) 2014 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.zxing.client.android.encode;
import android.telephony.PhoneNumberUtils;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* @author Sean Owen
*/
final class VCardTelDisplayFormatter implements Formatter {
private final List<Map<String,Set<String>>> metadataForIndex;
VCardTelDisplayFormatter() {
this(null);
}
VCardTelDisplayFormatter(List<Map<String,Set<String>>> metadataForIndex) {
this.metadataForIndex = metadataForIndex;
}
@Override
public CharSequence format(CharSequence value, int index) {
value = PhoneNumberUtils.formatNumber(value.toString());
Map<String,Set<String>> metadata =
metadataForIndex == null || metadataForIndex.size() <= index ? null : metadataForIndex.get(index);
value = formatMetadata(value, metadata);
return value;
}
private static CharSequence formatMetadata(CharSequence value, Map<String,Set<String>> metadata) {
if (metadata == null || metadata.isEmpty()) {
return value;
}
StringBuilder withMetadata = new StringBuilder();
for (Map.Entry<String,Set<String>> metadatum : metadata.entrySet()) {
Set<String> values = metadatum.getValue();
if (values == null || values.isEmpty()) {
continue;
}
Iterator<String> valuesIt = values.iterator();
withMetadata.append(valuesIt.next());
while (valuesIt.hasNext()) {
withMetadata.append(',').append(valuesIt.next());
}
}
if (withMetadata.length() > 0) {
withMetadata.append(' ');
}
withMetadata.append(value);
return withMetadata;
}
}
/*
* Copyright (C) 2008 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.zxing.client.android.result;
import android.app.Activity;
import android.telephony.PhoneNumberUtils;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.style.StyleSpan;
import com.google.zxing.client.result.AddressBookParsedResult;
import com.google.zxing.client.result.ParsedResult;
import com.senthink.ebike_administrer_tool.R;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
/**
* Handles address book entries.
*
* @author dswitkin@google.com (Daniel Switkin)
*/
public final class AddressBookResultHandler extends ResultHandler {
private static final DateFormat[] DATE_FORMATS = {
new SimpleDateFormat("yyyyMMdd", Locale.ENGLISH),
new SimpleDateFormat("yyyyMMdd'T'HHmmss", Locale.ENGLISH),
new SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH),
new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.ENGLISH),
};
static {
for (DateFormat format : DATE_FORMATS) {
format.setLenient(false);
}
}
private static final int[] BUTTON_TEXTS = {
R.string.button_add_contact,
R.string.button_show_map,
R.string.button_dial,
R.string.button_email,
};
private final boolean[] fields;
private int buttonCount;
// This takes all the work out of figuring out which buttons/actions should be in which
// positions, based on which fields are present in this barcode.
private int mapIndexToAction(int index) {
if (index < buttonCount) {
int count = -1;
for (int x = 0; x < MAX_BUTTON_COUNT; x++) {
if (fields[x]) {
count++;
}
if (count == index) {
return x;
}
}
}
return -1;
}
public AddressBookResultHandler(Activity activity, ParsedResult result) {
super(activity, result);
AddressBookParsedResult addressResult = (AddressBookParsedResult) result;
String[] addresses = addressResult.getAddresses();
boolean hasAddress = addresses != null && addresses.length > 0 && addresses[0] != null && !addresses[0].isEmpty();
String[] phoneNumbers = addressResult.getPhoneNumbers();
boolean hasPhoneNumber = phoneNumbers != null && phoneNumbers.length > 0;
String[] emails = addressResult.getEmails();
boolean hasEmailAddress = emails != null && emails.length > 0;
fields = new boolean[MAX_BUTTON_COUNT];
fields[0] = true; // Add contact is always available
fields[1] = hasAddress;
fields[2] = hasPhoneNumber;
fields[3] = hasEmailAddress;
buttonCount = 0;
for (int x = 0; x < MAX_BUTTON_COUNT; x++) {
if (fields[x]) {
buttonCount++;
}
}
}
@Override
public int getButtonCount() {
return buttonCount;
}
@Override
public int getButtonText(int index) {
return BUTTON_TEXTS[mapIndexToAction(index)];
}
@Override
public void handleButtonPress(int index) {
AddressBookParsedResult addressResult = (AddressBookParsedResult) getResult();
String[] addresses = addressResult.getAddresses();
String address1 = addresses == null || addresses.length < 1 ? null : addresses[0];
String[] addressTypes = addressResult.getAddressTypes();
String address1Type = addressTypes == null || addressTypes.length < 1 ? null : addressTypes[0];
int action = mapIndexToAction(index);
switch (action) {
case 0:
addContact(addressResult.getNames(),
addressResult.getNicknames(),
addressResult.getPronunciation(),
addressResult.getPhoneNumbers(),
addressResult.getPhoneTypes(),
addressResult.getEmails(),
addressResult.getEmailTypes(),
addressResult.getNote(),
addressResult.getInstantMessenger(),
address1,
address1Type,
addressResult.getOrg(),
addressResult.getTitle(),
addressResult.getURLs(),
addressResult.getBirthday(),
addressResult.getGeo());
break;
case 1:
searchMap(address1);
break;
case 2:
dialPhone(addressResult.getPhoneNumbers()[0]);
break;
case 3:
sendEmail(addressResult.getEmails(), null, null, null, null);
break;
default:
break;
}
}
private static Date parseDate(String s) {
for (DateFormat currentFormat : DATE_FORMATS) {
try {
return currentFormat.parse(s);
} catch (ParseException e) {
// continue
}
}
return null;
}
// Overriden so we can hyphenate phone numbers, format birthdays, and bold the name.
@Override
public CharSequence getDisplayContents() {
AddressBookParsedResult result = (AddressBookParsedResult) getResult();
StringBuilder contents = new StringBuilder(100);
ParsedResult.maybeAppend(result.getNames(), contents);
int namesLength = contents.length();
String pronunciation = result.getPronunciation();
if (pronunciation != null && !pronunciation.isEmpty()) {
contents.append("\n(");
contents.append(pronunciation);
contents.append(')');
}
ParsedResult.maybeAppend(result.getTitle(), contents);
ParsedResult.maybeAppend(result.getOrg(), contents);
ParsedResult.maybeAppend(result.getAddresses(), contents);
String[] numbers = result.getPhoneNumbers();
if (numbers != null) {
for (String number : numbers) {
if (number != null) {
ParsedResult.maybeAppend(PhoneNumberUtils.formatNumber(number), contents);
}
}
}
ParsedResult.maybeAppend(result.getEmails(), contents);
ParsedResult.maybeAppend(result.getURLs(), contents);
String birthday = result.getBirthday();
if (birthday != null && !birthday.isEmpty()) {
Date date = parseDate(birthday);
if (date != null) {
ParsedResult.maybeAppend(DateFormat.getDateInstance(DateFormat.MEDIUM).format(date.getTime()), contents);
}
}
ParsedResult.maybeAppend(result.getNote(), contents);
if (namesLength > 0) {
// Bold the full name to make it stand out a bit.
Spannable styled = new SpannableString(contents.toString());
styled.setSpan(new StyleSpan(android.graphics.Typeface.BOLD), 0, namesLength, 0);
return styled;
} else {
return contents.toString();
}
}
@Override
public int getDisplayTitle() {
return R.string.result_address_book;
}
}
/*
* Copyright (C) 2008 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.zxing.client.android.result;
import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.util.Log;
import com.google.zxing.client.result.CalendarParsedResult;
import com.google.zxing.client.result.ParsedResult;
import com.senthink.ebike_administrer_tool.R;
import java.text.DateFormat;
import java.util.Date;
/**
* Handles calendar entries encoded in QR Codes.
*
* @author dswitkin@google.com (Daniel Switkin)
* @author Sean Owen
*/
public final class CalendarResultHandler extends ResultHandler {
private static final String TAG = CalendarResultHandler.class.getSimpleName();
private static final int[] buttons = {
R.string.button_add_calendar
};
public CalendarResultHandler(Activity activity, ParsedResult result) {
super(activity, result);
}
@Override
public int getButtonCount() {
return buttons.length;
}
@Override
public int getButtonText(int index) {
return buttons[index];
}
@Override
public void handleButtonPress(int index) {
if (index == 0) {
CalendarParsedResult calendarResult = (CalendarParsedResult) getResult();
String description = calendarResult.getDescription();
String organizer = calendarResult.getOrganizer();
if (organizer != null) { // No separate Intent key, put in description
if (description == null) {
description = organizer;
} else {
description = description + '\n' + organizer;
}
}
addCalendarEvent(calendarResult.getSummary(),
calendarResult.getStart(),
calendarResult.isStartAllDay(),
calendarResult.getEnd(),
calendarResult.getLocation(),
description,
calendarResult.getAttendees());
}
}
/**
* Sends an intent to create a new calendar event by prepopulating the Add Event UI. Older
* versions of the system have a bug where the event title will not be filled out.
*
* @param summary A description of the event
* @param start The start time
* @param allDay if true, event is considered to be all day starting from start time
* @param end The end time (optional)
* @param location a text description of the event location
* @param description a text description of the event itself
* @param attendees attendees to invite
*/
private void addCalendarEvent(String summary,
Date start,
boolean allDay,
Date end,
String location,
String description,
String[] attendees) {
Intent intent = new Intent(Intent.ACTION_INSERT);
intent.setType("vnd.android.cursor.item/event");
long startMilliseconds = start.getTime();
intent.putExtra("beginTime", startMilliseconds);
if (allDay) {
intent.putExtra("allDay", true);
}
long endMilliseconds;
if (end == null) {
if (allDay) {
// + 1 day
endMilliseconds = startMilliseconds + 24 * 60 * 60 * 1000;
} else {
endMilliseconds = startMilliseconds;
}
} else {
endMilliseconds = end.getTime();
}
intent.putExtra("endTime", endMilliseconds);
intent.putExtra("title", summary);
intent.putExtra("eventLocation", location);
intent.putExtra("description", description);
if (attendees != null) {
intent.putExtra(Intent.EXTRA_EMAIL, attendees);
// Documentation says this is either a String[] or comma-separated String, which is right?
}
try {
// Do this manually at first
rawLaunchIntent(intent);
} catch (ActivityNotFoundException anfe) {
Log.w(TAG, "No calendar app available that responds to " + Intent.ACTION_INSERT);
// For calendar apps that don't like "INSERT":
intent.setAction(Intent.ACTION_EDIT);
launchIntent(intent); // Fail here for real if nothing can handle it
}
}
@Override
public CharSequence getDisplayContents() {
CalendarParsedResult calResult = (CalendarParsedResult) getResult();
StringBuilder result = new StringBuilder(100);
ParsedResult.maybeAppend(calResult.getSummary(), result);
Date start = calResult.getStart();
ParsedResult.maybeAppend(format(calResult.isStartAllDay(), start), result);
Date end = calResult.getEnd();
if (end != null) {
if (calResult.isEndAllDay() && !start.equals(end)) {
// Show only year/month/day
// if it's all-day and this is the end date, it's exclusive, so show the user
// that it ends on the day before to make more intuitive sense.
// But don't do it if the event already (incorrectly?) specifies the same start/end
end = new Date(end.getTime() - 24 * 60 * 60 * 1000);
}
ParsedResult.maybeAppend(format(calResult.isEndAllDay(), end), result);
}
ParsedResult.maybeAppend(calResult.getLocation(), result);
ParsedResult.maybeAppend(calResult.getOrganizer(), result);
ParsedResult.maybeAppend(calResult.getAttendees(), result);
ParsedResult.maybeAppend(calResult.getDescription(), result);
return result.toString();
}
private static String format(boolean allDay, Date date) {
if (date == null) {
return null;
}
DateFormat format = allDay
? DateFormat.getDateInstance(DateFormat.MEDIUM)
: DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM);
return format.format(date);
}
@Override
public int getDisplayTitle() {
return R.string.result_calendar;
}
}
/*
* Copyright (C) 2008 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.zxing.client.android.result;
import android.app.Activity;
import com.google.zxing.client.result.EmailAddressParsedResult;
import com.google.zxing.client.result.ParsedResult;
import com.senthink.ebike_administrer_tool.R;
/**
* Handles email addresses.
*
* @author dswitkin@google.com (Daniel Switkin)
*/
public final class EmailAddressResultHandler extends ResultHandler {
private static final int[] buttons = {
R.string.button_email,
R.string.button_add_contact
};
public EmailAddressResultHandler(Activity activity, ParsedResult result) {
super(activity, result);
}
@Override
public int getButtonCount() {
return buttons.length;
}
@Override
public int getButtonText(int index) {
return buttons[index];
}
@Override
public void handleButtonPress(int index) {
EmailAddressParsedResult emailResult = (EmailAddressParsedResult) getResult();
switch (index) {
case 0:
sendEmail(emailResult.getTos(),
emailResult.getCCs(),
emailResult.getBCCs(),
emailResult.getSubject(),
emailResult.getBody());
break;
case 1:
addEmailOnlyContact(emailResult.getTos(), null);
break;
}
}
@Override
public int getDisplayTitle() {
return R.string.result_email_address;
}
}
/*
* Copyright (C) 2008 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.zxing.client.android.result;
import android.app.Activity;
import com.google.zxing.client.result.GeoParsedResult;
import com.google.zxing.client.result.ParsedResult;
import com.senthink.ebike_administrer_tool.R;
/**
* Handles geographic coordinates (typically encoded as geo: URLs).
*
* @author dswitkin@google.com (Daniel Switkin)
*/
public final class GeoResultHandler extends ResultHandler {
private static final int[] buttons = {
R.string.button_show_map,
R.string.button_get_directions
};
public GeoResultHandler(Activity activity, ParsedResult result) {
super(activity, result);
}
@Override
public int getButtonCount() {
return buttons.length;
}
@Override
public int getButtonText(int index) {
return buttons[index];
}
@Override
public void handleButtonPress(int index) {
GeoParsedResult geoResult = (GeoParsedResult) getResult();
switch (index) {
case 0:
openMap(geoResult.getGeoURI());
break;
case 1:
getDirections(geoResult.getLatitude(), geoResult.getLongitude());
break;
}
}
@Override
public int getDisplayTitle() {
return R.string.result_geo;
}
}
/*
* Copyright (C) 2008 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.zxing.client.android.result;
import android.app.Activity;
import com.google.zxing.Result;
import com.google.zxing.client.result.ISBNParsedResult;
import com.google.zxing.client.result.ParsedResult;
import com.senthink.ebike_administrer_tool.R;
/**
* Handles books encoded by their ISBN values.
*
* @author dswitkin@google.com (Daniel Switkin)
*/
public final class ISBNResultHandler extends ResultHandler {
private static final int[] buttons = {
R.string.button_product_search,
R.string.button_book_search,
R.string.button_search_book_contents,
R.string.button_custom_product_search
};
public ISBNResultHandler(Activity activity, ParsedResult result, Result rawResult) {
super(activity, result, rawResult);
}
@Override
public int getButtonCount() {
return hasCustomProductSearch() ? buttons.length : buttons.length - 1;
}
@Override
public int getButtonText(int index) {
return buttons[index];
}
@Override
public void handleButtonPress(int index) {
ISBNParsedResult isbnResult = (ISBNParsedResult) getResult();
switch (index) {
case 0:
openProductSearch(isbnResult.getISBN());
break;
case 1:
openBookSearch(isbnResult.getISBN());
break;
case 2:
searchBookContents(isbnResult.getISBN());
break;
case 3:
openURL(fillInCustomSearchURL(isbnResult.getISBN()));
break;
}
}
@Override
public int getDisplayTitle() {
return R.string.result_isbn;
}
}
/*
* Copyright (C) 2008 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.zxing.client.android.result;
import android.app.Activity;
import com.google.zxing.Result;
import com.google.zxing.client.result.ExpandedProductParsedResult;
import com.google.zxing.client.result.ParsedResult;
import com.google.zxing.client.result.ProductParsedResult;
import com.senthink.ebike_administrer_tool.R;
/**
* Handles generic products which are not books.
*
* @author dswitkin@google.com (Daniel Switkin)
*/
public final class ProductResultHandler extends ResultHandler {
private static final int[] buttons = {
R.string.button_product_search,
R.string.button_web_search,
R.string.button_custom_product_search
};
public ProductResultHandler(Activity activity, ParsedResult result, Result rawResult) {
super(activity, result, rawResult);
}
@Override
public int getButtonCount() {
return hasCustomProductSearch() ? buttons.length : buttons.length - 1;
}
@Override
public int getButtonText(int index) {
return buttons[index];
}
@Override
public void handleButtonPress(int index) {
String productID = getProductIDFromResult(getResult());
switch (index) {
case 0:
openProductSearch(productID);
break;
case 1:
webSearch(productID);
break;
case 2:
openURL(fillInCustomSearchURL(productID));
break;
}
}
private static String getProductIDFromResult(ParsedResult rawResult) {
if (rawResult instanceof ProductParsedResult) {
return ((ProductParsedResult) rawResult).getNormalizedProductID();
}
if (rawResult instanceof ExpandedProductParsedResult) {
return ((ExpandedProductParsedResult) rawResult).getRawText();
}
throw new IllegalArgumentException(rawResult.getClass().toString());
}
@Override
public int getDisplayTitle() {
return R.string.result_product;
}
}
/*
* Copyright (C) 2008 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.zxing.client.android.result;
import android.view.View;
/**
* Handles the result of barcode decoding in the context of the Android platform, by dispatching the
* proper intents to open other activities like GMail, Maps, etc.
*
* @author dswitkin@google.com (Daniel Switkin)
*/
public final class ResultButtonListener implements View.OnClickListener {
private final ResultHandler resultHandler;
private final int index;
public ResultButtonListener(ResultHandler resultHandler, int index) {
this.resultHandler = resultHandler;
this.index = index;
}
@Override
public void onClick(View view) {
resultHandler.handleButtonPress(index);
}
}
/*
* Copyright (C) 2008 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.zxing.client.android.result;
import com.google.zxing.Result;
import com.google.zxing.client.android.CaptureActivity;
import com.google.zxing.client.result.ParsedResult;
import com.google.zxing.client.result.ResultParser;
/**
* Manufactures Android-specific handlers based on the barcode content's type.
*
* @author dswitkin@google.com (Daniel Switkin)
*/
public final class ResultHandlerFactory {
private ResultHandlerFactory() {
}
public static ResultHandler makeResultHandler(CaptureActivity activity, Result rawResult) {
ParsedResult result = parseResult(rawResult);
switch (result.getType()) {
case ADDRESSBOOK:
return new AddressBookResultHandler(activity, result);
case EMAIL_ADDRESS:
return new EmailAddressResultHandler(activity, result);
case PRODUCT:
return new ProductResultHandler(activity, result, rawResult);
/* case URI:
return new URIResultHandler(activity, result);
case WIFI:
return new WifiResultHandler(activity, result);*/
case GEO:
return new GeoResultHandler(activity, result);
/*case TEL:
return new TelResultHandler(activity, result);
case SMS:
return new SMSResultHandler(activity, result);*/
case CALENDAR:
return new CalendarResultHandler(activity, result);
case ISBN:
return new ISBNResultHandler(activity, result, rawResult);
default:
return new TextResultHandler(activity, result, rawResult);
}
}
private static ParsedResult parseResult(Result rawResult) {
return ResultParser.parseResult(rawResult);
}
}
/*
* Copyright (C) 2008 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.zxing.client.android.result;
import android.app.Activity;
import com.google.zxing.Result;
import com.google.zxing.client.result.ParsedResult;
import com.senthink.ebike_administrer_tool.R;
/**
* This class handles TextParsedResult as well as unknown formats. It's the fallback handler.
*
* @author dswitkin@google.com (Daniel Switkin)
*/
public final class TextResultHandler extends ResultHandler {
private static final int[] buttons = {
R.string.button_web_search,
R.string.button_share_by_email,
R.string.button_share_by_sms,
R.string.button_custom_product_search,
};
public TextResultHandler(Activity activity, ParsedResult result, Result rawResult) {
super(activity, result, rawResult);
}
@Override
public int getButtonCount() {
return hasCustomProductSearch() ? buttons.length : buttons.length - 1;
}
@Override
public int getButtonText(int index) {
return buttons[index];
}
@Override
public void handleButtonPress(int index) {
String text = getResult().getDisplayResult();
switch (index) {
case 0:
webSearch(text);
break;
case 1:
shareByEmail(text);
break;
case 2:
shareBySMS(text);
break;
case 3:
openURL(fillInCustomSearchURL(text));
break;
}
}
@Override
public int getDisplayTitle() {
return R.string.result_text;
}
}
package com.senthink.ebike_administrer_tool.fragment;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import com.google.zxing.client.android.CaptureActivity;
import com.senthink.ebike_administrer_tool.R;
import com.senthink.ebike_administrer_tool.adapter.DispatchOutAdapter;
import com.senthink.ebike_administrer_tool.bean.dispatch.Dispatchout;
import com.senthink.ebike_administrer_tool.common.Common;
import com.senthink.ebike_administrer_tool.presenter.impl.DIspatchOutPresenterImpl;
import com.senthink.ebike_administrer_tool.view.IDispatchFragment;
......@@ -24,6 +28,7 @@ import java.util.List;
import butterknife.BindView;
import butterknife.ButterKnife;
/**
* @Description : 调出车辆
* @Author : ni
......@@ -39,8 +44,10 @@ public class DispatchOutFragment extends Fragment implements IDispatchFragment {
DispatchOutAdapter mAdapter;
DIspatchOutPresenterImpl presenter;
private static final String TAG = DispatchFragment.class.getSimpleName();
private Dispatchout out = new Dispatchout();
private List<Dispatchout> mList = new ArrayList<>();
private static final int ACTION_SCAN_BARCODE = 1001;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
......@@ -68,7 +75,6 @@ public class DispatchOutFragment extends Fragment implements IDispatchFragment {
private void initData() {
presenter = new DIspatchOutPresenterImpl(this);
presenter.getCarInfo();
LinearLayoutManager layout = new LinearLayoutManager(getActivity());
recyclerView.setLayoutManager(layout);
......@@ -89,24 +95,34 @@ public class DispatchOutFragment extends Fragment implements IDispatchFragment {
@Override
public void scan() {
out.setParkId("123");
out.setCarId("3123");
mList.add(out);
// mAdapter.setData(mList);
mAdapter.notifyItemInserted(mList.size()-1);
mAdapter.notifyItemRangeChanged(mList.size()-1,mList.size()-1);
// out.setParkId("123");
// out.setCarId("3123");
// mList.add(out);
//// mAdapter.setData(mList);
// mAdapter.notifyItemInserted(mList.size()-1);
// mAdapter.notifyItemRangeChanged(mList.size()-1,mList.size()-1);
Intent intent = new Intent();
intent.setClass(getActivity(), CaptureActivity.class);
startActivityForResult(intent, ACTION_SCAN_BARCODE);
}
@Override
public void updateInfo() {
// TODO: 2017/6/12 获取数据
presenter.getCarInfo();
Log.i(TAG, "updateInfo: ");
}
@Override
public void submitSuccess() {
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == ACTION_SCAN_BARCODE
&& resultCode == 1070) {
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:bottomLeftRadius="@dimen/switch_button_corners_radius"
android:bottomRightRadius="@dimen/switch_button_corners_radius"
android:topLeftRadius="@dimen/switch_button_corners_radius"
android:topRightRadius="@dimen/switch_button_corners_radius"/>
<padding android:left="5dp"/>
<solid android:color="@color/white"/>
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_height="match_parent"
android:background="@color/background_color_white">
<LinearLayout
android:paddingTop="15dp"
......@@ -41,8 +42,7 @@
</LinearLayout>
<android.support.v4.view.ViewPager
android:id="@+id/vp_dispatch"
android:paddingLeft="20dp"
android:paddingRight="20dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</android.support.v4.view.ViewPager>
......
......@@ -2,10 +2,9 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingTop="10dp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:paddingBottom="10dp">
android:paddingLeft="20dp"
android:paddingRight="20dp"
>
<EditText
android:id="@+id/et_input_parkname"
......@@ -13,7 +12,7 @@
android:textSize="@dimen/small_text"
android:layout_width="match_parent"
android:layout_height="37dp"
android:background="@drawable/modify_input_frame" />
android:background="@drawable/search_park_name" />
<RelativeLayout
android:id="@+id/rl_text"
android:paddingTop="10dp"
......@@ -65,7 +64,10 @@
<android.support.v7.widget.RecyclerView
android:layout_below="@+id/rl_text"
android:background="@drawable/search_park_name"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
android:layout_above="@+id/btn_dispatch_in_scan"
android:id="@+id/recycleView_dispatch_in"
android:layout_width="match_parent"
android:layout_height="wrap_content"></android.support.v7.widget.RecyclerView>
......
......@@ -4,10 +4,9 @@
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingTop="10dp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:paddingBottom="10dp">
android:paddingLeft="20dp"
android:paddingRight="20dp"
>
<LinearLayout
android:id="@+id/ll_text"
android:orientation="horizontal"
......@@ -16,15 +15,21 @@
<TextView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:textSize="@dimen/toolbar_submit_size"
android:textColor="@color/tab_tv_normal"
android:text="共"/>
<TextView
android:id="@+id/tv_dispatch_out_num"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="@dimen/toolbar_submit_size"
android:textColor="@color/tab_tv_normal"
android:text="10"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:textSize="@dimen/toolbar_submit_size"
android:textColor="@color/tab_tv_normal"
android:text="辆"/>
</LinearLayout>
......@@ -35,7 +40,11 @@
<!--android:layout_width="match_parent"-->
<!--android:layout_height="wrap_content">-->
<android.support.v7.widget.RecyclerView
android:background="@drawable/search_park_name"
android:layout_below="@+id/ll_text"
android:layout_above="@+id/btn_dispatch_out_scan"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
android:id="@+id/recycleView_dispatch_out"
android:layout_width="match_parent"
android:layout_height="wrap_content"></android.support.v7.widget.RecyclerView>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment