获取Google Glass相机时出现间歇性错误

时间:2013-11-30 01:24:51

标签: google-glass google-gdk

在Glass GDK应用程序中获取相机时出现间歇性错误。该应用程序是一个简单的应用程序:

  1. 响应语音触发(“测试相机”)
  2. 启动活动以拍摄快照
  3. 返回调用Activity以显示快照。
  4. 问题在于该应用程序可以运行,但是它不时会不会获取相机。我已经将多个try / catch块中的相机调用完成处理(如果它无法获取相机,应用程序就会退出),但我想知道它为什么会在第一时间发生。

    除了以下内容,我不会担心这个:

    1. 我注意到这些错误经常发生在我用“拍照”语音提示拍摄照片后启动应用程序(好像“拍照”应用程序没有释放相机。)

    2. 我投入了很多次尝试/捕获来防止每次不良的相机通话,但......在我这样做之前,(即当我的代码不那么专注于释放相机时),该装置会非常温暖,以至于我不得不将其关闭再打开,以确保我没有损坏它。

    3. 我在日志中看到的唯一奇怪的事情是以下消息。我不知道 “未知消息类型8192” 可能

      11-29 19:38:16.344: E/Camera(4551): Received CAMERA_MSG_RELEASE
      11-29 19:38:16.493: D/Camera-JNI(4551): android_hardware_Camera_release - context->decStrong(thiz)
      11-29 19:38:16.524: E/Camera(4551): Unknown message type 8192
      

      因为我不知道造成这种情况的原因,我将发布整个项目,以查看xml文件中是否存在可能导致此问题的其他模糊位置。

      这是清单:

      <?xml version="1.0" encoding="utf-8"?>
      <manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.example.testcamera"
          android:versionCode="1"
          android:versionName="1.0" >
      
          <uses-sdk
              android:minSdkVersion="15"
              android:targetSdkVersion="15" />
      
          <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
          <uses-permission android:name="android.permission.CAMERA"/>
          <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
          <uses-feature android:name="android.hardware.camera" />
          <uses-feature android:name="android.hardware.camera.autofocus" />
          <uses-permission android:name="android.permission.INTERNET" />
          <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
      
          <application
              android:allowBackup="true"
              android:icon="@drawable/ic_launcher"
              android:label="@string/app_name" >
              <activity
                  android:name="com.example.testcamera.MainActivity"
                  android:label="@string/app_name" >
                  <intent-filter>
                  <action
                      android:name="com.google.android.glass.action.VOICE_TRIGGER" />
                  </intent-filter>
                  <meta-data android:name="com.google.android.glass.VoiceTrigger"
                             android:resource="@xml/voice_trigger" />
              </activity>
              <activity
                  android:name="com.example.testcamera.CameraActivity"
                  android:label="@string/app_name" />
          </application>
      
      </manifest>
      

      这是语音触发器:

      <?xml version="1.0" encoding="utf-8"?>
      <trigger keyword="@string/glass_voice_trigger">
              <constraints
              camera="true"
              network="true" 
              microphone="true" />
      </trigger>
      

      以下是字符串:

      <?xml version="1.0" encoding="utf-8"?>
      <resources>
      
          <string name="app_name">TestCamera</string>
          <string name="action_settings">Settings</string>
          <string name="hello_world">Hello world!</string>
          <string name="glass_voice_trigger">test the camera</string>
      
          <!-- Menu item strings. -->
          <string name="stop">Done</string>
          <string name="tapforoptions">Tap for options</string>
      
      </resources>
      

      以下是主要活动的布局:

      <?xml version="1.0" encoding="utf-8"?>
      <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
          android:layout_width="match_parent"
          android:layout_height="match_parent"
          android:background="@android:color/black">
      
              <ImageView
              android:id="@+id/bgPhoto"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:src="@drawable/black_bg"
              android:alpha="0.5" />
      
              <LinearLayout     android:id="@+id/queryLinearLayout"
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:layout_marginLeft="10dp"
          android:layout_marginRight="10dp"
          android:orientation="vertical">
      
             <TextView
              android:id="@+id/text1"
              android:layout_width="wrap_content"
              android:layout_marginLeft="2dp"
              android:layout_height="wrap_content"
              android:gravity="left"
              android:textColor="#FFFFFF"
              android:text="@string/hello_world"  />
      
             <TextView
              android:id="@+id/text2"
              android:layout_width="wrap_content"
              android:layout_marginLeft="2dp"
              android:layout_height="wrap_content"
              android:gravity="left"
              android:textColor="#FFFFFF"
              android:text="@string/hello_world"  />
      
      </LinearLayout>
      
                      <LinearLayout 
          android:id="@+id/resultLinearLayout"
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:layout_marginLeft="10dp"
          android:layout_marginRight="10dp"
          android:orientation="vertical">
      
             <TextView
              android:id="@+id/titleOfWork"
              android:layout_width="wrap_content"
              android:layout_marginLeft="2dp"
              android:layout_height="wrap_content"
              android:gravity="left"
              android:textColor="#FFFFFF"
              android:textSize="30sp"
              android:text="@string/hello_world"  />
      
             <TextView
              android:id="@+id/Singer"
              android:layout_width="wrap_content"
              android:layout_marginLeft="2dp"
              android:layout_height="wrap_content"
              android:gravity="left"
              android:textColor="#FFFFFF"
              android:textSize="36sp"
                      android:textStyle="bold"
              android:text="@string/hello_world"  />
      
      </LinearLayout>
      
             <ProgressBar
              android:id="@+id/my_progressBar"
              android:layout_height="wrap_content"
              android:layout_width="match_parent" 
              style="?android:attr/progressBarStyleHorizontal" 
              android:layout_gravity="bottom"
              android:layout_margin="10dp"
          />
      
                           <TextView
              android:id="@+id/tap_instruction"
              android:layout_width="fill_parent"
              android:layout_marginLeft="2dp"
              android:layout_height="wrap_content"
              android:gravity="center"
              android:layout_gravity="bottom"
              android:textColor="#FFFFFF"
              android:textSize="16sp"
              android:textStyle="bold"
              android:layout_margin="20dp"
              android:text="@string/tapforoptions"  />
      
      </FrameLayout>
      

      以下是相机活动的布局:

      <?xml version="1.0" encoding="utf-8"?>
      <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
          android:orientation="vertical"
          android:layout_width="fill_parent"
          android:layout_height="fill_parent" >
      
          <SurfaceView 
              android:id="@+id/surfaceView"
              android:layout_height="match_parent"
              android:layout_width="match_parent" 
               />    
          <ImageView
              android:id="@+id/imageView"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              />
      
      </LinearLayout>
      

      以下是主要活动的代码:

      package com.example.testcamera;
      
      import java.io.File;
      import com.google.android.glass.touchpad.Gesture;
      import com.google.android.glass.touchpad.GestureDetector;
      import android.os.Bundle;
      import android.os.Handler;
      import android.app.Activity;
      import android.content.Context;
      import android.content.Intent;
      import android.graphics.Bitmap;
      import android.graphics.BitmapFactory;
      import android.graphics.Point;
      import android.speech.tts.TextToSpeech;
      import android.util.Log;
      import android.view.Display;
      import android.view.Menu;
      import android.view.MenuItem;
      import android.view.MotionEvent;
      import android.view.View;
      import android.view.WindowManager;
      import android.widget.ImageView;
      import android.widget.LinearLayout;
      import android.widget.ProgressBar;
      import android.widget.TextView;
      
      public class MainActivity extends Activity {
      
          // App responds to voice trigger "test the camera", takes a picture with CameraActivity and then returns.
      
          private static final String TAG = MainActivity.class.getSimpleName();
          private static final int TAKE_PHOTO_CODE = 1;
          private static final int PROGRESS_TIMEOUT = 30000; // in ms --> 10s
          private static final String IMAGE_FILE_NAME = "/sdcard/ImageTest.jpg";
      
          private boolean picTaken = false; // flag to indicate if we just returned from the picture taking intent
          private String theImageFile = ""; // this holds the name of the image that was returned by the camera
      
          private TextView text1;
          private TextView text2;
      
          private ProgressBar myProgressBar;
          protected boolean mbActive;
      
          private String inputQueryString;
          private String queryCategory;
      
          final Handler myHandler = new Handler(); // handles looking for the returned image file
          private int numberOfImageFileAttempts = 0;
      
          private String responseBody = "";
      
          private TextToSpeech mSpeech;
      
          private boolean readyForMenu = false;
          private boolean gotImageMatch = false;
      
          private GestureDetector mGestureDetector;
      
          @Override
          protected void onCreate(Bundle savedInstanceState) {
              super.onCreate(savedInstanceState);
      
              Log.v(TAG,"creating activity");
      
              getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
      
              setContentView(R.layout.activity_main);
              text1 = (TextView) findViewById(R.id.text1);
              text2 = (TextView) findViewById(R.id.text2);
              text1.setText("");
              text2.setText("");
              myProgressBar = (ProgressBar) findViewById(R.id.my_progressBar);
              LinearLayout llResult = (LinearLayout) findViewById(R.id.resultLinearLayout);
              TextView tvResult = (TextView) findViewById(R.id.tap_instruction);
              llResult.setVisibility(View.INVISIBLE);
              tvResult.setVisibility(View.INVISIBLE);
              myProgressBar.setVisibility(View.INVISIBLE);
      
              // Even though the text-to-speech engine is only used in response to a menu action, we
              // initialize it when the application starts so that we avoid delays that could occur
              // if we waited until it was needed to start it up
              mSpeech = new TextToSpeech(this, new TextToSpeech.OnInitListener() {
                  @Override
                  public void onInit(int status) {
                      // Do nothing.
                  }
              });
      
              mGestureDetector = createGestureDetector(this);
      
          }
      
          @Override
          public boolean onCreateOptionsMenu(Menu menu) {
              // Inflate the menu; this adds items to the action bar if it is present.
              getMenuInflater().inflate(R.menu.main, menu);
              return true;
          }
      
          @Override
          protected void onResume() {
              super.onResume();
      
              if (!picTaken) {
                  Intent intent = new Intent(this, CameraActivity.class);
                  intent.putExtra("imageFileName",IMAGE_FILE_NAME);
                  startActivityForResult(intent,1);
              }
              else {
                  // do nothing
              }
          }
      
          /*
           * Send generic motion events to the gesture detector
           */
          @Override
          public boolean onGenericMotionEvent(MotionEvent event) {
              if (mGestureDetector != null) {
                  return mGestureDetector.onMotionEvent(event);
              }
              return false;
          }
      
          private GestureDetector createGestureDetector(Context context) {
              GestureDetector gestureDetector = new GestureDetector(context);
                  //Create a base listener for generic gestures
                  gestureDetector.setBaseListener( new GestureDetector.BaseListener() {
                      @Override
                      public boolean onGesture(Gesture gesture) {
                          if (gesture == Gesture.TAP) {
                              // do something on tap
                              Log.v(TAG,"tap");
                              //if (readyForMenu) {
                                  openOptionsMenu();
                              //}
                              return true;
                          } else if (gesture == Gesture.TWO_TAP) {
                              // do something on two finger tap
                              return true;
                          } else if (gesture == Gesture.SWIPE_RIGHT) {
                              // do something on right (forward) swipe
                              return true;
                          } else if (gesture == Gesture.SWIPE_LEFT) {
                              // do something on left (backwards) swipe
                              return true;
                          }
                          return false;
                      }
                  });
                  gestureDetector.setFingerListener(new GestureDetector.FingerListener() {
                      @Override
                      public void onFingerCountChanged(int previousCount, int currentCount) {
                        // do something on finger count changes
                      }
                  });
                  gestureDetector.setScrollListener(new GestureDetector.ScrollListener() {
                      @Override
                      public boolean onScroll(float displacement, float delta, float velocity) {
                          // do something on scrolling
                          return false;
                      }
                  });
                  return gestureDetector;
              }
      
          @Override
          public boolean onOptionsItemSelected(MenuItem item) {
              switch (item.getItemId()) {
                  case R.id.stop:
                      finish();
                      return true;
                  default:
                      return super.onOptionsItemSelected(item);
              }
          }
      
          @Override
          public void onActivityResult(int requestCode, int resultCode, Intent data) {
            super.onActivityResult(requestCode, resultCode, data);
            picTaken = true;
            switch(requestCode) {
              case (1) : {
                if (resultCode == Activity.RESULT_OK) {
                  // TODO Extract the data returned from the child Activity.
                    Log.v(TAG,"onActivityResult"); 
      
                    File f = new File(IMAGE_FILE_NAME);
                     if (f.exists()) {
                         Log.v(TAG,"image file from camera was found");
      
                         Bitmap b = BitmapFactory.decodeFile(IMAGE_FILE_NAME);
                         Log.v(TAG,"bmp width=" + b.getWidth() + " height=" + b.getHeight());
                         ImageView image = (ImageView) findViewById(R.id.bgPhoto);
                         image.setImageBitmap(b);
      
                         text1 = (TextView) findViewById(R.id.text1);
                         text2 = (TextView) findViewById(R.id.text2);
                         text1.setText("Got a picture.");
                         text2.setText("\nSaved successfully to " + IMAGE_FILE_NAME);
      
                         LinearLayout llResult = (LinearLayout) findViewById(R.id.resultLinearLayout);
                         llResult.setVisibility(View.VISIBLE);
                         TextView line1 = (TextView) findViewById(R.id.titleOfWork);
                         TextView line2 = (TextView) findViewById(R.id.Singer);
                         TextView tap = (TextView) findViewById(R.id.tap_instruction);
                         line1.setText("");
                         line2.setText("");
                         tap.setVisibility(View.VISIBLE);
                     }
                }
                else {
                    Log.v(TAG,"onActivityResult returned bad result code");
                    finish();
                }
                break;
              } 
            }
          }
      
          @Override
          protected void onDestroy() {
      
              //Close the Text to Speech Library
              if(mSpeech != null) {
                  mSpeech.stop();
                  mSpeech.shutdown();
                  mSpeech = null;
                  Log.d(TAG, "TTS Destroyed");
              }
              super.onDestroy();
          }
      
      }
      

      以下是相机活动的代码:

      package com.example.testcamera;
      
      import java.io.BufferedOutputStream;
      import java.io.FileNotFoundException;
      import java.io.FileOutputStream;
      import java.io.IOException;
      import java.util.List;
      
      import android.app.Activity;
      import android.content.Intent;
      import android.graphics.Bitmap;
      import android.graphics.BitmapFactory;
      import android.graphics.Bitmap.CompressFormat;
      import android.hardware.Camera;
      import android.hardware.Camera.Parameters;
      import android.os.Bundle;
      import android.util.Log;
      import android.view.SurfaceHolder;
      import android.view.SurfaceView;
      import android.widget.ImageView;
      
      public class CameraActivity extends Activity implements SurfaceHolder.Callback
      {
          private static final String TAG = CameraActivity.class.getSimpleName();
          public static final int BUFFER_SIZE = 1024 * 8;
          String imageFileName = "";
          //a variable to store a reference to the Image View at the main.xml file.
          private ImageView iv_image;
          //a variable to store a reference to the Surface View at the main.xml file
          private SurfaceView sv;
          //a bitmap to display the captured image
          private Bitmap bmp;
          //Camera variables
          //a surface holder
          private SurfaceHolder sHolder; 
          //a variable to control the camera
          private Camera mCamera;
          //the camera parameters
          private Parameters parameters;
      
        @Override
        public void onCreate(Bundle savedInstanceState)
        {
            Log.v(TAG,"onCreate");
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_camera);
            //get the Image View at the main.xml file
            iv_image = (ImageView) findViewById(R.id.imageView);
            sv = (SurfaceView) findViewById(R.id.surfaceView);
            //Get a surface
            sHolder = sv.getHolder();
            sHolder.addCallback(this);
            Bundle extras = getIntent().getExtras();
            // get the image file name from the caller to save the 640x360 image
            imageFileName = extras.getString("imageFileName");
        }
      
          public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3)
          {
            Log.v(TAG,"surfaceChanged");
                 //get camera parameters
            try {
                parameters = mCamera.getParameters();
                Log.v(TAG,"got parms");
                //set camera parameters
                parameters.setPreviewSize(640,360);
                parameters.setPictureSize(1280,720);
                //Camera.Parameters params = mCamera.getParameters();
                parameters.setPreviewFpsRange(30000, 30000);
                Log.v(TAG,"parms were set");
                mCamera.setParameters(parameters);
      
                mCamera.startPreview();
                Log.v(TAG,"preview started");
      
                //sets what code should be executed after the picture is taken
                Camera.PictureCallback mCall = new Camera.PictureCallback()
                {
                  public void onPictureTaken(byte[] data, Camera camera)
                  {
                      Log.v(TAG,"pictureTaken");
                      Log.v(TAG,"data bytes=" + data.length);
                        //decode the data obtained by the camera into a Bitmap
                      Bitmap bmp = decodeSampledBitmapFromData(data,640,360);
                      Log.v(TAG,"bmp width=" + bmp.getWidth() + " height=" + bmp.getHeight());
                      FileOutputStream outStream = null;
                      try{
                          FileOutputStream fos = new FileOutputStream(imageFileName);
                          final BufferedOutputStream bos = new BufferedOutputStream(fos, BUFFER_SIZE);
                          bmp.compress(CompressFormat.JPEG, 100, bos);
                          bos.flush();
                          bos.close();
                          fos.close();
                      } catch (FileNotFoundException e){
                          Log.v(TAG, e.getMessage());
                      } catch (IOException e){
                          Log.v(TAG, e.getMessage());
                      }
                      Intent resultIntent = new Intent();
                      // TODO Add extras or a data URI to this intent as appropriate.
                      resultIntent.putExtra("testString","here is my test");
                      setResult(Activity.RESULT_OK, resultIntent);
                      finish();
                  }
                };
                Log.v(TAG,"set callback");
                mCamera.takePicture(null, null, mCall);
            }       
            catch (Exception e) {
              try {
                    mCamera.release();
                    Log.e(TAG,"released the camera");
                }
                catch (Exception ee) {
                    // do nothing
                    Log.e(TAG,"error releasing camera");
                    Log.e(TAG,"Exception encountered relerasing camera, exiting:" + ee.getLocalizedMessage());
                }
              Log.e(TAG,"Exception encountered, exiting:" + e.getLocalizedMessage());
               mCamera = null;  
              Intent resultIntent = new Intent();
             setResult(Activity.RESULT_CANCELED, resultIntent);
             finish();
            }
          }
      
          public static Bitmap decodeSampledBitmapFromData(byte[] data,
                  int reqWidth, int reqHeight) {
      
              // First decode with inJustDecodeBounds=true to check dimensions
              final BitmapFactory.Options options = new BitmapFactory.Options();
              options.inJustDecodeBounds = true;
              BitmapFactory.decodeByteArray(data, 0, data.length,options);
              options.inSampleSize = 2; // saved image will be one half the width and height of the original (image captured is double the resolution of the screen size)
              // Decode bitmap with inSampleSize set
              options.inJustDecodeBounds = false;
              return BitmapFactory.decodeByteArray(data, 0, data.length,options);
          }
      
      
          public void surfaceCreated(SurfaceHolder holder)
          {
                Log.v(TAG,"surfaceCreated");
                // The Surface has been created, acquire the camera and tell it where
                // to draw the preview.
                try {
                    mCamera = Camera.open();
                    Log.v(TAG,"acquired the camera");
                    mCamera.setPreviewDisplay(holder);
                    Log.v(TAG,"set surface holder for preview");
                  }
                catch (Exception e) {
                    try {
                        mCamera.release();
                        Log.v(TAG,"released the camera");
                    }
                    catch (Exception ee) {
                        // do nothing
                        Log.e(TAG,"Exception encountered releasing camera, exiting:" + ee.getLocalizedMessage());
                    }
                    Log.e(TAG,"Exception encountered, exiting:" + e.getLocalizedMessage());
                    mCamera = null;  
                   Intent resultIntent = new Intent();
                   setResult(Activity.RESULT_CANCELED, resultIntent);
                   finish();
                }
      
           }
      
          public void surfaceDestroyed(SurfaceHolder holder)
          {
              Log.v(TAG,"surfaceDestroyed");
              if (mCamera != null) {
                  mCamera.stopPreview();
                  //release the camera
                  mCamera.release();
                  //unbind the camera from this object
                  mCamera = null;
              }  
          }
      
          @Override
          public void onPause()
          {
              Log.v(TAG,"onPause");
              super.onPause();
              if (mCamera != null) {
                  mCamera.stopPreview();
                  //release the camera
                  mCamera.release();
                  //unbind the camera from this object
                  mCamera = null;
              }
          }
      
          @Override
          public void onDestroy()
          {
              Log.v(TAG,"onDestroy");
              super.onDestroy();
      
              if (mCamera != null) {
                  mCamera.stopPreview();
                  //release the camera
                  mCamera.release();
                  //unbind the camera from this object
                  mCamera = null;
              }
          }
      }
      

      我敢打赌,这简直就是我看不到的......

1 个答案:

答案 0 :(得分:2)

实际上,我刚刚查看了Google Glass API错误报告,并查看了其他人遇到的完全相同的问题: https://code.google.com/p/google-glass-api/issues/detail?id=259

我注意到了同样的事情,这与语音触发有关。当我从滑动菜单中选择项目时,我没有看到相同的错误。

这可能会被关闭

*稍后* 只是更新此内容。我写了一个小样本应用程序,重复尝试获取相机。该项目位于:https://github.com/dazza222/GlassCameraSnapshot