我的摩托罗拉 Defy 中的这个应用程序(Mini4WD Lap Timer)有问题。他们提供了源代码。也许你可以帮助我在我的设备上兼容它 。https://play.google.com/store /apps/details?id=com.pimentoso.android.laptimer&feature=search_result#?t=W251bGwsMSwxLDEsImNvbS5waW1lbnRvc28uYW5kcm9pZC5sYXB0aW1lciJd
问题是校准时,它有库存..计时器左上角的小预览不起作用,只显示黑色..
这是代码
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.pimentoso.android.laptimer" android:versionCode="8"
android:versionName="1.4.1" android:installLocation="auto">
<uses-sdk android:minSdkVersion="8" android:targetSdkVersion="8" />
<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".TimerActivity" android:label="@string/app_name"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".SensitivityDialogActivity"
android:label="@string/label_sensitivity" android:theme="@android:style/Theme.Dialog" />
</application>
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.SET_ORIENTATION" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
</manifest>
FPSCounter.java
package com.pimentoso.android.laptimer;
import android.util.Log;
public class FPSCounter {
long startTime = System.nanoTime();
int frames = 0;
public void logFrame() {
frames++;
if(System.nanoTime() - startTime >= 1000000000) {
Log.d("FPSCounter", "fps: " + frames);
frames = 0;
startTime = System.nanoTime();
}
}
}
SensitivityDialogActivity.java
package com.pimentoso.android.laptimer;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup.LayoutParams;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;
public class SensitivityDialogActivity extends Activity implements OnClickListener, OnSeekBarChangeListener
{
private SeekBar bar;
private TextView barValue;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.sensitivity);
findViewById(R.id.button_sensitivity_close).setOnClickListener(this);
LayoutParams params = getWindow().getAttributes();
params.width = LayoutParams.FILL_PARENT;
getWindow().setAttributes((android.view.WindowManager.LayoutParams) params);
String currentValue = getPreferences(MODE_PRIVATE).getString("sensitivity", "15");
bar = (SeekBar) findViewById(R.id.seekbar_sensitivity);
bar.setOnSeekBarChangeListener(this);
barValue = (TextView) findViewById(R.id.seekbar_sensitivity_value);
barValue.setText(currentValue);
bar.setProgress(Integer.valueOf(currentValue));
// settare il valore nel timer a (25-barValue)
// barra 20 = 5
// barra 15 = 10
// barra 10 = 15
// barra 5 = 20
// barra 0 = 25
}
@Override
public void onClick(View v)
{
String finalValue = barValue.getText().toString();
getPreferences(MODE_PRIVATE).edit().putString("sensitivity", finalValue).commit();
TimerActivity.calibrateThreshold = 25 - Integer.valueOf(finalValue);
this.finish();
}
@Override
public void onProgressChanged(SeekBar arg0, int arg1, boolean arg2)
{
String t = String.valueOf(arg1);
barValue.setText(t);
}
@Override
public void onStartTrackingTouch(SeekBar arg0)
{
}
@Override
public void onStopTrackingTouch(SeekBar arg0)
{
}
}
TimerActivity.java
package com.pimentoso.android.laptimer;
import java.io.IOException;
import java.util.ArrayList;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.ImageFormat;
import android.hardware.Camera;
import android.os.Bundle;
import android.os.Handler;
import android.os.SystemClock;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
public class TimerActivity extends Activity implements SurfaceHolder.Callback, Camera.PreviewCallback, OnClickListener {
// elementi del layout
SurfaceView mSurfaceView;
SurfaceHolder mSurfaceHolder;
Camera mCamera;
TextView timerLabel;
TextView statusLabel;
TextView lap1Label;
TextView lap2Label;
TextView lap3Label;
TextView lapBestLabel;
Button startButton;
// flags
boolean isPreviewRunning = false;
boolean isCalibrating = false;
boolean isCalibrated = false;
boolean isStarted = false;
boolean isTimerRunning = false;
boolean caughtPreviousFrame = false;
// contatore dei frame per calibrazione
int frame = 0;
// offset dei pixel da controllare
int[] pixelOffset = new int[3];
// array di calibrazione
int[][] calibrateRange = new int[3][20];
// valori finali di calibrazione
int[] calibrateValue = new int[3];
// soglia di differenza di luminosità per catchare il frame
public static int calibrateThreshold = 10;
// tempo iniziale
long mStartTime = 0L;
// millisecondi di ultimo catch
long mLastCatchTime = 0;
// tempo del giro migliore
long bestLap = 0;
// tempi dei giri
// long[] laps = new long[3];
ArrayList<Long> laps = new ArrayList<Long>();
// contatore dei giri
int lapCount = 0;
FPSCounter fps = new FPSCounter();
Handler mHandler = new Handler();
StringBuffer timerBuffer;
StringBuffer lapBuffer;
private Runnable mUpdateTimeTask = new Runnable() {
public void run() {
long millis = SystemClock.uptimeMillis() - mStartTime;
timerLabel.setText(convertTime(millis));
mHandler.postAtTime(this, SystemClock.uptimeMillis() + 40);
}
};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
findViewById(R.id.button_start).setOnClickListener(this);
findViewById(R.id.button_calibrate).setOnClickListener(this);
mSurfaceView = (SurfaceView) findViewById(R.id.surface_camera);
mSurfaceHolder = mSurfaceView.getHolder();
mSurfaceHolder.addCallback(this);
mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
String threshold = getPreferences(MODE_PRIVATE).getString("sensitivity", "15");
calibrateThreshold = Integer.valueOf(threshold);
timerLabel = (TextView) findViewById(R.id.text_timer);
statusLabel = (TextView) findViewById(R.id.text_status);
lap1Label = (TextView) findViewById(R.id.text_lap_1);
lap2Label = (TextView) findViewById(R.id.text_lap_2);
lap3Label = (TextView) findViewById(R.id.text_lap_3);
lapBestLabel = (TextView) findViewById(R.id.text_lap_best);
startButton = (Button) findViewById(R.id.button_start);
statusLabel.setText(getString(R.string.label_status_init));
startButton.setEnabled(false);
}
@Override
public void onStart() {
super.onStart();
// show help
if (getPreferences(MODE_PRIVATE).getString("first_time", "1").equals("1")) {
showAlertBox();
getPreferences(MODE_PRIVATE).edit().putString("first_time", "0").commit();
}
}
@Override
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
}
@Override
public void surfaceCreated(SurfaceHolder arg0) {
synchronized (this) {
try {
mCamera = Camera.open();
}
catch (RuntimeException e) {
// camera service already in use: schianta
new AlertDialog.Builder(this).setMessage(getString(R.string.error_camera_locked_text)).setTitle("Error").setCancelable(true).setIcon(android.R.drawable.ic_dialog_info).setNeutralButton(android.R.string.ok, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
TimerActivity.this.finish();
}
}).show();
return;
}
if (mCamera == null) {
// camera not found: schianta
new AlertDialog.Builder(this).setMessage(getString(R.string.error_camera_null_text)).setTitle("Error").setCancelable(true).setIcon(android.R.drawable.ic_dialog_info).setNeutralButton(android.R.string.ok, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
TimerActivity.this.finish();
}
}).show();
return;
}
Camera.Parameters parameters = mCamera.getParameters();
Camera.Size mCameraSize = parameters.getPreviewSize();
int bytesPerPixel = ImageFormat.getBitsPerPixel(parameters.getPreviewFormat());
int bufferSize = (mCameraSize.width * mCameraSize.height * bytesPerPixel) >> 3;
mCamera.addCallbackBuffer(new byte[bufferSize]);
mCamera.addCallbackBuffer(new byte[bufferSize]);
mCamera.addCallbackBuffer(new byte[bufferSize]);
pixelOffset[0] = (int) (mCameraSize.width / 2) + (mCameraSize.width * (int) (mCameraSize.height * 0.1));
pixelOffset[1] = (int) (mCameraSize.width / 2) + (mCameraSize.width * (int) (mCameraSize.height * 0.5));
pixelOffset[2] = (int) (mCameraSize.width / 2) + (mCameraSize.width * (int) (mCameraSize.height * 0.9));
mCamera.setDisplayOrientation(90);
try {
mCamera.setPreviewDisplay(arg0);
}
catch (IOException e) {
Log.e("Camera", "Could not set preview display");
}
mCamera.setPreviewCallbackWithBuffer(this);
mCamera.startPreview();
isPreviewRunning = true;
}
}
@Override
public void surfaceDestroyed(SurfaceHolder arg0) {
synchronized (this) {
try {
if (mCamera != null) {
mCamera.setPreviewCallback(null);
mCamera.stopPreview();
isPreviewRunning = false;
}
}
catch (Exception e) {
Log.e("Camera", e.getMessage());
}
finally {
if (mCamera != null) {
mCamera.release();
}
}
}
}
@Override
public void onPreviewFrame(byte[] yuv, Camera arg1) {
int value0 = (int) yuv[pixelOffset[0]] & 0xFF;
int value1 = (int) yuv[pixelOffset[1]] & 0xFF;
int value2 = (int) yuv[pixelOffset[2]] & 0xFF;
// sto calibrando...
if (isCalibrating) {
frame++;
Log.d("Timer", "Calibrating, " + value0 + ";" + value1 + ";" + value2);
calibrateRange[0][frame - 1] = value0;
calibrateRange[1][frame - 1] = value1;
calibrateRange[2][frame - 1] = value2;
if (frame >= 20) {
// finito di calibrare
isCalibrating = false;
isCalibrated = true;
startButton.setEnabled(true);
statusLabel.setText(getString(R.string.label_status_ready));
// calcolo la media
int tot0 = 0, tot1 = 0, tot2 = 0;
for (int i = 0; i < 20; i++) {
tot0 += calibrateRange[0][i];
tot1 += calibrateRange[1][i];
tot2 += calibrateRange[2][i];
}
calibrateValue[0] = tot0 / 20;
calibrateValue[1] = tot1 / 20;
calibrateValue[2] = tot2 / 20;
Log.d("Timer", "Calibrated on [" + calibrateValue[0] + "][" + calibrateValue[1] + "][" + calibrateValue[2] + "]");
}
}
// sono in ascolto di variazioni
else if (isStarted) {
// catch del frame
if (isCalibrated && (value0 < calibrateValue[0] - calibrateThreshold || value0 > calibrateValue[0] + calibrateThreshold || value1 < calibrateValue[1] - calibrateThreshold || value1 > calibrateValue[1] + calibrateThreshold || value2 < calibrateValue[2] - calibrateThreshold || value2 > calibrateValue[2] + calibrateThreshold)) {
// se ho catchato il frame precedente, ignoro
if (!caughtPreviousFrame) {
Log.d("Timer", "Frame caught!");
caughtPreviousFrame = true;
if (isTimerRunning) {
// calcolo dei lap
long catchTime = SystemClock.uptimeMillis();
lapCount++;
long lapTime = catchTime - mLastCatchTime;
laps.add(lapTime);
if (lapCount == 1) {
bestLap = lapTime;
}
else if (bestLap > lapTime) {
bestLap = lapTime;
}
printLaps();
mLastCatchTime = catchTime;
}
else {
// devo far partire il timer
isTimerRunning = true;
mStartTime = SystemClock.uptimeMillis();
mLastCatchTime = mStartTime;
mHandler.removeCallbacks(mUpdateTimeTask);
mHandler.postDelayed(mUpdateTimeTask, 50);
}
}
}
else {
caughtPreviousFrame = false;
}
}
mCamera.addCallbackBuffer(yuv);
fps.logFrame();
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.button_start: {
if (!isCalibrated || isCalibrating) {
// non è calibrato
break;
}
if (isStarted) {
// ho stoppato
startButton.setText("Start");
statusLabel.setText(getString(R.string.label_status_ready));
isStarted = false;
isTimerRunning = false;
mHandler.removeCallbacks(mUpdateTimeTask);
}
else {
// ho startato
startButton.setText("Stop");
statusLabel.setText(getString(R.string.label_status_started));
timerLabel.setText("0:00:0");
isStarted = true;
mStartTime = 0L;
lapCount = 0;
// resetto i laps
laps = new ArrayList<Long>();
bestLap = 0;
printLaps();
}
break;
}
case R.id.button_calibrate: {
if (isTimerRunning) {
// devo stoppare prima di calibrare
break;
}
// ho pigiato calibra, devo resettare tutto
statusLabel.setText(getString(R.string.label_status_calibrating));
timerLabel.setText("0:00:0");
frame = 0;
mStartTime = 0L;
lapCount = 0;
isStarted = false;
isTimerRunning = false;
isCalibrating = true;
isCalibrated = false;
// resetto i laps
laps = new ArrayList<Long>();
bestLap = 0;
printLaps();
break;
}
}
}
private String convertTime(long millis) {
if (millis == 0) {
return "0:00:0";
}
timerBuffer = new StringBuffer();
int split = ((int) (millis / 100)) % 10;
int seconds = (int) (millis / 1000);
int minutes = seconds / 60;
seconds = seconds % 60;
if (seconds < 10) {
timerBuffer.append(minutes).append(":0").append(seconds).append(":").append(split);
return timerBuffer.toString();
}
else {
timerBuffer.append(minutes).append(":").append(seconds).append(":").append(split);
return timerBuffer.toString();
}
}
private void printLaps() {
lapBuffer = new StringBuffer();
try {
lapBuffer.append("Lap ").append(lapCount).append(": ").append(convertTime(laps.get(laps.size() - 1)));
}
catch (IndexOutOfBoundsException e) {
lapBuffer.append("Lap ").append(lapCount).append(": ").append(convertTime(0));
}
lap1Label.setText(lapBuffer.toString());
lapBuffer = new StringBuffer();
if (lapCount > 1) {
lapBuffer.append("Lap ").append(lapCount - 1);
}
else {
lapBuffer.append("Lap 0");
}
try {
lapBuffer.append(": ").append(convertTime(laps.get(laps.size() - 2)));
}
catch (IndexOutOfBoundsException e) {
lapBuffer.append(": ").append(convertTime(0));
}
lap2Label.setText(lapBuffer.toString());
lapBuffer = new StringBuffer();
if (lapCount > 2) {
lapBuffer.append("Lap ").append(lapCount - 2);
}
else {
lapBuffer.append("Lap 0");
}
try {
lapBuffer.append(": ").append(convertTime(laps.get(laps.size() - 3)));
}
catch (IndexOutOfBoundsException e) {
lapBuffer.append(": ").append(convertTime(0));
}
lap3Label.setText(lapBuffer.toString());
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_tutorial: {
showAlertBox();
return true;
}
case R.id.menu_sensitivity: {
// devo stoppare tutto
startButton.setText("Start");
statusLabel.setText(getString(R.string.label_status_ready));
isStarted = false;
isTimerRunning = false;
mHandler.removeCallbacks(mUpdateTimeTask);
Intent i = new Intent(this, SensitivityDialogActivity.class);
startActivity(i);
return true;
}
case R.id.menu_email: {
if (isStarted || isTimerRunning) {
Toast.makeText(this, getString(R.string.error_timer_started), Toast.LENGTH_SHORT).show();
return true;
}
if (laps == null || laps.size() == 0) {
Toast.makeText(this, getString(R.string.error_laps_empty), Toast.LENGTH_SHORT).show();
return true;
}
String emailBody = lapsToString();
final Intent emailIntent = new Intent(android.content.Intent.ACTION_SEND);
emailIntent.setType("plain/text");
emailIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, getString(R.string.app_name));
emailIntent.putExtra(android.content.Intent.EXTRA_TEXT, emailBody);
startActivity(Intent.createChooser(emailIntent, getString(R.string.menu_mail_laps)));
return true;
}
}
return false;
}
public void showAlertBox() {
new AlertDialog.Builder(this).setMessage(getString(R.string.dialog_tutorial_text)).setTitle("Tutorial").setCancelable(true).setIcon(android.R.drawable.ic_dialog_info).setNeutralButton(android.R.string.ok, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
}
}).show();
}
private String lapsToString() {
StringBuffer s = new StringBuffer();
s.append("Mini 4WD Android Lap Timer data");
s.append("\n\n");
for (int i = 0; i < laps.size(); i++) {
long lap = laps.get(i);
s.append("Lap ").append(i + 1).append(": ").append(convertTime(lap)).append("\n");
}
s.append("\n");
s.append("Best lap: " + convertTime(bestLap));
return s.toString();
}
}
先感谢您.. :)