Как определить событие подключения наушников в режиме "offline"


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

Я проверил несколько музыкальных плееров и выяснил, что они фиксируют это событие без каких-либо дополнительных услуг. Как они это делают? Какой-нибудь идеи?
1 3

1 ответ:

У меня в магазине уже три года есть приложение, которое отслеживает состояние проводной гарнитуры и bluetooth, и никто никогда не жаловался на разряд батареи. Но это потому, что я успешно использую один сервис и широковещательный приемник для обнаружения событий от обоих. Вот два ключевых класса:

public class HeadsetStateBroadcastReceiver extends BroadcastReceiver {

    public static final String[] HEADPHONE_ACTIONS = {
        Intent.ACTION_HEADSET_PLUG,
        "android.bluetooth.headset.action.STATE_CHANGED",
        "android.bluetooth.headset.profile.action.CONNECTION_STATE_CHANGED"
    };

    @Override
    public void onReceive(final Context context, final Intent intent) {

        boolean broadcast = false;

        // Wired headset monitoring
        if (intent.getAction().equals(HEADPHONE_ACTIONS[0]) {
            final int state = intent.getIntExtra("state", 0);
            AudioPreferences.setWiredHeadphoneState(context, state > 0);
            broadcast = true;
        }

        // Bluetooth monitoring
        // Works up to and including Honeycomb
        if (intent.getAction().equals(HEADPHONE_ACTIONS[1])) {
            int state = intent.getIntExtra("android.bluetooth.headset.extra.STATE", 0);
            AudioPreferences.setBluetoothHeadsetState(context, state == 2);
            broadcast = true;
        }

        // Works for Ice Cream Sandwich
        if (intent.getAction().equals(HEADPHONE_ACTIONS[2])) {
            int state = intent.getIntExtra("android.bluetooth.profile.extra.STATE", 0);
            AudioPreferences.setBluetoothHeadsetState(context, state == 2);
            broadcast = true;
        }

        // Used to inform interested activities that the headset state has changed
        if (broadcast) {
            LocalBroadcastManager.getInstance(context).sendBroadcast(new Intent("headsetStateChange"));
        }

    }

}

Вот сервис, который я использую для регистрации широковещательного приемника:

public class HeadsetMonitoringService extends Service {

    HeadsetStateBroadcastReceiver headsetStateReceiver;

    @Override
    public void onCreate() {

        headsetStateReceiver = new HeadsetStateBroadcastReceiver();
        final IntentFilter filter = new IntentFilter();
        for (String action: HeadsetStateBroadcastReceiver.HEADPHONE_ACTIONS) {
            filter.addAction(action);
        }

        registerReceiver(headsetStateReceiver, filter);

    }

    @Override
    public int onStartCommand(final Intent intent, final int flags, final int startId) {
        return START_STICKY;
    }

    @Override
    public void onDestroy() {
        unregisterReceiver(headsetStateReceiver);
    }

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

}

А вот моя запись в манифесте:

    <service
        android:name=".services.HeadsetMonitoringService"
        android:enabled="true"
        android:exported="false" >
        <intent-filter>
            <action android:name="initialiseHeadsetService" />
        </intent-filter>
    </service>

Он работает следующим образом:

Я использую широковещательный приемник on boot для отправки служебного сообщения start в HeadsetMonitoringService (вам не нужно делать это таким образом, вы можете просто сделать это, когда ваше приложение запускается вместо этого). HeadsetMonitoringService в свою очередь регистрирует экземпляр широковещательного прослушивателя, который прослушивает все интересующие меня события гарнитуры - они хранятся в массиве HEADPHONE_ACTIONS. Поскольку служба липкая, она висит вокруг - и, следовательно, слушатель вещания тоже. Но поскольку и служба, и прослушиватель широковещательной передачи управляются событиями, они не потребляют никакого питания, пока не произойдет изменение состояния гарнитуры. Кроме того, поскольку служба является липкой, она будет перезапущена ОС, если она неожиданно умрет.
Всякий раз, когда я получаю событие изменения состояния гарнитуры, я также запускаю локальную трансляцию, чтобы заинтересованные действия могли проверить новое состояние и принять необходимые меры.

Для полноты я должен указать, что я использую другой класс (не показанный здесь), AudioPreferences, чтобы сохранить в качестве предпочтений как состояние Bluetooth, так и состояние проводной гарнитуры, к которому затем можно получить доступ всякий раз, когда мне нужно знать состояние гарнитуры.

Вашему приложению понадобится андроид.разрешение.Разрешение BLUETOOTH, Если вас интересует состояние Bluetooth-гарнитуры. Если нет, просто извлеките связанные с Bluetooth действия из массива HEADPHONE_ACTIONS и удалите связанные блоки if из метода onReceive.