103a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff/*
203a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff * Copyright (C) 2009 The Android Open Source Project
303a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff *
403a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff * Licensed under the Apache License, Version 2.0 (the "License");
503a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff * you may not use this file except in compliance with the License.
603a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff * You may obtain a copy of the License at
703a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff *
803a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff *      http://www.apache.org/licenses/LICENSE-2.0
903a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff *
1003a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff * Unless required by applicable law or agreed to in writing, software
1103a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff * distributed under the License is distributed on an "AS IS" BASIS,
1203a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1303a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff * See the License for the specific language governing permissions and
1403a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff * limitations under the License.
1503a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff */
1603a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff
1703a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriffpackage com.android.settings.widget;
1803a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff
1985e2f61b2d349125e4bd5d7677cfa09ba09983caMaggieimport android.app.ActivityManager;
2003a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriffimport android.app.PendingIntent;
2103a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriffimport android.appwidget.AppWidgetManager;
2203a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriffimport android.appwidget.AppWidgetProvider;
23d63c0112251ab4e4e977545368dd703d875012a4Nick Pellyimport android.bluetooth.BluetoothAdapter;
2403a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriffimport android.content.ComponentName;
2503a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriffimport android.content.ContentResolver;
2603a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriffimport android.content.Context;
2703a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriffimport android.content.Intent;
2849c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasaniimport android.database.ContentObserver;
29dc15a76ed504f15b579302fb064bce89947b084eMichael Wrightimport android.hardware.display.DisplayManager;
3003a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriffimport android.location.LocationManager;
3103a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriffimport android.net.ConnectivityManager;
3203a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriffimport android.net.Uri;
3303a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriffimport android.net.wifi.WifiManager;
34046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrickimport android.os.AsyncTask;
3549c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasaniimport android.os.Handler;
36cd03f5320d42290b1619933954a344b59dc55f4fMike Lockwoodimport android.os.IPowerManager;
37748ba16a046a6ac4727f2e39db9a933d81d02465Jeff Brownimport android.os.PowerManager;
3885e2f61b2d349125e4bd5d7677cfa09ba09983caMaggieimport android.os.Process;
3903a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriffimport android.os.RemoteException;
4003a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriffimport android.os.ServiceManager;
41ea6260d887a7065d65d94be58c05903b3d1fc359Maggie Benthallimport android.os.UserManager;
4203a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriffimport android.provider.Settings;
4385e2f61b2d349125e4bd5d7677cfa09ba09983caMaggieimport android.provider.Settings.Secure;
4403a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriffimport android.util.Log;
4503a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriffimport android.widget.RemoteViews;
461d6bf8d46b07cb87d5842324190bc5a31eee5e4bJeff Sharkey
4703a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriffimport com.android.settings.R;
48f2982a9ba19340b474bafb6b0bf5832673984e0dJason Monkimport com.android.settings.bluetooth.Utils;
49f2982a9ba19340b474bafb6b0bf5832673984e0dJason Monkimport com.android.settingslib.bluetooth.LocalBluetoothAdapter;
50f2982a9ba19340b474bafb6b0bf5832673984e0dJason Monkimport com.android.settingslib.bluetooth.LocalBluetoothManager;
5103a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff
5203a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff/**
5303a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff * Provides control of power-related settings from a widget.
5403a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff */
5503a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriffpublic class SettingsAppWidgetProvider extends AppWidgetProvider {
5603a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    static final String TAG = "SettingsAppWidgetProvider";
5703a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff
5803a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    static final ComponentName THIS_APPWIDGET =
5903a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff            new ComponentName("com.android.settings",
6003a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff                    "com.android.settings.widget.SettingsAppWidgetProvider");
6103a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff
62436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    private static LocalBluetoothAdapter sLocalBluetoothAdapter = null;
6303a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff
6403a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    private static final int BUTTON_WIFI = 0;
6503a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    private static final int BUTTON_BRIGHTNESS = 1;
6603a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    private static final int BUTTON_SYNC = 2;
67681f79900787c2c40751463ddd8f3476f9b40476David Christie    private static final int BUTTON_LOCATION = 3;
6803a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    private static final int BUTTON_BLUETOOTH = 4;
6903a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff
7094ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick    // This widget keeps track of two sets of states:
7194ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick    // "3-state": STATE_DISABLED, STATE_ENABLED, STATE_INTERMEDIATE
7294ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick    // "5-state": STATE_DISABLED, STATE_ENABLED, STATE_TURNING_ON, STATE_TURNING_OFF, STATE_UNKNOWN
7303a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    private static final int STATE_DISABLED = 0;
7403a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    private static final int STATE_ENABLED = 1;
7594ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick    private static final int STATE_TURNING_ON = 2;
7694ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick    private static final int STATE_TURNING_OFF = 3;
7794ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick    private static final int STATE_UNKNOWN = 4;
7894ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick    private static final int STATE_INTERMEDIATE = 5;
7994ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick
80740edeaa42d276bca21ea7e077412badecc0eea3Amith Yamasani    // Position in the widget bar, to enable different graphics for left, center and right buttons
81740edeaa42d276bca21ea7e077412badecc0eea3Amith Yamasani    private static final int POS_LEFT = 0;
82740edeaa42d276bca21ea7e077412badecc0eea3Amith Yamasani    private static final int POS_CENTER = 1;
83740edeaa42d276bca21ea7e077412badecc0eea3Amith Yamasani    private static final int POS_RIGHT = 2;
84740edeaa42d276bca21ea7e077412badecc0eea3Amith Yamasani
85740edeaa42d276bca21ea7e077412badecc0eea3Amith Yamasani    private static final int[] IND_DRAWABLE_OFF = {
86a1252ccf7b31d01a9612fc0479dc7a632cabf8a7Peter Ng        R.drawable.appwidget_settings_ind_off_l_holo,
87a1252ccf7b31d01a9612fc0479dc7a632cabf8a7Peter Ng        R.drawable.appwidget_settings_ind_off_c_holo,
88a1252ccf7b31d01a9612fc0479dc7a632cabf8a7Peter Ng        R.drawable.appwidget_settings_ind_off_r_holo
89740edeaa42d276bca21ea7e077412badecc0eea3Amith Yamasani    };
90740edeaa42d276bca21ea7e077412badecc0eea3Amith Yamasani
91740edeaa42d276bca21ea7e077412badecc0eea3Amith Yamasani    private static final int[] IND_DRAWABLE_MID = {
92a1252ccf7b31d01a9612fc0479dc7a632cabf8a7Peter Ng        R.drawable.appwidget_settings_ind_mid_l_holo,
93a1252ccf7b31d01a9612fc0479dc7a632cabf8a7Peter Ng        R.drawable.appwidget_settings_ind_mid_c_holo,
94a1252ccf7b31d01a9612fc0479dc7a632cabf8a7Peter Ng        R.drawable.appwidget_settings_ind_mid_r_holo
95740edeaa42d276bca21ea7e077412badecc0eea3Amith Yamasani    };
96740edeaa42d276bca21ea7e077412badecc0eea3Amith Yamasani
97740edeaa42d276bca21ea7e077412badecc0eea3Amith Yamasani    private static final int[] IND_DRAWABLE_ON = {
98a1252ccf7b31d01a9612fc0479dc7a632cabf8a7Peter Ng        R.drawable.appwidget_settings_ind_on_l_holo,
99a1252ccf7b31d01a9612fc0479dc7a632cabf8a7Peter Ng        R.drawable.appwidget_settings_ind_on_c_holo,
100a1252ccf7b31d01a9612fc0479dc7a632cabf8a7Peter Ng        R.drawable.appwidget_settings_ind_on_r_holo
101740edeaa42d276bca21ea7e077412badecc0eea3Amith Yamasani    };
10203a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff
103a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani    /** Minimum brightness at which the indicator is shown at half-full and ON */
104748ba16a046a6ac4727f2e39db9a933d81d02465Jeff Brown    private static final float HALF_BRIGHTNESS_THRESHOLD = 0.3f;
105a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani    /** Minimum brightness at which the indicator is shown at full */
106748ba16a046a6ac4727f2e39db9a933d81d02465Jeff Brown    private static final float FULL_BRIGHTNESS_THRESHOLD = 0.8f;
10703a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff
10894ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick    private static final StateTracker sWifiState = new WifiStateTracker();
10994ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick    private static final StateTracker sBluetoothState = new BluetoothStateTracker();
110681f79900787c2c40751463ddd8f3476f9b40476David Christie    private static final StateTracker sLocationState = new LocationStateTracker();
111ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick    private static final StateTracker sSyncState = new SyncStateTracker();
11249c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani    private static SettingsObserver sSettingsObserver;
11394ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick
11494ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick    /**
115ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick     * The state machine for a setting's toggling, tracking reality
116ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick     * versus the user's intent.
11794ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick     *
11894ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick     * This is necessary because reality moves relatively slowly
11994ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick     * (turning on & off radio drivers), compared to user's
12094ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick     * expectations.
12194ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick     */
12294ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick    private abstract static class StateTracker {
12394ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        // Is the state in the process of changing?
12494ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        private boolean mInTransition = false;
12594ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        private Boolean mActualState = null;  // initially not set
12694ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        private Boolean mIntendedState = null;  // initially not set
12794ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick
12894ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        // Did a toggle request arrive while a state update was
12994ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        // already in-flight?  If so, the mIntendedState needs to be
13094ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        // requested when the other one is done, unless we happened to
13194ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        // arrive at that state already.
13294ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        private boolean mDeferredStateChangeRequestNeeded = false;
13394ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick
13494ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        /**
13594ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         * User pressed a button to change the state.  Something
13694ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         * should immediately appear to the user afterwards, even if
13794ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         * we effectively do nothing.  Their press must be heard.
13894ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         */
13994ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        public final void toggleState(Context context) {
14094ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            int currentState = getTriState(context);
14194ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            boolean newState = false;
14294ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            switch (currentState) {
14394ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                case STATE_ENABLED:
14494ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    newState = false;
14594ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    break;
14694ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                case STATE_DISABLED:
14794ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    newState = true;
14894ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    break;
14994ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                case STATE_INTERMEDIATE:
15094ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    if (mIntendedState != null) {
15194ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                        newState = !mIntendedState;
15294ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    }
15394ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    break;
15494ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            }
15594ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            mIntendedState = newState;
15694ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            if (mInTransition) {
15794ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                // We don't send off a transition request if we're
15894ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                // already transitioning.  Makes our state tracking
15994ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                // easier, and is probably nicer on lower levels.
16094ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                // (even though they should be able to take it...)
16194ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                mDeferredStateChangeRequestNeeded = true;
16294ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            } else {
16394ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                mInTransition = true;
164046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick                requestStateChange(context, newState);
16594ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            }
16694ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        }
16794ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick
16894ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        /**
169b9062f26785e53cfc44180e0044c8025ad33af2aalanv         * Return the ID of the clickable container for the setting.
170b9062f26785e53cfc44180e0044c8025ad33af2aalanv         */
171b9062f26785e53cfc44180e0044c8025ad33af2aalanv        public abstract int getContainerId();
172b9062f26785e53cfc44180e0044c8025ad33af2aalanv
173b9062f26785e53cfc44180e0044c8025ad33af2aalanv        /**
174ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick         * Return the ID of the main large image button for the setting.
175ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick         */
176ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        public abstract int getButtonId();
177ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick
178ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        /**
179ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick         * Returns the small indicator image ID underneath the setting.
180ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick         */
181ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        public abstract int getIndicatorId();
182ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick
183ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        /**
184b9062f26785e53cfc44180e0044c8025ad33af2aalanv         * Returns the resource ID of the setting's content description.
185b9062f26785e53cfc44180e0044c8025ad33af2aalanv         */
186b9062f26785e53cfc44180e0044c8025ad33af2aalanv        public abstract int getButtonDescription();
187b9062f26785e53cfc44180e0044c8025ad33af2aalanv
188b9062f26785e53cfc44180e0044c8025ad33af2aalanv        /**
189ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick         * Returns the resource ID of the image to show as a function of
190ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick         * the on-vs-off state.
191ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick         */
192ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        public abstract int getButtonImageId(boolean on);
193ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick
194ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        /**
195740edeaa42d276bca21ea7e077412badecc0eea3Amith Yamasani         * Returns the position in the button bar - either POS_LEFT, POS_RIGHT or POS_CENTER.
196740edeaa42d276bca21ea7e077412badecc0eea3Amith Yamasani         */
197740edeaa42d276bca21ea7e077412badecc0eea3Amith Yamasani        public int getPosition() { return POS_CENTER; }
198740edeaa42d276bca21ea7e077412badecc0eea3Amith Yamasani
199740edeaa42d276bca21ea7e077412badecc0eea3Amith Yamasani        /**
200ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick         * Updates the remote views depending on the state (off, on,
201ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick         * turning off, turning on) of the setting.
202ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick         */
203ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        public final void setImageViewResources(Context context, RemoteViews views) {
204b9062f26785e53cfc44180e0044c8025ad33af2aalanv            int containerId = getContainerId();
205ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick            int buttonId = getButtonId();
206ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick            int indicatorId = getIndicatorId();
207740edeaa42d276bca21ea7e077412badecc0eea3Amith Yamasani            int pos = getPosition();
208ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick            switch (getTriState(context)) {
209ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                case STATE_DISABLED:
210b9062f26785e53cfc44180e0044c8025ad33af2aalanv                    views.setContentDescription(containerId,
211b9062f26785e53cfc44180e0044c8025ad33af2aalanv                        getContentDescription(context, R.string.gadget_state_off));
212ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    views.setImageViewResource(buttonId, getButtonImageId(false));
213ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    views.setImageViewResource(
214740edeaa42d276bca21ea7e077412badecc0eea3Amith Yamasani                        indicatorId, IND_DRAWABLE_OFF[pos]);
215ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    break;
216ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                case STATE_ENABLED:
217b9062f26785e53cfc44180e0044c8025ad33af2aalanv                    views.setContentDescription(containerId,
218b9062f26785e53cfc44180e0044c8025ad33af2aalanv                        getContentDescription(context, R.string.gadget_state_on));
219ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    views.setImageViewResource(buttonId, getButtonImageId(true));
220ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    views.setImageViewResource(
221740edeaa42d276bca21ea7e077412badecc0eea3Amith Yamasani                        indicatorId, IND_DRAWABLE_ON[pos]);
222ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    break;
223ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                case STATE_INTERMEDIATE:
224ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    // In the transitional state, the bottom green bar
225ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    // shows the tri-state (on, off, transitioning), but
226ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    // the top dark-gray-or-bright-white logo shows the
227ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    // user's intent.  This is much easier to see in
228ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    // sunlight.
229ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    if (isTurningOn()) {
230b9062f26785e53cfc44180e0044c8025ad33af2aalanv                        views.setContentDescription(containerId,
231b9062f26785e53cfc44180e0044c8025ad33af2aalanv                            getContentDescription(context, R.string.gadget_state_turning_on));
232ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                        views.setImageViewResource(buttonId, getButtonImageId(true));
233ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                        views.setImageViewResource(
234740edeaa42d276bca21ea7e077412badecc0eea3Amith Yamasani                            indicatorId, IND_DRAWABLE_MID[pos]);
235ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    } else {
236b9062f26785e53cfc44180e0044c8025ad33af2aalanv                        views.setContentDescription(containerId,
237b9062f26785e53cfc44180e0044c8025ad33af2aalanv                            getContentDescription(context, R.string.gadget_state_turning_off));
238ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                        views.setImageViewResource(buttonId, getButtonImageId(false));
239ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                        views.setImageViewResource(
240740edeaa42d276bca21ea7e077412badecc0eea3Amith Yamasani                            indicatorId, IND_DRAWABLE_OFF[pos]);
241ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    }
242ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    break;
243ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick            }
244ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        }
245ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick
246ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        /**
247b9062f26785e53cfc44180e0044c8025ad33af2aalanv         * Returns the gadget state template populated with the gadget
248b9062f26785e53cfc44180e0044c8025ad33af2aalanv         * description and state.
249b9062f26785e53cfc44180e0044c8025ad33af2aalanv         */
250b9062f26785e53cfc44180e0044c8025ad33af2aalanv        private final String getContentDescription(Context context, int stateResId) {
251b9062f26785e53cfc44180e0044c8025ad33af2aalanv            final String gadget = context.getString(getButtonDescription());
252b9062f26785e53cfc44180e0044c8025ad33af2aalanv            final String state = context.getString(stateResId);
253b9062f26785e53cfc44180e0044c8025ad33af2aalanv            return context.getString(R.string.gadget_state_template, gadget, state);
254b9062f26785e53cfc44180e0044c8025ad33af2aalanv        }
255b9062f26785e53cfc44180e0044c8025ad33af2aalanv
256b9062f26785e53cfc44180e0044c8025ad33af2aalanv        /**
25794ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         * Update internal state from a broadcast state change.
25894ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         */
25994ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        public abstract void onActualStateChange(Context context, Intent intent);
26094ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick
26194ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        /**
26294ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         * Sets the value that we're now in.  To be called from onActualStateChange.
26394ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         *
26494ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         * @param newState one of STATE_DISABLED, STATE_ENABLED, STATE_TURNING_ON,
26594ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         *                 STATE_TURNING_OFF, STATE_UNKNOWN
26694ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         */
26794ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        protected final void setCurrentState(Context context, int newState) {
268046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick            final boolean wasInTransition = mInTransition;
26994ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            switch (newState) {
27094ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                case STATE_DISABLED:
27194ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    mInTransition = false;
27294ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    mActualState = false;
27394ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    break;
27494ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                case STATE_ENABLED:
27594ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    mInTransition = false;
27694ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    mActualState = true;
27794ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    break;
27894ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                case STATE_TURNING_ON:
27994ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    mInTransition = true;
28094ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    mActualState = false;
28194ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    break;
28294ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                case STATE_TURNING_OFF:
28394ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    mInTransition = true;
28494ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    mActualState = true;
28594ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    break;
28694ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            }
28794ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick
28894ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            if (wasInTransition && !mInTransition) {
28994ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                if (mDeferredStateChangeRequestNeeded) {
29094ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    Log.v(TAG, "processing deferred state change");
29194ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    if (mActualState != null && mIntendedState != null &&
29294ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                        mIntendedState.equals(mActualState)) {
29394ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                        Log.v(TAG, "... but intended state matches, so no changes.");
29494ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    } else if (mIntendedState != null) {
29594ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                        mInTransition = true;
296046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick                        requestStateChange(context, mIntendedState);
29794ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    }
29894ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    mDeferredStateChangeRequestNeeded = false;
29994ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                }
30094ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            }
30194ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        }
30294ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick
30394ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick
30494ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        /**
30594ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         * If we're in a transition mode, this returns true if we're
30694ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         * transitioning towards being enabled.
30794ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         */
30894ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        public final boolean isTurningOn() {
30994ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            return mIntendedState != null && mIntendedState;
31094ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        }
31194ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick
31294ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        /**
31394ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         * Returns simplified 3-state value from underlying 5-state.
31494ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         *
31594ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         * @param context
31694ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         * @return STATE_ENABLED, STATE_DISABLED, or STATE_INTERMEDIATE
31794ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         */
31894ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        public final int getTriState(Context context) {
319046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick            if (mInTransition) {
320046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick                // If we know we just got a toggle request recently
321046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick                // (which set mInTransition), don't even ask the
322046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick                // underlying interface for its state.  We know we're
323046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick                // changing.  This avoids blocking the UI thread
324046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick                // during UI refresh post-toggle if the underlying
325046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick                // service state accessor has coarse locking on its
326046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick                // state (to be fixed separately).
327046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick                return STATE_INTERMEDIATE;
328046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick            }
32994ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            switch (getActualState(context)) {
33094ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                case STATE_DISABLED:
33194ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    return STATE_DISABLED;
33294ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                case STATE_ENABLED:
33394ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    return STATE_ENABLED;
33494ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                default:
33594ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    return STATE_INTERMEDIATE;
33694ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            }
33794ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        }
33894ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick
33994ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        /**
34094ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         * Gets underlying actual state.
34194ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         *
34294ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         * @param context
34394ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         * @return STATE_ENABLED, STATE_DISABLED, STATE_ENABLING, STATE_DISABLING,
34494ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         *         or or STATE_UNKNOWN.
34594ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         */
34694ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        public abstract int getActualState(Context context);
34794ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick
34894ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        /**
34994ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         * Actually make the desired change to the underlying radio
35094ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         * API.
35194ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         */
352046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick        protected abstract void requestStateChange(Context context, boolean desiredState);
35394ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick    }
35494ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick
35594ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick    /**
35694ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick     * Subclass of StateTracker to get/set Wifi state.
35794ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick     */
35894ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick    private static final class WifiStateTracker extends StateTracker {
359b9062f26785e53cfc44180e0044c8025ad33af2aalanv        public int getContainerId() { return R.id.btn_wifi; }
360ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        public int getButtonId() { return R.id.img_wifi; }
361ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        public int getIndicatorId() { return R.id.ind_wifi; }
362b9062f26785e53cfc44180e0044c8025ad33af2aalanv        public int getButtonDescription() { return R.string.gadget_wifi; }
363ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        public int getButtonImageId(boolean on) {
364a1252ccf7b31d01a9612fc0479dc7a632cabf8a7Peter Ng            return on ? R.drawable.ic_appwidget_settings_wifi_on_holo
365a1252ccf7b31d01a9612fc0479dc7a632cabf8a7Peter Ng                    : R.drawable.ic_appwidget_settings_wifi_off_holo;
366ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        }
367ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick
36894ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        @Override
369740edeaa42d276bca21ea7e077412badecc0eea3Amith Yamasani        public int getPosition() { return POS_LEFT; }
370740edeaa42d276bca21ea7e077412badecc0eea3Amith Yamasani
371740edeaa42d276bca21ea7e077412badecc0eea3Amith Yamasani        @Override
37294ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        public int getActualState(Context context) {
37394ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
37494ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            if (wifiManager != null) {
37594ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                return wifiStateToFiveState(wifiManager.getWifiState());
37694ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            }
37794ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            return STATE_UNKNOWN;
37894ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        }
37994ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick
38094ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        @Override
381046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick        protected void requestStateChange(Context context, final boolean desiredState) {
382ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick            final WifiManager wifiManager =
383ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
38494ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            if (wifiManager == null) {
38594ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                Log.d(TAG, "No wifiManager.");
38694ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                return;
38794ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            }
388a6a74e222a994e29a1daa7178943a1fc9dd06c47Irfan Sheriff
389046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick            // Actually request the wifi change and persistent
390046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick            // settings write off the UI thread, as it can take a
391046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick            // user-noticeable amount of time, especially if there's
392046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick            // disk contention.
393046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick            new AsyncTask<Void, Void, Void>() {
394046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick                @Override
395046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick                protected Void doInBackground(Void... args) {
396046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick                    /**
397046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick                     * Disable tethering if enabling Wifi
398046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick                     */
399046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick                    int wifiApState = wifiManager.getWifiApState();
400046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick                    if (desiredState && ((wifiApState == WifiManager.WIFI_AP_STATE_ENABLING) ||
401046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick                                         (wifiApState == WifiManager.WIFI_AP_STATE_ENABLED))) {
402deca11c87dbe4d49b43961f6b755f4484936e2caRebecca Silberstein                        final ConnectivityManager connectivityManager =
403deca11c87dbe4d49b43961f6b755f4484936e2caRebecca Silberstein                                (ConnectivityManager) context.getSystemService(
404deca11c87dbe4d49b43961f6b755f4484936e2caRebecca Silberstein                                        Context.CONNECTIVITY_SERVICE);
405deca11c87dbe4d49b43961f6b755f4484936e2caRebecca Silberstein                        connectivityManager.stopTethering(ConnectivityManager.TETHERING_WIFI);
406046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick                    }
407046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick
408046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick                    wifiManager.setWifiEnabled(desiredState);
409046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick                    return null;
410046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick                }
411046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick            }.execute();
41294ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        }
41394ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick
41494ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        @Override
41594ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        public void onActualStateChange(Context context, Intent intent) {
41694ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            if (!WifiManager.WIFI_STATE_CHANGED_ACTION.equals(intent.getAction())) {
41794ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                return;
41894ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            }
41994ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            int wifiState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, -1);
42094ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            setCurrentState(context, wifiStateToFiveState(wifiState));
42194ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        }
42294ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick
42394ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        /**
42494ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         * Converts WifiManager's state values into our
42594ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         * Wifi/Bluetooth-common state values.
42694ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         */
42794ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        private static int wifiStateToFiveState(int wifiState) {
42894ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            switch (wifiState) {
42994ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                case WifiManager.WIFI_STATE_DISABLED:
43094ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    return STATE_DISABLED;
43194ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                case WifiManager.WIFI_STATE_ENABLED:
43294ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    return STATE_ENABLED;
43394ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                case WifiManager.WIFI_STATE_DISABLING:
43494ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    return STATE_TURNING_OFF;
43594ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                case WifiManager.WIFI_STATE_ENABLING:
43694ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    return STATE_TURNING_ON;
43794ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                default:
43894ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    return STATE_UNKNOWN;
43994ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            }
44094ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        }
44194ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick    }
44294ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick
44394ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick    /**
44494ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick     * Subclass of StateTracker to get/set Bluetooth state.
44594ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick     */
44694ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick    private static final class BluetoothStateTracker extends StateTracker {
447b9062f26785e53cfc44180e0044c8025ad33af2aalanv        public int getContainerId() { return R.id.btn_bluetooth; }
448ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        public int getButtonId() { return R.id.img_bluetooth; }
449ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        public int getIndicatorId() { return R.id.ind_bluetooth; }
450b9062f26785e53cfc44180e0044c8025ad33af2aalanv        public int getButtonDescription() { return R.string.gadget_bluetooth; }
451ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        public int getButtonImageId(boolean on) {
452a1252ccf7b31d01a9612fc0479dc7a632cabf8a7Peter Ng            return on ? R.drawable.ic_appwidget_settings_bluetooth_on_holo
453a1252ccf7b31d01a9612fc0479dc7a632cabf8a7Peter Ng                    : R.drawable.ic_appwidget_settings_bluetooth_off_holo;
454ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        }
45594ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick
45694ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        @Override
45794ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        public int getActualState(Context context) {
458436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            if (sLocalBluetoothAdapter == null) {
459f2982a9ba19340b474bafb6b0bf5832673984e0dJason Monk                LocalBluetoothManager manager = Utils.getLocalBtManager(context);
460436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                if (manager == null) {
46194ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    return STATE_UNKNOWN;  // On emulator?
46294ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                }
463436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                sLocalBluetoothAdapter = manager.getBluetoothAdapter();
4648d763c03028419884ced41c7b630ce9a5c45437dPrathmesh Prabhu                if (sLocalBluetoothAdapter == null) {
4658d763c03028419884ced41c7b630ce9a5c45437dPrathmesh Prabhu                    return STATE_UNKNOWN;  // On emulator?
4668d763c03028419884ced41c7b630ce9a5c45437dPrathmesh Prabhu                }
46794ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            }
468436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            return bluetoothStateToFiveState(sLocalBluetoothAdapter.getBluetoothState());
46994ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        }
47094ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick
47194ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        @Override
472046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick        protected void requestStateChange(Context context, final boolean desiredState) {
473436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            if (sLocalBluetoothAdapter == null) {
47494ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                Log.d(TAG, "No LocalBluetoothManager");
47594ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                return;
47694ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            }
477046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick            // Actually request the Bluetooth change and persistent
478046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick            // settings write off the UI thread, as it can take a
479046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick            // user-noticeable amount of time, especially if there's
480046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick            // disk contention.
481046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick            new AsyncTask<Void, Void, Void>() {
482046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick                @Override
483046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick                protected Void doInBackground(Void... args) {
484436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                    sLocalBluetoothAdapter.setBluetoothEnabled(desiredState);
485046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick                    return null;
486046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick                }
487046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick            }.execute();
48894ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        }
48994ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick
49094ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        @Override
49194ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        public void onActualStateChange(Context context, Intent intent) {
49294ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            if (!BluetoothAdapter.ACTION_STATE_CHANGED.equals(intent.getAction())) {
49394ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                return;
49494ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            }
49594ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            int bluetoothState = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1);
49694ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            setCurrentState(context, bluetoothStateToFiveState(bluetoothState));
49794ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        }
49894ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick
49994ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        /**
50094ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         * Converts BluetoothAdapter's state values into our
50194ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         * Wifi/Bluetooth-common state values.
50294ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         */
50394ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        private static int bluetoothStateToFiveState(int bluetoothState) {
50494ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            switch (bluetoothState) {
50594ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                case BluetoothAdapter.STATE_OFF:
50694ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    return STATE_DISABLED;
50794ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                case BluetoothAdapter.STATE_ON:
50894ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    return STATE_ENABLED;
50994ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                case BluetoothAdapter.STATE_TURNING_ON:
51094ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    return STATE_TURNING_ON;
51194ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                case BluetoothAdapter.STATE_TURNING_OFF:
51294ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    return STATE_TURNING_OFF;
51394ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                default:
51494ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    return STATE_UNKNOWN;
51594ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            }
51694ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        }
51794ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick    }
51894ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick
519ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick    /**
520681f79900787c2c40751463ddd8f3476f9b40476David Christie     * Subclass of StateTracker for location state.
521ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick     */
522681f79900787c2c40751463ddd8f3476f9b40476David Christie    private static final class LocationStateTracker extends StateTracker {
523587e6bf3fcfc8dffb4cf021227d896ffcb5488a9David Christie        private int mCurrentLocationMode = Settings.Secure.LOCATION_MODE_OFF;
524587e6bf3fcfc8dffb4cf021227d896ffcb5488a9David Christie
525681f79900787c2c40751463ddd8f3476f9b40476David Christie        public int getContainerId() { return R.id.btn_location; }
526681f79900787c2c40751463ddd8f3476f9b40476David Christie        public int getButtonId() { return R.id.img_location; }
527681f79900787c2c40751463ddd8f3476f9b40476David Christie        public int getIndicatorId() { return R.id.ind_location; }
528681f79900787c2c40751463ddd8f3476f9b40476David Christie        public int getButtonDescription() { return R.string.gadget_location; }
529ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        public int getButtonImageId(boolean on) {
530587e6bf3fcfc8dffb4cf021227d896ffcb5488a9David Christie            if (on) {
531587e6bf3fcfc8dffb4cf021227d896ffcb5488a9David Christie                switch (mCurrentLocationMode) {
532587e6bf3fcfc8dffb4cf021227d896ffcb5488a9David Christie                    case Settings.Secure.LOCATION_MODE_HIGH_ACCURACY:
533587e6bf3fcfc8dffb4cf021227d896ffcb5488a9David Christie                    case Settings.Secure.LOCATION_MODE_SENSORS_ONLY:
534587e6bf3fcfc8dffb4cf021227d896ffcb5488a9David Christie                        return R.drawable.ic_appwidget_settings_location_on_holo;
535587e6bf3fcfc8dffb4cf021227d896ffcb5488a9David Christie                    default:
536587e6bf3fcfc8dffb4cf021227d896ffcb5488a9David Christie                        return R.drawable.ic_appwidget_settings_location_saving_holo;
537587e6bf3fcfc8dffb4cf021227d896ffcb5488a9David Christie                }
538587e6bf3fcfc8dffb4cf021227d896ffcb5488a9David Christie            }
539587e6bf3fcfc8dffb4cf021227d896ffcb5488a9David Christie
540587e6bf3fcfc8dffb4cf021227d896ffcb5488a9David Christie            return R.drawable.ic_appwidget_settings_location_off_holo;
541ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        }
542ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick
543ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        @Override
544ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        public int getActualState(Context context) {
545ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick            ContentResolver resolver = context.getContentResolver();
546587e6bf3fcfc8dffb4cf021227d896ffcb5488a9David Christie            mCurrentLocationMode = Settings.Secure.getInt(resolver,
54793259c14f3aca4739e2cf7691cb0416ded509d8dTom O'Neill                    Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF);
548587e6bf3fcfc8dffb4cf021227d896ffcb5488a9David Christie            return (mCurrentLocationMode == Settings.Secure.LOCATION_MODE_OFF)
549587e6bf3fcfc8dffb4cf021227d896ffcb5488a9David Christie                    ? STATE_DISABLED : STATE_ENABLED;
550ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        }
551ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick
552ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        @Override
553ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        public void onActualStateChange(Context context, Intent unused) {
554ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick            // Note: the broadcast location providers changed intent
555ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick            // doesn't include an extras bundles saying what the new value is.
556ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick            setCurrentState(context, getActualState(context));
557ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        }
558ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick
559ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        @Override
560ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        public void requestStateChange(final Context context, final boolean desiredState) {
561ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick            final ContentResolver resolver = context.getContentResolver();
562ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick            new AsyncTask<Void, Void, Boolean>() {
563ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                @Override
564ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                protected Boolean doInBackground(Void... args) {
565ea6260d887a7065d65d94be58c05903b3d1fc359Maggie Benthall                    final UserManager um =
566ea6260d887a7065d65d94be58c05903b3d1fc359Maggie Benthall                            (UserManager) context.getSystemService(Context.USER_SERVICE);
5670c5a401a58b30041d5fe712d78fccbd47f5b744dMaggie Benthall                    if (!um.hasUserRestriction(UserManager.DISALLOW_SHARE_LOCATION)) {
56885e2f61b2d349125e4bd5d7677cfa09ba09983caMaggie                        LocationManager lm =
56985e2f61b2d349125e4bd5d7677cfa09ba09983caMaggie                                (LocationManager) context.getSystemService(
57085e2f61b2d349125e4bd5d7677cfa09ba09983caMaggie                                        Context.LOCATION_SERVICE);
57185e2f61b2d349125e4bd5d7677cfa09ba09983caMaggie                        boolean currentLocationEnabled = lm.isLocationEnabled();
57285e2f61b2d349125e4bd5d7677cfa09ba09983caMaggie                        lm.setLocationEnabledForUser(
57385e2f61b2d349125e4bd5d7677cfa09ba09983caMaggie                                !currentLocationEnabled, Process.myUserHandle());
57485e2f61b2d349125e4bd5d7677cfa09ba09983caMaggie                        return lm.isLocationEnabled();
575ea6260d887a7065d65d94be58c05903b3d1fc359Maggie Benthall                    }
5765eed792a76970e4271e03547e61dbbd6fabbf2f4David Christie                    return getActualState(context) == STATE_ENABLED;
577ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                }
578ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick
579ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                @Override
580ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                protected void onPostExecute(Boolean result) {
581ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    setCurrentState(
582ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                        context,
583ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                        result ? STATE_ENABLED : STATE_DISABLED);
584ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    updateWidget(context);
585ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                }
586ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick            }.execute();
587ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        }
588ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick    }
589ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick
590ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick    /**
591ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick     * Subclass of StateTracker for sync state.
592ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick     */
593ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick    private static final class SyncStateTracker extends StateTracker {
594b9062f26785e53cfc44180e0044c8025ad33af2aalanv        public int getContainerId() { return R.id.btn_sync; }
595ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        public int getButtonId() { return R.id.img_sync; }
596ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        public int getIndicatorId() { return R.id.ind_sync; }
597b9062f26785e53cfc44180e0044c8025ad33af2aalanv        public int getButtonDescription() { return R.string.gadget_sync; }
598ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        public int getButtonImageId(boolean on) {
599a1252ccf7b31d01a9612fc0479dc7a632cabf8a7Peter Ng            return on ? R.drawable.ic_appwidget_settings_sync_on_holo
600a1252ccf7b31d01a9612fc0479dc7a632cabf8a7Peter Ng                    : R.drawable.ic_appwidget_settings_sync_off_holo;
601ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        }
602ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick
603ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        @Override
604ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        public int getActualState(Context context) {
60549c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani            boolean on = ContentResolver.getMasterSyncAutomatically();
606ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick            return on ? STATE_ENABLED : STATE_DISABLED;
607ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        }
608ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick
609ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        @Override
610ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        public void onActualStateChange(Context context, Intent unused) {
611ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick            setCurrentState(context, getActualState(context));
612ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        }
613ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick
614ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        @Override
615ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        public void requestStateChange(final Context context, final boolean desiredState) {
616ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick            final ConnectivityManager connManager =
617ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
618ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick            final boolean sync = ContentResolver.getMasterSyncAutomatically();
619ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick
620ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick            new AsyncTask<Void, Void, Boolean>() {
621ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                @Override
622ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                protected Boolean doInBackground(Void... args) {
623ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    // Turning sync on.
624ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    if (desiredState) {
625ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                        if (!sync) {
626ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                            ContentResolver.setMasterSyncAutomatically(true);
627ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                        }
628ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                        return true;
629ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    }
630ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick
631ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    // Turning sync off
632ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    if (sync) {
633ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                        ContentResolver.setMasterSyncAutomatically(false);
634ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    }
635ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    return false;
636ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                }
637ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick
638ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                @Override
639ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                protected void onPostExecute(Boolean result) {
640ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    setCurrentState(
641ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                        context,
642ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                        result ? STATE_ENABLED : STATE_DISABLED);
643ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    updateWidget(context);
644ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                }
645ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick            }.execute();
646ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        }
647ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick    }
64894ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick
649a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani    private static void checkObserver(Context context) {
650a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani        if (sSettingsObserver == null) {
651a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani            sSettingsObserver = new SettingsObserver(new Handler(),
652a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani                    context.getApplicationContext());
653a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani            sSettingsObserver.startObserving();
654a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani        }
655a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani    }
656a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani
65703a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    @Override
65803a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    public void onUpdate(Context context, AppWidgetManager appWidgetManager,
65903a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff            int[] appWidgetIds) {
66003a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        // Update each requested appWidgetId
661436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        RemoteViews view = buildUpdate(context);
66203a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff
66303a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        for (int i = 0; i < appWidgetIds.length; i++) {
66403a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff            appWidgetManager.updateAppWidget(appWidgetIds[i], view);
66503a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        }
66603a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    }
66703a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff
66803a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    @Override
66903a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    public void onEnabled(Context context) {
670a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani        checkObserver(context);
67103a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    }
67203a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff
67303a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    @Override
67403a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    public void onDisabled(Context context) {
67549c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani        if (sSettingsObserver != null) {
67649c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani            sSettingsObserver.stopObserving();
67749c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani            sSettingsObserver = null;
67849c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani        }
67903a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    }
68003a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff
68103a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    /**
68203a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     * Load image for given widget and build {@link RemoteViews} for it.
68303a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     */
684436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    static RemoteViews buildUpdate(Context context) {
68503a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        RemoteViews views = new RemoteViews(context.getPackageName(),
68603a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff                R.layout.widget);
687436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        views.setOnClickPendingIntent(R.id.btn_wifi, getLaunchPendingIntent(context,
68803a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff                BUTTON_WIFI));
68903a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        views.setOnClickPendingIntent(R.id.btn_brightness,
69003a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff                getLaunchPendingIntent(context,
691436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                        BUTTON_BRIGHTNESS));
69203a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        views.setOnClickPendingIntent(R.id.btn_sync,
69303a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff                getLaunchPendingIntent(context,
694436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                        BUTTON_SYNC));
695681f79900787c2c40751463ddd8f3476f9b40476David Christie        views.setOnClickPendingIntent(R.id.btn_location,
696681f79900787c2c40751463ddd8f3476f9b40476David Christie                getLaunchPendingIntent(context, BUTTON_LOCATION));
69703a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        views.setOnClickPendingIntent(R.id.btn_bluetooth,
69803a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff                getLaunchPendingIntent(context,
699436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                        BUTTON_BLUETOOTH));
70003a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff
70103a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        updateButtons(views, context);
70203a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        return views;
70303a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    }
70403a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff
70503a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    /**
70603a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     * Updates the widget when something changes, or when a button is pushed.
70703a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     *
70803a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     * @param context
70903a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     */
71003a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    public static void updateWidget(Context context) {
711436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        RemoteViews views = buildUpdate(context);
71203a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        // Update specific list of appWidgetIds if given, otherwise default to all
71303a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        final AppWidgetManager gm = AppWidgetManager.getInstance(context);
71403a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        gm.updateAppWidget(THIS_APPWIDGET, views);
715a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani        checkObserver(context);
71603a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    }
71703a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff
71803a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    /**
71903a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     * Updates the buttons based on the underlying states of wifi, etc.
72003a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     *
72103a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     * @param views   The RemoteViews to update.
72203a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     * @param context
72303a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     */
72403a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    private static void updateButtons(RemoteViews views, Context context) {
725ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        sWifiState.setImageViewResources(context, views);
726ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        sBluetoothState.setImageViewResources(context, views);
727681f79900787c2c40751463ddd8f3476f9b40476David Christie        sLocationState.setImageViewResources(context, views);
728ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        sSyncState.setImageViewResources(context, views);
729ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick
7305c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik        if (getBrightnessMode(context)) {
731b9062f26785e53cfc44180e0044c8025ad33af2aalanv            views.setContentDescription(R.id.btn_brightness,
732b9062f26785e53cfc44180e0044c8025ad33af2aalanv                    context.getString(R.string.gadget_brightness_template,
733b9062f26785e53cfc44180e0044c8025ad33af2aalanv                            context.getString(R.string.gadget_brightness_state_auto)));
73494ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            views.setImageViewResource(R.id.img_brightness,
735a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani                    R.drawable.ic_appwidget_settings_brightness_auto_holo);
73694ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            views.setImageViewResource(R.id.ind_brightness,
737a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani                    R.drawable.appwidget_settings_ind_on_r_holo);
73803a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        } else {
739a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani            final int brightness = getBrightness(context);
740dc15a76ed504f15b579302fb064bce89947b084eMichael Wright            final PowerManager pm = context.getSystemService(PowerManager.class);
741a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani            // Set the icon
742748ba16a046a6ac4727f2e39db9a933d81d02465Jeff Brown            final int full = (int)(pm.getMaximumScreenBrightnessSetting()
743748ba16a046a6ac4727f2e39db9a933d81d02465Jeff Brown                    * FULL_BRIGHTNESS_THRESHOLD);
744748ba16a046a6ac4727f2e39db9a933d81d02465Jeff Brown            final int half = (int)(pm.getMaximumScreenBrightnessSetting()
745748ba16a046a6ac4727f2e39db9a933d81d02465Jeff Brown                    * HALF_BRIGHTNESS_THRESHOLD);
746748ba16a046a6ac4727f2e39db9a933d81d02465Jeff Brown            if (brightness > full) {
747b9062f26785e53cfc44180e0044c8025ad33af2aalanv                views.setContentDescription(R.id.btn_brightness,
748b9062f26785e53cfc44180e0044c8025ad33af2aalanv                        context.getString(R.string.gadget_brightness_template,
749b9062f26785e53cfc44180e0044c8025ad33af2aalanv                                context.getString(R.string.gadget_brightness_state_full)));
750a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani                views.setImageViewResource(R.id.img_brightness,
751a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani                        R.drawable.ic_appwidget_settings_brightness_full_holo);
752748ba16a046a6ac4727f2e39db9a933d81d02465Jeff Brown            } else if (brightness > half) {
753b9062f26785e53cfc44180e0044c8025ad33af2aalanv                views.setContentDescription(R.id.btn_brightness,
754b9062f26785e53cfc44180e0044c8025ad33af2aalanv                        context.getString(R.string.gadget_brightness_template,
755b9062f26785e53cfc44180e0044c8025ad33af2aalanv                                context.getString(R.string.gadget_brightness_state_half)));
756a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani                views.setImageViewResource(R.id.img_brightness,
757a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani                        R.drawable.ic_appwidget_settings_brightness_half_holo);
758a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani            } else {
759b9062f26785e53cfc44180e0044c8025ad33af2aalanv                views.setContentDescription(R.id.btn_brightness,
760b9062f26785e53cfc44180e0044c8025ad33af2aalanv                        context.getString(R.string.gadget_brightness_template,
761b9062f26785e53cfc44180e0044c8025ad33af2aalanv                                context.getString(R.string.gadget_brightness_state_off)));
762a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani                views.setImageViewResource(R.id.img_brightness,
763a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani                        R.drawable.ic_appwidget_settings_brightness_off_holo);
764a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani            }
765a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani            // Set the ON state
766748ba16a046a6ac4727f2e39db9a933d81d02465Jeff Brown            if (brightness > half) {
767a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani                views.setImageViewResource(R.id.ind_brightness,
768a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani                        R.drawable.appwidget_settings_ind_on_r_holo);
769a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani            } else {
770a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani                views.setImageViewResource(R.id.ind_brightness,
771a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani                        R.drawable.appwidget_settings_ind_off_r_holo);
772a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani            }
77303a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        }
77403a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    }
77503a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff
77603a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    /**
77703a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     * Creates PendingIntent to notify the widget of a button click.
77803a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     *
77903a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     * @param context
78003a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     * @return
78103a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     */
782436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    private static PendingIntent getLaunchPendingIntent(Context context,
783e936f5b386b39781e8f5e1ab423ebaf790dd9742Ken Shirriff            int buttonId) {
78403a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        Intent launchIntent = new Intent();
78503a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        launchIntent.setClass(context, SettingsAppWidgetProvider.class);
78603a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        launchIntent.addCategory(Intent.CATEGORY_ALTERNATIVE);
78703a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        launchIntent.setData(Uri.parse("custom:" + buttonId));
78803a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        PendingIntent pi = PendingIntent.getBroadcast(context, 0 /* no requestCode */,
78903a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff                launchIntent, 0 /* no flags */);
79003a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        return pi;
79103a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    }
79203a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff
79303a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    /**
79403a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     * Receives and processes a button pressed intent or state change.
79503a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     *
79603a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     * @param context
79703a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     * @param intent  Indicates the pressed button.
79803a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     */
79903a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    @Override
80003a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    public void onReceive(Context context, Intent intent) {
80103a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        super.onReceive(context, intent);
802ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        String action = intent.getAction();
803ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)) {
80494ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            sWifiState.onActualStateChange(context, intent);
805ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        } else if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) {
80694ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            sBluetoothState.onActualStateChange(context, intent);
8074af6514c78f2e468fe0f8f6070cf0f3e658b34a0Tom O'Neill        } else if (LocationManager.MODE_CHANGED_ACTION.equals(action)) {
808681f79900787c2c40751463ddd8f3476f9b40476David Christie            sLocationState.onActualStateChange(context, intent);
8091d6bf8d46b07cb87d5842324190bc5a31eee5e4bJeff Sharkey        } else if (ContentResolver.ACTION_SYNC_CONN_STATUS_CHANGED.equals(action)) {
810ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick            sSyncState.onActualStateChange(context, intent);
81194ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        } else if (intent.hasCategory(Intent.CATEGORY_ALTERNATIVE)) {
81203a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff            Uri data = intent.getData();
81303a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff            int buttonId = Integer.parseInt(data.getSchemeSpecificPart());
81403a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff            if (buttonId == BUTTON_WIFI) {
81594ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                sWifiState.toggleState(context);
81603a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff            } else if (buttonId == BUTTON_BRIGHTNESS) {
81703a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff                toggleBrightness(context);
81803a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff            } else if (buttonId == BUTTON_SYNC) {
819ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                sSyncState.toggleState(context);
820681f79900787c2c40751463ddd8f3476f9b40476David Christie            } else if (buttonId == BUTTON_LOCATION) {
821681f79900787c2c40751463ddd8f3476f9b40476David Christie                sLocationState.toggleState(context);
82203a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff            } else if (buttonId == BUTTON_BLUETOOTH) {
82394ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                sBluetoothState.toggleState(context);
82403a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff            }
825046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick        } else {
826046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick            // Don't fall-through to updating the widget.  The Intent
827046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick            // was something unrelated or that our super class took
828046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick            // care of.
829046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick            return;
83003a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        }
83194ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick
83203a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        // State changes fall through
83303a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        updateWidget(context);
83403a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    }
83503a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff
83603a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    /**
837a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani     * Gets brightness level.
83803a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     *
83903a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     * @param context
840a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani     * @return brightness level between 0 and 255.
84103a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     */
842a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani    private static int getBrightness(Context context) {
84303a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        try {
844748ba16a046a6ac4727f2e39db9a933d81d02465Jeff Brown            int brightness = Settings.System.getInt(context.getContentResolver(),
845748ba16a046a6ac4727f2e39db9a933d81d02465Jeff Brown                    Settings.System.SCREEN_BRIGHTNESS);
846748ba16a046a6ac4727f2e39db9a933d81d02465Jeff Brown            return brightness;
84703a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        } catch (Exception e) {
84803a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        }
849a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani        return 0;
85003a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    }
85103a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff
85203a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    /**
8535c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik     * Gets state of brightness mode.
8545c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik     *
8555c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik     * @param context
8565c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik     * @return true if auto brightness is on.
8575c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik     */
8585c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik    private static boolean getBrightnessMode(Context context) {
8595c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik        try {
860748ba16a046a6ac4727f2e39db9a933d81d02465Jeff Brown            int brightnessMode = Settings.System.getInt(context.getContentResolver(),
861748ba16a046a6ac4727f2e39db9a933d81d02465Jeff Brown                    Settings.System.SCREEN_BRIGHTNESS_MODE);
862748ba16a046a6ac4727f2e39db9a933d81d02465Jeff Brown            return brightnessMode == Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC;
8635c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik        } catch (Exception e) {
8645c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik            Log.d(TAG, "getBrightnessMode: " + e);
8655c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik        }
8665c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik        return false;
8675c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik    }
8685c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik
8695c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik    /**
87003a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     * Increases or decreases the brightness.
87103a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     *
87203a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     * @param context
87303a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     */
87403a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    private void toggleBrightness(Context context) {
87503a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        try {
876dc15a76ed504f15b579302fb064bce89947b084eMichael Wright            DisplayManager dm = context.getSystemService(DisplayManager.class);
877dc15a76ed504f15b579302fb064bce89947b084eMichael Wright            PowerManager pm = context.getSystemService(PowerManager.class);
8785c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik
879dc15a76ed504f15b579302fb064bce89947b084eMichael Wright            ContentResolver cr = context.getContentResolver();
880dc15a76ed504f15b579302fb064bce89947b084eMichael Wright            int brightness = Settings.System.getInt(cr,
881dc15a76ed504f15b579302fb064bce89947b084eMichael Wright                    Settings.System.SCREEN_BRIGHTNESS);
882dc15a76ed504f15b579302fb064bce89947b084eMichael Wright            int brightnessMode = Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL;
883dc15a76ed504f15b579302fb064bce89947b084eMichael Wright            //Only get brightness setting if available
884dc15a76ed504f15b579302fb064bce89947b084eMichael Wright            if (context.getResources().getBoolean(
885dc15a76ed504f15b579302fb064bce89947b084eMichael Wright                    com.android.internal.R.bool.config_automatic_brightness_available)) {
886dc15a76ed504f15b579302fb064bce89947b084eMichael Wright                brightnessMode = Settings.System.getInt(cr,
887dc15a76ed504f15b579302fb064bce89947b084eMichael Wright                        Settings.System.SCREEN_BRIGHTNESS_MODE);
888dc15a76ed504f15b579302fb064bce89947b084eMichael Wright            }
8895c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik
890dc15a76ed504f15b579302fb064bce89947b084eMichael Wright            // Rotate AUTO -> MINIMUM -> DEFAULT -> MAXIMUM
891dc15a76ed504f15b579302fb064bce89947b084eMichael Wright            // Technically, not a toggle...
892dc15a76ed504f15b579302fb064bce89947b084eMichael Wright            if (brightnessMode == Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC) {
893dc15a76ed504f15b579302fb064bce89947b084eMichael Wright                brightness = pm.getMinimumScreenBrightnessSetting();
894dc15a76ed504f15b579302fb064bce89947b084eMichael Wright                brightnessMode = Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL;
895dc15a76ed504f15b579302fb064bce89947b084eMichael Wright            } else if (brightness < pm.getDefaultScreenBrightnessSetting()) {
896dc15a76ed504f15b579302fb064bce89947b084eMichael Wright                brightness = pm.getDefaultScreenBrightnessSetting();
897dc15a76ed504f15b579302fb064bce89947b084eMichael Wright            } else if (brightness < pm.getMaximumScreenBrightnessSetting()) {
898dc15a76ed504f15b579302fb064bce89947b084eMichael Wright                brightness = pm.getMaximumScreenBrightnessSetting();
899dc15a76ed504f15b579302fb064bce89947b084eMichael Wright            } else {
900dc15a76ed504f15b579302fb064bce89947b084eMichael Wright                brightnessMode = Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC;
901dc15a76ed504f15b579302fb064bce89947b084eMichael Wright                brightness = pm.getMinimumScreenBrightnessSetting();
902dc15a76ed504f15b579302fb064bce89947b084eMichael Wright            }
903dc15a76ed504f15b579302fb064bce89947b084eMichael Wright
904dc15a76ed504f15b579302fb064bce89947b084eMichael Wright            if (context.getResources().getBoolean(
905dc15a76ed504f15b579302fb064bce89947b084eMichael Wright                    com.android.internal.R.bool.config_automatic_brightness_available)) {
906dc15a76ed504f15b579302fb064bce89947b084eMichael Wright                // Set screen brightness mode (automatic or manual)
907dc15a76ed504f15b579302fb064bce89947b084eMichael Wright                Settings.System.putInt(context.getContentResolver(),
908dc15a76ed504f15b579302fb064bce89947b084eMichael Wright                        Settings.System.SCREEN_BRIGHTNESS_MODE,
909dc15a76ed504f15b579302fb064bce89947b084eMichael Wright                        brightnessMode);
910dc15a76ed504f15b579302fb064bce89947b084eMichael Wright            } else {
911dc15a76ed504f15b579302fb064bce89947b084eMichael Wright                // Make sure we set the brightness if automatic mode isn't available
912dc15a76ed504f15b579302fb064bce89947b084eMichael Wright                brightnessMode = Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL;
913dc15a76ed504f15b579302fb064bce89947b084eMichael Wright            }
914dc15a76ed504f15b579302fb064bce89947b084eMichael Wright            if (brightnessMode == Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL) {
915dc15a76ed504f15b579302fb064bce89947b084eMichael Wright                dm.setTemporaryBrightness(brightness);
916dc15a76ed504f15b579302fb064bce89947b084eMichael Wright                Settings.System.putInt(cr, Settings.System.SCREEN_BRIGHTNESS, brightness);
91703a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff            }
91803a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        } catch (Settings.SettingNotFoundException e) {
91903a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff            Log.d(TAG, "toggleBrightness: " + e);
92003a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        }
92103a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    }
92249c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani
92349c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani    /** Observer to watch for changes to the BRIGHTNESS setting */
92449c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani    private static class SettingsObserver extends ContentObserver {
92549c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani
92649c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani        private Context mContext;
92749c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani
92849c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani        SettingsObserver(Handler handler, Context context) {
92949c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani            super(handler);
93049c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani            mContext = context;
93149c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani        }
93249c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani
93349c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani        void startObserving() {
93449c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani            ContentResolver resolver = mContext.getContentResolver();
93549c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani            // Listen to brightness and brightness mode
93649c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani            resolver.registerContentObserver(Settings.System
93749c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani                    .getUriFor(Settings.System.SCREEN_BRIGHTNESS), false, this);
93849c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani            resolver.registerContentObserver(Settings.System
93949c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani                    .getUriFor(Settings.System.SCREEN_BRIGHTNESS_MODE), false, this);
940fde3074faa5e87d10b972fde2ea0db10b3a3a9dalongyu.huang            resolver.registerContentObserver(Settings.System
941fde3074faa5e87d10b972fde2ea0db10b3a3a9dalongyu.huang                    .getUriFor(Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ), false, this);
94249c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani        }
94349c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani
94449c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani        void stopObserving() {
94549c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani            mContext.getContentResolver().unregisterContentObserver(this);
94649c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani        }
94749c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani
94849c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani        @Override
94949c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani        public void onChange(boolean selfChange) {
95049c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani            updateWidget(mContext);
95149c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani        }
95249c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani    }
95349c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani
95403a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff}
955