All Downloads are FREE. Search and download functionalities are using the official Maven repository.

src.com.android.clockwork.common.RadioToggler Maven / Gradle / Ivy

Go to download

A library jar that provides APIs for Applications written for the Google Android Platform.

There is a newer version: 15-robolectric-12650502
Show newest version
package com.android.clockwork.common;

import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;

import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;

/**
 * RadioToggler is a generic class useful for managing enable/disable operations on a radio.
 *
 * Most radio enable/disable operations are asynchronous over binder.  The radios themselves
 * may be in a number of states between "fully enabled" and "fully disabled".  This class provides
 * an idempotent interface for toggling a radio's state.
 *
 * Currently the Radio interface does not allow for special treatment of transitional radio states.
 * In practice, many radio managers (BluetoothAdapter, WifiManager) abstract these away and
 * basically treat "enabled" as enabled, and all other states as disabled. But the interface
 * specified here does not require that behavior - it merely requires that a specific decision
 * is made for what getEnabled() ought to return for any given state.
 */
public class RadioToggler {

    public interface Radio {
        String logTag();
        void setEnabled(boolean enabled);
        boolean getEnabled();
    }

    private static final int MSG_REFRESH_RADIO_STATE = 1;
    private static final int MSG_TOGGLE_RADIO = 2;

    final HandlerThread mHandlerThread;
    private final RadioHandler mHandler;

    private final Radio mRadio;
    private final PartialWakeLock mWakeLock;
    private final long mRadioToggleWaitMs;

    private final Object mObject = new Object();

    // mRadioEnabled is read-only on the main thread and read/write by the handler thread.
    // synchronization on this variable should be avoided so that the main thread can never
    // be blocked when reading it.
    private volatile boolean mRadioEnabled;

    public RadioToggler(Radio radio, PartialWakeLock wakeLock, long radioToggleWaitMs) {
        mRadio = radio;
        mWakeLock = wakeLock;
        mRadioToggleWaitMs = radioToggleWaitMs;

        mHandlerThread = new HandlerThread(mRadio.logTag() + ".Toggler");
        mHandlerThread.start();
        mHandler = new RadioHandler(mHandlerThread.getLooper());

        refreshRadioState();
    }

    public boolean getRadioEnabled() {
        return mRadioEnabled;
    }

    /**
     * Notify RadioToggler that the underlying radio state may have changed.
     */
    public void refreshRadioState() {
        Message msg = mHandler.obtainMessage(MSG_REFRESH_RADIO_STATE);
        if (!mHandler.hasMessages(MSG_REFRESH_RADIO_STATE)) {
            mHandler.sendMessage(msg);
        }
    }

    /**
     * Set the radio to the desired enable/disable state.
     */
    public void toggleRadio(boolean enable) {
        if (Log.isLoggable(mRadio.logTag(), Log.VERBOSE)) {
            Log.v(mRadio.logTag(), "ToggleRadio to: " + enable);
        }
        Message msg = mHandler.obtainMessage(MSG_TOGGLE_RADIO, enable);
        mHandler.removeMessages(MSG_TOGGLE_RADIO);
        mHandler.sendMessage(msg);
    }

    private class RadioHandler extends Handler {

        public RadioHandler(Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_REFRESH_RADIO_STATE:
                    mRadioEnabled = mRadio.getEnabled();
                    if (Log.isLoggable(mRadio.logTag(), Log.VERBOSE)) {
                        Log.v(mRadio.logTag(),
                                "REFRESH_RADIO [ enabled = " + mRadioEnabled + "]");
                    }
                    break;
                case MSG_TOGGLE_RADIO:
                    if (Log.isLoggable(mRadio.logTag(), Log.VERBOSE)) {
                      Log.v(mRadio.logTag(),
                              "TOGGLE_RADIO enter [enabled = " + mRadioEnabled + "]");
                    }

                    boolean enable = (boolean) msg.obj;
                    if (enable == mRadioEnabled) {
                        return;
                    }

                    try {
                        mWakeLock.acquire();
                        mRadio.setEnabled(enable);
                        if (mRadioToggleWaitMs > 0) {
                            synchronized (mObject) {
                                mObject.wait(mRadioToggleWaitMs);
                            }
                        }
                    } catch (InterruptedException e) {
                        // pass
                    } finally {
                        mWakeLock.release();
                    }

                    mRadioEnabled = mRadio.getEnabled();
                    if (Log.isLoggable(mRadio.logTag(), Log.VERBOSE)) {
                        Log.v(mRadio.logTag(),
                                "TOGGLE_RADIO exit [enabled = " + mRadioEnabled + "]");
                    }
                    break;
                default:
                    break;
            }
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy