SettingsAppWidgetProvider.java revision 03a6110b4f62e72592b451c05848cfaad8c65324
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
17package com.android.settings.widget;
18
19import android.app.PendingIntent;
20import android.appwidget.AppWidgetManager;
21import android.appwidget.AppWidgetProvider;
22import android.bluetooth.BluetoothDevice;
23import android.content.ComponentName;
24import android.content.ContentResolver;
25import android.content.Context;
26import android.content.IContentService;
27import android.content.Intent;
28import android.content.pm.PackageManager;
29import android.location.LocationManager;
30import android.net.ConnectivityManager;
31import android.net.Uri;
32import android.net.wifi.WifiManager;
33import android.os.IHardwareService;
34import android.os.RemoteException;
35import android.os.ServiceManager;
36import android.provider.Settings;
37import android.util.Log;
38import android.widget.RemoteViews;
39import com.android.settings.R;
40import com.android.settings.bluetooth.LocalBluetoothManager;
41
42/**
43 * Provides control of power-related settings from a widget.
44 */
45public class SettingsAppWidgetProvider extends AppWidgetProvider {
46    static final String TAG = "SettingsAppWidgetProvider";
47
48    static final ComponentName THIS_APPWIDGET =
49            new ComponentName("com.android.settings",
50                    "com.android.settings.widget.SettingsAppWidgetProvider");
51
52    private static LocalBluetoothManager mLocalBluetoothManager = null;
53
54    private static final int BUTTON_WIFI = 0;
55    private static final int BUTTON_BRIGHTNESS = 1;
56    private static final int BUTTON_SYNC = 2;
57    private static final int BUTTON_GPS = 3;
58    private static final int BUTTON_BLUETOOTH = 4;
59
60    private static final int STATE_DISABLED = 0;
61    private static final int STATE_ENABLED = 1;
62    private static final int STATE_INTERMEDIATE = 2;
63
64    /**
65     * Minimum and maximum brightnesses.  Don't go to 0 since that makes the display unusable
66     */
67    private static final int MINIMUM_BACKLIGHT = android.os.Power.BRIGHTNESS_DIM + 10;
68    private static final int MAXIMUM_BACKLIGHT = android.os.Power.BRIGHTNESS_ON;
69    private static final int DEFAULT_BACKLIGHT = (int) (android.os.Power.BRIGHTNESS_ON * 0.4f);
70
71    @Override
72    public void onUpdate(Context context, AppWidgetManager appWidgetManager,
73            int[] appWidgetIds) {
74        // Update each requested appWidgetId
75        RemoteViews view = buildUpdate(context, -1);
76
77        for (int i = 0; i < appWidgetIds.length; i++) {
78            appWidgetManager.updateAppWidget(appWidgetIds[i], view);
79        }
80    }
81
82    @Override
83    public void onEnabled(Context context) {
84        PackageManager pm = context.getPackageManager();
85        pm.setComponentEnabledSetting(
86                new ComponentName("com.android.settings", ".widget.SettingsAppWidgetProvider"),
87                PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
88                PackageManager.DONT_KILL_APP);
89    }
90
91    @Override
92    public void onDisabled(Context context) {
93        Class clazz = com.android.settings.widget.SettingsAppWidgetProvider.class;
94        PackageManager pm = context.getPackageManager();
95        pm.setComponentEnabledSetting(
96                new ComponentName("com.android.settings", ".widget.SettingsAppWidgetProvider"),
97                PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
98                PackageManager.DONT_KILL_APP);
99    }
100
101    /**
102     * Load image for given widget and build {@link RemoteViews} for it.
103     */
104    static RemoteViews buildUpdate(Context context, int appWidgetId) {
105        RemoteViews views = new RemoteViews(context.getPackageName(),
106                R.layout.widget);
107        views.setOnClickPendingIntent(R.id.btn_wifi, getLaunchPendingIntent(context, appWidgetId,
108                BUTTON_WIFI));
109        views.setOnClickPendingIntent(R.id.btn_brightness,
110                getLaunchPendingIntent(context,
111                        appWidgetId, BUTTON_BRIGHTNESS));
112        views.setOnClickPendingIntent(R.id.btn_sync,
113                getLaunchPendingIntent(context,
114                        appWidgetId, BUTTON_SYNC));
115        views.setOnClickPendingIntent(R.id.btn_gps,
116                getLaunchPendingIntent(context, appWidgetId, BUTTON_GPS));
117        views.setOnClickPendingIntent(R.id.btn_bluetooth,
118                getLaunchPendingIntent(context,
119                        appWidgetId, BUTTON_BLUETOOTH));
120
121        updateButtons(views, context);
122        return views;
123    }
124
125    /**
126     * Updates the widget when something changes, or when a button is pushed.
127     *
128     * @param context
129     */
130    public static void updateWidget(Context context) {
131        RemoteViews views = buildUpdate(context, -1);
132        // Update specific list of appWidgetIds if given, otherwise default to all
133        final AppWidgetManager gm = AppWidgetManager.getInstance(context);
134        gm.updateAppWidget(THIS_APPWIDGET, views);
135    }
136
137    /**
138     * Updates the buttons based on the underlying states of wifi, etc.
139     *
140     * @param views   The RemoteViews to update.
141     * @param context
142     */
143    private static void updateButtons(RemoteViews views, Context context) {
144        switch (getWifiState(context)) {
145            case STATE_DISABLED:
146                views.setImageViewResource(R.id.btn_wifi, R.drawable.widget_btn_wifi_off);
147                break;
148            case STATE_ENABLED:
149                views.setImageViewResource(R.id.btn_wifi, R.drawable.widget_btn_wifi);
150                break;
151            case STATE_INTERMEDIATE:
152                views.setImageViewResource(R.id.btn_wifi, R.drawable.widget_btn_wifi_gray);
153                break;
154        }
155        if (getBrightness(context)) {
156            views.setImageViewResource(R.id.btn_brightness, R.drawable.widget_btn_brightness);
157        } else {
158            views.setImageViewResource(R.id.btn_brightness, R.drawable.widget_btn_brightness_off);
159        }
160        if (getBackgroundDataState(context)) {
161            views.setImageViewResource(R.id.btn_sync, R.drawable.widget_btn_sync);
162        } else {
163            views.setImageViewResource(R.id.btn_sync, R.drawable.widget_btn_sync_off);
164        }
165        if (getGpsState(context)) {
166            views.setImageViewResource(R.id.btn_gps, R.drawable.widget_btn_gps);
167        } else {
168            views.setImageViewResource(R.id.btn_gps, R.drawable.widget_btn_gps_off);
169        }
170        switch (getBluetoothState(context)) {
171            case STATE_DISABLED:
172                views.setImageViewResource(R.id.btn_bluetooth, R.drawable.widget_btn_bluetooth_off);
173                break;
174            case STATE_ENABLED:
175                views.setImageViewResource(R.id.btn_bluetooth, R.drawable.widget_btn_bluetooth);
176                break;
177            case STATE_INTERMEDIATE:
178                views.setImageViewResource(R.id.btn_bluetooth, R.drawable.widget_btn_bluetooth_gray);
179                break;
180        }
181    }
182
183    /**
184     * Creates PendingIntent to notify the widget of a button click.
185     *
186     * @param context
187     * @param appWidgetId
188     * @return
189     */
190    private static PendingIntent getLaunchPendingIntent(Context context, int appWidgetId, int buttonId) {
191        Intent launchIntent = new Intent();
192        launchIntent.setClass(context, SettingsAppWidgetProvider.class);
193        launchIntent.addCategory(Intent.CATEGORY_ALTERNATIVE);
194        launchIntent.setData(Uri.parse("custom:" + buttonId));
195        PendingIntent pi = PendingIntent.getBroadcast(context, 0 /* no requestCode */,
196                launchIntent, 0 /* no flags */);
197        return pi;
198    }
199
200    /**
201     * Receives and processes a button pressed intent or state change.
202     *
203     * @param context
204     * @param intent  Indicates the pressed button.
205     */
206    @Override
207    public void onReceive(Context context, Intent intent) {
208        super.onReceive(context, intent);
209        if (intent.hasCategory(Intent.CATEGORY_ALTERNATIVE)) {
210            Uri data = intent.getData();
211            int buttonId = Integer.parseInt(data.getSchemeSpecificPart());
212            if (buttonId == BUTTON_WIFI) {
213                toggleWifi(context);
214            } else if (buttonId == BUTTON_BRIGHTNESS) {
215                toggleBrightness(context);
216            } else if (buttonId == BUTTON_SYNC) {
217                toggleBackgroundData(context);
218            } else if (buttonId == BUTTON_GPS) {
219                toggleGps(context);
220            } else if (buttonId == BUTTON_BLUETOOTH) {
221                toggleBluetooth(context);
222            }
223        }
224        // State changes fall through
225        updateWidget(context);
226    }
227
228    /**
229     * Gets the state of Wi-Fi
230     *
231     * @param context
232     * @return STATE_ENABLED, STATE_DISABLED, or STATE_INTERMEDIATE
233     */
234    private static int getWifiState(Context context) {
235        WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
236        int wifiState = wifiManager.getWifiState();
237        if (wifiState == WifiManager.WIFI_STATE_DISABLED) {
238            return STATE_DISABLED;
239        } else if (wifiState == WifiManager.WIFI_STATE_ENABLED) {
240            return STATE_ENABLED;
241        } else {
242            return STATE_INTERMEDIATE;
243        }
244    }
245
246    /**
247     * Toggles the state of Wi-Fi
248     *
249     * @param context
250     */
251    private void toggleWifi(Context context) {
252        WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
253        int wifiState = getWifiState(context);
254        if (wifiState == STATE_ENABLED) {
255            wifiManager.setWifiEnabled(false);
256        } else if (wifiState == STATE_DISABLED) {
257            wifiManager.setWifiEnabled(true);
258            mLocalBluetoothManager.setBluetoothEnabled(true);
259        }
260    }
261
262    /**
263     * Gets the state of background data.
264     *
265     * @param context
266     * @return true if enabled
267     */
268    private static boolean getBackgroundDataState(Context context) {
269        ConnectivityManager connManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
270        return connManager.getBackgroundDataSetting();
271    }
272
273    /**
274     * Toggle background data and sync tickles.
275     *
276     * @param context
277     */
278    private void toggleBackgroundData(Context context) {
279        ConnectivityManager connManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
280        boolean sync = getBackgroundDataState(context);
281        connManager.setBackgroundDataSetting(!sync);
282
283        IContentService contentService = ContentResolver.getContentService();
284        try {
285            contentService.setListenForNetworkTickles(!sync);
286        } catch (RemoteException e) {
287            Log.d(TAG, "toggleBackgroundData: " + e);
288        }
289    }
290
291    /**
292     * Gets the state of GPS location.
293     *
294     * @param context
295     * @return true if enabled.
296     */
297    private static boolean getGpsState(Context context) {
298        ContentResolver resolver = context.getContentResolver();
299        return Settings.Secure.isLocationProviderEnabled(resolver, LocationManager.GPS_PROVIDER);
300    }
301
302    /**
303     * Toggles the state of GPS.
304     *
305     * @param context
306     */
307    private void toggleGps(Context context) {
308        ContentResolver resolver = context.getContentResolver();
309        boolean enabled = getGpsState(context);
310        Settings.Secure.setLocationProviderEnabled(resolver, LocationManager.GPS_PROVIDER, !enabled);
311    }
312
313    /**
314     * Gets state of brightness.
315     *
316     * @param context
317     * @return true if more than moderately bright.
318     */
319    private static boolean getBrightness(Context context) {
320        try {
321            IHardwareService hardware = IHardwareService.Stub.asInterface(
322                    ServiceManager.getService("hardware"));
323            if (hardware != null) {
324                int brightness = Settings.System.getInt(context.getContentResolver(),
325                        Settings.System.SCREEN_BRIGHTNESS);
326                return brightness > 100;
327            }
328        } catch (Exception e) {
329            Log.d(TAG, "getBrightness: " + e);
330        }
331        return false;
332    }
333
334    /**
335     * Increases or decreases the brightness.
336     *
337     * @param context
338     */
339    private void toggleBrightness(Context context) {
340        try {
341            IHardwareService hardware = IHardwareService.Stub.asInterface(
342                    ServiceManager.getService("hardware"));
343            if (hardware != null) {
344                ContentResolver cr = context.getContentResolver();
345                int brightness = Settings.System.getInt(cr,
346                        Settings.System.SCREEN_BRIGHTNESS);
347                // Rotate MINIMUM -> DEFAULT -> MAXIMUM
348                // Technically, not a toggle...
349                if (brightness < DEFAULT_BACKLIGHT) {
350                    brightness = DEFAULT_BACKLIGHT;
351                } else if (brightness < MAXIMUM_BACKLIGHT) {
352                    brightness = MAXIMUM_BACKLIGHT;
353                } else {
354                    brightness = MINIMUM_BACKLIGHT;
355                }
356                hardware.setBacklights(brightness);
357                Settings.System.putInt(cr, Settings.System.SCREEN_BRIGHTNESS, brightness);
358                brightness = Settings.System.getInt(cr,
359                        Settings.System.SCREEN_BRIGHTNESS);
360            }
361        } catch (RemoteException e) {
362            Log.d(TAG, "toggleBrightness: " + e);
363        } catch (Settings.SettingNotFoundException e) {
364            Log.d(TAG, "toggleBrightness: " + e);
365        }
366    }
367
368    /**
369     * Gets state of bluetooth
370     *
371     * @param context
372     * @return STATE_ENABLED, STATE_DISABLED, or STATE_INTERMEDIATE
373     */
374    private static int getBluetoothState(Context context) {
375        if (mLocalBluetoothManager == null) {
376            mLocalBluetoothManager = LocalBluetoothManager.getInstance(context);
377            if (mLocalBluetoothManager == null) {
378                return STATE_INTERMEDIATE; // On emulator?
379            }
380        }
381        int state = mLocalBluetoothManager.getBluetoothState();
382        if (state == BluetoothDevice.BLUETOOTH_STATE_OFF) {
383            return STATE_DISABLED;
384        } else if (state == BluetoothDevice.BLUETOOTH_STATE_ON) {
385            return STATE_ENABLED;
386        } else {
387            return STATE_INTERMEDIATE;
388        }
389    }
390
391    /**
392     * Toggles the state of bluetooth
393     *
394     * @param context
395     */
396    private void toggleBluetooth(Context context) {
397        int state = getBluetoothState(context);
398        if (state == STATE_ENABLED) {
399            mLocalBluetoothManager.setBluetoothEnabled(false);
400        } else if (state == STATE_DISABLED) {
401            mLocalBluetoothManager.setBluetoothEnabled(true);
402        }
403    }
404}
405