java - 相机活动Android中的绿色N白屏问题
问题描述
此错误仅在某些设备上。
项目范围: 用于商场/船舶定位商店的室内导航系统。它使用信标来定位具有蓝牙连接的商店。它使用相机显示方向(箭头)图像叠加。
在 ArCameraActivity 中,相机预览中显示半绿屏。
代码:
import android.Manifest;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.hardware.Camera;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.opengl.Matrix;
import android.os.Build;
import android.os.Handler;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import javax.inject.Inject;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import dagger.android.support.DaggerAppCompatActivity;
public class ARActivity extends DaggerAppCompatActivity implements SensorEventListener, LocationListener,
ActivityCompat.OnRequestPermissionsResultCallback, ARView {
private static boolean IS_NAVIGATION_CLICKED = false;
@Inject
ARPresenter presenter;
@BindView(R.id.img_clear)
ImageView imgClear;
@BindView(R.id.img_logout)
ImageView imgLogout;
@BindView(R.id.img_map)
ImageView imgMap;
@BindView(R.id.img_navigation)
ImageView imgNavigation;
final static String TAG = "ARActivity";
private SurfaceView surfaceView;
private FrameLayout cameraContainerLayout;
private AROverlayView arOverlayView;
private Camera camera;
private ARCamera arCamera;
private TextView tvCurrentLocation;
private SensorManager sensorManager;
private final static int REQUEST_CAMERA_PERMISSIONS_CODE = 11;
public static final int REQUEST_LOCATION_PERMISSIONS_CODE = 0;
private static final long MIN_DISTANCE_CHANGE_FOR_UPDATES = 0; // 10 meters
private static final long MIN_TIME_BW_UPDATES = 0;//1000 * 60 * 1; // 1 minute
private LocationManager locationManager;
public Location location;
boolean isGPSEnabled;
boolean isNetworkEnabled;
boolean locationServiceAvailable;
private ScanRegionsService scanRegionsService;
private boolean isBeaconLoaded = false;
// private static GetMallResponse.Data.Mall identifiedMall;
private Dialog dialog = null;
private static final String IMAGE_URL = "http://98.156.231.92/maps/";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_ar);
ButterKnife.bind(this);
sensorManager = (SensorManager) this.getSystemService(SENSOR_SERVICE);
cameraContainerLayout = (FrameLayout) findViewById(R.id.camera_container_layout);
surfaceView = (SurfaceView) findViewById(R.id.surface_view);
tvCurrentLocation = (TextView) findViewById(R.id.tv_current_location);
arOverlayView = new AROverlayView(this);
scanRegionsService = new ScanRegionsService(this);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
beginService();
}
}
if (Util.getSelectedShop() != null) {
showLoading();
}
}
private Runnable mRunnable = new Runnable() {
@Override
public void run() {
if (!isBeaconLoaded) {
Log.d(TAG, "run: "+ isBeaconLoaded);
dismissLoading();
if(!isFinishing()) {
new AlertDialog.Builder(ARActivity.this)
.setIcon(android.R.drawable.ic_dialog_alert)
.setTitle("There is no beacon in your surroundings")
.setMessage("Are you sure you want to stop navigation?")
.setPositiveButton("Yes",
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Util.setSelectedShop(null);
finish();
}
})
.show();
}
}
}
};
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
for (int i = 0; i < permissions.length; i++) {
if (permissions[i].equalsIgnoreCase(Manifest.permission.ACCESS_FINE_LOCATION) &&
grantResults[i] == PackageManager.PERMISSION_GRANTED) {
beginService();
} else if (permissions[i].equalsIgnoreCase(Manifest.permission.CAMERA) &&
grantResults[i] == PackageManager.PERMISSION_DENIED) {
Intent intent = new Intent(this, MainActivity.class);
startActivity(intent);
finish();
}
}
}
private void beginService() {
isBeaconLoaded = false;
arOverlayView.registerReceiver();
scanRegionsService.setupSpaces();
scanRegionsService.startScanning();
onMallIdentified(Util.getSelectedMall());
new Handler().postDelayed(mRunnable, 10000);
}
@OnClick(R.id.img_map)
public void onMapClicked() {
arOverlayView.unregisterReceiver();
// Util.getRouteMap().clear();
Util.setSelectedShop(null);
// Intent intent = new Intent(this, MainActivity.class);
// startActivity(intent);
finish();
}
@OnClick(R.id.img_navigation)
public void onNavClicked() {
if (!IS_NAVIGATION_CLICKED) {
IS_NAVIGATION_CLICKED = true;
arOverlayView.showNavigationMap();
imgNavigation.setImageDrawable(getResources().getDrawable(R.drawable.navigation_on));
} else {
IS_NAVIGATION_CLICKED = false;
arOverlayView.hideNavigationMap();
imgNavigation.setImageDrawable(getResources().getDrawable(R.drawable.navigation_off));
}
}
@OnClick(R.id.img_logout)
public void onLogoutClicked() {
new AlertDialog.Builder(this)
.setIcon(android.R.drawable.ic_dialog_alert)
.setTitle("Confirm")
.setMessage("Are you sure you want to logout?")
.setPositiveButton("Yes",
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Util.set("authToken", "");
Intent intent = new Intent(ARActivity.this, LoginActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(intent);
finish();
}
})
.setNegativeButton("No", null)
.show();
}
@Override
public void onBackPressed() {
if(!((Activity) this).isFinishing()) {
new AlertDialog.Builder(this)
.setIcon(android.R.drawable.ic_dialog_alert)
.setTitle("Confirm")
.setMessage("Are you sure you want to exit the screen?")
.setPositiveButton("Yes",
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
finish();
}
})
.setNegativeButton("No", null)
.show();
}
}
@Override
public void onResume() {
super.onResume();
requestLocationPermission();
requestCameraPermission();
registerSensors();
initAROverlayView();
IntentFilter intentFilter = new IntentFilter(ForegroundScanService.ACTION_DEVICE_DISCOVERED);
registerReceiver(scanningBroadcastReceiver, intentFilter);
}
public void showClearMap() {
imgClear.setVisibility(View.VISIBLE);
}
public void hideClearMap() {
imgClear.setVisibility(View.GONE);
}
@OnClick(R.id.img_clear)
public void onClearClicked() {
new AlertDialog.Builder(this)
.setIcon(android.R.drawable.ic_dialog_alert)
.setTitle("Confirm")
.setMessage("Are you sure you want to stop navigation?")
.setPositiveButton("Yes",
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Util.setSelectedShop(null);
}
})
.setNegativeButton("No", null)
.show();
}
@Override
public void onPause() {
unregisterReceiver(scanningBroadcastReceiver);
releaseCamera();
super.onPause();
}
public void requestCameraPermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M &&
this.checkSelfPermission(Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
this.requestPermissions(new String[]{Manifest.permission.CAMERA}, REQUEST_CAMERA_PERMISSIONS_CODE);
} else {
initARCameraView();
}
}
public void requestLocationPermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M &&
this.checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
this.requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_LOCATION_PERMISSIONS_CODE);
} else {
initLocationService();
}
}
public void initAROverlayView() {
if (arOverlayView.getParent() != null) {
((ViewGroup) arOverlayView.getParent()).removeView(arOverlayView);
}
cameraContainerLayout.addView(arOverlayView);
}
public void initARCameraView() {
reloadSurfaceView();
if (arCamera == null) {
arCamera = new ARCamera(this, surfaceView);
}
if (arCamera.getParent() != null) {
((ViewGroup) arCamera.getParent()).removeView(arCamera);
}
cameraContainerLayout.addView(arCamera);
arCamera.setKeepScreenOn(true);
initCamera();
}
private void initCamera() {
int numCams = Camera.getNumberOfCameras();
if (numCams > 0) {
try {
camera = Camera.open();
camera.startPreview();
arCamera.setCamera(camera);
} catch (RuntimeException ex) {
Toast.makeText(this, "Camera not found", Toast.LENGTH_LONG).show();
}
}
}
private void reloadSurfaceView() {
if (surfaceView.getParent() != null) {
((ViewGroup) surfaceView.getParent()).removeView(surfaceView);
}
cameraContainerLayout.addView(surfaceView);
}
private void releaseCamera() {
if (camera != null) {
camera.setPreviewCallback(null);
camera.stopPreview();
arCamera.setCamera(null);
camera.release();
camera = null;
}
}
private void registerSensors() {
sensorManager.registerListener(this,
sensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR),
SensorManager.SENSOR_DELAY_FASTEST);
}
@Override
public void onSensorChanged(SensorEvent sensorEvent) {
if (sensorEvent.sensor.getType() == Sensor.TYPE_ROTATION_VECTOR) {
float[] rotationMatrixFromVector = new float[16];
float[] projectionMatrix = new float[16];
float[] rotatedProjectionMatrix = new float[16];
SensorManager.getRotationMatrixFromVector(rotationMatrixFromVector, sensorEvent.values);
if (arCamera != null) {
projectionMatrix = arCamera.getProjectionMatrix();
}
Matrix.multiplyMM(rotatedProjectionMatrix, 0, projectionMatrix, 0, rotationMatrixFromVector, 0);
this.arOverlayView.updateRotatedProjectionMatrix(rotatedProjectionMatrix);
}
}
@Override
public void onAccuracyChanged(Sensor sensor, int i) {
//do nothing
}
private void initLocationService() {
if (Build.VERSION.SDK_INT >= 23 &&
ContextCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
try {
this.locationManager = (LocationManager) this.getSystemService(this.LOCATION_SERVICE);
// Get GPS and network status
this.isGPSEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
this.isNetworkEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
if (!isNetworkEnabled && !isGPSEnabled) {
// cannot get location
this.locationServiceAvailable = false;
}
this.locationServiceAvailable = true;
if (isNetworkEnabled) {
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER,
MIN_TIME_BW_UPDATES,
MIN_DISTANCE_CHANGE_FOR_UPDATES, this);
if (locationManager != null) {
location = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
updateLatestLocation();
}
}
if (isGPSEnabled) {
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,
MIN_TIME_BW_UPDATES,
MIN_DISTANCE_CHANGE_FOR_UPDATES, this);
if (locationManager != null) {
location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
updateLatestLocation();
}
}
} catch (Exception ex) {
Log.e(TAG, ex.getMessage());
}
}
private void updateLatestLocation() {
if (arOverlayView != null && location != null) {
arOverlayView.updateCurrentLocation(location);
tvCurrentLocation.setText(String.format("lat: %s \nlon: %s \naltitude: %s \n",
location.getLatitude(), location.getLongitude(), location.getAltitude()));
}
}
@Override
public void onLocationChanged(Location location) {
updateLatestLocation();
}
@Override
public void onStatusChanged(String s, int i, Bundle bundle) {
}
@Override
public void onProviderEnabled(String s) {
}
@Override
public void onProviderDisabled(String s) {
}
private final BroadcastReceiver scanningBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "onReceive: ");
isBeaconLoaded = true;
String shopname=Util.getSelectedShop().getShopImage();
Toast.makeText(context, "You are in "+shopname, Toast.LENGTH_LONG).show();
int devicesCount = intent.getIntExtra(BackgroundScanService.EXTRA_DEVICES_COUNT, 0);
RemoteBluetoothDevice device = intent.getParcelableExtra(BackgroundScanService.EXTRA_DEVICE);
Log.i("BEACON", String.format("Total discovered devices: %d\n\nLast scanned device:\n%s", devicesCount, device.toString()));
// statusText.setText(String.format("Total discovered devices: %d\n\nLast scanned device:\n%s", devicesCount, device.toString()));
}
};
@Override
public void onMallIdentified(GetMallResponse.Data.Mall mall) {
// identifiedMall = mall;
// Toast.makeText(this, "Identified "+mall.getPropertyName(), Toast.LENGTH_LONG).show();
presenter.loadShops(mall.getId());
presenter.loadRouteBeacons(mall.getId());
}
public void onUnkownPlaceIdentified() {
arOverlayView.registerReceiver();
Toast.makeText(this, "Unknown place identified", Toast.LENGTH_LONG).show();
List<GetRouteBeaconsResponse.Data.Route> floorRoute = new ArrayList<>();
}
@Override
public void onShopLoaded(List<GetShopsResponse.Data.Shop> shops) {
Log.i(TAG, "onShopLoaded");
if (shops.size() > 0) {
Util.shopMap.clear();
Log.i(TAG, "onShopLoaded shops.size " + shops.size());
Util.activeDeviceMap.clear();
for (GetShopsResponse.Data.Shop shop : shops) {
Util.shopMap.put("" + shop.getId(), shop);
if (shop.getAdImage().length() > 0) {
Drawable drbl = Util.promoImageMap.get(IMAGE_URL + shop.getAdImage());
if (drbl == null) {
String imgkey = IMAGE_URL + shop.getAdImage();
drbl = getResources().getDrawable(R.drawable.promo1, null);
Util.promoImageMap.put(imgkey, drbl);
Runnable runnable = new Runnable() {
@Override
public void run() {
try {
Drawable drb2 = drawableFromUrl(imgkey);
Util.promoImageMap.put(IMAGE_URL + shop.getAdImage(), drb2);
} catch (Exception e) {
Log.i(TAG, "Unable to download image");
}
}
};
new Thread(runnable).start();
}
}
}
}
}
@Override
public void onRouteBeaconLoaded(List<GetRouteBeaconsResponse.Data.Route> floors) {
Log.d(TAG, "onRouteBeaconLoaded: ");
Log.i(TAG, "onRouteBeaconLoaded");
// if (floors.size()>0 && Util.getSelectedShop()!=null){
// Log.i(TAG, "onRouteBeaconLoaded floors.size "+floors.size());
// Util.getRouteMap().clear();
// for (GetRouteBeaconsResponse.Data.Route route: floors){
// String comkey = route.proximityUUID+route.major+route.minor;
// Util.getRouteMap().put(comkey, route);
// }
// Util.setSelectedShop(Util.getSelectedShop());
// Log.i(TAG, "onShopLoaded setup space scanRegionsService");
// scanRegionsService.setupSpaces();
// Log.i(TAG, "onShopLoaded startScanning");
// scanRegionsService.startScanning();
// }
if (floors.size() > 0) {
Log.i(TAG, "onRouteBeaconLoaded floors.size " + floors.size());
Util.getRouteMap().clear();
for (GetRouteBeaconsResponse.Data.Route route : floors) {
String comkey = route.proximityUUID + route.major + route.minor;
Util.getRouteMap().put(comkey, route);
}
Log.i(TAG, "onShopLoaded setup space scanRegionsService");
scanRegionsService.setupSpaces();
Log.i(TAG, "onShopLoaded startScanning");
scanRegionsService.startScanning();
}
arOverlayView.registerReceiver();
}
public static Drawable drawableFromUrl(String url) throws IOException {
Bitmap x;
HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
connection.connect();
InputStream input = connection.getInputStream();
x = BitmapFactory.decodeStream(input);
return new BitmapDrawable(x);
}
private void initLoadingDialog() {
dialog = new Dialog(this);
dialog.setCancelable(false);
dialog.setContentView(R.layout.show_loading);
TextView txtFind = dialog.findViewById(R.id.findingBeacons);
txtFind.setVisibility(View.VISIBLE);
dialog.setOnKeyListener(new Dialog.OnKeyListener() {
@Override
public boolean onKey(DialogInterface arg0, int keyCode,
KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
dialog.dismiss();
}
return true;
}
});
dialog.getWindow().setBackgroundDrawable(new ColorDrawable(android.graphics.Color.TRANSPARENT));
}
public void showLoading() {
try {
if (dialog != null) {
dialog.show();
} else {
initLoadingDialog();
dialog.show();
}
} catch (Exception e) {
}
}
public void dismissLoading() {
try {
if (dialog != null && dialog.isShowing()) {
dialog.dismiss();
}
} catch (Exception e) {
}
}
}
绿屏 仅限 redmi y2 手机中的相机活动。它在其他模型上运行良好。可能是什么问题?它在相机中显示使用信标设备购物的方向。安卓操作系统版本没问题。
某些设备上的白屏 - 三星标签、一加 7、BLU G9 Pro 手机 白屏
此活动借助相机中的信标显示导航,显示图像视图的叠加。它适用于某些设备,我尝试了各种方法来解决它,但不起作用。添加了最新的相机 v2 api。
我该如何解决这个问题?提前致谢。
解决方案
有时这个“绿屏”问题是由相机的预览分辨率引起的。尝试从相机实例中获取支持的预览大小。
mParams = mCamera.getParameters();
List<Camera.Size> supportedPreviewSizes = mParams.getSupportedPreviewSizes();
Camera.Size bestPreviewSize = supportedPreviewSizes.get(0);
for (Camera.Size sz : supportedPreviewSizes) {
/* perfect match */
if(sz.width == mWidth && sz.height == mHeight) {
bestPreviewSize = sz;
break;
} else {
int bestArea = bestPreviewSize.width*bestPreviewSize.height;
int currArea = sz.width*sz.height;
int targetArea = mWidth*mHeight;
if (Math.abs(currArea-targetArea) < Math.abs(bestArea-targetArea)) {
bestPreviewSize = sz;
}
}
}
mCurrWidth = bestPreviewSize.width;
mCurrHeight = bestPreviewSize.height;
mParams.setPreviewSize(mCurrWidth, mCurrHeight);
/* Set preview format */
mParams.setPreviewFormat(ImageFormat.NV21);
/* Apply Parameters */
mCamera.setParameters(mParams);
mCamera.startPreview();
您还可以尝试根据某些设备条件(例如显示宽度)强制某些固定分辨率。我发现一些对我的用例有用的解决方案:
width = 1280;
heigth = 720;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
WindowMetrics windowMetrics = getWindowManager().getCurrentWindowMetrics();
if (isPortrait) {
if (windowMetrics.getBounds().width() <= 720) {
width = 720;
heigth = 480;
}
} else {
if (windowMetrics.getBounds().width() <= 1344) {
width = 960;
heigth = 540;
}
}
} else {
if (isPortrait) {
if (getDisplay().getWidth() <= 720) {
width = 720;
heigth = 480;
}
} else {
if (getDisplay().getWidth() <= 1344) {
width = 960;
heigth = 540;
}
}
}
请记住,对我来说最好的解决方案是获取支持的尺寸来计算最佳预览尺寸。
推荐阅读
- html - CSS Grid分数单位根据内容而变化?
- centos7 - 已挂载目录中的 Cloud-init 挂载设备
- javascript - 如何标准化 [x,y] 时间序列数据集?
- java - 类型参数“S”的推断类型“S”不在其范围内;应该扩展'com.javatest.entity.User'
- reactjs - React Stripe 元素没有出现?
- c# - 在 ASP.NET Core 中设置 cookie 后立即获取 cookie 失败
- r - 为分组数据中的操作选择前面的 X 观测值
- dynamics-crm-portals - 使用 JavaScript 或 Liquid 获取 Portal 版本
- python-3.x - 如何在 Python 中解密 openssl 加密文件
- powerbi - 如何根据上个月计算 Lost customer power bi