java - 打开相机时调用 CONNECTIVITY_CHANGE

标签 java android broadcastreceiver android-camera

我正在尝试构建一个带有摄像头的应用程序,当连接从 3G/4G 或其他方式更改为 Wi-Fi 时,该应用程序会执行某些操作。为了检测何时发生这种情况,我使用了一个扩展 BroadCastReceiver 的类:

public class WifiReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(context);
        boolean syncPopup = sharedPref.getBoolean("syncPopup", true);
        if (syncPopup) {
            DigginSQLiteHelper db = new DigginSQLiteHelper(context);
            if (db.getAllToBeSyncedPhotos().size() > 0) {
                ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
                NetworkInfo networkInfo = null;
                if (manager != null) {
                    networkInfo = manager.getActiveNetworkInfo();
                }
                SharedPreferences sharedPref2 = context.getSharedPreferences(context.getString(R.string.connType), Context.MODE_PRIVATE);
                int connType = sharedPref2.getInt(context.getString(R.string.connType), 0);
                if (networkInfo != null && networkInfo.getType() == ConnectivityManager.TYPE_WIFI && networkInfo.isConnectedOrConnecting() && connType != ConnectivityManager.TYPE_WIFI) {
                    showNotification(context);
                }
                SharedPreferences.Editor editor = sharedPref2.edit();
                editor.putInt(context.getString(R.string.connType), networkInfo.getType());
                editor.commit();
            }
        } else {
            ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
            NetworkInfo networkInfo;
            if (manager != null) {
                networkInfo = manager.getActiveNetworkInfo();
                SharedPreferences.Editor editor= context.getSharedPreferences(context.getString(R.string.connType), Context.MODE_PRIVATE).edit();
                editor.putInt(context.getString(R.string.connType), networkInfo.getType());
                editor.commit();
            }
        }
    }

    private void showNotification(Context context) {
        PendingIntent contentIntent = PendingIntent.getActivity(context, 0,
                new Intent(context, MainActivity.class), 0);

        NotificationCompat.Builder mBuilder =
                new NotificationCompat.Builder(context)
                        .setSmallIcon(R.drawable.icon_camera)
                        .setContentTitle("My notification")
                        .setContentText("Connected to Wifi, ready to sync!");
        mBuilder.setContentIntent(contentIntent);
        mBuilder.setDefaults(Notification.DEFAULT_SOUND);
        mBuilder.setAutoCancel(true);
        NotificationManager mNotificationManager =
                (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
        mNotificationManager.notify(1, mBuilder.build());

    }
}

但是每当我的相机的 Activity 打开和关闭时,WifiReceiver 都会将其检测为更改(这不是我想要的,我只希望当用户通过 WiFi 连接时发生这种情况)。我只是不知道要检查什么或做什么,以便在打开/关闭 CameraActivity 时不会调用 showNotification(Context context)

这是相机 Activity :

package com.example.sition.diggin;

import android.Manifest;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.hardware.Camera;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.RotateAnimation;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.ImageView;

import com.example.sition.diggin.compass.BearingToNorthProvider;
import com.example.sition.diggin.misc.CameraView;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;

@SuppressWarnings("deprecation")
public class CameraActivity extends AppCompatActivity implements BearingToNorthProvider.ChangeEventListener {

    //region fields
    private Camera mCamera;
    private CameraView mCameraView;
    private float mDist = 0f;
    private String flashMode;
    private ImageButton flashButton;
    private Intent intent;
    private BearingToNorthProvider mBearingProvider;
    private boolean pictureTaken = false;
    private byte[] currentData;

    private double bearing;
    private double currentBearing = 0d;
    private String cardinalDirection = "?";
    private double rotation = 0d;

    private final int REQUEST_CODE_ASK_PERMISSIONS = 2;
    //endregion

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_camera);
        mCamera = getCameraInstance();
        mCameraView = new CameraView(this, mCamera);
        FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);
        preview.addView(mCameraView);
        ImageButton captureButton = (ImageButton) findViewById(R.id.btnCapture);
        captureButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Camera.Parameters params = mCamera.getParameters();
                params.setFlashMode(flashMode);
                mCamera.setParameters(params);
                mCamera.takePicture(null, null, mPicture);
            }
        });
        SharedPreferences sharedPref = this.getSharedPreferences(getString(R.string.flashMode), Context.MODE_PRIVATE);
        flashMode = sharedPref.getString(getString(R.string.flashMode), Camera.Parameters.FLASH_MODE_OFF);
        flashButton = (ImageButton) findViewById(R.id.btnFlash);
        setFlashButton();
        mBearingProvider = new BearingToNorthProvider(this,this);
        mBearingProvider.setChangeEventListener(this);
        mBearingProvider.start();
    }

    @Override
    protected void onPause() {
        super.onPause();
        mBearingProvider.stop();
    }

    /**
     * Helper method to access the camera returns null if it cannot get the
     * camera or does not exist
     *
     * @return the instance of the camera
     */
    private Camera getCameraInstance() {
        Camera camera = null;
        try {
            camera = Camera.open();
        } catch (Exception e) {
            Log.e("CamException", e.toString());
        }
        return camera;
    }

    private Camera.PictureCallback mPicture = new Camera.PictureCallback() {
        @Override
        public void onPictureTaken(byte[] data, Camera camera) {
            currentData = data;
            mBearingProvider.updateBearing();
            bearing = mBearingProvider.getBearing();
            cardinalDirection = bearingToString(bearing);
            Log.e("Direction", cardinalDirection + "," + bearing);
            findViewById(R.id.btnFlash).setVisibility(View.INVISIBLE);
            findViewById(R.id.btnCapture).setVisibility(View.INVISIBLE);
            findViewById(R.id.ivCompass).setVisibility(View.INVISIBLE);
            findViewById(R.id.ivFocusPoint).setVisibility(View.INVISIBLE);
            findViewById(R.id.ivCompassPointer).setVisibility(View.INVISIBLE);
            findViewById(R.id.pictureOverlay).setVisibility(View.VISIBLE);
        }
    };

    //region Picture Intents
    /**
     * Method that puts the necessary data in the intent and then sends it back to the ProjectOverview
     * @param v the view that activated this method
     */
    public void confirmPicture(View v) {
        String path = createFile(currentData);
        intent = new Intent();
        intent.putExtra("path", path);
        String description = String.valueOf(((EditText) findViewById(R.id.tvPictureDesc)).getText());
        intent.putExtra("direction", cardinalDirection);
        intent.putExtra("description", description);

        //close this Activity...
        setResult(Activity.RESULT_OK, intent);
        finish();
    }

    /**
     * Method that puts no data in the intent and then sends it back to the ProjectOverview
     * @param v the view that activated this method
     */
    public void deletePicture(View v) {
        setResult(Activity.RESULT_CANCELED);
        finish();
    }

    /**
     * Method that restarts the camera giving the user a change to retake the picture
     * @param v the view that activated this method
     */
    public void retryPicture(View v) {
        findViewById(R.id.btnFlash).setVisibility(View.VISIBLE);
        findViewById(R.id.btnCapture).setVisibility(View.VISIBLE);
        findViewById(R.id.ivCompass).setVisibility(View.VISIBLE);
        findViewById(R.id.ivFocusPoint).setVisibility(View.VISIBLE);
        findViewById(R.id.ivCompassPointer).setVisibility(View.VISIBLE);
        findViewById(R.id.pictureOverlay).setVisibility(View.INVISIBLE);
        pictureTaken = false;
        mCamera.startPreview();
    }

    //endregion

    //region File Methods

    /**
     * Method that creates a file from the given byte array and saves the file in the Pictures Directory
     * @param data is the array of bytes that represent the picture taken by the camera
     * @return the path of created file
     */
    private String createFile(byte[] data){
        checkFilePermissions();
        File picFile = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) + File.separator + "tempPic.jpg" + File.separator);
        String path = picFile.getPath();
        try {
            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(picFile));
            bos.write(data);
            bos.flush();
            bos.close();
            return path;
        } catch (IOException e) {
            e.printStackTrace();
            return "";
        }
    }

    /**
     * Checks the permission for reading to and writing from the external storage
     */
    private void checkFilePermissions() {
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
            int hasWriteExternalStoragePermission = checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE);
            if (hasWriteExternalStoragePermission != PackageManager.PERMISSION_GRANTED) {
                requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
                        REQUEST_CODE_ASK_PERMISSIONS);
            }
        }
    }

    //endregion

    //region Zoom Methods

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        // Get the pointer ID
        Camera.Parameters params = mCamera.getParameters();
        int action = event.getAction();


        if (event.getPointerCount() > 1) {
            // handle multi-touch events
            if (action == MotionEvent.ACTION_POINTER_DOWN) {
                mDist = getFingerSpacing(event);
            } else if (action == MotionEvent.ACTION_MOVE && params.isZoomSupported()) {
                mCamera.cancelAutoFocus();
                handleZoom(event, params);
            }
        } else {
            // handle single touch events
            if (action == MotionEvent.ACTION_UP) {
                handleFocus(event, params);
            }
        }
        return true;
    }

    /**
     * Method that handles the zoom of the camera
     * @param event the event that activated this method
     * @param params the parameters of the camera
     */
    private void handleZoom(MotionEvent event, Camera.Parameters params) {
        int maxZoom = params.getMaxZoom();
        int zoom = params.getZoom();
        float newDist = getFingerSpacing(event);
        if (newDist > mDist) {
            //zoom in
            if (zoom < maxZoom)
                zoom++;
        } else if (newDist < mDist) {
            //zoom out
            if (zoom > 0)
                zoom--;
        }
        mDist = newDist;
        params.setZoom(zoom);
        mCamera.setParameters(params);
    }

    /**
     * Method that handles the focus of the camera when zooming
     * @param event the event that activated this method
     * @param params the parameters of the camera
     */
    private void handleFocus(MotionEvent event, Camera.Parameters params) {
        int pointerId = event.getPointerId(0);
        int pointerIndex = event.findPointerIndex(pointerId);
        // Get the pointer's current position

        List<String> supportedFocusModes = params.getSupportedFocusModes();
        if (supportedFocusModes != null && supportedFocusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
            mCamera.autoFocus(new Camera.AutoFocusCallback() {
                @Override
                public void onAutoFocus(boolean b, Camera camera) {
                    // currently set to auto-focus on single touch
                }
            });
        }
    }

    /** Determine the space between the first two fingers */
    private float getFingerSpacing(MotionEvent event) {
        double x = event.getX(0) - event.getX(1);
        double y = event.getY(0) - event.getY(1);
        return (float) Math.sqrt(x * x + y * y);
    }

    //endregion

    //region Flash Methods

    /**
     * Method that changes the flash mode the camera currently uses (on/off/auto)
     * @param v the view that activated this method
     */
    public void changeFlashMode(View v) {
        switch (flashMode) {
            case Camera.Parameters.FLASH_MODE_ON :
                flashMode = Camera.Parameters.FLASH_MODE_AUTO;
                break;
            case Camera.Parameters.FLASH_MODE_AUTO :
                flashMode = Camera.Parameters.FLASH_MODE_OFF;
                break;
            case Camera.Parameters.FLASH_MODE_OFF :
                flashMode = Camera.Parameters.FLASH_MODE_ON;
                break;
        }
        SharedPreferences sharedPref = getSharedPreferences(getString(R.string.flashMode), Context.MODE_PRIVATE);
        SharedPreferences.Editor editor = sharedPref.edit();
        editor.putString(getString(R.string.flashMode), flashMode);
        editor.commit();
        setFlashButton();
    }

    /**
     * Method that changes the image of the button based on flash mode
     */
    private void setFlashButton() {
        switch (flashMode) {
            case Camera.Parameters.FLASH_MODE_ON :
                flashButton.setImageDrawable(getResources().getDrawable(R.drawable.camera_flash_on));
                break;
            case Camera.Parameters.FLASH_MODE_AUTO :
                flashButton.setImageDrawable(getResources().getDrawable(R.drawable.camera_flash_auto));
                break;
            case Camera.Parameters.FLASH_MODE_OFF :
                flashButton.setImageDrawable(getResources().getDrawable(R.drawable.camera_flash_off));
                break;
        }
    }

    //endregion

    //region Bearing Methods

    /**
     * Method that gives a cardinal direction based on the current bearing to the true north
     * @param bearing is the bearing to the true north
     * @return cardinal direction that belongs to the bearing
     */
    private String bearingToString(Double bearing) {
        String strHeading = "?";
        if (isBetween(bearing,-180.0,-157.5)) { strHeading = "South"; }
        else if (isBetween(bearing,-157.5,-112.5)) { strHeading = "SouthWest"; }
        else if (isBetween(bearing,-112.5,-67.5)) { strHeading = "West"; }
        else if (isBetween(bearing,-67.5,-22.5)) { strHeading = "NorthWest"; }
        else if (isBetween(bearing,-22.5,22.5)) { strHeading = "North"; }
        else if (isBetween(bearing,22.5,67.5)) { strHeading = "NorthEast"; }
        else if (isBetween(bearing,67.5,112.5)) { strHeading = "East"; }
        else if (isBetween(bearing,112.5,157.5)) { strHeading = "SouthEast"; }
        else if (isBetween(bearing,157.5,180.0)) { strHeading = "South"; }
        return strHeading;
    }

    /**
     * Method that checks if a certain number is in a certain range of numbers
     * @param x is the number to check
     * @param lower is the number that defines the lower boundary of the number range
     * @param upper is the number that defines the upper boundary of the number range
     * @return true if the number is between the other numbers, false otherwise
     */
    private boolean isBetween(double x, double lower, double upper) {
        return lower <= x && x <= upper;
    }

    /*
    Method that triggers when the bearing changes, it sets the current bearing and sends an updated context to the provider
     */
    @Override
    public void onBearingChanged(double bearing) {
        this.bearing = bearing;
        mBearingProvider.setContext(this);

        ImageView image = (ImageView) findViewById(R.id.ivCompass);
        if (image.getVisibility() == View.VISIBLE) {

            // create a rotation animation (reverse turn degree degrees)
            if (bearing < 0) {
                bearing += 360;
            }
            RotateAnimation ra = new RotateAnimation((float) currentBearing, (float) -bearing, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);

            // how long the animation will take place
            ra.setDuration(210);

            // set the animation after the end of the reservation status
            ra.setFillAfter(true);

            // Start the animation
            image.startAnimation(ra);
            rotation += currentBearing + bearing;
            currentBearing = -bearing;
        } else if (!pictureTaken){

            ImageView image2 = (ImageView) findViewById(R.id.ivCompass2);
            image2.setRotation((float) -rotation);
            image.clearAnimation();
            pictureTaken = true;
        }
        mBearingProvider.setContext(this);
    }

    //endregion
}

编辑:

更糟糕的是,WifiReceiver 似乎也在应用程序的其他位置调用 onReceive(似乎是随机的)。

编辑2:

我不知道这是否有帮助,但这里是 list 中有关 WifiReceiver 的一段代码:

<receiver android:name=".misc.WifiReceiver">
    <intent-filter>
        <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
    </intent-filter>
</receiver>

最佳答案

在寻找答案很长一段时间后,我偶然发现了 this post 。我发现我在 Intent 过滤器中使用了错误的操作,所以现在我正在使用:

<receiver android:name=".misc.WifiReceiver">
    <intent-filter>
        <action android:name="android.net.wifi.WIFI_STATE_CHANGED"/>
        <action android:name="android.net.wifi.STATE_CHANGE"/>
    </intent-filter>
</receiver>

我还没有机会在我希望它工作的确切情况下测试它,但目前看来它工作得很好。

关于java - 打开相机时调用 CONNECTIVITY_CHANGE,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36307014/

相关文章:

java - 如何在 Android PreferenceScreen 中打开本地 HTML 文件?

Java:当类加载器加载时,为类的物理字节分配的内存在哪里?

android - BroadcastReceiver Intent.ACTION_PACKAGE_ADDED/REMOVED Android Oreo

android - 从最近列表中刷应用程序后,BroadcastReceiver 不工作

Java Swing 将字体信息吐出到标准输出

java - 复制对象并更改它(在 Java 中)

android - token android.os.BinderProxy@be12cf1 的应用程序有太多 Windows 20

android - 调用 onContentChanged 时 CheckboxPreference 状态没有改变

android - 在 Activity 消失时删除 Firebase 监听器?

android - BroadcastReceiver 太慢?