Home | History | Annotate | Download | only in widget
      1 /*
      2  * Copyright (C) 2009 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.settings.widget;
     18 
     19 import android.app.PendingIntent;
     20 import android.appwidget.AppWidgetManager;
     21 import android.appwidget.AppWidgetProvider;
     22 import android.bluetooth.BluetoothAdapter;
     23 import android.content.ComponentName;
     24 import android.content.ContentResolver;
     25 import android.content.Context;
     26 import android.content.IContentService;
     27 import android.content.Intent;
     28 import android.content.pm.PackageManager;
     29 import android.location.LocationManager;
     30 import android.net.ConnectivityManager;
     31 import android.net.Uri;
     32 import android.net.wifi.WifiManager;
     33 import android.os.AsyncTask;
     34 import android.os.IPowerManager;
     35 import android.os.RemoteException;
     36 import android.os.ServiceManager;
     37 import android.provider.Settings;
     38 import android.util.Log;
     39 import android.widget.RemoteViews;
     40 import com.android.settings.R;
     41 import com.android.settings.bluetooth.LocalBluetoothManager;
     42 
     43 /**
     44  * Provides control of power-related settings from a widget.
     45  */
     46 public class SettingsAppWidgetProvider extends AppWidgetProvider {
     47     static final String TAG = "SettingsAppWidgetProvider";
     48 
     49     static final ComponentName THIS_APPWIDGET =
     50             new ComponentName("com.android.settings",
     51                     "com.android.settings.widget.SettingsAppWidgetProvider");
     52 
     53     private static LocalBluetoothManager sLocalBluetoothManager = null;
     54 
     55     private static final int BUTTON_WIFI = 0;
     56     private static final int BUTTON_BRIGHTNESS = 1;
     57     private static final int BUTTON_SYNC = 2;
     58     private static final int BUTTON_GPS = 3;
     59     private static final int BUTTON_BLUETOOTH = 4;
     60 
     61     // This widget keeps track of two sets of states:
     62     // "3-state": STATE_DISABLED, STATE_ENABLED, STATE_INTERMEDIATE
     63     // "5-state": STATE_DISABLED, STATE_ENABLED, STATE_TURNING_ON, STATE_TURNING_OFF, STATE_UNKNOWN
     64     private static final int STATE_DISABLED = 0;
     65     private static final int STATE_ENABLED = 1;
     66     private static final int STATE_TURNING_ON = 2;
     67     private static final int STATE_TURNING_OFF = 3;
     68     private static final int STATE_UNKNOWN = 4;
     69     private static final int STATE_INTERMEDIATE = 5;
     70 
     71 
     72     /**
     73      * Minimum and maximum brightnesses.  Don't go to 0 since that makes the display unusable
     74      */
     75     private static final int MINIMUM_BACKLIGHT = android.os.Power.BRIGHTNESS_DIM + 10;
     76     private static final int MAXIMUM_BACKLIGHT = android.os.Power.BRIGHTNESS_ON;
     77     private static final int DEFAULT_BACKLIGHT = (int) (android.os.Power.BRIGHTNESS_ON * 0.4f);
     78 
     79     private static final StateTracker sWifiState = new WifiStateTracker();
     80     private static final StateTracker sBluetoothState = new BluetoothStateTracker();
     81 
     82     /**
     83      * The state machine for Wifi and Bluetooth toggling, tracking
     84      * reality versus the user's intent.
     85      *
     86      * This is necessary because reality moves relatively slowly
     87      * (turning on & off radio drivers), compared to user's
     88      * expectations.
     89      */
     90     private abstract static class StateTracker {
     91         // Is the state in the process of changing?
     92         private boolean mInTransition = false;
     93         private Boolean mActualState = null;  // initially not set
     94         private Boolean mIntendedState = null;  // initially not set
     95 
     96         // Did a toggle request arrive while a state update was
     97         // already in-flight?  If so, the mIntendedState needs to be
     98         // requested when the other one is done, unless we happened to
     99         // arrive at that state already.
    100         private boolean mDeferredStateChangeRequestNeeded = false;
    101 
    102         /**
    103          * User pressed a button to change the state.  Something
    104          * should immediately appear to the user afterwards, even if
    105          * we effectively do nothing.  Their press must be heard.
    106          */
    107         public final void toggleState(Context context) {
    108             int currentState = getTriState(context);
    109             boolean newState = false;
    110             switch (currentState) {
    111                 case STATE_ENABLED:
    112                     newState = false;
    113                     break;
    114                 case STATE_DISABLED:
    115                     newState = true;
    116                     break;
    117                 case STATE_INTERMEDIATE:
    118                     if (mIntendedState != null) {
    119                         newState = !mIntendedState;
    120                     }
    121                     break;
    122             }
    123             mIntendedState = newState;
    124             if (mInTransition) {
    125                 // We don't send off a transition request if we're
    126                 // already transitioning.  Makes our state tracking
    127                 // easier, and is probably nicer on lower levels.
    128                 // (even though they should be able to take it...)
    129                 mDeferredStateChangeRequestNeeded = true;
    130             } else {
    131                 mInTransition = true;
    132                 requestStateChange(context, newState);
    133             }
    134         }
    135 
    136         /**
    137          * Update internal state from a broadcast state change.
    138          */
    139         public abstract void onActualStateChange(Context context, Intent intent);
    140 
    141         /**
    142          * Sets the value that we're now in.  To be called from onActualStateChange.
    143          *
    144          * @param newState one of STATE_DISABLED, STATE_ENABLED, STATE_TURNING_ON,
    145          *                 STATE_TURNING_OFF, STATE_UNKNOWN
    146          */
    147         protected final void setCurrentState(Context context, int newState) {
    148             final boolean wasInTransition = mInTransition;
    149             switch (newState) {
    150                 case STATE_DISABLED:
    151                     mInTransition = false;
    152                     mActualState = false;
    153                     break;
    154                 case STATE_ENABLED:
    155                     mInTransition = false;
    156                     mActualState = true;
    157                     break;
    158                 case STATE_TURNING_ON:
    159                     mInTransition = true;
    160                     mActualState = false;
    161                     break;
    162                 case STATE_TURNING_OFF:
    163                     mInTransition = true;
    164                     mActualState = true;
    165                     break;
    166             }
    167 
    168             if (wasInTransition && !mInTransition) {
    169                 if (mDeferredStateChangeRequestNeeded) {
    170                     Log.v(TAG, "processing deferred state change");
    171                     if (mActualState != null && mIntendedState != null &&
    172                         mIntendedState.equals(mActualState)) {
    173                         Log.v(TAG, "... but intended state matches, so no changes.");
    174                     } else if (mIntendedState != null) {
    175                         mInTransition = true;
    176                         requestStateChange(context, mIntendedState);
    177                     }
    178                     mDeferredStateChangeRequestNeeded = false;
    179                 }
    180             }
    181         }
    182 
    183 
    184         /**
    185          * If we're in a transition mode, this returns true if we're
    186          * transitioning towards being enabled.
    187          */
    188         public final boolean isTurningOn() {
    189             return mIntendedState != null && mIntendedState;
    190         }
    191 
    192         /**
    193          * Returns simplified 3-state value from underlying 5-state.
    194          *
    195          * @param context
    196          * @return STATE_ENABLED, STATE_DISABLED, or STATE_INTERMEDIATE
    197          */
    198         public final int getTriState(Context context) {
    199             if (mInTransition) {
    200                 // If we know we just got a toggle request recently
    201                 // (which set mInTransition), don't even ask the
    202                 // underlying interface for its state.  We know we're
    203                 // changing.  This avoids blocking the UI thread
    204                 // during UI refresh post-toggle if the underlying
    205                 // service state accessor has coarse locking on its
    206                 // state (to be fixed separately).
    207                 return STATE_INTERMEDIATE;
    208             }
    209             switch (getActualState(context)) {
    210                 case STATE_DISABLED:
    211                     return STATE_DISABLED;
    212                 case STATE_ENABLED:
    213                     return STATE_ENABLED;
    214                 default:
    215                     return STATE_INTERMEDIATE;
    216             }
    217         }
    218 
    219         /**
    220          * Gets underlying actual state.
    221          *
    222          * @param context
    223          * @return STATE_ENABLED, STATE_DISABLED, STATE_ENABLING, STATE_DISABLING,
    224          *         or or STATE_UNKNOWN.
    225          */
    226         public abstract int getActualState(Context context);
    227 
    228         /**
    229          * Actually make the desired change to the underlying radio
    230          * API.
    231          */
    232         protected abstract void requestStateChange(Context context, boolean desiredState);
    233     }
    234 
    235     /**
    236      * Subclass of StateTracker to get/set Wifi state.
    237      */
    238     private static final class WifiStateTracker extends StateTracker {
    239         @Override
    240         public int getActualState(Context context) {
    241             WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
    242             if (wifiManager != null) {
    243                 return wifiStateToFiveState(wifiManager.getWifiState());
    244             }
    245             return STATE_UNKNOWN;
    246         }
    247 
    248         @Override
    249         protected void requestStateChange(Context context, final boolean desiredState) {
    250             final WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
    251             if (wifiManager == null) {
    252                 Log.d(TAG, "No wifiManager.");
    253                 return;
    254             }
    255 
    256             // Actually request the wifi change and persistent
    257             // settings write off the UI thread, as it can take a
    258             // user-noticeable amount of time, especially if there's
    259             // disk contention.
    260             new AsyncTask<Void, Void, Void>() {
    261                 @Override
    262                 protected Void doInBackground(Void... args) {
    263                     /**
    264                      * Disable tethering if enabling Wifi
    265                      */
    266                     int wifiApState = wifiManager.getWifiApState();
    267                     if (desiredState && ((wifiApState == WifiManager.WIFI_AP_STATE_ENABLING) ||
    268                                          (wifiApState == WifiManager.WIFI_AP_STATE_ENABLED))) {
    269                         wifiManager.setWifiApEnabled(null, false);
    270                     }
    271 
    272                     wifiManager.setWifiEnabled(desiredState);
    273                     return null;
    274                 }
    275             }.execute();
    276         }
    277 
    278         @Override
    279         public void onActualStateChange(Context context, Intent intent) {
    280             if (!WifiManager.WIFI_STATE_CHANGED_ACTION.equals(intent.getAction())) {
    281                 return;
    282             }
    283             int wifiState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, -1);
    284             setCurrentState(context, wifiStateToFiveState(wifiState));
    285         }
    286 
    287         /**
    288          * Converts WifiManager's state values into our
    289          * Wifi/Bluetooth-common state values.
    290          */
    291         private static int wifiStateToFiveState(int wifiState) {
    292             switch (wifiState) {
    293                 case WifiManager.WIFI_STATE_DISABLED:
    294                     return STATE_DISABLED;
    295                 case WifiManager.WIFI_STATE_ENABLED:
    296                     return STATE_ENABLED;
    297                 case WifiManager.WIFI_STATE_DISABLING:
    298                     return STATE_TURNING_OFF;
    299                 case WifiManager.WIFI_STATE_ENABLING:
    300                     return STATE_TURNING_ON;
    301                 default:
    302                     return STATE_UNKNOWN;
    303             }
    304         }
    305     }
    306 
    307     /**
    308      * Subclass of StateTracker to get/set Bluetooth state.
    309      */
    310     private static final class BluetoothStateTracker extends StateTracker {
    311 
    312         @Override
    313         public int getActualState(Context context) {
    314             if (sLocalBluetoothManager == null) {
    315                 sLocalBluetoothManager = LocalBluetoothManager.getInstance(context);
    316                 if (sLocalBluetoothManager == null) {
    317                     return STATE_UNKNOWN;  // On emulator?
    318                 }
    319             }
    320             return bluetoothStateToFiveState(sLocalBluetoothManager.getBluetoothState());
    321         }
    322 
    323         @Override
    324         protected void requestStateChange(Context context, final boolean desiredState) {
    325             if (sLocalBluetoothManager == null) {
    326                 Log.d(TAG, "No LocalBluetoothManager");
    327                 return;
    328             }
    329             // Actually request the Bluetooth change and persistent
    330             // settings write off the UI thread, as it can take a
    331             // user-noticeable amount of time, especially if there's
    332             // disk contention.
    333             new AsyncTask<Void, Void, Void>() {
    334                 @Override
    335                 protected Void doInBackground(Void... args) {
    336                     sLocalBluetoothManager.setBluetoothEnabled(desiredState);
    337                     return null;
    338                 }
    339             }.execute();
    340         }
    341 
    342         @Override
    343         public void onActualStateChange(Context context, Intent intent) {
    344             if (!BluetoothAdapter.ACTION_STATE_CHANGED.equals(intent.getAction())) {
    345                 return;
    346             }
    347             int bluetoothState = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1);
    348             setCurrentState(context, bluetoothStateToFiveState(bluetoothState));
    349         }
    350 
    351         /**
    352          * Converts BluetoothAdapter's state values into our
    353          * Wifi/Bluetooth-common state values.
    354          */
    355         private static int bluetoothStateToFiveState(int bluetoothState) {
    356             switch (bluetoothState) {
    357                 case BluetoothAdapter.STATE_OFF:
    358                     return STATE_DISABLED;
    359                 case BluetoothAdapter.STATE_ON:
    360                     return STATE_ENABLED;
    361                 case BluetoothAdapter.STATE_TURNING_ON:
    362                     return STATE_TURNING_ON;
    363                 case BluetoothAdapter.STATE_TURNING_OFF:
    364                     return STATE_TURNING_OFF;
    365                 default:
    366                     return STATE_UNKNOWN;
    367             }
    368         }
    369     }
    370 
    371 
    372     @Override
    373     public void onUpdate(Context context, AppWidgetManager appWidgetManager,
    374             int[] appWidgetIds) {
    375         // Update each requested appWidgetId
    376         RemoteViews view = buildUpdate(context, -1);
    377 
    378         for (int i = 0; i < appWidgetIds.length; i++) {
    379             appWidgetManager.updateAppWidget(appWidgetIds[i], view);
    380         }
    381     }
    382 
    383     @Override
    384     public void onEnabled(Context context) {
    385         PackageManager pm = context.getPackageManager();
    386         pm.setComponentEnabledSetting(
    387                 new ComponentName("com.android.settings", ".widget.SettingsAppWidgetProvider"),
    388                 PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
    389                 PackageManager.DONT_KILL_APP);
    390     }
    391 
    392     @Override
    393     public void onDisabled(Context context) {
    394         Class clazz = com.android.settings.widget.SettingsAppWidgetProvider.class;
    395         PackageManager pm = context.getPackageManager();
    396         pm.setComponentEnabledSetting(
    397                 new ComponentName("com.android.settings", ".widget.SettingsAppWidgetProvider"),
    398                 PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
    399                 PackageManager.DONT_KILL_APP);
    400     }
    401 
    402     /**
    403      * Load image for given widget and build {@link RemoteViews} for it.
    404      */
    405     static RemoteViews buildUpdate(Context context, int appWidgetId) {
    406         RemoteViews views = new RemoteViews(context.getPackageName(),
    407                 R.layout.widget);
    408         views.setOnClickPendingIntent(R.id.btn_wifi, getLaunchPendingIntent(context, appWidgetId,
    409                 BUTTON_WIFI));
    410         views.setOnClickPendingIntent(R.id.btn_brightness,
    411                 getLaunchPendingIntent(context,
    412                         appWidgetId, BUTTON_BRIGHTNESS));
    413         views.setOnClickPendingIntent(R.id.btn_sync,
    414                 getLaunchPendingIntent(context,
    415                         appWidgetId, BUTTON_SYNC));
    416         views.setOnClickPendingIntent(R.id.btn_gps,
    417                 getLaunchPendingIntent(context, appWidgetId, BUTTON_GPS));
    418         views.setOnClickPendingIntent(R.id.btn_bluetooth,
    419                 getLaunchPendingIntent(context,
    420                         appWidgetId, BUTTON_BLUETOOTH));
    421 
    422         updateButtons(views, context);
    423         return views;
    424     }
    425 
    426     /**
    427      * Updates the widget when something changes, or when a button is pushed.
    428      *
    429      * @param context
    430      */
    431     public static void updateWidget(Context context) {
    432         RemoteViews views = buildUpdate(context, -1);
    433         // Update specific list of appWidgetIds if given, otherwise default to all
    434         final AppWidgetManager gm = AppWidgetManager.getInstance(context);
    435         gm.updateAppWidget(THIS_APPWIDGET, views);
    436     }
    437 
    438     /**
    439      * Updates the buttons based on the underlying states of wifi, etc.
    440      *
    441      * @param views   The RemoteViews to update.
    442      * @param context
    443      */
    444     private static void updateButtons(RemoteViews views, Context context) {
    445         switch (sWifiState.getTriState(context)) {
    446             case STATE_DISABLED:
    447                 views.setImageViewResource(R.id.img_wifi,
    448                                            R.drawable.ic_appwidget_settings_wifi_off);
    449                 views.setImageViewResource(R.id.ind_wifi,
    450                                            R.drawable.appwidget_settings_ind_off_l);
    451                 break;
    452             case STATE_ENABLED:
    453                 views.setImageViewResource(R.id.img_wifi,
    454                                            R.drawable.ic_appwidget_settings_wifi_on);
    455                 views.setImageViewResource(R.id.ind_wifi,
    456                                            R.drawable.appwidget_settings_ind_on_l);
    457                 break;
    458             case STATE_INTERMEDIATE:
    459                 // In the transitional state, the bottom green bar
    460                 // shows the tri-state (on, off, transitioning), but
    461                 // the top dark-gray-or-bright-white logo shows the
    462                 // user's intent.  This is much easier to see in
    463                 // sunlight.
    464                 if (sWifiState.isTurningOn()) {
    465                     views.setImageViewResource(R.id.img_wifi,
    466                                                R.drawable.ic_appwidget_settings_wifi_on);
    467                     views.setImageViewResource(R.id.ind_wifi,
    468                                                R.drawable.appwidget_settings_ind_mid_l);
    469                 } else {
    470                     views.setImageViewResource(R.id.img_wifi,
    471                                                R.drawable.ic_appwidget_settings_wifi_off);
    472                     views.setImageViewResource(R.id.ind_wifi,
    473                                                R.drawable.appwidget_settings_ind_off_l);
    474                 }
    475                 break;
    476         }
    477         if (getBrightnessMode(context)) {
    478             views.setImageViewResource(R.id.img_brightness,
    479                                        R.drawable.ic_appwidget_settings_brightness_auto);
    480             views.setImageViewResource(R.id.ind_brightness,
    481                                        R.drawable.appwidget_settings_ind_on_r);
    482         } else if (getBrightness(context)) {
    483             views.setImageViewResource(R.id.img_brightness,
    484                                        R.drawable.ic_appwidget_settings_brightness_on);
    485             views.setImageViewResource(R.id.ind_brightness,
    486                                        R.drawable.appwidget_settings_ind_on_r);
    487         } else {
    488             views.setImageViewResource(R.id.img_brightness,
    489                                        R.drawable.ic_appwidget_settings_brightness_off);
    490             views.setImageViewResource(R.id.ind_brightness,
    491                                        R.drawable.appwidget_settings_ind_off_r);
    492         }
    493         if (getSync(context)) {
    494             views.setImageViewResource(R.id.img_sync, R.drawable.ic_appwidget_settings_sync_on);
    495             views.setImageViewResource(R.id.ind_sync, R.drawable.appwidget_settings_ind_on_c);
    496         } else {
    497             views.setImageViewResource(R.id.img_sync, R.drawable.ic_appwidget_settings_sync_off);
    498             views.setImageViewResource(R.id.ind_sync, R.drawable.appwidget_settings_ind_off_c);
    499         }
    500         if (getGpsState(context)) {
    501             views.setImageViewResource(R.id.img_gps, R.drawable.ic_appwidget_settings_gps_on);
    502             views.setImageViewResource(R.id.ind_gps, R.drawable.appwidget_settings_ind_on_c);
    503         } else {
    504             views.setImageViewResource(R.id.img_gps, R.drawable.ic_appwidget_settings_gps_off);
    505             views.setImageViewResource(R.id.ind_gps, R.drawable.appwidget_settings_ind_off_c);
    506         }
    507         switch (sBluetoothState.getTriState(context)) {
    508             case STATE_DISABLED:
    509                 views.setImageViewResource(R.id.img_bluetooth,
    510                                            R.drawable.ic_appwidget_settings_bluetooth_off);
    511                 views.setImageViewResource(R.id.ind_bluetooth,
    512                                            R.drawable.appwidget_settings_ind_off_c);
    513                 break;
    514             case STATE_ENABLED:
    515                 views.setImageViewResource(R.id.img_bluetooth,
    516                                            R.drawable.ic_appwidget_settings_bluetooth_on);
    517                 views.setImageViewResource(R.id.ind_bluetooth,
    518                                            R.drawable.appwidget_settings_ind_on_c);
    519                 break;
    520             case STATE_INTERMEDIATE:
    521                 // In the transitional state, the bottom green bar
    522                 // shows the tri-state (on, off, transitioning), but
    523                 // the top dark-gray-or-bright-white logo shows the
    524                 // user's intent.  This is much easier to see in
    525                 // sunlight.
    526                 if (sBluetoothState.isTurningOn()) {
    527                     views.setImageViewResource(R.id.img_bluetooth,
    528                                                R.drawable.ic_appwidget_settings_bluetooth_on);
    529                     views.setImageViewResource(R.id.ind_bluetooth,
    530                                                R.drawable.appwidget_settings_ind_mid_c);
    531                 } else {
    532                     views.setImageViewResource(R.id.img_bluetooth,
    533                                                R.drawable.ic_appwidget_settings_bluetooth_off);
    534                     views.setImageViewResource(R.id.ind_bluetooth,
    535                                                R.drawable.appwidget_settings_ind_off_c);
    536                 }
    537                 break;
    538         }
    539     }
    540 
    541     /**
    542      * Creates PendingIntent to notify the widget of a button click.
    543      *
    544      * @param context
    545      * @param appWidgetId
    546      * @return
    547      */
    548     private static PendingIntent getLaunchPendingIntent(Context context, int appWidgetId,
    549             int buttonId) {
    550         Intent launchIntent = new Intent();
    551         launchIntent.setClass(context, SettingsAppWidgetProvider.class);
    552         launchIntent.addCategory(Intent.CATEGORY_ALTERNATIVE);
    553         launchIntent.setData(Uri.parse("custom:" + buttonId));
    554         PendingIntent pi = PendingIntent.getBroadcast(context, 0 /* no requestCode */,
    555                 launchIntent, 0 /* no flags */);
    556         return pi;
    557     }
    558 
    559     /**
    560      * Receives and processes a button pressed intent or state change.
    561      *
    562      * @param context
    563      * @param intent  Indicates the pressed button.
    564      */
    565     @Override
    566     public void onReceive(Context context, Intent intent) {
    567         super.onReceive(context, intent);
    568         if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(intent.getAction())) {
    569             sWifiState.onActualStateChange(context, intent);
    570         } else if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(intent.getAction())) {
    571             sBluetoothState.onActualStateChange(context, intent);
    572         } else if (intent.hasCategory(Intent.CATEGORY_ALTERNATIVE)) {
    573             Uri data = intent.getData();
    574             int buttonId = Integer.parseInt(data.getSchemeSpecificPart());
    575             if (buttonId == BUTTON_WIFI) {
    576                 sWifiState.toggleState(context);
    577             } else if (buttonId == BUTTON_BRIGHTNESS) {
    578                 toggleBrightness(context);
    579             } else if (buttonId == BUTTON_SYNC) {
    580                 toggleSync(context);
    581             } else if (buttonId == BUTTON_GPS) {
    582                 toggleGps(context);
    583             } else if (buttonId == BUTTON_BLUETOOTH) {
    584                 sBluetoothState.toggleState(context);
    585             }
    586         } else {
    587             // Don't fall-through to updating the widget.  The Intent
    588             // was something unrelated or that our super class took
    589             // care of.
    590             return;
    591         }
    592 
    593         // State changes fall through
    594         updateWidget(context);
    595     }
    596 
    597     /**
    598      * Gets the state of background data.
    599      *
    600      * @param context
    601      * @return true if enabled
    602      */
    603     private static boolean getBackgroundDataState(Context context) {
    604         ConnectivityManager connManager =
    605                 (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
    606         return connManager.getBackgroundDataSetting();
    607     }
    608 
    609     /**
    610      * Gets the state of auto-sync.
    611      *
    612      * @param context
    613      * @return true if enabled
    614      */
    615     private static boolean getSync(Context context) {
    616         boolean backgroundData = getBackgroundDataState(context);
    617         boolean sync = ContentResolver.getMasterSyncAutomatically();
    618         return backgroundData && sync;
    619     }
    620 
    621     /**
    622      * Toggle auto-sync
    623      *
    624      * @param context
    625      */
    626     private void toggleSync(Context context) {
    627         ConnectivityManager connManager =
    628                 (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
    629         boolean backgroundData = getBackgroundDataState(context);
    630         boolean sync = ContentResolver.getMasterSyncAutomatically();
    631 
    632         // four cases to handle:
    633         // setting toggled from off to on:
    634         // 1. background data was off, sync was off: turn on both
    635         if (!backgroundData && !sync) {
    636             connManager.setBackgroundDataSetting(true);
    637             ContentResolver.setMasterSyncAutomatically(true);
    638         }
    639 
    640         // 2. background data was off, sync was on: turn on background data
    641         if (!backgroundData && sync) {
    642             connManager.setBackgroundDataSetting(true);
    643         }
    644 
    645         // 3. background data was on, sync was off: turn on sync
    646         if (backgroundData && !sync) {
    647             ContentResolver.setMasterSyncAutomatically(true);
    648         }
    649 
    650         // setting toggled from on to off:
    651         // 4. background data was on, sync was on: turn off sync
    652         if (backgroundData && sync) {
    653             ContentResolver.setMasterSyncAutomatically(false);
    654         }
    655     }
    656 
    657     /**
    658      * Gets the state of GPS location.
    659      *
    660      * @param context
    661      * @return true if enabled.
    662      */
    663     private static boolean getGpsState(Context context) {
    664         ContentResolver resolver = context.getContentResolver();
    665         return Settings.Secure.isLocationProviderEnabled(resolver, LocationManager.GPS_PROVIDER);
    666     }
    667 
    668     /**
    669      * Toggles the state of GPS.
    670      *
    671      * @param context
    672      */
    673     private void toggleGps(Context context) {
    674         ContentResolver resolver = context.getContentResolver();
    675         boolean enabled = getGpsState(context);
    676         Settings.Secure.setLocationProviderEnabled(resolver, LocationManager.GPS_PROVIDER,
    677                 !enabled);
    678     }
    679 
    680     /**
    681      * Gets state of brightness.
    682      *
    683      * @param context
    684      * @return true if more than moderately bright.
    685      */
    686     private static boolean getBrightness(Context context) {
    687         try {
    688             IPowerManager power = IPowerManager.Stub.asInterface(
    689                     ServiceManager.getService("power"));
    690             if (power != null) {
    691                 int brightness = Settings.System.getInt(context.getContentResolver(),
    692                         Settings.System.SCREEN_BRIGHTNESS);
    693                 return brightness > 100;
    694             }
    695         } catch (Exception e) {
    696             Log.d(TAG, "getBrightness: " + e);
    697         }
    698         return false;
    699     }
    700 
    701     /**
    702      * Gets state of brightness mode.
    703      *
    704      * @param context
    705      * @return true if auto brightness is on.
    706      */
    707     private static boolean getBrightnessMode(Context context) {
    708         try {
    709             IPowerManager power = IPowerManager.Stub.asInterface(
    710                     ServiceManager.getService("power"));
    711             if (power != null) {
    712                 int brightnessMode = Settings.System.getInt(context.getContentResolver(),
    713                         Settings.System.SCREEN_BRIGHTNESS_MODE);
    714                 return brightnessMode == Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC;
    715             }
    716         } catch (Exception e) {
    717             Log.d(TAG, "getBrightnessMode: " + e);
    718         }
    719         return false;
    720     }
    721 
    722     /**
    723      * Increases or decreases the brightness.
    724      *
    725      * @param context
    726      */
    727     private void toggleBrightness(Context context) {
    728         try {
    729             IPowerManager power = IPowerManager.Stub.asInterface(
    730                     ServiceManager.getService("power"));
    731             if (power != null) {
    732                 ContentResolver cr = context.getContentResolver();
    733                 int brightness = Settings.System.getInt(cr,
    734                         Settings.System.SCREEN_BRIGHTNESS);
    735                 int brightnessMode = Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL;
    736                 //Only get brightness setting if available
    737                 if (context.getResources().getBoolean(
    738                         com.android.internal.R.bool.config_automatic_brightness_available)) {
    739                     brightnessMode = Settings.System.getInt(cr,
    740                             Settings.System.SCREEN_BRIGHTNESS_MODE);
    741                 }
    742 
    743                 // Rotate AUTO -> MINIMUM -> DEFAULT -> MAXIMUM
    744                 // Technically, not a toggle...
    745                 if (brightnessMode == Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC) {
    746                     brightness = MINIMUM_BACKLIGHT;
    747                     brightnessMode = Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL;
    748                 } else if (brightness < DEFAULT_BACKLIGHT) {
    749                     brightness = DEFAULT_BACKLIGHT;
    750                 } else if (brightness < MAXIMUM_BACKLIGHT) {
    751                     brightness = MAXIMUM_BACKLIGHT;
    752                 } else {
    753                     brightnessMode = Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC;
    754                     brightness = MINIMUM_BACKLIGHT;
    755                 }
    756 
    757                 if (context.getResources().getBoolean(
    758                         com.android.internal.R.bool.config_automatic_brightness_available)) {
    759                     // Set screen brightness mode (automatic or manual)
    760                     Settings.System.putInt(context.getContentResolver(),
    761                             Settings.System.SCREEN_BRIGHTNESS_MODE,
    762                             brightnessMode);
    763                 } else {
    764                     // Make sure we set the brightness if automatic mode isn't available
    765                     brightnessMode = Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL;
    766                 }
    767                 if (brightnessMode == Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL) {
    768                     power.setBacklightBrightness(brightness);
    769                     Settings.System.putInt(cr, Settings.System.SCREEN_BRIGHTNESS, brightness);
    770                 }
    771             }
    772         } catch (RemoteException e) {
    773             Log.d(TAG, "toggleBrightness: " + e);
    774         } catch (Settings.SettingNotFoundException e) {
    775             Log.d(TAG, "toggleBrightness: " + e);
    776         }
    777     }
    778 }
    779