OSDN Git Service

Implement the power-control widget.
authorKen Shirriff <kens@google.com>
Mon, 8 Jun 2009 20:49:05 +0000 (13:49 -0700)
committerKen Shirriff <kens@google.com>
Mon, 8 Jun 2009 20:57:26 +0000 (13:57 -0700)
This widget allows uses to turn on/off bluetooth, wifi, gps, and sync,
and adjust brightness without going through the settings menu.

The widget provider updates the settings when the buttons are pressed.
The widget provider is also a receiver for events indicating that the
status was updated elsewhere and the buttons need to be changed.

23 files changed:
AndroidManifest.xml
res/drawable/icon.png [new file with mode: 0755]
res/drawable/widget_bg.9.png [new file with mode: 0644]
res/drawable/widget_btn.xml [new file with mode: 0644]
res/drawable/widget_btn_bluetooth.png [new file with mode: 0644]
res/drawable/widget_btn_bluetooth_gray.png [new file with mode: 0644]
res/drawable/widget_btn_bluetooth_off.png [new file with mode: 0644]
res/drawable/widget_btn_brightness.png [new file with mode: 0644]
res/drawable/widget_btn_brightness_off.png [new file with mode: 0644]
res/drawable/widget_btn_default.9.png [new file with mode: 0644]
res/drawable/widget_btn_gps.png [new file with mode: 0644]
res/drawable/widget_btn_gps_off.png [new file with mode: 0644]
res/drawable/widget_btn_pressed.9.png [new file with mode: 0644]
res/drawable/widget_btn_selected.9.png [new file with mode: 0644]
res/drawable/widget_btn_sync.png [new file with mode: 0644]
res/drawable/widget_btn_sync_off.png [new file with mode: 0644]
res/drawable/widget_btn_wifi.png [new file with mode: 0644]
res/drawable/widget_btn_wifi_gray.png [new file with mode: 0644]
res/drawable/widget_btn_wifi_off.png [new file with mode: 0644]
res/layout/widget.xml [new file with mode: 0644]
res/values/strings.xml
res/xml/appwidget_info.xml [new file with mode: 0644]
src/com/android/settings/widget/SettingsAppWidgetProvider.java [new file with mode: 0644]

index 204da69..150e27d 100644 (file)
                 <category android:name="android.intent.category.DEFAULT" />
             </intent-filter>
         </activity>
-    </application>
 
+        <receiver android:name=".widget.SettingsAppWidgetProvider" android:label="@string/gadget_title">
+            <intent-filter>
+                <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
+                <action android:name="android.net.wifi.WIFI_STATE_CHANGED" />
+                <action android:name="android.net.conn.BACKGROUND_DATA_SETTING_CHANGED" />
+                <action android:name="android.bluetooth.intent.action.BLUETOOTH_STATE_CHANGED" />
+                <action android:name="android.intent.action.CLOSE_SYSTEM_DIALOGS" /> <!-- pick up misc changes -->
+            </intent-filter>
+            <meta-data android:name="android.appwidget.provider" android:resource="@xml/appwidget_info" />
+        </receiver>
+    </application>
 </manifest>
-
-
-
diff --git a/res/drawable/icon.png b/res/drawable/icon.png
new file mode 100755 (executable)
index 0000000..16db056
Binary files /dev/null and b/res/drawable/icon.png differ
diff --git a/res/drawable/widget_bg.9.png b/res/drawable/widget_bg.9.png
new file mode 100644 (file)
index 0000000..a2007ad
Binary files /dev/null and b/res/drawable/widget_bg.9.png differ
diff --git a/res/drawable/widget_btn.xml b/res/drawable/widget_btn.xml
new file mode 100644 (file)
index 0000000..720bc49
--- /dev/null
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <item android:state_window_focused="false" android:state_enabled="true"
+        android:drawable="@drawable/widget_btn_default" />
+
+    <item android:state_pressed="true"
+        android:drawable="@drawable/widget_btn_pressed" />
+
+    <item android:state_focused="true" android:state_enabled="true"
+        android:drawable="@drawable/widget_btn_selected" />
+
+    <item android:state_enabled="true"
+        android:drawable="@drawable/widget_btn_default" />
+
+    <item
+         android:drawable="@drawable/widget_btn_default" />
+</selector>
diff --git a/res/drawable/widget_btn_bluetooth.png b/res/drawable/widget_btn_bluetooth.png
new file mode 100644 (file)
index 0000000..5de9d78
Binary files /dev/null and b/res/drawable/widget_btn_bluetooth.png differ
diff --git a/res/drawable/widget_btn_bluetooth_gray.png b/res/drawable/widget_btn_bluetooth_gray.png
new file mode 100644 (file)
index 0000000..843dcce
Binary files /dev/null and b/res/drawable/widget_btn_bluetooth_gray.png differ
diff --git a/res/drawable/widget_btn_bluetooth_off.png b/res/drawable/widget_btn_bluetooth_off.png
new file mode 100644 (file)
index 0000000..b831a46
Binary files /dev/null and b/res/drawable/widget_btn_bluetooth_off.png differ
diff --git a/res/drawable/widget_btn_brightness.png b/res/drawable/widget_btn_brightness.png
new file mode 100644 (file)
index 0000000..a162899
Binary files /dev/null and b/res/drawable/widget_btn_brightness.png differ
diff --git a/res/drawable/widget_btn_brightness_off.png b/res/drawable/widget_btn_brightness_off.png
new file mode 100644 (file)
index 0000000..0f42f2d
Binary files /dev/null and b/res/drawable/widget_btn_brightness_off.png differ
diff --git a/res/drawable/widget_btn_default.9.png b/res/drawable/widget_btn_default.9.png
new file mode 100644 (file)
index 0000000..febf222
Binary files /dev/null and b/res/drawable/widget_btn_default.9.png differ
diff --git a/res/drawable/widget_btn_gps.png b/res/drawable/widget_btn_gps.png
new file mode 100644 (file)
index 0000000..3394cb4
Binary files /dev/null and b/res/drawable/widget_btn_gps.png differ
diff --git a/res/drawable/widget_btn_gps_off.png b/res/drawable/widget_btn_gps_off.png
new file mode 100644 (file)
index 0000000..7f481d8
Binary files /dev/null and b/res/drawable/widget_btn_gps_off.png differ
diff --git a/res/drawable/widget_btn_pressed.9.png b/res/drawable/widget_btn_pressed.9.png
new file mode 100644 (file)
index 0000000..70a200b
Binary files /dev/null and b/res/drawable/widget_btn_pressed.9.png differ
diff --git a/res/drawable/widget_btn_selected.9.png b/res/drawable/widget_btn_selected.9.png
new file mode 100644 (file)
index 0000000..6f2989f
Binary files /dev/null and b/res/drawable/widget_btn_selected.9.png differ
diff --git a/res/drawable/widget_btn_sync.png b/res/drawable/widget_btn_sync.png
new file mode 100644 (file)
index 0000000..9682879
Binary files /dev/null and b/res/drawable/widget_btn_sync.png differ
diff --git a/res/drawable/widget_btn_sync_off.png b/res/drawable/widget_btn_sync_off.png
new file mode 100644 (file)
index 0000000..0f48a1d
Binary files /dev/null and b/res/drawable/widget_btn_sync_off.png differ
diff --git a/res/drawable/widget_btn_wifi.png b/res/drawable/widget_btn_wifi.png
new file mode 100644 (file)
index 0000000..ff7d2ef
Binary files /dev/null and b/res/drawable/widget_btn_wifi.png differ
diff --git a/res/drawable/widget_btn_wifi_gray.png b/res/drawable/widget_btn_wifi_gray.png
new file mode 100644 (file)
index 0000000..8a3cc49
Binary files /dev/null and b/res/drawable/widget_btn_wifi_gray.png differ
diff --git a/res/drawable/widget_btn_wifi_off.png b/res/drawable/widget_btn_wifi_off.png
new file mode 100644 (file)
index 0000000..8f15b4f
Binary files /dev/null and b/res/drawable/widget_btn_wifi_off.png differ
diff --git a/res/layout/widget.xml b/res/layout/widget.xml
new file mode 100644 (file)
index 0000000..63ce5a5
--- /dev/null
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+id/main"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal"
+        android:paddingLeft="12dip"
+        android:paddingRight="12dip"
+        android:paddingTop="7dip"
+        android:paddingBottom="13dip"
+        android:background="@drawable/widget_bg" >
+
+        <ImageButton
+            android:id="@+id/btn_wifi"
+            android:layout_width="wrap_content"
+            android:layout_height="fill_parent"
+            android:layout_marginLeft="8dip"
+            android:background="@drawable/widget_btn"
+            android:layout_gravity="center_horizontal"
+        />
+
+        <ImageButton
+            android:id="@+id/btn_brightness"
+            android:layout_width="wrap_content"
+            android:layout_height="fill_parent"
+            android:layout_marginLeft="8dip"
+            android:background="@drawable/widget_btn"
+            android:layout_gravity="center_horizontal"
+
+        />
+
+        <ImageButton
+            android:id="@+id/btn_sync"
+            android:layout_width="wrap_content"
+            android:layout_height="fill_parent"
+            android:layout_marginLeft="8dip"
+            android:background="@drawable/widget_btn"
+            android:layout_gravity="center_horizontal"
+
+        />
+
+        <ImageButton
+            android:id="@+id/btn_gps"
+            android:layout_width="wrap_content"
+            android:layout_height="fill_parent"
+            android:layout_marginLeft="8dip"
+            android:background="@drawable/widget_btn"
+            android:layout_gravity="center_horizontal"
+
+        />
+
+            <ImageButton
+            android:id="@+id/btn_bluetooth"
+            android:layout_width="wrap_content"
+            android:layout_height="fill_parent"
+            android:layout_marginLeft="8dip"
+            android:background="@drawable/widget_btn"
+            android:layout_gravity="center_horizontal"
+
+        />
+    </LinearLayout>
index 9ea852b..62120fc 100644 (file)
@@ -1649,6 +1649,6 @@ found in the list of installed applications.</string>
     <!-- Menu label for refreshing with latest usage numbers -->
     <string name="menu_stats_refresh">Refresh</string>
 
+    <!-- Power Control Widget -->
+    <string name="gadget_title">Power Control</string>
 </resources>
-
-
diff --git a/res/xml/appwidget_info.xml b/res/xml/appwidget_info.xml
new file mode 100644 (file)
index 0000000..2186dab
--- /dev/null
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
+    android:minWidth="294dip"
+    android:minHeight="72dip"
+    android:initialLayout="@layout/widget"
+    >
+</appwidget-provider>
diff --git a/src/com/android/settings/widget/SettingsAppWidgetProvider.java b/src/com/android/settings/widget/SettingsAppWidgetProvider.java
new file mode 100644 (file)
index 0000000..002816f
--- /dev/null
@@ -0,0 +1,404 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.widget;
+
+import android.app.PendingIntent;
+import android.appwidget.AppWidgetManager;
+import android.appwidget.AppWidgetProvider;
+import android.bluetooth.BluetoothDevice;
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.IContentService;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.location.LocationManager;
+import android.net.ConnectivityManager;
+import android.net.Uri;
+import android.net.wifi.WifiManager;
+import android.os.IHardwareService;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.provider.Settings;
+import android.util.Log;
+import android.widget.RemoteViews;
+import com.android.settings.R;
+import com.android.settings.bluetooth.LocalBluetoothManager;
+
+/**
+ * Provides control of power-related settings from a widget.
+ */
+public class SettingsAppWidgetProvider extends AppWidgetProvider {
+    static final String TAG = "SettingsAppWidgetProvider";
+
+    static final ComponentName THIS_APPWIDGET =
+            new ComponentName("com.android.settings",
+                    "com.android.settings.widget.SettingsAppWidgetProvider");
+
+    private static LocalBluetoothManager mLocalBluetoothManager = null;
+
+    private static final int BUTTON_WIFI = 0;
+    private static final int BUTTON_BRIGHTNESS = 1;
+    private static final int BUTTON_SYNC = 2;
+    private static final int BUTTON_GPS = 3;
+    private static final int BUTTON_BLUETOOTH = 4;
+
+    private static final int STATE_DISABLED = 0;
+    private static final int STATE_ENABLED = 1;
+    private static final int STATE_INTERMEDIATE = 2;
+
+    /**
+     * Minimum and maximum brightnesses.  Don't go to 0 since that makes the display unusable
+     */
+    private static final int MINIMUM_BACKLIGHT = android.os.Power.BRIGHTNESS_DIM + 10;
+    private static final int MAXIMUM_BACKLIGHT = android.os.Power.BRIGHTNESS_ON;
+    private static final int DEFAULT_BACKLIGHT = (int) (android.os.Power.BRIGHTNESS_ON * 0.4f);
+
+    @Override
+    public void onUpdate(Context context, AppWidgetManager appWidgetManager,
+            int[] appWidgetIds) {
+        // Update each requested appWidgetId
+        RemoteViews view = buildUpdate(context, -1);
+
+        for (int i = 0; i < appWidgetIds.length; i++) {
+            appWidgetManager.updateAppWidget(appWidgetIds[i], view);
+        }
+    }
+
+    @Override
+    public void onEnabled(Context context) {
+        PackageManager pm = context.getPackageManager();
+        pm.setComponentEnabledSetting(
+                new ComponentName("com.android.settings", ".widget.SettingsAppWidgetProvider"),
+                PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
+                PackageManager.DONT_KILL_APP);
+    }
+
+    @Override
+    public void onDisabled(Context context) {
+        Class clazz = com.android.settings.widget.SettingsAppWidgetProvider.class;
+        PackageManager pm = context.getPackageManager();
+        pm.setComponentEnabledSetting(
+                new ComponentName("com.android.settings", ".widget.SettingsAppWidgetProvider"),
+                PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
+                PackageManager.DONT_KILL_APP);
+    }
+
+    /**
+     * Load image for given widget and build {@link RemoteViews} for it.
+     */
+    static RemoteViews buildUpdate(Context context, int appWidgetId) {
+        RemoteViews views = new RemoteViews(context.getPackageName(),
+                R.layout.widget);
+        views.setOnClickPendingIntent(R.id.btn_wifi, getLaunchPendingIntent(context, appWidgetId,
+                BUTTON_WIFI));
+        views.setOnClickPendingIntent(R.id.btn_brightness,
+                getLaunchPendingIntent(context,
+                        appWidgetId, BUTTON_BRIGHTNESS));
+        views.setOnClickPendingIntent(R.id.btn_sync,
+                getLaunchPendingIntent(context,
+                        appWidgetId, BUTTON_SYNC));
+        views.setOnClickPendingIntent(R.id.btn_gps,
+                getLaunchPendingIntent(context, appWidgetId, BUTTON_GPS));
+        views.setOnClickPendingIntent(R.id.btn_bluetooth,
+                getLaunchPendingIntent(context,
+                        appWidgetId, BUTTON_BLUETOOTH));
+
+        updateButtons(views, context);
+        return views;
+    }
+
+    /**
+     * Updates the widget when something changes, or when a button is pushed.
+     *
+     * @param context
+     */
+    public static void updateWidget(Context context) {
+        RemoteViews views = buildUpdate(context, -1);
+        // Update specific list of appWidgetIds if given, otherwise default to all
+        final AppWidgetManager gm = AppWidgetManager.getInstance(context);
+        gm.updateAppWidget(THIS_APPWIDGET, views);
+    }
+
+    /**
+     * Updates the buttons based on the underlying states of wifi, etc.
+     *
+     * @param views   The RemoteViews to update.
+     * @param context
+     */
+    private static void updateButtons(RemoteViews views, Context context) {
+        switch (getWifiState(context)) {
+            case STATE_DISABLED:
+                views.setImageViewResource(R.id.btn_wifi, R.drawable.widget_btn_wifi_off);
+                break;
+            case STATE_ENABLED:
+                views.setImageViewResource(R.id.btn_wifi, R.drawable.widget_btn_wifi);
+                break;
+            case STATE_INTERMEDIATE:
+                views.setImageViewResource(R.id.btn_wifi, R.drawable.widget_btn_wifi_gray);
+                break;
+        }
+        if (getBrightness(context)) {
+            views.setImageViewResource(R.id.btn_brightness, R.drawable.widget_btn_brightness);
+        } else {
+            views.setImageViewResource(R.id.btn_brightness, R.drawable.widget_btn_brightness_off);
+        }
+        if (getBackgroundDataState(context)) {
+            views.setImageViewResource(R.id.btn_sync, R.drawable.widget_btn_sync);
+        } else {
+            views.setImageViewResource(R.id.btn_sync, R.drawable.widget_btn_sync_off);
+        }
+        if (getGpsState(context)) {
+            views.setImageViewResource(R.id.btn_gps, R.drawable.widget_btn_gps);
+        } else {
+            views.setImageViewResource(R.id.btn_gps, R.drawable.widget_btn_gps_off);
+        }
+        switch (getBluetoothState(context)) {
+            case STATE_DISABLED:
+                views.setImageViewResource(R.id.btn_bluetooth, R.drawable.widget_btn_bluetooth_off);
+                break;
+            case STATE_ENABLED:
+                views.setImageViewResource(R.id.btn_bluetooth, R.drawable.widget_btn_bluetooth);
+                break;
+            case STATE_INTERMEDIATE:
+                views.setImageViewResource(R.id.btn_bluetooth, R.drawable.widget_btn_bluetooth_gray);
+                break;
+        }
+    }
+
+    /**
+     * Creates PendingIntent to notify the widget of a button click.
+     *
+     * @param context
+     * @param appWidgetId
+     * @return
+     */
+    private static PendingIntent getLaunchPendingIntent(Context context, int appWidgetId, int buttonId) {
+        Intent launchIntent = new Intent();
+        launchIntent.setClass(context, SettingsAppWidgetProvider.class);
+        launchIntent.addCategory(Intent.CATEGORY_ALTERNATIVE);
+        launchIntent.setData(Uri.parse("custom:" + buttonId));
+        PendingIntent pi = PendingIntent.getBroadcast(context, 0 /* no requestCode */,
+                launchIntent, 0 /* no flags */);
+        return pi;
+    }
+
+    /**
+     * Receives and processes a button pressed intent or state change.
+     *
+     * @param context
+     * @param intent  Indicates the pressed button.
+     */
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        super.onReceive(context, intent);
+        if (intent.hasCategory(Intent.CATEGORY_ALTERNATIVE)) {
+            Uri data = intent.getData();
+            int buttonId = Integer.parseInt(data.getSchemeSpecificPart());
+            if (buttonId == BUTTON_WIFI) {
+                toggleWifi(context);
+            } else if (buttonId == BUTTON_BRIGHTNESS) {
+                toggleBrightness(context);
+            } else if (buttonId == BUTTON_SYNC) {
+                toggleBackgroundData(context);
+            } else if (buttonId == BUTTON_GPS) {
+                toggleGps(context);
+            } else if (buttonId == BUTTON_BLUETOOTH) {
+                toggleBluetooth(context);
+            }
+        }
+        // State changes fall through
+        updateWidget(context);
+    }
+
+    /**
+     * Gets the state of Wi-Fi
+     *
+     * @param context
+     * @return STATE_ENABLED, STATE_DISABLED, or STATE_INTERMEDIATE
+     */
+    private static int getWifiState(Context context) {
+        WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
+        int wifiState = wifiManager.getWifiState();
+        if (wifiState == WifiManager.WIFI_STATE_DISABLED) {
+            return STATE_DISABLED;
+        } else if (wifiState == WifiManager.WIFI_STATE_ENABLED) {
+            return STATE_ENABLED;
+        } else {
+            return STATE_INTERMEDIATE;
+        }
+    }
+
+    /**
+     * Toggles the state of Wi-Fi
+     *
+     * @param context
+     */
+    private void toggleWifi(Context context) {
+        WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
+        int wifiState = getWifiState(context);
+        if (wifiState == STATE_ENABLED) {
+            wifiManager.setWifiEnabled(false);
+        } else if (wifiState == STATE_DISABLED) {
+            wifiManager.setWifiEnabled(true);
+            mLocalBluetoothManager.setBluetoothEnabled(true);
+        }
+    }
+
+    /**
+     * Gets the state of background data.
+     *
+     * @param context
+     * @return true if enabled
+     */
+    private static boolean getBackgroundDataState(Context context) {
+        ConnectivityManager connManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
+        return connManager.getBackgroundDataSetting();
+    }
+
+    /**
+     * Toggle background data and sync tickles.
+     *
+     * @param context
+     */
+    private void toggleBackgroundData(Context context) {
+        ConnectivityManager connManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
+        boolean sync = getBackgroundDataState(context);
+        connManager.setBackgroundDataSetting(!sync);
+
+        IContentService contentService = ContentResolver.getContentService();
+        try {
+            contentService.setListenForNetworkTickles(!sync);
+        } catch (RemoteException e) {
+            Log.d(TAG, "toggleBackgroundData: " + e);
+        }
+    }
+
+    /**
+     * Gets the state of GPS location.
+     *
+     * @param context
+     * @return true if enabled.
+     */
+    private static boolean getGpsState(Context context) {
+        ContentResolver resolver = context.getContentResolver();
+        return Settings.Secure.isLocationProviderEnabled(resolver, LocationManager.GPS_PROVIDER);
+    }
+
+    /**
+     * Toggles the state of GPS.
+     *
+     * @param context
+     */
+    private void toggleGps(Context context) {
+        ContentResolver resolver = context.getContentResolver();
+        boolean enabled = getGpsState(context);
+        Settings.Secure.setLocationProviderEnabled(resolver, LocationManager.GPS_PROVIDER, !enabled);
+    }
+
+    /**
+     * Gets state of brightness.
+     *
+     * @param context
+     * @return true if more than moderately bright.
+     */
+    private static boolean getBrightness(Context context) {
+        try {
+            IHardwareService hardware = IHardwareService.Stub.asInterface(
+                    ServiceManager.getService("hardware"));
+            if (hardware != null) {
+                int brightness = Settings.System.getInt(context.getContentResolver(),
+                        Settings.System.SCREEN_BRIGHTNESS);
+                return brightness > 100;
+            }
+        } catch (Exception e) {
+            Log.d(TAG, "getBrightness: " + e);
+        }
+        return false;
+    }
+
+    /**
+     * Increases or decreases the brightness.
+     *
+     * @param context
+     */
+    private void toggleBrightness(Context context) {
+        try {
+            IHardwareService hardware = IHardwareService.Stub.asInterface(
+                    ServiceManager.getService("hardware"));
+            if (hardware != null) {
+                ContentResolver cr = context.getContentResolver();
+                int brightness = Settings.System.getInt(cr,
+                        Settings.System.SCREEN_BRIGHTNESS);
+                // Rotate MINIMUM -> DEFAULT -> MAXIMUM
+                // Technically, not a toggle...
+                if (brightness < DEFAULT_BACKLIGHT) {
+                    brightness = DEFAULT_BACKLIGHT;
+                } else if (brightness < MAXIMUM_BACKLIGHT) {
+                    brightness = MAXIMUM_BACKLIGHT;
+                } else {
+                    brightness = MINIMUM_BACKLIGHT;
+                }
+                hardware.setBacklights(brightness);
+                Settings.System.putInt(cr, Settings.System.SCREEN_BRIGHTNESS, brightness);
+                brightness = Settings.System.getInt(cr,
+                        Settings.System.SCREEN_BRIGHTNESS);
+            }
+        } catch (RemoteException e) {
+            Log.d(TAG, "toggleBrightness: " + e);
+        } catch (Settings.SettingNotFoundException e) {
+            Log.d(TAG, "toggleBrightness: " + e);
+        }
+    }
+
+    /**
+     * Gets state of bluetooth
+     *
+     * @param context
+     * @return STATE_ENABLED, STATE_DISABLED, or STATE_INTERMEDIATE
+     */
+    private static int getBluetoothState(Context context) {
+        if (mLocalBluetoothManager == null) {
+            mLocalBluetoothManager = LocalBluetoothManager.getInstance(context);
+            if (mLocalBluetoothManager == null) {
+                return STATE_INTERMEDIATE; // On emulator?
+            }
+        }
+        int state = mLocalBluetoothManager.getBluetoothState();
+        if (state == BluetoothDevice.BLUETOOTH_STATE_OFF) {
+            return STATE_DISABLED;
+        } else if (state == BluetoothDevice.BLUETOOTH_STATE_ON) {
+            return STATE_ENABLED;
+        } else {
+            return STATE_INTERMEDIATE;
+        }
+    }
+
+    /**
+     * Toggles the state of bluetooth
+     *
+     * @param context
+     */
+    private void toggleBluetooth(Context context) {
+        int state = getBluetoothState(context);
+        if (state == STATE_ENABLED) {
+            mLocalBluetoothManager.setBluetoothEnabled(false);
+        } else if (state == STATE_DISABLED) {
+            mLocalBluetoothManager.setBluetoothEnabled(true);
+        }
+    }
+}