首页 > 解决方案 > 相机活动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。


我该如何解决这个问题?提前致谢。

标签: javaandroidcameraandroid-cameradevice

解决方案


有时这个“绿屏”问题是由相机的预览分辨率引起的。尝试从相机实例中获取支持的预览大小。

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;
        }
    }
}

请记住,对我来说最好的解决方案是获取支持的尺寸来计算最佳预览尺寸。


推荐阅读