diff options
Diffstat (limited to 'services/java/com/android/server/status/widget/StateTracker.java')
-rw-r--r-- | services/java/com/android/server/status/widget/StateTracker.java | 160 |
1 files changed, 160 insertions, 0 deletions
diff --git a/services/java/com/android/server/status/widget/StateTracker.java b/services/java/com/android/server/status/widget/StateTracker.java new file mode 100644 index 0000000..fd476b6 --- /dev/null +++ b/services/java/com/android/server/status/widget/StateTracker.java @@ -0,0 +1,160 @@ +package com.android.server.status.widget; + +import com.android.server.status.widget.PowerButton; +import android.content.Context; +import android.content.Intent; +import android.util.Log; + + +/** + * The state machine for Wifi and Bluetooth toggling, tracking reality + * versus the user's intent. + * + * This is necessary because reality moves relatively slowly (turning on + * & off radio drivers), compared to user's expectations. + */ +public abstract class StateTracker { + // Is the state in the process of changing? + private boolean mInTransition = false; + private Boolean mActualState = null; // initially not set + private Boolean mIntendedState = null; // initially not set + + // Did a toggle request arrive while a state update was + // already in-flight? If so, the mIntendedState needs to be + // requested when the other one is done, unless we happened to + // arrive at that state already. + private boolean mDeferredStateChangeRequestNeeded = false; + + /** + * User pressed a button to change the state. Something should + * immediately appear to the user afterwards, even if we effectively do + * nothing. Their press must be heard. + */ + public final void toggleState(Context context) { + int currentState = getTriState(context); + boolean newState = false; + switch (currentState) { + case PowerButton.STATE_ENABLED: + newState = false; + break; + case PowerButton.STATE_DISABLED: + newState = true; + break; + case PowerButton.STATE_INTERMEDIATE: + if (mIntendedState != null) { + newState = !mIntendedState; + } + break; + } + mIntendedState = newState; + if (mInTransition) { + // We don't send off a transition request if we're + // already transitioning. Makes our state tracking + // easier, and is probably nicer on lower levels. + // (even though they should be able to take it...) + mDeferredStateChangeRequestNeeded = true; + } else { + mInTransition = true; + requestStateChange(context, newState); + } + } + + /** + * Update internal state from a broadcast state change. + */ + public abstract void onActualStateChange(Context context, Intent intent); + + /** + * Sets the value that we're now in. To be called from + * onActualStateChange. + * + * @param newState + * one of STATE_DISABLED, STATE_ENABLED, STATE_TURNING_ON, + * STATE_TURNING_OFF, STATE_UNKNOWN + */ + protected final void setCurrentState(Context context, int newState) { + final boolean wasInTransition = mInTransition; + switch (newState) { + case PowerButton.STATE_DISABLED: + mInTransition = false; + mActualState = false; + break; + case PowerButton.STATE_ENABLED: + mInTransition = false; + mActualState = true; + break; + case PowerButton.STATE_TURNING_ON: + mInTransition = true; + mActualState = false; + break; + case PowerButton.STATE_TURNING_OFF: + mInTransition = true; + mActualState = true; + break; + } + + if (wasInTransition && !mInTransition) { + if (mDeferredStateChangeRequestNeeded) { + Log.v("StateTracker", "processing deferred state change"); + if (mActualState != null && mIntendedState != null + && mIntendedState.equals(mActualState)) { + Log.v("StateTracker", "... but intended state matches, so no changes."); + } else if (mIntendedState != null) { + mInTransition = true; + requestStateChange(context, mIntendedState); + } + mDeferredStateChangeRequestNeeded = false; + } + } + } + + /** + * If we're in a transition mode, this returns true if we're + * transitioning towards being enabled. + */ + public final boolean isTurningOn() { + return mIntendedState != null && mIntendedState; + } + + /** + * Returns simplified 3-state value from underlying 5-state. + * + * @param context + * @return STATE_ENABLED, STATE_DISABLED, or STATE_INTERMEDIATE + */ + public final int getTriState(Context context) { + /*if (mInTransition) { + // If we know we just got a toggle request recently + // (which set mInTransition), don't even ask the + // underlying interface for its state. We know we're + // changing. This avoids blocking the UI thread + // during UI refresh post-toggle if the underlying + // service state accessor has coarse locking on its + // state (to be fixed separately). + return PowerButton.STATE_INTERMEDIATE; + }*/ + switch (getActualState(context)) { + case PowerButton.STATE_DISABLED: + return PowerButton.STATE_DISABLED; + case PowerButton.STATE_ENABLED: + return PowerButton.STATE_ENABLED; + default: + return PowerButton.STATE_INTERMEDIATE; + } + } + + /** + * Gets underlying actual state. + * + * @param context + * @return STATE_ENABLED, STATE_DISABLED, STATE_ENABLING, + * STATE_DISABLING, or or STATE_UNKNOWN. + */ + public abstract int getActualState(Context context); + + /** + * Actually make the desired change to the underlying radio API. + */ + protected abstract void requestStateChange(Context context, + boolean desiredState); +} |