Android应用程序Mini4WD Lap Timer,使用相机作为传感器

时间:2012-11-09 11:27:24

标签: android timer camera calibration

我的摩托罗拉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();
    }
}

提前谢谢.. :))

0 个答案:

没有答案