Выключить фонарик, когда телефон перестает звонить?

Я делаю приложение, которое включает фонарик, когда телефон начинает звонить, и выключает его, когда он перестает звонить. Проблема в том, что камера блокируется, когда телефон начинает звонить, и объектная ссылка на нее теряется, поэтому я не знаю, как это отключить позже.

Я использую BroadcastReceiver для включения/выключения:

@Override
public void onReceive(Context context, Intent intent) {
    String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);

    if (TelephonyManager.EXTRA_STATE_RINGING.equals(state)) {
        if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH)) {   
            cam = Camera.open();
            Parameters p = cam.getParameters();
            p.setFlashMode(Parameters.FLASH_MODE_TORCH);
            cam.setParameters(p);
            cam.startPreview();
        }
    }

    if (TelephonyManager.EXTRA_STATE_IDLE.equals(state)) {
        cam = Camera.open();
        cam.stopPreview();
        cam.release();
    }
}

Кто-нибудь знает, как сохранить ссылку на объект камеры или какой-либо обходной путь? Мне приходит на ум использование службы, но другие приложения на рынке, похоже, не используют службы для выполнения той же задачи.


person Filip V.    schedule 08.02.2013    source источник


Ответы (2)


Согласно документации по управлению камерой, вы должны держать ссылку в классе к объекту Camera и отпустите его, когда закончите с ним. Они делают это, обращаясь к объекту через поле.

Возможно, вы сможете просто решить свою проблему, сделав то же самое:

public TelephonyReceiver extends BroadcastReceiver {

    Camera mCamera;

    @Override
    public void onReceive(Context context, Intent intent) {
        String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);

        if (TelephonyManager.EXTRA_STATE_RINGING.equals(state)) {
            if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH)) {   
                mCamera = Camera.open();
                Parameters p = mCamera.getParameters();
                p.setFlashMode(Parameters.FLASH_MODE_TORCH);
                mCamera.setParameters(p);
                mCamera.startPreview();
            }
        }

        if (TelephonyManager.EXTRA_STATE_IDLE.equals(state) && mCamera != null) {
            mCamera.stopPreview();
            mCamera.release();
            // Make sure to clear the reference, otherwise we might attempt to
            // release the camera a second time
            mCamera = null;
        }
    }

}

Если вы делаете это из службы, я бы предложил также добавить логику освобождения камеры в onDestroy(), чтобы убедиться, что камера правильно освобождена. Возможно, даже выпустите его после фиксированной максимальной продолжительности, чтобы он не оставался включенным в течение длительного периода времени.

Звучит как отличное приложение!

person Paul Lammertsma    schedule 08.02.2013
comment
Да, именно этим я и занимаюсь в данный момент. Но когда BroadcastReceiver запускается, он живет только на время действия метода onReceive (поэтому при запуске звонка он запускает фонарик, а затем весь экземпляр умирает вместе с моей ссылкой на камеру), при следующем запуске создается новый объект ( который также создает новый объект камеры, который не может получить доступ к камере, поскольку камера используется предыдущим мертвым объектом камеры). - person Filip V.; 09.02.2013
comment
Тогда это корень вашей проблемы. Вам нужно будет инкапсулировать BroadcastReceiver внутри службы. - person Paul Lammertsma; 09.02.2013
comment
Да, ты прав. Я решил это, также внедрив сервис. - person Filip V.; 11.02.2013

Спасибо Полу Ламмертсма за совет. Я решил проблему, добавив службу, которая сохраняет объект камеры.

Код получателя:

public class Receiver extends BroadcastReceiver {
SharedPreferences prefs = null;
boolean enabled = false;
@Override
public void onReceive(Context context, Intent intent) {
    prefs = PreferenceManager.getDefaultSharedPreferences(context);

    AudioManager am = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
    int ringState = am.getRingerMode();
    enabled = prefs.getBoolean("full", false);
    if (!enabled || ringState != AudioManager.RINGER_MODE_NORMAL) {
        return;
    }

    String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);

    if (TelephonyManager.EXTRA_STATE_RINGING.equals(state) ||
            TelephonyManager.EXTRA_STATE_IDLE.equals(state) ||
            TelephonyManager.EXTRA_STATE_OFFHOOK.equals(state)) {
        context.startService(new Intent(context, MyService.class).putExtra("state", state));
    }
}
}

Код услуги:

public class MyService extends Service {
Camera cam = null;
boolean offhook = false;

@Override
public IBinder onBind(Intent intent) {
    return null;
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {

    String state = intent.getStringExtra("state");

    if (TelephonyManager.EXTRA_STATE_RINGING.equals(state)) {
        if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH) && !offhook) {
                    cam = Camera.open();
                    Parameters p = cam.getParameters();
                    p.setFlashMode(Parameters.FLASH_MODE_TORCH);
                    cam.setParameters(p);
        }
    }

    if (TelephonyManager.EXTRA_STATE_IDLE.equals(state)) {
        if (!offhook) {
            if (cam != null) {
                cam.release();
                cam = null;
            }
            this.stopSelf();
        } else {
            offhook = false;
        }
    }

    if (TelephonyManager.EXTRA_STATE_OFFHOOK.equals(state)) {
        offhook = true;
        if (cam != null) {
            cam.stopPreview();
            cam.release();
            cam = null;
        }
        this.stopSelf();
    }

    return super.onStartCommand(intent, flags, startId);
}

@Override
public void onDestroy() {
    if (cam != null) {
        cam.release();
        cam = null;
    }
    super.onDestroy();
}   
}
person Filip V.    schedule 10.02.2013