SettingsAppWidgetProvider.java revision 4af6514c78f2e468fe0f8f6070cf0f3e658b34a0
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;
44436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hambyimport com.android.settings.bluetooth.LocalBluetoothAdapter;
4503a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriffimport com.android.settings.bluetooth.LocalBluetoothManager;
4603a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff
4703a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff/**
4803a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff * Provides control of power-related settings from a widget.
4903a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff */
5003a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriffpublic class SettingsAppWidgetProvider extends AppWidgetProvider {
5103a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    static final String TAG = "SettingsAppWidgetProvider";
5203a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff
5303a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    static final ComponentName THIS_APPWIDGET =
5403a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff            new ComponentName("com.android.settings",
5503a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff                    "com.android.settings.widget.SettingsAppWidgetProvider");
5603a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff
57436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    private static LocalBluetoothAdapter sLocalBluetoothAdapter = null;
5803a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff
5903a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    private static final int BUTTON_WIFI = 0;
6003a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    private static final int BUTTON_BRIGHTNESS = 1;
6103a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    private static final int BUTTON_SYNC = 2;
62681f79900787c2c40751463ddd8f3476f9b40476David Christie    private static final int BUTTON_LOCATION = 3;
6303a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    private static final int BUTTON_BLUETOOTH = 4;
6403a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff
6594ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick    // This widget keeps track of two sets of states:
6694ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick    // "3-state": STATE_DISABLED, STATE_ENABLED, STATE_INTERMEDIATE
6794ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick    // "5-state": STATE_DISABLED, STATE_ENABLED, STATE_TURNING_ON, STATE_TURNING_OFF, STATE_UNKNOWN
6803a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    private static final int STATE_DISABLED = 0;
6903a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    private static final int STATE_ENABLED = 1;
7094ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick    private static final int STATE_TURNING_ON = 2;
7194ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick    private static final int STATE_TURNING_OFF = 3;
7294ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick    private static final int STATE_UNKNOWN = 4;
7394ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick    private static final int STATE_INTERMEDIATE = 5;
7494ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick
75740edeaa42d276bca21ea7e077412badecc0eea3Amith Yamasani    // Position in the widget bar, to enable different graphics for left, center and right buttons
76740edeaa42d276bca21ea7e077412badecc0eea3Amith Yamasani    private static final int POS_LEFT = 0;
77740edeaa42d276bca21ea7e077412badecc0eea3Amith Yamasani    private static final int POS_CENTER = 1;
78740edeaa42d276bca21ea7e077412badecc0eea3Amith Yamasani    private static final int POS_RIGHT = 2;
79740edeaa42d276bca21ea7e077412badecc0eea3Amith Yamasani
80740edeaa42d276bca21ea7e077412badecc0eea3Amith Yamasani    private static final int[] IND_DRAWABLE_OFF = {
81a1252ccf7b31d01a9612fc0479dc7a632cabf8a7Peter Ng        R.drawable.appwidget_settings_ind_off_l_holo,
82a1252ccf7b31d01a9612fc0479dc7a632cabf8a7Peter Ng        R.drawable.appwidget_settings_ind_off_c_holo,
83a1252ccf7b31d01a9612fc0479dc7a632cabf8a7Peter Ng        R.drawable.appwidget_settings_ind_off_r_holo
84740edeaa42d276bca21ea7e077412badecc0eea3Amith Yamasani    };
85740edeaa42d276bca21ea7e077412badecc0eea3Amith Yamasani
86740edeaa42d276bca21ea7e077412badecc0eea3Amith Yamasani    private static final int[] IND_DRAWABLE_MID = {
87a1252ccf7b31d01a9612fc0479dc7a632cabf8a7Peter Ng        R.drawable.appwidget_settings_ind_mid_l_holo,
88a1252ccf7b31d01a9612fc0479dc7a632cabf8a7Peter Ng        R.drawable.appwidget_settings_ind_mid_c_holo,
89a1252ccf7b31d01a9612fc0479dc7a632cabf8a7Peter Ng        R.drawable.appwidget_settings_ind_mid_r_holo
90740edeaa42d276bca21ea7e077412badecc0eea3Amith Yamasani    };
91740edeaa42d276bca21ea7e077412badecc0eea3Amith Yamasani
92740edeaa42d276bca21ea7e077412badecc0eea3Amith Yamasani    private static final int[] IND_DRAWABLE_ON = {
93a1252ccf7b31d01a9612fc0479dc7a632cabf8a7Peter Ng        R.drawable.appwidget_settings_ind_on_l_holo,
94a1252ccf7b31d01a9612fc0479dc7a632cabf8a7Peter Ng        R.drawable.appwidget_settings_ind_on_c_holo,
95a1252ccf7b31d01a9612fc0479dc7a632cabf8a7Peter Ng        R.drawable.appwidget_settings_ind_on_r_holo
96740edeaa42d276bca21ea7e077412badecc0eea3Amith Yamasani    };
9703a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff
98a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani    /** Minimum brightness at which the indicator is shown at half-full and ON */
99748ba16a046a6ac4727f2e39db9a933d81d02465Jeff Brown    private static final float HALF_BRIGHTNESS_THRESHOLD = 0.3f;
100a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani    /** Minimum brightness at which the indicator is shown at full */
101748ba16a046a6ac4727f2e39db9a933d81d02465Jeff Brown    private static final float FULL_BRIGHTNESS_THRESHOLD = 0.8f;
10203a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff
10394ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick    private static final StateTracker sWifiState = new WifiStateTracker();
10494ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick    private static final StateTracker sBluetoothState = new BluetoothStateTracker();
105681f79900787c2c40751463ddd8f3476f9b40476David Christie    private static final StateTracker sLocationState = new LocationStateTracker();
106ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick    private static final StateTracker sSyncState = new SyncStateTracker();
10749c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani    private static SettingsObserver sSettingsObserver;
10894ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick
10994ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick    /**
110ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick     * The state machine for a setting's toggling, tracking reality
111ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick     * versus the user's intent.
11294ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick     *
11394ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick     * This is necessary because reality moves relatively slowly
11494ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick     * (turning on & off radio drivers), compared to user's
11594ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick     * expectations.
11694ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick     */
11794ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick    private abstract static class StateTracker {
11894ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        // Is the state in the process of changing?
11994ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        private boolean mInTransition = false;
12094ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        private Boolean mActualState = null;  // initially not set
12194ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        private Boolean mIntendedState = null;  // initially not set
12294ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick
12394ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        // Did a toggle request arrive while a state update was
12494ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        // already in-flight?  If so, the mIntendedState needs to be
12594ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        // requested when the other one is done, unless we happened to
12694ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        // arrive at that state already.
12794ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        private boolean mDeferredStateChangeRequestNeeded = false;
12894ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick
12994ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        /**
13094ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         * User pressed a button to change the state.  Something
13194ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         * should immediately appear to the user afterwards, even if
13294ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         * we effectively do nothing.  Their press must be heard.
13394ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         */
13494ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        public final void toggleState(Context context) {
13594ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            int currentState = getTriState(context);
13694ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            boolean newState = false;
13794ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            switch (currentState) {
13894ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                case STATE_ENABLED:
13994ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    newState = false;
14094ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    break;
14194ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                case STATE_DISABLED:
14294ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    newState = true;
14394ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    break;
14494ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                case STATE_INTERMEDIATE:
14594ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    if (mIntendedState != null) {
14694ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                        newState = !mIntendedState;
14794ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    }
14894ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    break;
14994ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            }
15094ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            mIntendedState = newState;
15194ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            if (mInTransition) {
15294ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                // We don't send off a transition request if we're
15394ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                // already transitioning.  Makes our state tracking
15494ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                // easier, and is probably nicer on lower levels.
15594ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                // (even though they should be able to take it...)
15694ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                mDeferredStateChangeRequestNeeded = true;
15794ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            } else {
15894ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                mInTransition = true;
159046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick                requestStateChange(context, newState);
16094ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            }
16194ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        }
16294ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick
16394ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        /**
164b9062f26785e53cfc44180e0044c8025ad33af2aalanv         * Return the ID of the clickable container for the setting.
165b9062f26785e53cfc44180e0044c8025ad33af2aalanv         */
166b9062f26785e53cfc44180e0044c8025ad33af2aalanv        public abstract int getContainerId();
167b9062f26785e53cfc44180e0044c8025ad33af2aalanv
168b9062f26785e53cfc44180e0044c8025ad33af2aalanv        /**
169ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick         * Return the ID of the main large image button for the setting.
170ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick         */
171ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        public abstract int getButtonId();
172ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick
173ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        /**
174ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick         * Returns the small indicator image ID underneath the setting.
175ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick         */
176ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        public abstract int getIndicatorId();
177ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick
178ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        /**
179b9062f26785e53cfc44180e0044c8025ad33af2aalanv         * Returns the resource ID of the setting's content description.
180b9062f26785e53cfc44180e0044c8025ad33af2aalanv         */
181b9062f26785e53cfc44180e0044c8025ad33af2aalanv        public abstract int getButtonDescription();
182b9062f26785e53cfc44180e0044c8025ad33af2aalanv
183b9062f26785e53cfc44180e0044c8025ad33af2aalanv        /**
184ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick         * Returns the resource ID of the image to show as a function of
185ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick         * the on-vs-off state.
186ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick         */
187ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        public abstract int getButtonImageId(boolean on);
188ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick
189ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        /**
190740edeaa42d276bca21ea7e077412badecc0eea3Amith Yamasani         * Returns the position in the button bar - either POS_LEFT, POS_RIGHT or POS_CENTER.
191740edeaa42d276bca21ea7e077412badecc0eea3Amith Yamasani         */
192740edeaa42d276bca21ea7e077412badecc0eea3Amith Yamasani        public int getPosition() { return POS_CENTER; }
193740edeaa42d276bca21ea7e077412badecc0eea3Amith Yamasani
194740edeaa42d276bca21ea7e077412badecc0eea3Amith Yamasani        /**
195ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick         * Updates the remote views depending on the state (off, on,
196ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick         * turning off, turning on) of the setting.
197ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick         */
198ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        public final void setImageViewResources(Context context, RemoteViews views) {
199b9062f26785e53cfc44180e0044c8025ad33af2aalanv            int containerId = getContainerId();
200ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick            int buttonId = getButtonId();
201ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick            int indicatorId = getIndicatorId();
202740edeaa42d276bca21ea7e077412badecc0eea3Amith Yamasani            int pos = getPosition();
203ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick            switch (getTriState(context)) {
204ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                case STATE_DISABLED:
205b9062f26785e53cfc44180e0044c8025ad33af2aalanv                    views.setContentDescription(containerId,
206b9062f26785e53cfc44180e0044c8025ad33af2aalanv                        getContentDescription(context, R.string.gadget_state_off));
207ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    views.setImageViewResource(buttonId, getButtonImageId(false));
208ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    views.setImageViewResource(
209740edeaa42d276bca21ea7e077412badecc0eea3Amith Yamasani                        indicatorId, IND_DRAWABLE_OFF[pos]);
210ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    break;
211ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                case STATE_ENABLED:
212b9062f26785e53cfc44180e0044c8025ad33af2aalanv                    views.setContentDescription(containerId,
213b9062f26785e53cfc44180e0044c8025ad33af2aalanv                        getContentDescription(context, R.string.gadget_state_on));
214ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    views.setImageViewResource(buttonId, getButtonImageId(true));
215ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    views.setImageViewResource(
216740edeaa42d276bca21ea7e077412badecc0eea3Amith Yamasani                        indicatorId, IND_DRAWABLE_ON[pos]);
217ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    break;
218ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                case STATE_INTERMEDIATE:
219ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    // In the transitional state, the bottom green bar
220ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    // shows the tri-state (on, off, transitioning), but
221ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    // the top dark-gray-or-bright-white logo shows the
222ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    // user's intent.  This is much easier to see in
223ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    // sunlight.
224ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    if (isTurningOn()) {
225b9062f26785e53cfc44180e0044c8025ad33af2aalanv                        views.setContentDescription(containerId,
226b9062f26785e53cfc44180e0044c8025ad33af2aalanv                            getContentDescription(context, R.string.gadget_state_turning_on));
227ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                        views.setImageViewResource(buttonId, getButtonImageId(true));
228ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                        views.setImageViewResource(
229740edeaa42d276bca21ea7e077412badecc0eea3Amith Yamasani                            indicatorId, IND_DRAWABLE_MID[pos]);
230ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    } else {
231b9062f26785e53cfc44180e0044c8025ad33af2aalanv                        views.setContentDescription(containerId,
232b9062f26785e53cfc44180e0044c8025ad33af2aalanv                            getContentDescription(context, R.string.gadget_state_turning_off));
233ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                        views.setImageViewResource(buttonId, getButtonImageId(false));
234ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                        views.setImageViewResource(
235740edeaa42d276bca21ea7e077412badecc0eea3Amith Yamasani                            indicatorId, IND_DRAWABLE_OFF[pos]);
236ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    }
237ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    break;
238ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick            }
239ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        }
240ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick
241ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        /**
242b9062f26785e53cfc44180e0044c8025ad33af2aalanv         * Returns the gadget state template populated with the gadget
243b9062f26785e53cfc44180e0044c8025ad33af2aalanv         * description and state.
244b9062f26785e53cfc44180e0044c8025ad33af2aalanv         */
245b9062f26785e53cfc44180e0044c8025ad33af2aalanv        private final String getContentDescription(Context context, int stateResId) {
246b9062f26785e53cfc44180e0044c8025ad33af2aalanv            final String gadget = context.getString(getButtonDescription());
247b9062f26785e53cfc44180e0044c8025ad33af2aalanv            final String state = context.getString(stateResId);
248b9062f26785e53cfc44180e0044c8025ad33af2aalanv            return context.getString(R.string.gadget_state_template, gadget, state);
249b9062f26785e53cfc44180e0044c8025ad33af2aalanv        }
250b9062f26785e53cfc44180e0044c8025ad33af2aalanv
251b9062f26785e53cfc44180e0044c8025ad33af2aalanv        /**
25294ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         * Update internal state from a broadcast state change.
25394ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         */
25494ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        public abstract void onActualStateChange(Context context, Intent intent);
25594ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick
25694ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        /**
25794ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         * Sets the value that we're now in.  To be called from onActualStateChange.
25894ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         *
25994ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         * @param newState one of STATE_DISABLED, STATE_ENABLED, STATE_TURNING_ON,
26094ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         *                 STATE_TURNING_OFF, STATE_UNKNOWN
26194ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         */
26294ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        protected final void setCurrentState(Context context, int newState) {
263046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick            final boolean wasInTransition = mInTransition;
26494ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            switch (newState) {
26594ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                case STATE_DISABLED:
26694ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    mInTransition = false;
26794ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    mActualState = false;
26894ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    break;
26994ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                case STATE_ENABLED:
27094ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    mInTransition = false;
27194ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    mActualState = true;
27294ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    break;
27394ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                case STATE_TURNING_ON:
27494ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    mInTransition = true;
27594ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    mActualState = false;
27694ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    break;
27794ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                case STATE_TURNING_OFF:
27894ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    mInTransition = true;
27994ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    mActualState = true;
28094ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    break;
28194ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            }
28294ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick
28394ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            if (wasInTransition && !mInTransition) {
28494ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                if (mDeferredStateChangeRequestNeeded) {
28594ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    Log.v(TAG, "processing deferred state change");
28694ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    if (mActualState != null && mIntendedState != null &&
28794ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                        mIntendedState.equals(mActualState)) {
28894ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                        Log.v(TAG, "... but intended state matches, so no changes.");
28994ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    } else if (mIntendedState != null) {
29094ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                        mInTransition = true;
291046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick                        requestStateChange(context, mIntendedState);
29294ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    }
29394ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    mDeferredStateChangeRequestNeeded = false;
29494ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                }
29594ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            }
29694ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        }
29794ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick
29894ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick
29994ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        /**
30094ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         * If we're in a transition mode, this returns true if we're
30194ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         * transitioning towards being enabled.
30294ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         */
30394ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        public final boolean isTurningOn() {
30494ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            return mIntendedState != null && mIntendedState;
30594ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        }
30694ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick
30794ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        /**
30894ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         * Returns simplified 3-state value from underlying 5-state.
30994ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         *
31094ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         * @param context
31194ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         * @return STATE_ENABLED, STATE_DISABLED, or STATE_INTERMEDIATE
31294ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         */
31394ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        public final int getTriState(Context context) {
314046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick            if (mInTransition) {
315046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick                // If we know we just got a toggle request recently
316046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick                // (which set mInTransition), don't even ask the
317046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick                // underlying interface for its state.  We know we're
318046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick                // changing.  This avoids blocking the UI thread
319046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick                // during UI refresh post-toggle if the underlying
320046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick                // service state accessor has coarse locking on its
321046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick                // state (to be fixed separately).
322046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick                return STATE_INTERMEDIATE;
323046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick            }
32494ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            switch (getActualState(context)) {
32594ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                case STATE_DISABLED:
32694ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    return STATE_DISABLED;
32794ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                case STATE_ENABLED:
32894ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    return STATE_ENABLED;
32994ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                default:
33094ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    return STATE_INTERMEDIATE;
33194ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            }
33294ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        }
33394ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick
33494ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        /**
33594ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         * Gets underlying actual state.
33694ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         *
33794ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         * @param context
33894ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         * @return STATE_ENABLED, STATE_DISABLED, STATE_ENABLING, STATE_DISABLING,
33994ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         *         or or STATE_UNKNOWN.
34094ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         */
34194ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        public abstract int getActualState(Context context);
34294ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick
34394ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        /**
34494ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         * Actually make the desired change to the underlying radio
34594ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         * API.
34694ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         */
347046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick        protected abstract void requestStateChange(Context context, boolean desiredState);
34894ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick    }
34994ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick
35094ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick    /**
35194ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick     * Subclass of StateTracker to get/set Wifi state.
35294ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick     */
35394ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick    private static final class WifiStateTracker extends StateTracker {
354b9062f26785e53cfc44180e0044c8025ad33af2aalanv        public int getContainerId() { return R.id.btn_wifi; }
355ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        public int getButtonId() { return R.id.img_wifi; }
356ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        public int getIndicatorId() { return R.id.ind_wifi; }
357b9062f26785e53cfc44180e0044c8025ad33af2aalanv        public int getButtonDescription() { return R.string.gadget_wifi; }
358ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        public int getButtonImageId(boolean on) {
359a1252ccf7b31d01a9612fc0479dc7a632cabf8a7Peter Ng            return on ? R.drawable.ic_appwidget_settings_wifi_on_holo
360a1252ccf7b31d01a9612fc0479dc7a632cabf8a7Peter Ng                    : R.drawable.ic_appwidget_settings_wifi_off_holo;
361ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        }
362ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick
36394ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        @Override
364740edeaa42d276bca21ea7e077412badecc0eea3Amith Yamasani        public int getPosition() { return POS_LEFT; }
365740edeaa42d276bca21ea7e077412badecc0eea3Amith Yamasani
366740edeaa42d276bca21ea7e077412badecc0eea3Amith Yamasani        @Override
36794ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        public int getActualState(Context context) {
36894ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
36994ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            if (wifiManager != null) {
37094ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                return wifiStateToFiveState(wifiManager.getWifiState());
37194ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            }
37294ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            return STATE_UNKNOWN;
37394ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        }
37494ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick
37594ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        @Override
376046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick        protected void requestStateChange(Context context, final boolean desiredState) {
377ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick            final WifiManager wifiManager =
378ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
37994ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            if (wifiManager == null) {
38094ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                Log.d(TAG, "No wifiManager.");
38194ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                return;
38294ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            }
383a6a74e222a994e29a1daa7178943a1fc9dd06c47Irfan Sheriff
384046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick            // Actually request the wifi change and persistent
385046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick            // settings write off the UI thread, as it can take a
386046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick            // user-noticeable amount of time, especially if there's
387046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick            // disk contention.
388046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick            new AsyncTask<Void, Void, Void>() {
389046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick                @Override
390046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick                protected Void doInBackground(Void... args) {
391046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick                    /**
392046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick                     * Disable tethering if enabling Wifi
393046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick                     */
394046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick                    int wifiApState = wifiManager.getWifiApState();
395046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick                    if (desiredState && ((wifiApState == WifiManager.WIFI_AP_STATE_ENABLING) ||
396046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick                                         (wifiApState == WifiManager.WIFI_AP_STATE_ENABLED))) {
397046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick                        wifiManager.setWifiApEnabled(null, false);
398046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick                    }
399046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick
400046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick                    wifiManager.setWifiEnabled(desiredState);
401046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick                    return null;
402046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick                }
403046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick            }.execute();
40494ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        }
40594ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick
40694ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        @Override
40794ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        public void onActualStateChange(Context context, Intent intent) {
40894ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            if (!WifiManager.WIFI_STATE_CHANGED_ACTION.equals(intent.getAction())) {
40994ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                return;
41094ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            }
41194ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            int wifiState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, -1);
41294ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            setCurrentState(context, wifiStateToFiveState(wifiState));
41394ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        }
41494ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick
41594ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        /**
41694ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         * Converts WifiManager's state values into our
41794ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         * Wifi/Bluetooth-common state values.
41894ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         */
41994ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        private static int wifiStateToFiveState(int wifiState) {
42094ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            switch (wifiState) {
42194ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                case WifiManager.WIFI_STATE_DISABLED:
42294ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    return STATE_DISABLED;
42394ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                case WifiManager.WIFI_STATE_ENABLED:
42494ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    return STATE_ENABLED;
42594ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                case WifiManager.WIFI_STATE_DISABLING:
42694ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    return STATE_TURNING_OFF;
42794ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                case WifiManager.WIFI_STATE_ENABLING:
42894ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    return STATE_TURNING_ON;
42994ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                default:
43094ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    return STATE_UNKNOWN;
43194ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            }
43294ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        }
43394ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick    }
43494ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick
43594ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick    /**
43694ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick     * Subclass of StateTracker to get/set Bluetooth state.
43794ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick     */
43894ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick    private static final class BluetoothStateTracker extends StateTracker {
439b9062f26785e53cfc44180e0044c8025ad33af2aalanv        public int getContainerId() { return R.id.btn_bluetooth; }
440ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        public int getButtonId() { return R.id.img_bluetooth; }
441ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        public int getIndicatorId() { return R.id.ind_bluetooth; }
442b9062f26785e53cfc44180e0044c8025ad33af2aalanv        public int getButtonDescription() { return R.string.gadget_bluetooth; }
443ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        public int getButtonImageId(boolean on) {
444a1252ccf7b31d01a9612fc0479dc7a632cabf8a7Peter Ng            return on ? R.drawable.ic_appwidget_settings_bluetooth_on_holo
445a1252ccf7b31d01a9612fc0479dc7a632cabf8a7Peter Ng                    : R.drawable.ic_appwidget_settings_bluetooth_off_holo;
446ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        }
44794ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick
44894ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        @Override
44994ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        public int getActualState(Context context) {
450436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            if (sLocalBluetoothAdapter == null) {
451436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                LocalBluetoothManager manager = LocalBluetoothManager.getInstance(context);
452436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                if (manager == null) {
45394ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    return STATE_UNKNOWN;  // On emulator?
45494ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                }
455436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                sLocalBluetoothAdapter = manager.getBluetoothAdapter();
45694ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            }
457436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            return bluetoothStateToFiveState(sLocalBluetoothAdapter.getBluetoothState());
45894ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        }
45994ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick
46094ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        @Override
461046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick        protected void requestStateChange(Context context, final boolean desiredState) {
462436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            if (sLocalBluetoothAdapter == null) {
46394ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                Log.d(TAG, "No LocalBluetoothManager");
46494ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                return;
46594ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            }
466046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick            // Actually request the Bluetooth change and persistent
467046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick            // settings write off the UI thread, as it can take a
468046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick            // user-noticeable amount of time, especially if there's
469046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick            // disk contention.
470046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick            new AsyncTask<Void, Void, Void>() {
471046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick                @Override
472046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick                protected Void doInBackground(Void... args) {
473436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                    sLocalBluetoothAdapter.setBluetoothEnabled(desiredState);
474046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick                    return null;
475046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick                }
476046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick            }.execute();
47794ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        }
47894ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick
47994ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        @Override
48094ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        public void onActualStateChange(Context context, Intent intent) {
48194ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            if (!BluetoothAdapter.ACTION_STATE_CHANGED.equals(intent.getAction())) {
48294ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                return;
48394ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            }
48494ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            int bluetoothState = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1);
48594ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            setCurrentState(context, bluetoothStateToFiveState(bluetoothState));
48694ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        }
48794ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick
48894ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        /**
48994ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         * Converts BluetoothAdapter's state values into our
49094ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         * Wifi/Bluetooth-common state values.
49194ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick         */
49294ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        private static int bluetoothStateToFiveState(int bluetoothState) {
49394ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            switch (bluetoothState) {
49494ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                case BluetoothAdapter.STATE_OFF:
49594ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    return STATE_DISABLED;
49694ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                case BluetoothAdapter.STATE_ON:
49794ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    return STATE_ENABLED;
49894ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                case BluetoothAdapter.STATE_TURNING_ON:
49994ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    return STATE_TURNING_ON;
50094ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                case BluetoothAdapter.STATE_TURNING_OFF:
50194ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    return STATE_TURNING_OFF;
50294ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                default:
50394ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                    return STATE_UNKNOWN;
50494ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            }
50594ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        }
50694ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick    }
50794ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick
508ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick    /**
509681f79900787c2c40751463ddd8f3476f9b40476David Christie     * Subclass of StateTracker for location state.
510ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick     */
511681f79900787c2c40751463ddd8f3476f9b40476David Christie    private static final class LocationStateTracker extends StateTracker {
512681f79900787c2c40751463ddd8f3476f9b40476David Christie        public int getContainerId() { return R.id.btn_location; }
513681f79900787c2c40751463ddd8f3476f9b40476David Christie        public int getButtonId() { return R.id.img_location; }
514681f79900787c2c40751463ddd8f3476f9b40476David Christie        public int getIndicatorId() { return R.id.ind_location; }
515681f79900787c2c40751463ddd8f3476f9b40476David Christie        public int getButtonDescription() { return R.string.gadget_location; }
516ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        public int getButtonImageId(boolean on) {
517681f79900787c2c40751463ddd8f3476f9b40476David Christie            return on ? R.drawable.ic_appwidget_settings_location_on_holo
518681f79900787c2c40751463ddd8f3476f9b40476David Christie                    : R.drawable.ic_appwidget_settings_location_off_holo;
519ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        }
520ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick
521ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        @Override
522ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        public int getActualState(Context context) {
523ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick            ContentResolver resolver = context.getContentResolver();
52493259c14f3aca4739e2cf7691cb0416ded509d8dTom O'Neill            int currentLocationMode = Settings.Secure.getInt(resolver,
52593259c14f3aca4739e2cf7691cb0416ded509d8dTom O'Neill                    Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF);
5265eed792a76970e4271e03547e61dbbd6fabbf2f4David Christie            switch (currentLocationMode) {
5275eed792a76970e4271e03547e61dbbd6fabbf2f4David Christie                case Settings.Secure.LOCATION_MODE_BATTERY_SAVING:
5285eed792a76970e4271e03547e61dbbd6fabbf2f4David Christie                case Settings.Secure.LOCATION_MODE_OFF:
5295eed792a76970e4271e03547e61dbbd6fabbf2f4David Christie                    return STATE_DISABLED;
5305eed792a76970e4271e03547e61dbbd6fabbf2f4David Christie            }
5315eed792a76970e4271e03547e61dbbd6fabbf2f4David Christie
5325eed792a76970e4271e03547e61dbbd6fabbf2f4David Christie            return STATE_ENABLED;
533ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        }
534ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick
535ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        @Override
536ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        public void onActualStateChange(Context context, Intent unused) {
537ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick            // Note: the broadcast location providers changed intent
538ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick            // doesn't include an extras bundles saying what the new value is.
539ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick            setCurrentState(context, getActualState(context));
540ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        }
541ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick
542ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        @Override
543ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        public void requestStateChange(final Context context, final boolean desiredState) {
544ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick            final ContentResolver resolver = context.getContentResolver();
545ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick            new AsyncTask<Void, Void, Boolean>() {
546ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                @Override
547ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                protected Boolean doInBackground(Void... args) {
548ea6260d887a7065d65d94be58c05903b3d1fc359Maggie Benthall                    final UserManager um =
549ea6260d887a7065d65d94be58c05903b3d1fc359Maggie Benthall                            (UserManager) context.getSystemService(Context.USER_SERVICE);
5500c5a401a58b30041d5fe712d78fccbd47f5b744dMaggie Benthall                    if (!um.hasUserRestriction(UserManager.DISALLOW_SHARE_LOCATION)) {
5513d0bee59b875c7a47045408a46a599ae290659efLifu Tang                        int currentMode = Settings.Secure.getInt(resolver,
5523d0bee59b875c7a47045408a46a599ae290659efLifu Tang                                Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF);
5533d0bee59b875c7a47045408a46a599ae290659efLifu Tang                        int mode = Settings.Secure.LOCATION_MODE_HIGH_ACCURACY;
5543d0bee59b875c7a47045408a46a599ae290659efLifu Tang                        switch (currentMode) {
5553d0bee59b875c7a47045408a46a599ae290659efLifu Tang                            case Settings.Secure.LOCATION_MODE_HIGH_ACCURACY:
5563d0bee59b875c7a47045408a46a599ae290659efLifu Tang                                mode = Settings.Secure.LOCATION_MODE_BATTERY_SAVING;
5573d0bee59b875c7a47045408a46a599ae290659efLifu Tang                                break;
5583d0bee59b875c7a47045408a46a599ae290659efLifu Tang                            case Settings.Secure.LOCATION_MODE_BATTERY_SAVING:
5593d0bee59b875c7a47045408a46a599ae290659efLifu Tang                                mode = Settings.Secure.LOCATION_MODE_HIGH_ACCURACY;
5603d0bee59b875c7a47045408a46a599ae290659efLifu Tang                                break;
5613d0bee59b875c7a47045408a46a599ae290659efLifu Tang                            case Settings.Secure.LOCATION_MODE_SENSORS_ONLY:
5623d0bee59b875c7a47045408a46a599ae290659efLifu Tang                                mode = Settings.Secure.LOCATION_MODE_OFF;
5633d0bee59b875c7a47045408a46a599ae290659efLifu Tang                                break;
5643d0bee59b875c7a47045408a46a599ae290659efLifu Tang                            case Settings.Secure.LOCATION_MODE_OFF:
5653d0bee59b875c7a47045408a46a599ae290659efLifu Tang                                mode = Settings.Secure.LOCATION_MODE_HIGH_ACCURACY;
5663d0bee59b875c7a47045408a46a599ae290659efLifu Tang                                break;
5673d0bee59b875c7a47045408a46a599ae290659efLifu Tang                        }
56893259c14f3aca4739e2cf7691cb0416ded509d8dTom O'Neill                        Settings.Secure.putInt(resolver, Settings.Secure.LOCATION_MODE, mode);
569ea6260d887a7065d65d94be58c05903b3d1fc359Maggie Benthall                        return desiredState;
570ea6260d887a7065d65d94be58c05903b3d1fc359Maggie Benthall                    }
571681f79900787c2c40751463ddd8f3476f9b40476David Christie
5725eed792a76970e4271e03547e61dbbd6fabbf2f4David Christie                    return getActualState(context) == STATE_ENABLED;
573ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                }
574ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick
575ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                @Override
576ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                protected void onPostExecute(Boolean result) {
577ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    setCurrentState(
578ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                        context,
579ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                        result ? STATE_ENABLED : STATE_DISABLED);
580ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    updateWidget(context);
581ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                }
582ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick            }.execute();
583ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        }
584ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick    }
585ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick
586ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick    /**
587ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick     * Subclass of StateTracker for sync state.
588ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick     */
589ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick    private static final class SyncStateTracker extends StateTracker {
590b9062f26785e53cfc44180e0044c8025ad33af2aalanv        public int getContainerId() { return R.id.btn_sync; }
591ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        public int getButtonId() { return R.id.img_sync; }
592ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        public int getIndicatorId() { return R.id.ind_sync; }
593b9062f26785e53cfc44180e0044c8025ad33af2aalanv        public int getButtonDescription() { return R.string.gadget_sync; }
594ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        public int getButtonImageId(boolean on) {
595a1252ccf7b31d01a9612fc0479dc7a632cabf8a7Peter Ng            return on ? R.drawable.ic_appwidget_settings_sync_on_holo
596a1252ccf7b31d01a9612fc0479dc7a632cabf8a7Peter Ng                    : R.drawable.ic_appwidget_settings_sync_off_holo;
597ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        }
598ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick
599ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        @Override
600ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        public int getActualState(Context context) {
60149c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani            boolean on = ContentResolver.getMasterSyncAutomatically();
602ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick            return on ? STATE_ENABLED : STATE_DISABLED;
603ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        }
604ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick
605ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        @Override
606ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        public void onActualStateChange(Context context, Intent unused) {
607ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick            setCurrentState(context, getActualState(context));
608ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        }
609ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick
610ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        @Override
611ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        public void requestStateChange(final Context context, final boolean desiredState) {
612ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick            final ConnectivityManager connManager =
613ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
614ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick            final boolean sync = ContentResolver.getMasterSyncAutomatically();
615ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick
616ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick            new AsyncTask<Void, Void, Boolean>() {
617ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                @Override
618ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                protected Boolean doInBackground(Void... args) {
619ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    // Turning sync on.
620ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    if (desiredState) {
621ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                        if (!sync) {
622ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                            ContentResolver.setMasterSyncAutomatically(true);
623ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                        }
624ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                        return true;
625ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    }
626ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick
627ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    // Turning sync off
628ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    if (sync) {
629ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                        ContentResolver.setMasterSyncAutomatically(false);
630ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    }
631ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    return false;
632ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                }
633ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick
634ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                @Override
635ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                protected void onPostExecute(Boolean result) {
636ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    setCurrentState(
637ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                        context,
638ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                        result ? STATE_ENABLED : STATE_DISABLED);
639ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                    updateWidget(context);
640ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                }
641ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick            }.execute();
642ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        }
643ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick    }
64494ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick
645a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani    private static void checkObserver(Context context) {
646a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani        if (sSettingsObserver == null) {
647a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani            sSettingsObserver = new SettingsObserver(new Handler(),
648a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani                    context.getApplicationContext());
649a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani            sSettingsObserver.startObserving();
650a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani        }
651a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani    }
652a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani
65303a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    @Override
65403a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    public void onUpdate(Context context, AppWidgetManager appWidgetManager,
65503a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff            int[] appWidgetIds) {
65603a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        // Update each requested appWidgetId
657436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        RemoteViews view = buildUpdate(context);
65803a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff
65903a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        for (int i = 0; i < appWidgetIds.length; i++) {
66003a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff            appWidgetManager.updateAppWidget(appWidgetIds[i], view);
66103a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        }
66203a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    }
66303a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff
66403a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    @Override
66503a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    public void onEnabled(Context context) {
666a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani        checkObserver(context);
66703a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    }
66803a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff
66903a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    @Override
67003a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    public void onDisabled(Context context) {
67149c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani        if (sSettingsObserver != null) {
67249c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani            sSettingsObserver.stopObserving();
67349c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani            sSettingsObserver = null;
67449c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani        }
67503a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    }
67603a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff
67703a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    /**
67803a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     * Load image for given widget and build {@link RemoteViews} for it.
67903a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     */
680436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    static RemoteViews buildUpdate(Context context) {
68103a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        RemoteViews views = new RemoteViews(context.getPackageName(),
68203a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff                R.layout.widget);
683436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        views.setOnClickPendingIntent(R.id.btn_wifi, getLaunchPendingIntent(context,
68403a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff                BUTTON_WIFI));
68503a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        views.setOnClickPendingIntent(R.id.btn_brightness,
68603a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff                getLaunchPendingIntent(context,
687436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                        BUTTON_BRIGHTNESS));
68803a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        views.setOnClickPendingIntent(R.id.btn_sync,
68903a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff                getLaunchPendingIntent(context,
690436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                        BUTTON_SYNC));
691681f79900787c2c40751463ddd8f3476f9b40476David Christie        views.setOnClickPendingIntent(R.id.btn_location,
692681f79900787c2c40751463ddd8f3476f9b40476David Christie                getLaunchPendingIntent(context, BUTTON_LOCATION));
69303a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        views.setOnClickPendingIntent(R.id.btn_bluetooth,
69403a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff                getLaunchPendingIntent(context,
695436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                        BUTTON_BLUETOOTH));
69603a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff
69703a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        updateButtons(views, context);
69803a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        return views;
69903a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    }
70003a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff
70103a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    /**
70203a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     * Updates the widget when something changes, or when a button is pushed.
70303a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     *
70403a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     * @param context
70503a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     */
70603a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    public static void updateWidget(Context context) {
707436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        RemoteViews views = buildUpdate(context);
70803a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        // Update specific list of appWidgetIds if given, otherwise default to all
70903a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        final AppWidgetManager gm = AppWidgetManager.getInstance(context);
71003a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        gm.updateAppWidget(THIS_APPWIDGET, views);
711a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani        checkObserver(context);
71203a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    }
71303a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff
71403a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    /**
71503a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     * Updates the buttons based on the underlying states of wifi, etc.
71603a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     *
71703a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     * @param views   The RemoteViews to update.
71803a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     * @param context
71903a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     */
72003a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    private static void updateButtons(RemoteViews views, Context context) {
721ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        sWifiState.setImageViewResources(context, views);
722ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        sBluetoothState.setImageViewResources(context, views);
723681f79900787c2c40751463ddd8f3476f9b40476David Christie        sLocationState.setImageViewResources(context, views);
724ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        sSyncState.setImageViewResources(context, views);
725ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick
7265c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik        if (getBrightnessMode(context)) {
727b9062f26785e53cfc44180e0044c8025ad33af2aalanv            views.setContentDescription(R.id.btn_brightness,
728b9062f26785e53cfc44180e0044c8025ad33af2aalanv                    context.getString(R.string.gadget_brightness_template,
729b9062f26785e53cfc44180e0044c8025ad33af2aalanv                            context.getString(R.string.gadget_brightness_state_auto)));
73094ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            views.setImageViewResource(R.id.img_brightness,
731a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani                    R.drawable.ic_appwidget_settings_brightness_auto_holo);
73294ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            views.setImageViewResource(R.id.ind_brightness,
733a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani                    R.drawable.appwidget_settings_ind_on_r_holo);
73403a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        } else {
735a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani            final int brightness = getBrightness(context);
736748ba16a046a6ac4727f2e39db9a933d81d02465Jeff Brown            final PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
737a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani            // Set the icon
738748ba16a046a6ac4727f2e39db9a933d81d02465Jeff Brown            final int full = (int)(pm.getMaximumScreenBrightnessSetting()
739748ba16a046a6ac4727f2e39db9a933d81d02465Jeff Brown                    * FULL_BRIGHTNESS_THRESHOLD);
740748ba16a046a6ac4727f2e39db9a933d81d02465Jeff Brown            final int half = (int)(pm.getMaximumScreenBrightnessSetting()
741748ba16a046a6ac4727f2e39db9a933d81d02465Jeff Brown                    * HALF_BRIGHTNESS_THRESHOLD);
742748ba16a046a6ac4727f2e39db9a933d81d02465Jeff Brown            if (brightness > full) {
743b9062f26785e53cfc44180e0044c8025ad33af2aalanv                views.setContentDescription(R.id.btn_brightness,
744b9062f26785e53cfc44180e0044c8025ad33af2aalanv                        context.getString(R.string.gadget_brightness_template,
745b9062f26785e53cfc44180e0044c8025ad33af2aalanv                                context.getString(R.string.gadget_brightness_state_full)));
746a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani                views.setImageViewResource(R.id.img_brightness,
747a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani                        R.drawable.ic_appwidget_settings_brightness_full_holo);
748748ba16a046a6ac4727f2e39db9a933d81d02465Jeff Brown            } else if (brightness > half) {
749b9062f26785e53cfc44180e0044c8025ad33af2aalanv                views.setContentDescription(R.id.btn_brightness,
750b9062f26785e53cfc44180e0044c8025ad33af2aalanv                        context.getString(R.string.gadget_brightness_template,
751b9062f26785e53cfc44180e0044c8025ad33af2aalanv                                context.getString(R.string.gadget_brightness_state_half)));
752a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani                views.setImageViewResource(R.id.img_brightness,
753a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani                        R.drawable.ic_appwidget_settings_brightness_half_holo);
754a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani            } else {
755b9062f26785e53cfc44180e0044c8025ad33af2aalanv                views.setContentDescription(R.id.btn_brightness,
756b9062f26785e53cfc44180e0044c8025ad33af2aalanv                        context.getString(R.string.gadget_brightness_template,
757b9062f26785e53cfc44180e0044c8025ad33af2aalanv                                context.getString(R.string.gadget_brightness_state_off)));
758a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani                views.setImageViewResource(R.id.img_brightness,
759a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani                        R.drawable.ic_appwidget_settings_brightness_off_holo);
760a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani            }
761a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani            // Set the ON state
762748ba16a046a6ac4727f2e39db9a933d81d02465Jeff Brown            if (brightness > half) {
763a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani                views.setImageViewResource(R.id.ind_brightness,
764a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani                        R.drawable.appwidget_settings_ind_on_r_holo);
765a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani            } else {
766a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani                views.setImageViewResource(R.id.ind_brightness,
767a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani                        R.drawable.appwidget_settings_ind_off_r_holo);
768a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani            }
76903a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        }
77003a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    }
77103a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff
77203a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    /**
77303a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     * Creates PendingIntent to notify the widget of a button click.
77403a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     *
77503a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     * @param context
77603a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     * @return
77703a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     */
778436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    private static PendingIntent getLaunchPendingIntent(Context context,
779e936f5b386b39781e8f5e1ab423ebaf790dd9742Ken Shirriff            int buttonId) {
78003a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        Intent launchIntent = new Intent();
78103a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        launchIntent.setClass(context, SettingsAppWidgetProvider.class);
78203a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        launchIntent.addCategory(Intent.CATEGORY_ALTERNATIVE);
78303a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        launchIntent.setData(Uri.parse("custom:" + buttonId));
78403a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        PendingIntent pi = PendingIntent.getBroadcast(context, 0 /* no requestCode */,
78503a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff                launchIntent, 0 /* no flags */);
78603a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        return pi;
78703a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    }
78803a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff
78903a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    /**
79003a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     * Receives and processes a button pressed intent or state change.
79103a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     *
79203a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     * @param context
79303a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     * @param intent  Indicates the pressed button.
79403a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     */
79503a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    @Override
79603a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    public void onReceive(Context context, Intent intent) {
79703a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        super.onReceive(context, intent);
798ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        String action = intent.getAction();
799ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)) {
80094ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            sWifiState.onActualStateChange(context, intent);
801ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick        } else if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) {
80294ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick            sBluetoothState.onActualStateChange(context, intent);
8034af6514c78f2e468fe0f8f6070cf0f3e658b34a0Tom O'Neill        } else if (LocationManager.MODE_CHANGED_ACTION.equals(action)) {
804681f79900787c2c40751463ddd8f3476f9b40476David Christie            sLocationState.onActualStateChange(context, intent);
8051d6bf8d46b07cb87d5842324190bc5a31eee5e4bJeff Sharkey        } else if (ContentResolver.ACTION_SYNC_CONN_STATUS_CHANGED.equals(action)) {
806ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick            sSyncState.onActualStateChange(context, intent);
80794ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick        } else if (intent.hasCategory(Intent.CATEGORY_ALTERNATIVE)) {
80803a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff            Uri data = intent.getData();
80903a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff            int buttonId = Integer.parseInt(data.getSchemeSpecificPart());
81003a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff            if (buttonId == BUTTON_WIFI) {
81194ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                sWifiState.toggleState(context);
81203a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff            } else if (buttonId == BUTTON_BRIGHTNESS) {
81303a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff                toggleBrightness(context);
81403a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff            } else if (buttonId == BUTTON_SYNC) {
815ae0ff95272fe2a7e32114ef4565e8c6b52c269b4Brad Fitzpatrick                sSyncState.toggleState(context);
816681f79900787c2c40751463ddd8f3476f9b40476David Christie            } else if (buttonId == BUTTON_LOCATION) {
817681f79900787c2c40751463ddd8f3476f9b40476David Christie                sLocationState.toggleState(context);
81803a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff            } else if (buttonId == BUTTON_BLUETOOTH) {
81994ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick                sBluetoothState.toggleState(context);
82003a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff            }
821046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick        } else {
822046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick            // Don't fall-through to updating the widget.  The Intent
823046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick            // was something unrelated or that our super class took
824046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick            // care of.
825046915c4c8088ea222cb5a0ea8f0d3988e65c1c3Brad Fitzpatrick            return;
82603a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        }
82794ea6e21c337225f01856b65318d34fbaa044ac4Brad Fitzpatrick
82803a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        // State changes fall through
82903a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        updateWidget(context);
83003a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    }
83103a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff
83203a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    /**
833a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani     * Gets brightness level.
83403a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     *
83503a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     * @param context
836a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani     * @return brightness level between 0 and 255.
83703a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     */
838a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani    private static int getBrightness(Context context) {
83903a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        try {
840748ba16a046a6ac4727f2e39db9a933d81d02465Jeff Brown            int brightness = Settings.System.getInt(context.getContentResolver(),
841748ba16a046a6ac4727f2e39db9a933d81d02465Jeff Brown                    Settings.System.SCREEN_BRIGHTNESS);
842748ba16a046a6ac4727f2e39db9a933d81d02465Jeff Brown            return brightness;
84303a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        } catch (Exception e) {
84403a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        }
845a9125d4d59bb3293dd1c92189bec3d0ab9e71d52Amith Yamasani        return 0;
84603a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    }
84703a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff
84803a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    /**
8495c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik     * Gets state of brightness mode.
8505c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik     *
8515c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik     * @param context
8525c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik     * @return true if auto brightness is on.
8535c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik     */
8545c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik    private static boolean getBrightnessMode(Context context) {
8555c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik        try {
856748ba16a046a6ac4727f2e39db9a933d81d02465Jeff Brown            int brightnessMode = Settings.System.getInt(context.getContentResolver(),
857748ba16a046a6ac4727f2e39db9a933d81d02465Jeff Brown                    Settings.System.SCREEN_BRIGHTNESS_MODE);
858748ba16a046a6ac4727f2e39db9a933d81d02465Jeff Brown            return brightnessMode == Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC;
8595c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik        } catch (Exception e) {
8605c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik            Log.d(TAG, "getBrightnessMode: " + e);
8615c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik        }
8625c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik        return false;
8635c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik    }
8645c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik
8655c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik    /**
86603a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     * Increases or decreases the brightness.
86703a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     *
86803a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     * @param context
86903a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff     */
87003a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    private void toggleBrightness(Context context) {
87103a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        try {
872cd03f5320d42290b1619933954a344b59dc55f4fMike Lockwood            IPowerManager power = IPowerManager.Stub.asInterface(
873cd03f5320d42290b1619933954a344b59dc55f4fMike Lockwood                    ServiceManager.getService("power"));
874cd03f5320d42290b1619933954a344b59dc55f4fMike Lockwood            if (power != null) {
875748ba16a046a6ac4727f2e39db9a933d81d02465Jeff Brown                PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
876748ba16a046a6ac4727f2e39db9a933d81d02465Jeff Brown
87703a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff                ContentResolver cr = context.getContentResolver();
87803a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff                int brightness = Settings.System.getInt(cr,
87903a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff                        Settings.System.SCREEN_BRIGHTNESS);
8805c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik                int brightnessMode = Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL;
8815c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik                //Only get brightness setting if available
8825c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik                if (context.getResources().getBoolean(
8835c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik                        com.android.internal.R.bool.config_automatic_brightness_available)) {
8845c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik                    brightnessMode = Settings.System.getInt(cr,
8855c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik                            Settings.System.SCREEN_BRIGHTNESS_MODE);
8865c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik                }
8875c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik
8885c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik                // Rotate AUTO -> MINIMUM -> DEFAULT -> MAXIMUM
88903a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff                // Technically, not a toggle...
8905c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik                if (brightnessMode == Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC) {
891748ba16a046a6ac4727f2e39db9a933d81d02465Jeff Brown                    brightness = pm.getMinimumScreenBrightnessSetting();
8925c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik                    brightnessMode = Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL;
893748ba16a046a6ac4727f2e39db9a933d81d02465Jeff Brown                } else if (brightness < pm.getDefaultScreenBrightnessSetting()) {
894748ba16a046a6ac4727f2e39db9a933d81d02465Jeff Brown                    brightness = pm.getDefaultScreenBrightnessSetting();
895748ba16a046a6ac4727f2e39db9a933d81d02465Jeff Brown                } else if (brightness < pm.getMaximumScreenBrightnessSetting()) {
896748ba16a046a6ac4727f2e39db9a933d81d02465Jeff Brown                    brightness = pm.getMaximumScreenBrightnessSetting();
89703a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff                } else {
8985c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik                    brightnessMode = Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC;
899748ba16a046a6ac4727f2e39db9a933d81d02465Jeff Brown                    brightness = pm.getMinimumScreenBrightnessSetting();
90003a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff                }
9015c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik
902c4a0576473bd14eec1307ae1e0001a1db4fb5e94Ken Shirriff                if (context.getResources().getBoolean(
903c4a0576473bd14eec1307ae1e0001a1db4fb5e94Ken Shirriff                        com.android.internal.R.bool.config_automatic_brightness_available)) {
9045c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik                    // Set screen brightness mode (automatic or manual)
905c4a0576473bd14eec1307ae1e0001a1db4fb5e94Ken Shirriff                    Settings.System.putInt(context.getContentResolver(),
906c4a0576473bd14eec1307ae1e0001a1db4fb5e94Ken Shirriff                            Settings.System.SCREEN_BRIGHTNESS_MODE,
9075c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik                            brightnessMode);
9085bc5cedc7ae2808ed487d90ff86caedc722021dbErik                } else {
9095bc5cedc7ae2808ed487d90ff86caedc722021dbErik                    // Make sure we set the brightness if automatic mode isn't available
9105bc5cedc7ae2808ed487d90ff86caedc722021dbErik                    brightnessMode = Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL;
9115c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik                }
9125c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik                if (brightnessMode == Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL) {
913748ba16a046a6ac4727f2e39db9a933d81d02465Jeff Brown                    power.setTemporaryScreenBrightnessSettingOverride(brightness);
9145c9f9ce263b1ce24831d3bb2cc924ea40de1ec7aErik                    Settings.System.putInt(cr, Settings.System.SCREEN_BRIGHTNESS, brightness);
915c4a0576473bd14eec1307ae1e0001a1db4fb5e94Ken Shirriff                }
91603a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff            }
91703a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        } catch (RemoteException e) {
91803a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff            Log.d(TAG, "toggleBrightness: " + e);
91903a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        } catch (Settings.SettingNotFoundException e) {
92003a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff            Log.d(TAG, "toggleBrightness: " + e);
92103a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff        }
92203a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff    }
92349c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani
92449c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani    /** Observer to watch for changes to the BRIGHTNESS setting */
92549c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani    private static class SettingsObserver extends ContentObserver {
92649c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani
92749c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani        private Context mContext;
92849c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani
92949c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani        SettingsObserver(Handler handler, Context context) {
93049c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani            super(handler);
93149c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani            mContext = context;
93249c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani        }
93349c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani
93449c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani        void startObserving() {
93549c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani            ContentResolver resolver = mContext.getContentResolver();
93649c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani            // Listen to brightness and brightness mode
93749c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani            resolver.registerContentObserver(Settings.System
93849c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani                    .getUriFor(Settings.System.SCREEN_BRIGHTNESS), false, this);
93949c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani            resolver.registerContentObserver(Settings.System
94049c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani                    .getUriFor(Settings.System.SCREEN_BRIGHTNESS_MODE), false, this);
94149c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani        }
94249c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani
94349c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani        void stopObserving() {
94449c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani            mContext.getContentResolver().unregisterContentObserver(this);
94549c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani        }
94649c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani
94749c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani        @Override
94849c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani        public void onChange(boolean selfChange) {
94949c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani            updateWidget(mContext);
95049c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani        }
95149c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani    }
95249c3ef901bd3add86511a17417ee5394771c33f6Amith Yamasani
95303a6110b4f62e72592b451c05848cfaad8c65324Ken Shirriff}
954