/* * 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); } } /** * 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); } } }