在Glass GDK应用程序中获取相机时出现间歇性错误。该应用程序是一个简单的应用程序:
问题在于该应用程序可以运行,但是它不时会不会获取相机。我已经将多个try / catch块中的相机调用完成处理(如果它无法获取相机,应用程序就会退出),但我想知道它为什么会在第一时间发生。
除了以下内容,我不会担心这个:
我注意到这些错误经常发生在我用“拍照”语音提示拍摄照片后启动应用程序(好像“拍照”应用程序没有释放相机。)
我投入了很多次尝试/捕获来防止每次不良的相机通话,但......在我这样做之前,(即当我的代码不那么专注于释放相机时),该装置会非常温暖,以至于我不得不将其关闭再打开,以确保我没有损坏它。
我在日志中看到的唯一奇怪的事情是以下消息。我不知道 “未知消息类型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;
}
}
}
我敢打赌,这简直就是我看不到的......
答案 0 :(得分:2)
实际上,我刚刚查看了Google Glass API错误报告,并查看了其他人遇到的完全相同的问题: https://code.google.com/p/google-glass-api/issues/detail?id=259
我注意到了同样的事情,这与语音触发有关。当我从滑动菜单中选择项目时,我没有看到相同的错误。
这可能会被关闭
*稍后* 只是更新此内容。我写了一个小样本应用程序,重复尝试获取相机。该项目位于:https://github.com/dazza222/GlassCameraSnapshot