OSDN Git Service

2fd618cddfda1ce799a2b64a2918bcee26915f90
[android-x86/packages-apps-Settings.git] / src / com / android / settings / widget / SettingsAppWidgetProvider.java
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.IPowerManager;
34 import android.os.RemoteException;
35 import android.os.ServiceManager;
36 import android.provider.Settings;
37 import android.util.Log;
38 import android.widget.RemoteViews;
39 import android.widget.Toast;
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                 boolean showToast = newState;  // only show Toast on the up transition
133                 requestStateChange(context, newState, showToast);
134             }
135         }
136
137         /**
138          * Update internal state from a broadcast state change.
139          */
140         public abstract void onActualStateChange(Context context, Intent intent);
141
142         /**
143          * Sets the value that we're now in.  To be called from onActualStateChange.
144          *
145          * @param newState one of STATE_DISABLED, STATE_ENABLED, STATE_TURNING_ON,
146          *                 STATE_TURNING_OFF, STATE_UNKNOWN
147          */
148         protected final void setCurrentState(Context context, int newState) {
149             boolean wasInTransition = mInTransition;
150             switch (newState) {
151                 case STATE_DISABLED:
152                     mInTransition = false;
153                     mActualState = false;
154                     break;
155                 case STATE_ENABLED:
156                     mInTransition = false;
157                     mActualState = true;
158                     break;
159                 case STATE_TURNING_ON:
160                     mInTransition = true;
161                     mActualState = false;
162                     break;
163                 case STATE_TURNING_OFF:
164                     mInTransition = true;
165                     mActualState = true;
166                     break;
167             }
168
169             if (wasInTransition && !mInTransition) {
170                 if (mDeferredStateChangeRequestNeeded) {
171                     Log.v(TAG, "processing deferred state change");
172                     if (mActualState != null && mIntendedState != null &&
173                         mIntendedState.equals(mActualState)) {
174                         Log.v(TAG, "... but intended state matches, so no changes.");
175                     } else if (mIntendedState != null) {
176                         mInTransition = true;
177                         requestStateChange(context, mIntendedState, false /* no toast */);
178                     }
179                     mDeferredStateChangeRequestNeeded = false;
180                 }
181             }
182         }
183
184
185         /**
186          * If we're in a transition mode, this returns true if we're
187          * transitioning towards being enabled.
188          */
189         public final boolean isTurningOn() {
190             return mIntendedState != null && mIntendedState;
191         }
192
193         /**
194          * Returns simplified 3-state value from underlying 5-state.
195          *
196          * @param context
197          * @return STATE_ENABLED, STATE_DISABLED, or STATE_INTERMEDIATE
198          */
199         public final int getTriState(Context context) {
200             switch (getActualState(context)) {
201                 case STATE_DISABLED:
202                     return STATE_DISABLED;
203                 case STATE_ENABLED:
204                     return STATE_ENABLED;
205                 default:
206                     return STATE_INTERMEDIATE;
207             }
208         }
209
210         /**
211          * Gets underlying actual state.
212          *
213          * @param context
214          * @return STATE_ENABLED, STATE_DISABLED, STATE_ENABLING, STATE_DISABLING,
215          *         or or STATE_UNKNOWN.
216          */
217         public abstract int getActualState(Context context);
218
219         /**
220          * Actually make the desired change to the underlying radio
221          * API.
222          */
223         protected abstract void requestStateChange(Context context,
224                                                    boolean desiredState, boolean withToast);
225     }
226
227     /**
228      * Subclass of StateTracker to get/set Wifi state.
229      */
230     private static final class WifiStateTracker extends StateTracker {
231         @Override
232         public int getActualState(Context context) {
233             WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
234             if (wifiManager != null) {
235                 return wifiStateToFiveState(wifiManager.getWifiState());
236             }
237             return STATE_UNKNOWN;
238         }
239
240         @Override
241         protected void requestStateChange(Context context,
242                                           boolean desiredState, boolean withToast) {
243             WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
244             if (wifiManager == null) {
245                 Log.d(TAG, "No wifiManager.");
246                 return;
247             }
248             if (withToast) {
249                 Toast.makeText(context, R.string.gadget_toggle_wifi, Toast.LENGTH_SHORT).show();
250             }
251             wifiManager.setWifiEnabled(desiredState);
252         }
253
254         @Override
255         public void onActualStateChange(Context context, Intent intent) {
256             if (!WifiManager.WIFI_STATE_CHANGED_ACTION.equals(intent.getAction())) {
257                 return;
258             }
259             int wifiState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, -1);
260             setCurrentState(context, wifiStateToFiveState(wifiState));
261         }
262
263         /**
264          * Converts WifiManager's state values into our
265          * Wifi/Bluetooth-common state values.
266          */
267         private static int wifiStateToFiveState(int wifiState) {
268             switch (wifiState) {
269                 case WifiManager.WIFI_STATE_DISABLED:
270                     return STATE_DISABLED;
271                 case WifiManager.WIFI_STATE_ENABLED:
272                     return STATE_ENABLED;
273                 case WifiManager.WIFI_STATE_DISABLING:
274                     return STATE_TURNING_OFF;
275                 case WifiManager.WIFI_STATE_ENABLING:
276                     return STATE_TURNING_ON;
277                 default:
278                     return STATE_UNKNOWN;
279             }
280         }
281     }
282
283     /**
284      * Subclass of StateTracker to get/set Bluetooth state.
285      */
286     private static final class BluetoothStateTracker extends StateTracker {
287
288         @Override
289         public int getActualState(Context context) {
290             if (sLocalBluetoothManager == null) {
291                 sLocalBluetoothManager = LocalBluetoothManager.getInstance(context);
292                 if (sLocalBluetoothManager == null) {
293                     return STATE_UNKNOWN;  // On emulator?
294                 }
295             }
296             return bluetoothStateToFiveState(sLocalBluetoothManager.getBluetoothState());
297         }
298
299         @Override
300         protected void requestStateChange(Context context,
301                                           boolean desiredState, boolean withToast) {
302             if (sLocalBluetoothManager == null) {
303                 Log.d(TAG, "No LocalBluetoothManager");
304                 return;
305             }
306             if (withToast) {
307                 Toast.makeText(context,
308                                R.string.gadget_toggle_bluetooth, Toast.LENGTH_SHORT).show();
309             }
310             sLocalBluetoothManager.setBluetoothEnabled(desiredState);
311         }
312
313         @Override
314         public void onActualStateChange(Context context, Intent intent) {
315             if (!BluetoothAdapter.ACTION_STATE_CHANGED.equals(intent.getAction())) {
316                 return;
317             }
318             int bluetoothState = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1);
319             setCurrentState(context, bluetoothStateToFiveState(bluetoothState));
320         }
321
322         /**
323          * Converts BluetoothAdapter's state values into our
324          * Wifi/Bluetooth-common state values.
325          */
326         private static int bluetoothStateToFiveState(int bluetoothState) {
327             switch (bluetoothState) {
328                 case BluetoothAdapter.STATE_OFF:
329                     return STATE_DISABLED;
330                 case BluetoothAdapter.STATE_ON:
331                     return STATE_ENABLED;
332                 case BluetoothAdapter.STATE_TURNING_ON:
333                     return STATE_TURNING_ON;
334                 case BluetoothAdapter.STATE_TURNING_OFF:
335                     return STATE_TURNING_OFF;
336                 default:
337                     return STATE_UNKNOWN;
338             }
339         }
340     }
341
342
343     @Override
344     public void onUpdate(Context context, AppWidgetManager appWidgetManager,
345             int[] appWidgetIds) {
346         // Update each requested appWidgetId
347         RemoteViews view = buildUpdate(context, -1);
348
349         for (int i = 0; i < appWidgetIds.length; i++) {
350             appWidgetManager.updateAppWidget(appWidgetIds[i], view);
351         }
352     }
353
354     @Override
355     public void onEnabled(Context context) {
356         PackageManager pm = context.getPackageManager();
357         pm.setComponentEnabledSetting(
358                 new ComponentName("com.android.settings", ".widget.SettingsAppWidgetProvider"),
359                 PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
360                 PackageManager.DONT_KILL_APP);
361     }
362
363     @Override
364     public void onDisabled(Context context) {
365         Class clazz = com.android.settings.widget.SettingsAppWidgetProvider.class;
366         PackageManager pm = context.getPackageManager();
367         pm.setComponentEnabledSetting(
368                 new ComponentName("com.android.settings", ".widget.SettingsAppWidgetProvider"),
369                 PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
370                 PackageManager.DONT_KILL_APP);
371     }
372
373     /**
374      * Load image for given widget and build {@link RemoteViews} for it.
375      */
376     static RemoteViews buildUpdate(Context context, int appWidgetId) {
377         RemoteViews views = new RemoteViews(context.getPackageName(),
378                 R.layout.widget);
379         views.setOnClickPendingIntent(R.id.btn_wifi, getLaunchPendingIntent(context, appWidgetId,
380                 BUTTON_WIFI));
381         views.setOnClickPendingIntent(R.id.btn_brightness,
382                 getLaunchPendingIntent(context,
383                         appWidgetId, BUTTON_BRIGHTNESS));
384         views.setOnClickPendingIntent(R.id.btn_sync,
385                 getLaunchPendingIntent(context,
386                         appWidgetId, BUTTON_SYNC));
387         views.setOnClickPendingIntent(R.id.btn_gps,
388                 getLaunchPendingIntent(context, appWidgetId, BUTTON_GPS));
389         views.setOnClickPendingIntent(R.id.btn_bluetooth,
390                 getLaunchPendingIntent(context,
391                         appWidgetId, BUTTON_BLUETOOTH));
392
393         updateButtons(views, context);
394         return views;
395     }
396
397     /**
398      * Updates the widget when something changes, or when a button is pushed.
399      *
400      * @param context
401      */
402     public static void updateWidget(Context context) {
403         RemoteViews views = buildUpdate(context, -1);
404         // Update specific list of appWidgetIds if given, otherwise default to all
405         final AppWidgetManager gm = AppWidgetManager.getInstance(context);
406         gm.updateAppWidget(THIS_APPWIDGET, views);
407     }
408
409     /**
410      * Updates the buttons based on the underlying states of wifi, etc.
411      *
412      * @param views   The RemoteViews to update.
413      * @param context
414      */
415     private static void updateButtons(RemoteViews views, Context context) {
416         switch (sWifiState.getTriState(context)) {
417             case STATE_DISABLED:
418                 views.setImageViewResource(R.id.img_wifi,
419                                            R.drawable.ic_appwidget_settings_wifi_off);
420                 views.setImageViewResource(R.id.ind_wifi,
421                                            R.drawable.appwidget_settings_ind_off_l);
422                 break;
423             case STATE_ENABLED:
424                 views.setImageViewResource(R.id.img_wifi,
425                                            R.drawable.ic_appwidget_settings_wifi_on);
426                 views.setImageViewResource(R.id.ind_wifi,
427                                            R.drawable.appwidget_settings_ind_on_l);
428                 break;
429             case STATE_INTERMEDIATE:
430                 // In the transitional state, the bottom green bar
431                 // shows the tri-state (on, off, transitioning), but
432                 // the top dark-gray-or-bright-white logo shows the
433                 // user's intent.  This is much easier to see in
434                 // sunlight.
435                 if (sWifiState.isTurningOn()) {
436                     views.setImageViewResource(R.id.img_wifi,
437                                                R.drawable.ic_appwidget_settings_wifi_on);
438                     views.setImageViewResource(R.id.ind_wifi,
439                                                R.drawable.appwidget_settings_ind_mid_l);
440                 } else {
441                     views.setImageViewResource(R.id.img_wifi,
442                                                R.drawable.ic_appwidget_settings_wifi_off);
443                     views.setImageViewResource(R.id.ind_wifi,
444                                                R.drawable.appwidget_settings_ind_off_l);
445                 }
446                 break;
447         }
448         if (getBrightnessMode(context)) {
449             views.setImageViewResource(R.id.img_brightness,
450                                        R.drawable.ic_appwidget_settings_brightness_auto);
451             views.setImageViewResource(R.id.ind_brightness,
452                                        R.drawable.appwidget_settings_ind_on_r);
453         } else if (getBrightness(context)) {
454             views.setImageViewResource(R.id.img_brightness,
455                                        R.drawable.ic_appwidget_settings_brightness_on);
456             views.setImageViewResource(R.id.ind_brightness,
457                                        R.drawable.appwidget_settings_ind_on_r);
458         } else {
459             views.setImageViewResource(R.id.img_brightness,
460                                        R.drawable.ic_appwidget_settings_brightness_off);
461             views.setImageViewResource(R.id.ind_brightness,
462                                        R.drawable.appwidget_settings_ind_off_r);
463         }
464         if (getSync(context)) {
465             views.setImageViewResource(R.id.img_sync, R.drawable.ic_appwidget_settings_sync_on);
466             views.setImageViewResource(R.id.ind_sync, R.drawable.appwidget_settings_ind_on_c);
467         } else {
468             views.setImageViewResource(R.id.img_sync, R.drawable.ic_appwidget_settings_sync_off);
469             views.setImageViewResource(R.id.ind_sync, R.drawable.appwidget_settings_ind_off_c);
470         }
471         if (getGpsState(context)) {
472             views.setImageViewResource(R.id.img_gps, R.drawable.ic_appwidget_settings_gps_on);
473             views.setImageViewResource(R.id.ind_gps, R.drawable.appwidget_settings_ind_on_c);
474         } else {
475             views.setImageViewResource(R.id.img_gps, R.drawable.ic_appwidget_settings_gps_off);
476             views.setImageViewResource(R.id.ind_gps, R.drawable.appwidget_settings_ind_off_c);
477         }
478         switch (sBluetoothState.getTriState(context)) {
479             case STATE_DISABLED:
480                 views.setImageViewResource(R.id.img_bluetooth,
481                                            R.drawable.ic_appwidget_settings_bluetooth_off);
482                 views.setImageViewResource(R.id.ind_bluetooth,
483                                            R.drawable.appwidget_settings_ind_off_c);
484                 break;
485             case STATE_ENABLED:
486                 views.setImageViewResource(R.id.img_bluetooth,
487                                            R.drawable.ic_appwidget_settings_bluetooth_on);
488                 views.setImageViewResource(R.id.ind_bluetooth,
489                                            R.drawable.appwidget_settings_ind_on_c);
490                 break;
491             case STATE_INTERMEDIATE:
492                 // In the transitional state, the bottom green bar
493                 // shows the tri-state (on, off, transitioning), but
494                 // the top dark-gray-or-bright-white logo shows the
495                 // user's intent.  This is much easier to see in
496                 // sunlight.
497                 if (sBluetoothState.isTurningOn()) {
498                     views.setImageViewResource(R.id.img_bluetooth,
499                                                R.drawable.ic_appwidget_settings_bluetooth_on);
500                     views.setImageViewResource(R.id.ind_bluetooth,
501                                                R.drawable.appwidget_settings_ind_mid_c);
502                 } else {
503                     views.setImageViewResource(R.id.img_bluetooth,
504                                                R.drawable.ic_appwidget_settings_bluetooth_off);
505                     views.setImageViewResource(R.id.ind_bluetooth,
506                                                R.drawable.appwidget_settings_ind_off_c);
507                 }
508                 break;
509         }
510     }
511
512     /**
513      * Creates PendingIntent to notify the widget of a button click.
514      *
515      * @param context
516      * @param appWidgetId
517      * @return
518      */
519     private static PendingIntent getLaunchPendingIntent(Context context, int appWidgetId,
520             int buttonId) {
521         Intent launchIntent = new Intent();
522         launchIntent.setClass(context, SettingsAppWidgetProvider.class);
523         launchIntent.addCategory(Intent.CATEGORY_ALTERNATIVE);
524         launchIntent.setData(Uri.parse("custom:" + buttonId));
525         PendingIntent pi = PendingIntent.getBroadcast(context, 0 /* no requestCode */,
526                 launchIntent, 0 /* no flags */);
527         return pi;
528     }
529
530     /**
531      * Receives and processes a button pressed intent or state change.
532      *
533      * @param context
534      * @param intent  Indicates the pressed button.
535      */
536     @Override
537     public void onReceive(Context context, Intent intent) {
538         super.onReceive(context, intent);
539         if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(intent.getAction())) {
540             sWifiState.onActualStateChange(context, intent);
541         } else if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(intent.getAction())) {
542             sBluetoothState.onActualStateChange(context, intent);
543         } else if (intent.hasCategory(Intent.CATEGORY_ALTERNATIVE)) {
544             Uri data = intent.getData();
545             int buttonId = Integer.parseInt(data.getSchemeSpecificPart());
546             if (buttonId == BUTTON_WIFI) {
547                 sWifiState.toggleState(context);
548             } else if (buttonId == BUTTON_BRIGHTNESS) {
549                 toggleBrightness(context);
550             } else if (buttonId == BUTTON_SYNC) {
551                 toggleSync(context);
552             } else if (buttonId == BUTTON_GPS) {
553                 toggleGps(context);
554             } else if (buttonId == BUTTON_BLUETOOTH) {
555                 sBluetoothState.toggleState(context);
556             }
557         }
558
559         // State changes fall through
560         updateWidget(context);
561     }
562
563     /**
564      * Gets the state of background data.
565      *
566      * @param context
567      * @return true if enabled
568      */
569     private static boolean getBackgroundDataState(Context context) {
570         ConnectivityManager connManager =
571                 (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
572         return connManager.getBackgroundDataSetting();
573     }
574
575     /**
576      * Gets the state of auto-sync.
577      *
578      * @param context
579      * @return true if enabled
580      */
581     private static boolean getSync(Context context) {
582         boolean backgroundData = getBackgroundDataState(context);
583         boolean sync = ContentResolver.getMasterSyncAutomatically();
584         return backgroundData && sync;
585     }
586
587     /**
588      * Toggle auto-sync
589      *
590      * @param context
591      */
592     private void toggleSync(Context context) {
593         ConnectivityManager connManager =
594                 (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
595         boolean backgroundData = getBackgroundDataState(context);
596         boolean sync = ContentResolver.getMasterSyncAutomatically();
597
598         // four cases to handle:
599         // setting toggled from off to on:
600         // 1. background data was off, sync was off: turn on both
601         if (!backgroundData && !sync) {
602             connManager.setBackgroundDataSetting(true);
603             ContentResolver.setMasterSyncAutomatically(true);
604         }
605
606         // 2. background data was off, sync was on: turn on background data
607         if (!backgroundData && sync) {
608             connManager.setBackgroundDataSetting(true);
609         }
610
611         // 3. background data was on, sync was off: turn on sync
612         if (backgroundData && !sync) {
613             ContentResolver.setMasterSyncAutomatically(true);
614         }
615
616         // setting toggled from on to off:
617         // 4. background data was on, sync was on: turn off sync
618         if (backgroundData && sync) {
619             ContentResolver.setMasterSyncAutomatically(false);
620         }
621     }
622
623     /**
624      * Gets the state of GPS location.
625      *
626      * @param context
627      * @return true if enabled.
628      */
629     private static boolean getGpsState(Context context) {
630         ContentResolver resolver = context.getContentResolver();
631         return Settings.Secure.isLocationProviderEnabled(resolver, LocationManager.GPS_PROVIDER);
632     }
633
634     /**
635      * Toggles the state of GPS.
636      *
637      * @param context
638      */
639     private void toggleGps(Context context) {
640         ContentResolver resolver = context.getContentResolver();
641         boolean enabled = getGpsState(context);
642         Settings.Secure.setLocationProviderEnabled(resolver, LocationManager.GPS_PROVIDER,
643                 !enabled);
644     }
645
646     /**
647      * Gets state of brightness.
648      *
649      * @param context
650      * @return true if more than moderately bright.
651      */
652     private static boolean getBrightness(Context context) {
653         try {
654             IPowerManager power = IPowerManager.Stub.asInterface(
655                     ServiceManager.getService("power"));
656             if (power != null) {
657                 int brightness = Settings.System.getInt(context.getContentResolver(),
658                         Settings.System.SCREEN_BRIGHTNESS);
659                 return brightness > 100;
660             }
661         } catch (Exception e) {
662             Log.d(TAG, "getBrightness: " + e);
663         }
664         return false;
665     }
666
667     /**
668      * Gets state of brightness mode.
669      *
670      * @param context
671      * @return true if auto brightness is on.
672      */
673     private static boolean getBrightnessMode(Context context) {
674         try {
675             IPowerManager power = IPowerManager.Stub.asInterface(
676                     ServiceManager.getService("power"));
677             if (power != null) {
678                 int brightnessMode = Settings.System.getInt(context.getContentResolver(),
679                         Settings.System.SCREEN_BRIGHTNESS_MODE);
680                 return brightnessMode == Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC;
681             }
682         } catch (Exception e) {
683             Log.d(TAG, "getBrightnessMode: " + e);
684         }
685         return false;
686     }
687
688     /**
689      * Increases or decreases the brightness.
690      *
691      * @param context
692      */
693     private void toggleBrightness(Context context) {
694         try {
695             IPowerManager power = IPowerManager.Stub.asInterface(
696                     ServiceManager.getService("power"));
697             if (power != null) {
698                 ContentResolver cr = context.getContentResolver();
699                 int brightness = Settings.System.getInt(cr,
700                         Settings.System.SCREEN_BRIGHTNESS);
701                 int brightnessMode = Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL;
702                 //Only get brightness setting if available
703                 if (context.getResources().getBoolean(
704                         com.android.internal.R.bool.config_automatic_brightness_available)) {
705                     brightnessMode = Settings.System.getInt(cr,
706                             Settings.System.SCREEN_BRIGHTNESS_MODE);
707                 }
708
709                 // Rotate AUTO -> MINIMUM -> DEFAULT -> MAXIMUM
710                 // Technically, not a toggle...
711                 if (brightnessMode == Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC) {
712                     brightness = MINIMUM_BACKLIGHT;
713                     brightnessMode = Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL;
714                 } else if (brightness < DEFAULT_BACKLIGHT) {
715                     brightness = DEFAULT_BACKLIGHT;
716                 } else if (brightness < MAXIMUM_BACKLIGHT) {
717                     brightness = MAXIMUM_BACKLIGHT;
718                 } else {
719                     brightnessMode = Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC;
720                     brightness = MINIMUM_BACKLIGHT;
721                 }
722
723                 if (context.getResources().getBoolean(
724                         com.android.internal.R.bool.config_automatic_brightness_available)) {
725                     // Set screen brightness mode (automatic or manual)
726                     Settings.System.putInt(context.getContentResolver(),
727                             Settings.System.SCREEN_BRIGHTNESS_MODE,
728                             brightnessMode);
729                 } else {
730                     // Make sure we set the brightness if automatic mode isn't available
731                     brightnessMode = Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL;
732                 }
733                 if (brightnessMode == Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL) {
734                     power.setBacklightBrightness(brightness);
735                     Settings.System.putInt(cr, Settings.System.SCREEN_BRIGHTNESS, brightness);
736                 }
737             }
738         } catch (RemoteException e) {
739             Log.d(TAG, "toggleBrightness: " + e);
740         } catch (Settings.SettingNotFoundException e) {
741             Log.d(TAG, "toggleBrightness: " + e);
742         }
743     }
744 }