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
1903a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriffimport android.app.PendingIntent;
2003a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriffimport android.appwidget.AppWidgetManager;
2103a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriffimport android.appwidget.AppWidgetProvider;
22d63c0112251ab4e4e977545368dd703d875012a4Nick Pellyimport android.bluetooth.BluetoothAdapter;
2303a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriffimport android.content.ComponentName;
2403a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriffimport android.content.ContentResolver;
2503a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriffimport android.content.Context;
2603a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriffimport android.content.Intent;
2749c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasaniimport android.database.ContentObserver;
2803a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriffimport android.location.LocationManager;
2903a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriffimport android.net.ConnectivityManager;
3003a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriffimport android.net.Uri;
3103a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriffimport android.net.wifi.WifiManager;
32046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrickimport android.os.AsyncTask;
3349c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasaniimport android.os.Handler;
34cd03f5320d42290b1619933954a344b59dc55f4fMike Lockwoodimport android.os.IPowerManager;
35748ba16a046a6ac4727f2e39db9a933d81d02465Jeff Brownimport android.os.PowerManager;
3603a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriffimport android.os.RemoteException;
3703a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriffimport android.os.ServiceManager;
38ea6260d887a7065d65d94be58c05903b3d1fc359Maggie Benthallimport android.os.UserManager;
3903a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriffimport android.provider.Settings;
4003a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriffimport android.util.Log;
4103a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriffimport android.widget.RemoteViews;
421d6bf8d46b07cb87d5842324190bc5a31eee5e4bJeff Sharkey
4303a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriffimport com.android.settings.R;
44f2982a9ba19340b474bafb6b0bf5832673984e0dJason Monkimport com.android.settings.bluetooth.Utils;
45f2982a9ba19340b474bafb6b0bf5832673984e0dJason Monkimport com.android.settingslib.bluetooth.LocalBluetoothAdapter;
46f2982a9ba19340b474bafb6b0bf5832673984e0dJason Monkimport com.android.settingslib.bluetooth.LocalBluetoothManager;
4703a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff
4803a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff/**
4903a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff * Provides control of power-related settings from a widget.
5003a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff */
5103a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriffpublic class SettingsAppWidgetProvider extends AppWidgetProvider {
5203a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    static final String TAG = "SettingsAppWidgetProvider";
5303a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff
5403a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    static final ComponentName THIS_APPWIDGET =
5503a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff            new ComponentName("com.android.settings",
5603a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff                    "com.android.settings.widget.SettingsAppWidgetProvider");
5703a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff
58436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    private static LocalBluetoothAdapter sLocalBluetoothAdapter = null;
5903a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff
6003a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    private static final int BUTTON_WIFI = 0;
6103a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    private static final int BUTTON_BRIGHTNESS = 1;
6203a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    private static final int BUTTON_SYNC = 2;
63681f79900787c2c40751463ddd8f3476f9b40476David Christie    private static final int BUTTON_LOCATION = 3;
6403a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    private static final int BUTTON_BLUETOOTH = 4;
6503a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff
6694ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick    // This widget keeps track of two sets of states:
6794ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick    // "3-state": STATE_DISABLED, STATE_ENABLED, STATE_INTERMEDIATE
6894ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick    // "5-state": STATE_DISABLED, STATE_ENABLED, STATE_TURNING_ON, STATE_TURNING_OFF, STATE_UNKNOWN
6903a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    private static final int STATE_DISABLED = 0;
7003a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    private static final int STATE_ENABLED = 1;
7194ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick    private static final int STATE_TURNING_ON = 2;
7294ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick    private static final int STATE_TURNING_OFF = 3;
7394ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick    private static final int STATE_UNKNOWN = 4;
7494ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick    private static final int STATE_INTERMEDIATE = 5;
7594ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick
76740edeaa42d276bca21ea7e077412badecc0eea3Amith Yamasani    // Position in the widget bar, to enable different graphics for left, center and right buttons
77740edeaa42d276bca21ea7e077412badecc0eea3Amith Yamasani    private static final int POS_LEFT = 0;
78740edeaa42d276bca21ea7e077412badecc0eea3Amith Yamasani    private static final int POS_CENTER = 1;
79740edeaa42d276bca21ea7e077412badecc0eea3Amith Yamasani    private static final int POS_RIGHT = 2;
80740edeaa42d276bca21ea7e077412badecc0eea3Amith Yamasani
81740edeaa42d276bca21ea7e077412badecc0eea3Amith Yamasani    private static final int[] IND_DRAWABLE_OFF = {
82a1252ccf7b31d01a9612fc0479dc7a632cabf8a7Peter Ng        R.drawable.appwidget_settings_ind_off_l_holo,
83a1252ccf7b31d01a9612fc0479dc7a632cabf8a7Peter Ng        R.drawable.appwidget_settings_ind_off_c_holo,
84a1252ccf7b31d01a9612fc0479dc7a632cabf8a7Peter Ng        R.drawable.appwidget_settings_ind_off_r_holo
85740edeaa42d276bca21ea7e077412badecc0eea3Amith Yamasani    };
86740edeaa42d276bca21ea7e077412badecc0eea3Amith Yamasani
87740edeaa42d276bca21ea7e077412badecc0eea3Amith Yamasani    private static final int[] IND_DRAWABLE_MID = {
88a1252ccf7b31d01a9612fc0479dc7a632cabf8a7Peter Ng        R.drawable.appwidget_settings_ind_mid_l_holo,
89a1252ccf7b31d01a9612fc0479dc7a632cabf8a7Peter Ng        R.drawable.appwidget_settings_ind_mid_c_holo,
90a1252ccf7b31d01a9612fc0479dc7a632cabf8a7Peter Ng        R.drawable.appwidget_settings_ind_mid_r_holo
91740edeaa42d276bca21ea7e077412badecc0eea3Amith Yamasani    };
92740edeaa42d276bca21ea7e077412badecc0eea3Amith Yamasani
93740edeaa42d276bca21ea7e077412badecc0eea3Amith Yamasani    private static final int[] IND_DRAWABLE_ON = {
94a1252ccf7b31d01a9612fc0479dc7a632cabf8a7Peter Ng        R.drawable.appwidget_settings_ind_on_l_holo,
95a1252ccf7b31d01a9612fc0479dc7a632cabf8a7Peter Ng        R.drawable.appwidget_settings_ind_on_c_holo,
96a1252ccf7b31d01a9612fc0479dc7a632cabf8a7Peter Ng        R.drawable.appwidget_settings_ind_on_r_holo
97740edeaa42d276bca21ea7e077412badecc0eea3Amith Yamasani    };
9803a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff
99a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani    /** Minimum brightness at which the indicator is shown at half-full and ON */
100748ba16a046a6ac4727f2e39db9a933d81d02465Jeff Brown    private static final float HALF_BRIGHTNESS_THRESHOLD = 0.3f;
101a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani    /** Minimum brightness at which the indicator is shown at full */
102748ba16a046a6ac4727f2e39db9a933d81d02465Jeff Brown    private static final float FULL_BRIGHTNESS_THRESHOLD = 0.8f;
10303a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff
10494ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick    private static final StateTracker sWifiState = new WifiStateTracker();
10594ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick    private static final StateTracker sBluetoothState = new BluetoothStateTracker();
106681f79900787c2c40751463ddd8f3476f9b40476David Christie    private static final StateTracker sLocationState = new LocationStateTracker();
107ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick    private static final StateTracker sSyncState = new SyncStateTracker();
10849c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani    private static SettingsObserver sSettingsObserver;
10994ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick
11094ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick    /**
111ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick     * The state machine for a setting's toggling, tracking reality
112ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick     * versus the user's intent.
11394ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick     *
11494ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick     * This is necessary because reality moves relatively slowly
11594ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick     * (turning on & off radio drivers), compared to user's
11694ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick     * expectations.
11794ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick     */
11894ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick    private abstract static class StateTracker {
11994ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        // Is the state in the process of changing?
12094ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        private boolean mInTransition = false;
12194ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        private Boolean mActualState = null;  // initially not set
12294ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        private Boolean mIntendedState = null;  // initially not set
12394ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick
12494ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        // Did a toggle request arrive while a state update was
12594ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        // already in-flight?  If so, the mIntendedState needs to be
12694ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        // requested when the other one is done, unless we happened to
12794ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        // arrive at that state already.
12894ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        private boolean mDeferredStateChangeRequestNeeded = false;
12994ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick
13094ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        /**
13194ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         * User pressed a button to change the state.  Something
13294ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         * should immediately appear to the user afterwards, even if
13394ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         * we effectively do nothing.  Their press must be heard.
13494ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         */
13594ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        public final void toggleState(Context context) {
13694ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            int currentState = getTriState(context);
13794ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            boolean newState = false;
13894ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            switch (currentState) {
13994ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                case STATE_ENABLED:
14094ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    newState = false;
14194ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    break;
14294ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                case STATE_DISABLED:
14394ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    newState = true;
14494ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    break;
14594ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                case STATE_INTERMEDIATE:
14694ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    if (mIntendedState != null) {
14794ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                        newState = !mIntendedState;
14894ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    }
14994ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    break;
15094ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            }
15194ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            mIntendedState = newState;
15294ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            if (mInTransition) {
15394ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                // We don't send off a transition request if we're
15494ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                // already transitioning.  Makes our state tracking
15594ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                // easier, and is probably nicer on lower levels.
15694ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                // (even though they should be able to take it...)
15794ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                mDeferredStateChangeRequestNeeded = true;
15894ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            } else {
15994ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                mInTransition = true;
160046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick                requestStateChange(context, newState);
16194ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            }
16294ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        }
16394ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick
16494ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        /**
165b9062f26785e53cfc44180e0044c8025ad33af2aalanv         * Return the ID of the clickable container for the setting.
166b9062f26785e53cfc44180e0044c8025ad33af2aalanv         */
167b9062f26785e53cfc44180e0044c8025ad33af2aalanv        public abstract int getContainerId();
168b9062f26785e53cfc44180e0044c8025ad33af2aalanv
169b9062f26785e53cfc44180e0044c8025ad33af2aalanv        /**
170ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick         * Return the ID of the main large image button for the setting.
171ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick         */
172ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        public abstract int getButtonId();
173ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick
174ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        /**
175ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick         * Returns the small indicator image ID underneath the setting.
176ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick         */
177ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        public abstract int getIndicatorId();
178ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick
179ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        /**
180b9062f26785e53cfc44180e0044c8025ad33af2aalanv         * Returns the resource ID of the setting's content description.
181b9062f26785e53cfc44180e0044c8025ad33af2aalanv         */
182b9062f26785e53cfc44180e0044c8025ad33af2aalanv        public abstract int getButtonDescription();
183b9062f26785e53cfc44180e0044c8025ad33af2aalanv
184b9062f26785e53cfc44180e0044c8025ad33af2aalanv        /**
185ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick         * Returns the resource ID of the image to show as a function of
186ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick         * the on-vs-off state.
187ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick         */
188ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        public abstract int getButtonImageId(boolean on);
189ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick
190ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        /**
191740edeaa42d276bca21ea7e077412badecc0eea3Amith Yamasani         * Returns the position in the button bar - either POS_LEFT, POS_RIGHT or POS_CENTER.
192740edeaa42d276bca21ea7e077412badecc0eea3Amith Yamasani         */
193740edeaa42d276bca21ea7e077412badecc0eea3Amith Yamasani        public int getPosition() { return POS_CENTER; }
194740edeaa42d276bca21ea7e077412badecc0eea3Amith Yamasani
195740edeaa42d276bca21ea7e077412badecc0eea3Amith Yamasani        /**
196ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick         * Updates the remote views depending on the state (off, on,
197ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick         * turning off, turning on) of the setting.
198ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick         */
199ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        public final void setImageViewResources(Context context, RemoteViews views) {
200b9062f26785e53cfc44180e0044c8025ad33af2aalanv            int containerId = getContainerId();
201ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick            int buttonId = getButtonId();
202ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick            int indicatorId = getIndicatorId();
203740edeaa42d276bca21ea7e077412badecc0eea3Amith Yamasani            int pos = getPosition();
204ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick            switch (getTriState(context)) {
205ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                case STATE_DISABLED:
206b9062f26785e53cfc44180e0044c8025ad33af2aalanv                    views.setContentDescription(containerId,
207b9062f26785e53cfc44180e0044c8025ad33af2aalanv                        getContentDescription(context, R.string.gadget_state_off));
208ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    views.setImageViewResource(buttonId, getButtonImageId(false));
209ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    views.setImageViewResource(
210740edeaa42d276bca21ea7e077412badecc0eea3Amith Yamasani                        indicatorId, IND_DRAWABLE_OFF[pos]);
211ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    break;
212ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                case STATE_ENABLED:
213b9062f26785e53cfc44180e0044c8025ad33af2aalanv                    views.setContentDescription(containerId,
214b9062f26785e53cfc44180e0044c8025ad33af2aalanv                        getContentDescription(context, R.string.gadget_state_on));
215ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    views.setImageViewResource(buttonId, getButtonImageId(true));
216ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    views.setImageViewResource(
217740edeaa42d276bca21ea7e077412badecc0eea3Amith Yamasani                        indicatorId, IND_DRAWABLE_ON[pos]);
218ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    break;
219ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                case STATE_INTERMEDIATE:
220ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    // In the transitional state, the bottom green bar
221ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    // shows the tri-state (on, off, transitioning), but
222ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    // the top dark-gray-or-bright-white logo shows the
223ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    // user's intent.  This is much easier to see in
224ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    // sunlight.
225ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    if (isTurningOn()) {
226b9062f26785e53cfc44180e0044c8025ad33af2aalanv                        views.setContentDescription(containerId,
227b9062f26785e53cfc44180e0044c8025ad33af2aalanv                            getContentDescription(context, R.string.gadget_state_turning_on));
228ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                        views.setImageViewResource(buttonId, getButtonImageId(true));
229ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                        views.setImageViewResource(
230740edeaa42d276bca21ea7e077412badecc0eea3Amith Yamasani                            indicatorId, IND_DRAWABLE_MID[pos]);
231ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    } else {
232b9062f26785e53cfc44180e0044c8025ad33af2aalanv                        views.setContentDescription(containerId,
233b9062f26785e53cfc44180e0044c8025ad33af2aalanv                            getContentDescription(context, R.string.gadget_state_turning_off));
234ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                        views.setImageViewResource(buttonId, getButtonImageId(false));
235ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                        views.setImageViewResource(
236740edeaa42d276bca21ea7e077412badecc0eea3Amith Yamasani                            indicatorId, IND_DRAWABLE_OFF[pos]);
237ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    }
238ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    break;
239ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick            }
240ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        }
241ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick
242ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        /**
243b9062f26785e53cfc44180e0044c8025ad33af2aalanv         * Returns the gadget state template populated with the gadget
244b9062f26785e53cfc44180e0044c8025ad33af2aalanv         * description and state.
245b9062f26785e53cfc44180e0044c8025ad33af2aalanv         */
246b9062f26785e53cfc44180e0044c8025ad33af2aalanv        private final String getContentDescription(Context context, int stateResId) {
247b9062f26785e53cfc44180e0044c8025ad33af2aalanv            final String gadget = context.getString(getButtonDescription());
248b9062f26785e53cfc44180e0044c8025ad33af2aalanv            final String state = context.getString(stateResId);
249b9062f26785e53cfc44180e0044c8025ad33af2aalanv            return context.getString(R.string.gadget_state_template, gadget, state);
250b9062f26785e53cfc44180e0044c8025ad33af2aalanv        }
251b9062f26785e53cfc44180e0044c8025ad33af2aalanv
252b9062f26785e53cfc44180e0044c8025ad33af2aalanv        /**
25394ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         * Update internal state from a broadcast state change.
25494ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         */
25594ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        public abstract void onActualStateChange(Context context, Intent intent);
25694ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick
25794ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        /**
25894ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         * Sets the value that we're now in.  To be called from onActualStateChange.
25994ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         *
26094ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         * @param newState one of STATE_DISABLED, STATE_ENABLED, STATE_TURNING_ON,
26194ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         *                 STATE_TURNING_OFF, STATE_UNKNOWN
26294ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         */
26394ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        protected final void setCurrentState(Context context, int newState) {
264046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick            final boolean wasInTransition = mInTransition;
26594ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            switch (newState) {
26694ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                case STATE_DISABLED:
26794ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    mInTransition = false;
26894ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    mActualState = false;
26994ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    break;
27094ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                case STATE_ENABLED:
27194ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    mInTransition = false;
27294ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    mActualState = true;
27394ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    break;
27494ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                case STATE_TURNING_ON:
27594ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    mInTransition = true;
27694ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    mActualState = false;
27794ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    break;
27894ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                case STATE_TURNING_OFF:
27994ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    mInTransition = true;
28094ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    mActualState = true;
28194ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    break;
28294ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            }
28394ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick
28494ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            if (wasInTransition && !mInTransition) {
28594ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                if (mDeferredStateChangeRequestNeeded) {
28694ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    Log.v(TAG, "processing deferred state change");
28794ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    if (mActualState != null && mIntendedState != null &&
28894ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                        mIntendedState.equals(mActualState)) {
28994ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                        Log.v(TAG, "... but intended state matches, so no changes.");
29094ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    } else if (mIntendedState != null) {
29194ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                        mInTransition = true;
292046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick                        requestStateChange(context, mIntendedState);
29394ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    }
29494ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    mDeferredStateChangeRequestNeeded = false;
29594ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                }
29694ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            }
29794ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        }
29894ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick
29994ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick
30094ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        /**
30194ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         * If we're in a transition mode, this returns true if we're
30294ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         * transitioning towards being enabled.
30394ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         */
30494ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        public final boolean isTurningOn() {
30594ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            return mIntendedState != null && mIntendedState;
30694ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        }
30794ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick
30894ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        /**
30994ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         * Returns simplified 3-state value from underlying 5-state.
31094ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         *
31194ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         * @param context
31294ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         * @return STATE_ENABLED, STATE_DISABLED, or STATE_INTERMEDIATE
31394ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         */
31494ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        public final int getTriState(Context context) {
315046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick            if (mInTransition) {
316046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick                // If we know we just got a toggle request recently
317046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick                // (which set mInTransition), don't even ask the
318046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick                // underlying interface for its state.  We know we're
319046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick                // changing.  This avoids blocking the UI thread
320046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick                // during UI refresh post-toggle if the underlying
321046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick                // service state accessor has coarse locking on its
322046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick                // state (to be fixed separately).
323046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick                return STATE_INTERMEDIATE;
324046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick            }
32594ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            switch (getActualState(context)) {
32694ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                case STATE_DISABLED:
32794ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    return STATE_DISABLED;
32894ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                case STATE_ENABLED:
32994ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    return STATE_ENABLED;
33094ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                default:
33194ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    return STATE_INTERMEDIATE;
33294ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            }
33394ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        }
33494ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick
33594ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        /**
33694ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         * Gets underlying actual state.
33794ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         *
33894ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         * @param context
33994ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         * @return STATE_ENABLED, STATE_DISABLED, STATE_ENABLING, STATE_DISABLING,
34094ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         *         or or STATE_UNKNOWN.
34194ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         */
34294ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        public abstract int getActualState(Context context);
34394ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick
34494ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        /**
34594ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         * Actually make the desired change to the underlying radio
34694ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         * API.
34794ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         */
348046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick        protected abstract void requestStateChange(Context context, boolean desiredState);
34994ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick    }
35094ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick
35194ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick    /**
35294ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick     * Subclass of StateTracker to get/set Wifi state.
35394ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick     */
35494ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick    private static final class WifiStateTracker extends StateTracker {
355b9062f26785e53cfc44180e0044c8025ad33af2aalanv        public int getContainerId() { return R.id.btn_wifi; }
356ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        public int getButtonId() { return R.id.img_wifi; }
357ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        public int getIndicatorId() { return R.id.ind_wifi; }
358b9062f26785e53cfc44180e0044c8025ad33af2aalanv        public int getButtonDescription() { return R.string.gadget_wifi; }
359ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        public int getButtonImageId(boolean on) {
360a1252ccf7b31d01a9612fc0479dc7a632cabf8a7Peter Ng            return on ? R.drawable.ic_appwidget_settings_wifi_on_holo
361a1252ccf7b31d01a9612fc0479dc7a632cabf8a7Peter Ng                    : R.drawable.ic_appwidget_settings_wifi_off_holo;
362ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        }
363ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick
36494ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        @Override
365740edeaa42d276bca21ea7e077412badecc0eea3Amith Yamasani        public int getPosition() { return POS_LEFT; }
366740edeaa42d276bca21ea7e077412badecc0eea3Amith Yamasani
367740edeaa42d276bca21ea7e077412badecc0eea3Amith Yamasani        @Override
36894ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        public int getActualState(Context context) {
36994ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
37094ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            if (wifiManager != null) {
37194ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                return wifiStateToFiveState(wifiManager.getWifiState());
37294ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            }
37394ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            return STATE_UNKNOWN;
37494ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        }
37594ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick
37694ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        @Override
377046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick        protected void requestStateChange(Context context, final boolean desiredState) {
378ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick            final WifiManager wifiManager =
379ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
38094ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            if (wifiManager == null) {
38194ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                Log.d(TAG, "No wifiManager.");
38294ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                return;
38394ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            }
384a6a74e222a994e29a1daa7178943a1fc9dd06c47Irfan Sheriff
385046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick            // Actually request the wifi change and persistent
386046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick            // settings write off the UI thread, as it can take a
387046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick            // user-noticeable amount of time, especially if there's
388046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick            // disk contention.
389046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick            new AsyncTask<Void, Void, Void>() {
390046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick                @Override
391046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick                protected Void doInBackground(Void... args) {
392046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick                    /**
393046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick                     * Disable tethering if enabling Wifi
394046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick                     */
395046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick                    int wifiApState = wifiManager.getWifiApState();
396046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick                    if (desiredState && ((wifiApState == WifiManager.WIFI_AP_STATE_ENABLING) ||
397046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick                                         (wifiApState == WifiManager.WIFI_AP_STATE_ENABLED))) {
398deca11c87dbe4d49b43961f6b755f4484936e2caRebecca Silberstein                        final ConnectivityManager connectivityManager =
399deca11c87dbe4d49b43961f6b755f4484936e2caRebecca Silberstein                                (ConnectivityManager) context.getSystemService(
400deca11c87dbe4d49b43961f6b755f4484936e2caRebecca Silberstein                                        Context.CONNECTIVITY_SERVICE);
401deca11c87dbe4d49b43961f6b755f4484936e2caRebecca Silberstein                        connectivityManager.stopTethering(ConnectivityManager.TETHERING_WIFI);
402046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick                    }
403046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick
404046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick                    wifiManager.setWifiEnabled(desiredState);
405046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick                    return null;
406046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick                }
407046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick            }.execute();
40894ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        }
40994ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick
41094ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        @Override
41194ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        public void onActualStateChange(Context context, Intent intent) {
41294ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            if (!WifiManager.WIFI_STATE_CHANGED_ACTION.equals(intent.getAction())) {
41394ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                return;
41494ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            }
41594ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            int wifiState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, -1);
41694ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            setCurrentState(context, wifiStateToFiveState(wifiState));
41794ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        }
41894ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick
41994ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        /**
42094ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         * Converts WifiManager's state values into our
42194ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         * Wifi/Bluetooth-common state values.
42294ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         */
42394ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        private static int wifiStateToFiveState(int wifiState) {
42494ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            switch (wifiState) {
42594ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                case WifiManager.WIFI_STATE_DISABLED:
42694ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    return STATE_DISABLED;
42794ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                case WifiManager.WIFI_STATE_ENABLED:
42894ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    return STATE_ENABLED;
42994ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                case WifiManager.WIFI_STATE_DISABLING:
43094ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    return STATE_TURNING_OFF;
43194ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                case WifiManager.WIFI_STATE_ENABLING:
43294ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    return STATE_TURNING_ON;
43394ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                default:
43494ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    return STATE_UNKNOWN;
43594ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            }
43694ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        }
43794ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick    }
43894ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick
43994ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick    /**
44094ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick     * Subclass of StateTracker to get/set Bluetooth state.
44194ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick     */
44294ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick    private static final class BluetoothStateTracker extends StateTracker {
443b9062f26785e53cfc44180e0044c8025ad33af2aalanv        public int getContainerId() { return R.id.btn_bluetooth; }
444ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        public int getButtonId() { return R.id.img_bluetooth; }
445ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        public int getIndicatorId() { return R.id.ind_bluetooth; }
446b9062f26785e53cfc44180e0044c8025ad33af2aalanv        public int getButtonDescription() { return R.string.gadget_bluetooth; }
447ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        public int getButtonImageId(boolean on) {
448a1252ccf7b31d01a9612fc0479dc7a632cabf8a7Peter Ng            return on ? R.drawable.ic_appwidget_settings_bluetooth_on_holo
449a1252ccf7b31d01a9612fc0479dc7a632cabf8a7Peter Ng                    : R.drawable.ic_appwidget_settings_bluetooth_off_holo;
450ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        }
45194ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick
45294ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        @Override
45394ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        public int getActualState(Context context) {
454436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            if (sLocalBluetoothAdapter == null) {
455f2982a9ba19340b474bafb6b0bf5832673984e0dJason Monk                LocalBluetoothManager manager = Utils.getLocalBtManager(context);
456436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                if (manager == null) {
45794ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    return STATE_UNKNOWN;  // On emulator?
45894ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                }
459436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                sLocalBluetoothAdapter = manager.getBluetoothAdapter();
4608d763c03028419884ced41c7b630ce9a5c45437dPrathmesh Prabhu                if (sLocalBluetoothAdapter == null) {
4618d763c03028419884ced41c7b630ce9a5c45437dPrathmesh Prabhu                    return STATE_UNKNOWN;  // On emulator?
4628d763c03028419884ced41c7b630ce9a5c45437dPrathmesh Prabhu                }
46394ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            }
464436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            return bluetoothStateToFiveState(sLocalBluetoothAdapter.getBluetoothState());
46594ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        }
46694ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick
46794ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        @Override
468046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick        protected void requestStateChange(Context context, final boolean desiredState) {
469436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            if (sLocalBluetoothAdapter == null) {
47094ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                Log.d(TAG, "No LocalBluetoothManager");
47194ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                return;
47294ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            }
473046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick            // Actually request the Bluetooth change and persistent
474046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick            // settings write off the UI thread, as it can take a
475046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick            // user-noticeable amount of time, especially if there's
476046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick            // disk contention.
477046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick            new AsyncTask<Void, Void, Void>() {
478046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick                @Override
479046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick                protected Void doInBackground(Void... args) {
480436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                    sLocalBluetoothAdapter.setBluetoothEnabled(desiredState);
481046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick                    return null;
482046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick                }
483046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick            }.execute();
48494ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        }
48594ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick
48694ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        @Override
48794ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        public void onActualStateChange(Context context, Intent intent) {
48894ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            if (!BluetoothAdapter.ACTION_STATE_CHANGED.equals(intent.getAction())) {
48994ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                return;
49094ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            }
49194ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            int bluetoothState = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1);
49294ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            setCurrentState(context, bluetoothStateToFiveState(bluetoothState));
49394ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        }
49494ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick
49594ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        /**
49694ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         * Converts BluetoothAdapter's state values into our
49794ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         * Wifi/Bluetooth-common state values.
49894ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         */
49994ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        private static int bluetoothStateToFiveState(int bluetoothState) {
50094ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            switch (bluetoothState) {
50194ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                case BluetoothAdapter.STATE_OFF:
50294ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    return STATE_DISABLED;
50394ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                case BluetoothAdapter.STATE_ON:
50494ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    return STATE_ENABLED;
50594ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                case BluetoothAdapter.STATE_TURNING_ON:
50694ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    return STATE_TURNING_ON;
50794ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                case BluetoothAdapter.STATE_TURNING_OFF:
50894ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    return STATE_TURNING_OFF;
50994ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                default:
51094ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    return STATE_UNKNOWN;
51194ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            }
51294ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        }
51394ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick    }
51494ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick
515ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick    /**
516681f79900787c2c40751463ddd8f3476f9b40476David Christie     * Subclass of StateTracker for location state.
517ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick     */
518681f79900787c2c40751463ddd8f3476f9b40476David Christie    private static final class LocationStateTracker extends StateTracker {
519587e6bf3fcfc8dffb4cf021227d896ffcb5488a9David Christie        private int mCurrentLocationMode = Settings.Secure.LOCATION_MODE_OFF;
520587e6bf3fcfc8dffb4cf021227d896ffcb5488a9David Christie
521681f79900787c2c40751463ddd8f3476f9b40476David Christie        public int getContainerId() { return R.id.btn_location; }
522681f79900787c2c40751463ddd8f3476f9b40476David Christie        public int getButtonId() { return R.id.img_location; }
523681f79900787c2c40751463ddd8f3476f9b40476David Christie        public int getIndicatorId() { return R.id.ind_location; }
524681f79900787c2c40751463ddd8f3476f9b40476David Christie        public int getButtonDescription() { return R.string.gadget_location; }
525ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        public int getButtonImageId(boolean on) {
526587e6bf3fcfc8dffb4cf021227d896ffcb5488a9David Christie            if (on) {
527587e6bf3fcfc8dffb4cf021227d896ffcb5488a9David Christie                switch (mCurrentLocationMode) {
528587e6bf3fcfc8dffb4cf021227d896ffcb5488a9David Christie                    case Settings.Secure.LOCATION_MODE_HIGH_ACCURACY:
529587e6bf3fcfc8dffb4cf021227d896ffcb5488a9David Christie                    case Settings.Secure.LOCATION_MODE_SENSORS_ONLY:
530587e6bf3fcfc8dffb4cf021227d896ffcb5488a9David Christie                        return R.drawable.ic_appwidget_settings_location_on_holo;
531587e6bf3fcfc8dffb4cf021227d896ffcb5488a9David Christie                    default:
532587e6bf3fcfc8dffb4cf021227d896ffcb5488a9David Christie                        return R.drawable.ic_appwidget_settings_location_saving_holo;
533587e6bf3fcfc8dffb4cf021227d896ffcb5488a9David Christie                }
534587e6bf3fcfc8dffb4cf021227d896ffcb5488a9David Christie            }
535587e6bf3fcfc8dffb4cf021227d896ffcb5488a9David Christie
536587e6bf3fcfc8dffb4cf021227d896ffcb5488a9David Christie            return R.drawable.ic_appwidget_settings_location_off_holo;
537ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        }
538ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick
539ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        @Override
540ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        public int getActualState(Context context) {
541ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick            ContentResolver resolver = context.getContentResolver();
542587e6bf3fcfc8dffb4cf021227d896ffcb5488a9David Christie            mCurrentLocationMode = Settings.Secure.getInt(resolver,
54393259c14f3aca4739e2cf7691cb0416ded509d8dTom O'Neill                    Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF);
544587e6bf3fcfc8dffb4cf021227d896ffcb5488a9David Christie            return (mCurrentLocationMode == Settings.Secure.LOCATION_MODE_OFF)
545587e6bf3fcfc8dffb4cf021227d896ffcb5488a9David Christie                    ? STATE_DISABLED : STATE_ENABLED;
546ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        }
547ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick
548ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        @Override
549ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        public void onActualStateChange(Context context, Intent unused) {
550ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick            // Note: the broadcast location providers changed intent
551ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick            // doesn't include an extras bundles saying what the new value is.
552ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick            setCurrentState(context, getActualState(context));
553ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        }
554ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick
555ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        @Override
556ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        public void requestStateChange(final Context context, final boolean desiredState) {
557ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick            final ContentResolver resolver = context.getContentResolver();
558ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick            new AsyncTask<Void, Void, Boolean>() {
559ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                @Override
560ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                protected Boolean doInBackground(Void... args) {
561ea6260d887a7065d65d94be58c05903b3d1fc359Maggie Benthall                    final UserManager um =
562ea6260d887a7065d65d94be58c05903b3d1fc359Maggie Benthall                            (UserManager) context.getSystemService(Context.USER_SERVICE);
5630c5a401a58b30041d5fe712d78fccbd47f5b744dMaggie Benthall                    if (!um.hasUserRestriction(UserManager.DISALLOW_SHARE_LOCATION)) {
5643d0bee59b875c7a47045408a46a599ae290659efLifu Tang                        int currentMode = Settings.Secure.getInt(resolver,
5653d0bee59b875c7a47045408a46a599ae290659efLifu Tang                                Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF);
5663d0bee59b875c7a47045408a46a599ae290659efLifu Tang                        int mode = Settings.Secure.LOCATION_MODE_HIGH_ACCURACY;
5673d0bee59b875c7a47045408a46a599ae290659efLifu Tang                        switch (currentMode) {
5683d0bee59b875c7a47045408a46a599ae290659efLifu Tang                            case Settings.Secure.LOCATION_MODE_HIGH_ACCURACY:
5693d0bee59b875c7a47045408a46a599ae290659efLifu Tang                                mode = Settings.Secure.LOCATION_MODE_BATTERY_SAVING;
5703d0bee59b875c7a47045408a46a599ae290659efLifu Tang                                break;
5713d0bee59b875c7a47045408a46a599ae290659efLifu Tang                            case Settings.Secure.LOCATION_MODE_BATTERY_SAVING:
5723d0bee59b875c7a47045408a46a599ae290659efLifu Tang                                mode = Settings.Secure.LOCATION_MODE_HIGH_ACCURACY;
5733d0bee59b875c7a47045408a46a599ae290659efLifu Tang                                break;
5743d0bee59b875c7a47045408a46a599ae290659efLifu Tang                            case Settings.Secure.LOCATION_MODE_SENSORS_ONLY:
5753d0bee59b875c7a47045408a46a599ae290659efLifu Tang                                mode = Settings.Secure.LOCATION_MODE_OFF;
5763d0bee59b875c7a47045408a46a599ae290659efLifu Tang                                break;
5773d0bee59b875c7a47045408a46a599ae290659efLifu Tang                            case Settings.Secure.LOCATION_MODE_OFF:
578ee0db4c35bd4284102e6a59a4426c85b463b7841Lifu Tang                                mode = Settings.Secure.LOCATION_MODE_PREVIOUS;
5793d0bee59b875c7a47045408a46a599ae290659efLifu Tang                                break;
5803d0bee59b875c7a47045408a46a599ae290659efLifu Tang                        }
58193259c14f3aca4739e2cf7691cb0416ded509d8dTom O'Neill                        Settings.Secure.putInt(resolver, Settings.Secure.LOCATION_MODE, mode);
582587e6bf3fcfc8dffb4cf021227d896ffcb5488a9David Christie                        return mode != Settings.Secure.LOCATION_MODE_OFF;
583ea6260d887a7065d65d94be58c05903b3d1fc359Maggie Benthall                    }
584681f79900787c2c40751463ddd8f3476f9b40476David Christie
5855eed792a76970e4271e03547e61dbbd6fabbf2f4David Christie                    return getActualState(context) == STATE_ENABLED;
586ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                }
587ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick
588ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                @Override
589ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                protected void onPostExecute(Boolean result) {
590ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    setCurrentState(
591ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                        context,
592ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                        result ? STATE_ENABLED : STATE_DISABLED);
593ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    updateWidget(context);
594ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                }
595ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick            }.execute();
596ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        }
597ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick    }
598ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick
599ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick    /**
600ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick     * Subclass of StateTracker for sync state.
601ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick     */
602ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick    private static final class SyncStateTracker extends StateTracker {
603b9062f26785e53cfc44180e0044c8025ad33af2aalanv        public int getContainerId() { return R.id.btn_sync; }
604ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        public int getButtonId() { return R.id.img_sync; }
605ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        public int getIndicatorId() { return R.id.ind_sync; }
606b9062f26785e53cfc44180e0044c8025ad33af2aalanv        public int getButtonDescription() { return R.string.gadget_sync; }
607ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        public int getButtonImageId(boolean on) {
608a1252ccf7b31d01a9612fc0479dc7a632cabf8a7Peter Ng            return on ? R.drawable.ic_appwidget_settings_sync_on_holo
609a1252ccf7b31d01a9612fc0479dc7a632cabf8a7Peter Ng                    : R.drawable.ic_appwidget_settings_sync_off_holo;
610ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        }
611ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick
612ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        @Override
613ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        public int getActualState(Context context) {
61449c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani            boolean on = ContentResolver.getMasterSyncAutomatically();
615ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick            return on ? STATE_ENABLED : STATE_DISABLED;
616ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        }
617ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick
618ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        @Override
619ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        public void onActualStateChange(Context context, Intent unused) {
620ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick            setCurrentState(context, getActualState(context));
621ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        }
622ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick
623ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        @Override
624ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        public void requestStateChange(final Context context, final boolean desiredState) {
625ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick            final ConnectivityManager connManager =
626ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
627ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick            final boolean sync = ContentResolver.getMasterSyncAutomatically();
628ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick
629ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick            new AsyncTask<Void, Void, Boolean>() {
630ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                @Override
631ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                protected Boolean doInBackground(Void... args) {
632ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    // Turning sync on.
633ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    if (desiredState) {
634ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                        if (!sync) {
635ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                            ContentResolver.setMasterSyncAutomatically(true);
636ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                        }
637ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                        return true;
638ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    }
639ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick
640ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    // Turning sync off
641ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    if (sync) {
642ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                        ContentResolver.setMasterSyncAutomatically(false);
643ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    }
644ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    return false;
645ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                }
646ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick
647ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                @Override
648ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                protected void onPostExecute(Boolean result) {
649ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    setCurrentState(
650ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                        context,
651ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                        result ? STATE_ENABLED : STATE_DISABLED);
652ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    updateWidget(context);
653ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                }
654ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick            }.execute();
655ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        }
656ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick    }
65794ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick
658a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani    private static void checkObserver(Context context) {
659a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani        if (sSettingsObserver == null) {
660a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani            sSettingsObserver = new SettingsObserver(new Handler(),
661a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani                    context.getApplicationContext());
662a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani            sSettingsObserver.startObserving();
663a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani        }
664a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani    }
665a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani
66603a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    @Override
66703a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    public void onUpdate(Context context, AppWidgetManager appWidgetManager,
66803a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff            int[] appWidgetIds) {
66903a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        // Update each requested appWidgetId
670436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        RemoteViews view = buildUpdate(context);
67103a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff
67203a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        for (int i = 0; i < appWidgetIds.length; i++) {
67303a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff            appWidgetManager.updateAppWidget(appWidgetIds[i], view);
67403a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        }
67503a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    }
67603a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff
67703a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    @Override
67803a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    public void onEnabled(Context context) {
679a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani        checkObserver(context);
68003a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    }
68103a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff
68203a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    @Override
68303a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    public void onDisabled(Context context) {
68449c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani        if (sSettingsObserver != null) {
68549c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani            sSettingsObserver.stopObserving();
68649c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani            sSettingsObserver = null;
68749c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani        }
68803a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    }
68903a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff
69003a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    /**
69103a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     * Load image for given widget and build {@link RemoteViews} for it.
69203a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     */
693436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    static RemoteViews buildUpdate(Context context) {
69403a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        RemoteViews views = new RemoteViews(context.getPackageName(),
69503a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff                R.layout.widget);
696436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        views.setOnClickPendingIntent(R.id.btn_wifi, getLaunchPendingIntent(context,
69703a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff                BUTTON_WIFI));
69803a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        views.setOnClickPendingIntent(R.id.btn_brightness,
69903a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff                getLaunchPendingIntent(context,
700436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                        BUTTON_BRIGHTNESS));
70103a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        views.setOnClickPendingIntent(R.id.btn_sync,
70203a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff                getLaunchPendingIntent(context,
703436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                        BUTTON_SYNC));
704681f79900787c2c40751463ddd8f3476f9b40476David Christie        views.setOnClickPendingIntent(R.id.btn_location,
705681f79900787c2c40751463ddd8f3476f9b40476David Christie                getLaunchPendingIntent(context, BUTTON_LOCATION));
70603a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        views.setOnClickPendingIntent(R.id.btn_bluetooth,
70703a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff                getLaunchPendingIntent(context,
708436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                        BUTTON_BLUETOOTH));
70903a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff
71003a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        updateButtons(views, context);
71103a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        return views;
71203a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    }
71303a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff
71403a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    /**
71503a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     * Updates the widget when something changes, or when a button is pushed.
71603a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     *
71703a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     * @param context
71803a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     */
71903a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    public static void updateWidget(Context context) {
720436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        RemoteViews views = buildUpdate(context);
72103a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        // Update specific list of appWidgetIds if given, otherwise default to all
72203a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        final AppWidgetManager gm = AppWidgetManager.getInstance(context);
72303a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        gm.updateAppWidget(THIS_APPWIDGET, views);
724a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani        checkObserver(context);
72503a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    }
72603a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff
72703a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    /**
72803a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     * Updates the buttons based on the underlying states of wifi, etc.
72903a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     *
73003a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     * @param views   The RemoteViews to update.
73103a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     * @param context
73203a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     */
73303a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    private static void updateButtons(RemoteViews views, Context context) {
734ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        sWifiState.setImageViewResources(context, views);
735ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        sBluetoothState.setImageViewResources(context, views);
736681f79900787c2c40751463ddd8f3476f9b40476David Christie        sLocationState.setImageViewResources(context, views);
737ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        sSyncState.setImageViewResources(context, views);
738ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick
7395c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik        if (getBrightnessMode(context)) {
740b9062f26785e53cfc44180e0044c8025ad33af2aalanv            views.setContentDescription(R.id.btn_brightness,
741b9062f26785e53cfc44180e0044c8025ad33af2aalanv                    context.getString(R.string.gadget_brightness_template,
742b9062f26785e53cfc44180e0044c8025ad33af2aalanv                            context.getString(R.string.gadget_brightness_state_auto)));
74394ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            views.setImageViewResource(R.id.img_brightness,
744a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani                    R.drawable.ic_appwidget_settings_brightness_auto_holo);
74594ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            views.setImageViewResource(R.id.ind_brightness,
746a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani                    R.drawable.appwidget_settings_ind_on_r_holo);
74703a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        } else {
748a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani            final int brightness = getBrightness(context);
749748ba16a046a6ac4727f2e39db9a933d81d02465Jeff Brown            final PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
750a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani            // Set the icon
751748ba16a046a6ac4727f2e39db9a933d81d02465Jeff Brown            final int full = (int)(pm.getMaximumScreenBrightnessSetting()
752748ba16a046a6ac4727f2e39db9a933d81d02465Jeff Brown                    * FULL_BRIGHTNESS_THRESHOLD);
753748ba16a046a6ac4727f2e39db9a933d81d02465Jeff Brown            final int half = (int)(pm.getMaximumScreenBrightnessSetting()
754748ba16a046a6ac4727f2e39db9a933d81d02465Jeff Brown                    * HALF_BRIGHTNESS_THRESHOLD);
755748ba16a046a6ac4727f2e39db9a933d81d02465Jeff Brown            if (brightness > full) {
756b9062f26785e53cfc44180e0044c8025ad33af2aalanv                views.setContentDescription(R.id.btn_brightness,
757b9062f26785e53cfc44180e0044c8025ad33af2aalanv                        context.getString(R.string.gadget_brightness_template,
758b9062f26785e53cfc44180e0044c8025ad33af2aalanv                                context.getString(R.string.gadget_brightness_state_full)));
759a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani                views.setImageViewResource(R.id.img_brightness,
760a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani                        R.drawable.ic_appwidget_settings_brightness_full_holo);
761748ba16a046a6ac4727f2e39db9a933d81d02465Jeff Brown            } else if (brightness > half) {
762b9062f26785e53cfc44180e0044c8025ad33af2aalanv                views.setContentDescription(R.id.btn_brightness,
763b9062f26785e53cfc44180e0044c8025ad33af2aalanv                        context.getString(R.string.gadget_brightness_template,
764b9062f26785e53cfc44180e0044c8025ad33af2aalanv                                context.getString(R.string.gadget_brightness_state_half)));
765a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani                views.setImageViewResource(R.id.img_brightness,
766a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani                        R.drawable.ic_appwidget_settings_brightness_half_holo);
767a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani            } else {
768b9062f26785e53cfc44180e0044c8025ad33af2aalanv                views.setContentDescription(R.id.btn_brightness,
769b9062f26785e53cfc44180e0044c8025ad33af2aalanv                        context.getString(R.string.gadget_brightness_template,
770b9062f26785e53cfc44180e0044c8025ad33af2aalanv                                context.getString(R.string.gadget_brightness_state_off)));
771a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani                views.setImageViewResource(R.id.img_brightness,
772a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani                        R.drawable.ic_appwidget_settings_brightness_off_holo);
773a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani            }
774a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani            // Set the ON state
775748ba16a046a6ac4727f2e39db9a933d81d02465Jeff Brown            if (brightness > half) {
776a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani                views.setImageViewResource(R.id.ind_brightness,
777a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani                        R.drawable.appwidget_settings_ind_on_r_holo);
778a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani            } else {
779a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani                views.setImageViewResource(R.id.ind_brightness,
780a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani                        R.drawable.appwidget_settings_ind_off_r_holo);
781a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani            }
78203a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        }
78303a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    }
78403a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff
78503a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    /**
78603a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     * Creates PendingIntent to notify the widget of a button click.
78703a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     *
78803a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     * @param context
78903a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     * @return
79003a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     */
791436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    private static PendingIntent getLaunchPendingIntent(Context context,
792e936f5b386b39781e8f5e1ab423ebaf790dd9742Ken Shirriff            int buttonId) {
79303a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        Intent launchIntent = new Intent();
79403a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        launchIntent.setClass(context, SettingsAppWidgetProvider.class);
79503a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        launchIntent.addCategory(Intent.CATEGORY_ALTERNATIVE);
79603a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        launchIntent.setData(Uri.parse("custom:" + buttonId));
79703a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        PendingIntent pi = PendingIntent.getBroadcast(context, 0 /* no requestCode */,
79803a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff                launchIntent, 0 /* no flags */);
79903a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        return pi;
80003a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    }
80103a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff
80203a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    /**
80303a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     * Receives and processes a button pressed intent or state change.
80403a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     *
80503a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     * @param context
80603a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     * @param intent  Indicates the pressed button.
80703a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     */
80803a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    @Override
80903a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    public void onReceive(Context context, Intent intent) {
81003a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        super.onReceive(context, intent);
811ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        String action = intent.getAction();
812ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)) {
81394ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            sWifiState.onActualStateChange(context, intent);
814ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        } else if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) {
81594ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            sBluetoothState.onActualStateChange(context, intent);
8164af6514c78f2e468fe0f8f6070cf0f3e658b34a0Tom O'Neill        } else if (LocationManager.MODE_CHANGED_ACTION.equals(action)) {
817681f79900787c2c40751463ddd8f3476f9b40476David Christie            sLocationState.onActualStateChange(context, intent);
8181d6bf8d46b07cb87d5842324190bc5a31eee5e4bJeff Sharkey        } else if (ContentResolver.ACTION_SYNC_CONN_STATUS_CHANGED.equals(action)) {
819ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick            sSyncState.onActualStateChange(context, intent);
82094ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        } else if (intent.hasCategory(Intent.CATEGORY_ALTERNATIVE)) {
82103a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff            Uri data = intent.getData();
82203a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff            int buttonId = Integer.parseInt(data.getSchemeSpecificPart());
82303a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff            if (buttonId == BUTTON_WIFI) {
82494ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                sWifiState.toggleState(context);
82503a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff            } else if (buttonId == BUTTON_BRIGHTNESS) {
82603a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff                toggleBrightness(context);
82703a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff            } else if (buttonId == BUTTON_SYNC) {
828ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                sSyncState.toggleState(context);
829681f79900787c2c40751463ddd8f3476f9b40476David Christie            } else if (buttonId == BUTTON_LOCATION) {
830681f79900787c2c40751463ddd8f3476f9b40476David Christie                sLocationState.toggleState(context);
83103a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff            } else if (buttonId == BUTTON_BLUETOOTH) {
83294ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                sBluetoothState.toggleState(context);
83303a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff            }
834046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick        } else {
835046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick            // Don't fall-through to updating the widget.  The Intent
836046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick            // was something unrelated or that our super class took
837046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick            // care of.
838046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick            return;
83903a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        }
84094ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick
84103a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        // State changes fall through
84203a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        updateWidget(context);
84303a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    }
84403a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff
84503a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    /**
846a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani     * Gets brightness level.
84703a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     *
84803a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     * @param context
849a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani     * @return brightness level between 0 and 255.
85003a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     */
851a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani    private static int getBrightness(Context context) {
85203a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        try {
853748ba16a046a6ac4727f2e39db9a933d81d02465Jeff Brown            int brightness = Settings.System.getInt(context.getContentResolver(),
854748ba16a046a6ac4727f2e39db9a933d81d02465Jeff Brown                    Settings.System.SCREEN_BRIGHTNESS);
855748ba16a046a6ac4727f2e39db9a933d81d02465Jeff Brown            return brightness;
85603a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        } catch (Exception e) {
85703a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        }
858a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani        return 0;
85903a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    }
86003a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff
86103a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    /**
8625c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik     * Gets state of brightness mode.
8635c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik     *
8645c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik     * @param context
8655c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik     * @return true if auto brightness is on.
8665c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik     */
8675c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik    private static boolean getBrightnessMode(Context context) {
8685c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik        try {
869748ba16a046a6ac4727f2e39db9a933d81d02465Jeff Brown            int brightnessMode = Settings.System.getInt(context.getContentResolver(),
870748ba16a046a6ac4727f2e39db9a933d81d02465Jeff Brown                    Settings.System.SCREEN_BRIGHTNESS_MODE);
871748ba16a046a6ac4727f2e39db9a933d81d02465Jeff Brown            return brightnessMode == Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC;
8725c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik        } catch (Exception e) {
8735c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik            Log.d(TAG, "getBrightnessMode: " + e);
8745c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik        }
8755c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik        return false;
8765c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik    }
8775c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik
8785c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik    /**
87903a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     * Increases or decreases the brightness.
88003a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     *
88103a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     * @param context
88203a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     */
88303a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    private void toggleBrightness(Context context) {
88403a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        try {
885cd03f5320d42290b1619933954a344b59dc55f4fMike Lockwood            IPowerManager power = IPowerManager.Stub.asInterface(
886cd03f5320d42290b1619933954a344b59dc55f4fMike Lockwood                    ServiceManager.getService("power"));
887cd03f5320d42290b1619933954a344b59dc55f4fMike Lockwood            if (power != null) {
888748ba16a046a6ac4727f2e39db9a933d81d02465Jeff Brown                PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
889748ba16a046a6ac4727f2e39db9a933d81d02465Jeff Brown
89003a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff                ContentResolver cr = context.getContentResolver();
89103a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff                int brightness = Settings.System.getInt(cr,
89203a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff                        Settings.System.SCREEN_BRIGHTNESS);
8935c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik                int brightnessMode = Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL;
8945c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik                //Only get brightness setting if available
8955c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik                if (context.getResources().getBoolean(
8965c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik                        com.android.internal.R.bool.config_automatic_brightness_available)) {
8975c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik                    brightnessMode = Settings.System.getInt(cr,
8985c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik                            Settings.System.SCREEN_BRIGHTNESS_MODE);
8995c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik                }
9005c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik
9015c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik                // Rotate AUTO -> MINIMUM -> DEFAULT -> MAXIMUM
90203a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff                // Technically, not a toggle...
9035c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik                if (brightnessMode == Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC) {
904748ba16a046a6ac4727f2e39db9a933d81d02465Jeff Brown                    brightness = pm.getMinimumScreenBrightnessSetting();
9055c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik                    brightnessMode = Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL;
906748ba16a046a6ac4727f2e39db9a933d81d02465Jeff Brown                } else if (brightness < pm.getDefaultScreenBrightnessSetting()) {
907748ba16a046a6ac4727f2e39db9a933d81d02465Jeff Brown                    brightness = pm.getDefaultScreenBrightnessSetting();
908748ba16a046a6ac4727f2e39db9a933d81d02465Jeff Brown                } else if (brightness < pm.getMaximumScreenBrightnessSetting()) {
909748ba16a046a6ac4727f2e39db9a933d81d02465Jeff Brown                    brightness = pm.getMaximumScreenBrightnessSetting();
91003a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff                } else {
9115c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik                    brightnessMode = Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC;
912748ba16a046a6ac4727f2e39db9a933d81d02465Jeff Brown                    brightness = pm.getMinimumScreenBrightnessSetting();
91303a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff                }
9145c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik
915c4a0576473bd14eec1307ae1e0001a1db4fb5e94Ken Shirriff                if (context.getResources().getBoolean(
916c4a0576473bd14eec1307ae1e0001a1db4fb5e94Ken Shirriff                        com.android.internal.R.bool.config_automatic_brightness_available)) {
9175c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik                    // Set screen brightness mode (automatic or manual)
918c4a0576473bd14eec1307ae1e0001a1db4fb5e94Ken Shirriff                    Settings.System.putInt(context.getContentResolver(),
919c4a0576473bd14eec1307ae1e0001a1db4fb5e94Ken Shirriff                            Settings.System.SCREEN_BRIGHTNESS_MODE,
9205c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik                            brightnessMode);
9215bc5cedc7ae2808ed487d90ff86caedc722021dbErik                } else {
9225bc5cedc7ae2808ed487d90ff86caedc722021dbErik                    // Make sure we set the brightness if automatic mode isn't available
9235bc5cedc7ae2808ed487d90ff86caedc722021dbErik                    brightnessMode = Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL;
9245c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik                }
9255c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik                if (brightnessMode == Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL) {
926748ba16a046a6ac4727f2e39db9a933d81d02465Jeff Brown                    power.setTemporaryScreenBrightnessSettingOverride(brightness);
9275c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik                    Settings.System.putInt(cr, Settings.System.SCREEN_BRIGHTNESS, brightness);
928c4a0576473bd14eec1307ae1e0001a1db4fb5e94Ken Shirriff                }
92903a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff            }
93003a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        } catch (RemoteException e) {
93103a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff            Log.d(TAG, "toggleBrightness: " + e);
93203a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        } catch (Settings.SettingNotFoundException e) {
93303a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff            Log.d(TAG, "toggleBrightness: " + e);
93403a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        }
93503a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    }
93649c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani
93749c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani    /** Observer to watch for changes to the BRIGHTNESS setting */
93849c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani    private static class SettingsObserver extends ContentObserver {
93949c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani
94049c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani        private Context mContext;
94149c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani
94249c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani        SettingsObserver(Handler handler, Context context) {
94349c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani            super(handler);
94449c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani            mContext = context;
94549c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani        }
94649c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani
94749c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani        void startObserving() {
94849c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani            ContentResolver resolver = mContext.getContentResolver();
94949c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani            // Listen to brightness and brightness mode
95049c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani            resolver.registerContentObserver(Settings.System
95149c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani                    .getUriFor(Settings.System.SCREEN_BRIGHTNESS), false, this);
95249c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani            resolver.registerContentObserver(Settings.System
95349c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani                    .getUriFor(Settings.System.SCREEN_BRIGHTNESS_MODE), false, this);
954fde3074faa5e87d10b972fde2ea0db10b3a3a9dalongyu.huang            resolver.registerContentObserver(Settings.System
955fde3074faa5e87d10b972fde2ea0db10b3a3a9dalongyu.huang                    .getUriFor(Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ), false, this);
95649c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani        }
95749c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani
95849c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani        void stopObserving() {
95949c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani            mContext.getContentResolver().unregisterContentObserver(this);
96049c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani        }
96149c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani
96249c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani        @Override
96349c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani        public void onChange(boolean selfChange) {
96449c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani            updateWidget(mContext);
96549c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani        }
96649c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani    }
96749c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani
96803a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff}
969