Back to project page Battery-Indicator.
The source code is released under:
GNU General Public License
If you think the Android project Battery-Indicator listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.
/* Copyright (c) 2009-2013 Darshan-Josiah Barber //from www . j a v a2s . co m This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. */ package com.darshancomputing.BatteryIndicatorPro; import android.app.AlarmManager; import android.app.KeyguardManager; import android.app.KeyguardManager.KeyguardLock; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.app.Service; import android.appwidget.AppWidgetManager; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.res.Resources; import android.content.ServiceConnection; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; import android.database.Cursor; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.os.Messenger; import android.os.PowerManager; import android.preference.PreferenceManager; import android.util.Log; import android.view.View; import android.widget.RemoteViews; import java.util.Date; import java.util.HashSet; public class BatteryInfoService extends Service { private final IntentFilter batteryChanged = new IntentFilter(Intent.ACTION_BATTERY_CHANGED); private final IntentFilter userPresent = new IntentFilter(Intent.ACTION_USER_PRESENT); private PendingIntent mainWindowPendingIntent; private PendingIntent updatePredictorPendingIntent; private Intent alarmsIntent; private final PluginServiceConnection pluginServiceConnection = new PluginServiceConnection(); private Intent pluginIntent; private String pluginPackage; private NotificationManager mNotificationManager; private AlarmManager alarmManager; private static SharedPreferences settings; private static SharedPreferences sp_store; private static SharedPreferences.Editor sps_editor; private KeyguardLock kl; private KeyguardManager km; private android.os.Vibrator mVibrator; private android.media.AudioManager mAudioManager; private Notification kgUnlockedNotification; private Context context; private Resources res; private Str str; private AlarmDatabase alarms; private LogDatabase log_db; private BatteryLevel bl; private CircleWidgetBackground cwbg; private BatteryInfo info; private long now; private boolean updated_lasts; private static java.util.HashSet<Messenger> clientMessengers; private static Messenger messenger; private static HashSet<Integer> widgetIds = new HashSet<Integer>(); private static AppWidgetManager widgetManager; private static int nWidgetsPresent = 0; private static final String LOG_TAG = "com.darshancomputing.BatteryIndicatorPro - BatteryInfoService"; private static final int NOTIFICATION_PRIMARY = 1; private static final int NOTIFICATION_KG_UNLOCKED = 2; private static final int NOTIFICATION_ALARM_CHARGE = 3; private static final int NOTIFICATION_ALARM_HEALTH = 4; private static final int NOTIFICATION_ALARM_TEMP = 5; public static final String KEY_PREVIOUS_CHARGE = "previous_charge"; public static final String KEY_PREVIOUS_TEMP = "previous_temp"; public static final String KEY_PREVIOUS_HEALTH = "previous_health"; public static final String KEY_DISABLE_LOCKING = "disable_lock_screen"; public static final String KEY_SERVICE_DESIRED = "serviceDesired"; public static final String KEY_SHOW_NOTIFICATION = "show_notification"; public static final String KEY_WIDGETS_PRESENT = "widgets_present"; public static final String KEY_NWIDGETS_PRESENT = "n_widgets_present"; private static final String EXTRA_UPDATE_PREDICTOR = "com.darshancomputing.BatteryBotPro.EXTRA_UPDATE_PREDICTOR"; private static final Object[] EMPTY_OBJECT_ARRAY = {}; private static final Class[] EMPTY_CLASS_ARRAY = {}; private static final int plainIcon0 = R.drawable.plain000; private static final int small_plainIcon0 = R.drawable.small_plain000; private static final int chargingIcon0 = R.drawable.charging000; private static final int small_chargingIcon0 = R.drawable.small_charging000; /* Global variables for these Notification Runnables */ private Notification mainNotification; private String mainNotificationTopLine, mainNotificationBottomLine; private RemoteViews notificationRV; private Predictor predictor; private final Handler mHandler = new Handler(); private final Runnable mPluginNotify = new Runnable() { public void run() { try { stopForeground(true); if (pluginServiceConnection.service == null) return; Class<?> c = pluginServiceConnection.service.getClass(); java.lang.reflect.Method m = c.getMethod("notify", new Class[] {int.class, int.class, String.class, String.class, PendingIntent.class}); m.invoke(pluginServiceConnection.service, new Object[] {info.percent, info.status, mainNotificationTopLine, mainNotificationBottomLine, mainWindowPendingIntent}); mHandler.removeCallbacks(mPluginNotify); mHandler.removeCallbacks(mNotify); } catch (Exception e) { e.printStackTrace(); } } }; private final Runnable mNotify = new Runnable() { public void run() { if (! pluginPackage.equals("none")) disconnectPlugin(); startForeground(NOTIFICATION_PRIMARY, mainNotification); mHandler.removeCallbacks(mPluginNotify); mHandler.removeCallbacks(mNotify); } }; private final Runnable runDisableKeyguard = new Runnable() { public void run() { kl = km.newKeyguardLock(getPackageName()); kl.disableKeyguard(); updateKeyguardNotification(); } }; @Override public void onCreate() { res = getResources(); str = new Str(res); context = getApplicationContext(); log_db = new LogDatabase(context); info = new BatteryInfo(); messenger = new Messenger(new MessageHandler()); clientMessengers = new java.util.HashSet<Messenger>(); predictor = new Predictor(context); bl = new BatteryLevel(context, BatteryLevel.SIZE_NOTIFICATION); cwbg = new CircleWidgetBackground(context); alarms = new AlarmDatabase(context); mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); mVibrator = (android.os.Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE); mAudioManager = (android.media.AudioManager) getSystemService(Context.AUDIO_SERVICE); alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); loadSettingsFiles(context); Intent mainWindowIntent = new Intent(context, BatteryInfoActivity.class); mainWindowPendingIntent = PendingIntent.getActivity(context, 0, mainWindowIntent, 0); Intent updatePredictorIntent = new Intent(context, BatteryInfoService.class); updatePredictorIntent.putExtra(EXTRA_UPDATE_PREDICTOR, true); updatePredictorPendingIntent = PendingIntent.getService(context, 0, updatePredictorIntent, 0); alarmsIntent = new Intent(context, AlarmsActivity.class); kgUnlockedNotification = new Notification(R.drawable.kg_unlocked, null, 0); kgUnlockedNotification.flags |= Notification.FLAG_ONGOING_EVENT | Notification.FLAG_NO_CLEAR; kgUnlockedNotification.setLatestEventInfo(context, "Lock Screen Disabled", "Press to re-enable", mainWindowPendingIntent); km = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE); if (sp_store.getBoolean(KEY_DISABLE_LOCKING, false)) setEnablednessOfKeyguard(false); pluginPackage = "none"; widgetManager = AppWidgetManager.getInstance(context); Class[] appWidgetProviders = {BatteryInfoAppWidgetProvider.class, /* Circle widget! */ FullAppWidgetProvider.class}; for (int i = 0; i < appWidgetProviders.length; i++) { int[] ids = widgetManager.getAppWidgetIds(new ComponentName(context, appWidgetProviders[i])); for (int j = 0; j < ids.length; j++) { widgetIds.add(ids[j]); } } nWidgetsPresent = sp_store.getInt(KEY_NWIDGETS_PRESENT, 0); if (sp_store.getBoolean(KEY_WIDGETS_PRESENT, false)) { nWidgetsPresent += 1; // v8.1.1 Circle widget sps_editor = sp_store.edit(); sps_editor.putBoolean(KEY_WIDGETS_PRESENT, false); sps_editor.putInt(KEY_NWIDGETS_PRESENT, nWidgetsPresent); sps_editor.commit(); } Intent bc_intent = registerReceiver(mBatteryInfoReceiver, batteryChanged); info.load(bc_intent, sp_store); } @Override public void onDestroy() { alarmManager.cancel(updatePredictorPendingIntent); setEnablednessOfKeyguard(true); alarms.close(); if (! pluginPackage.equals("none")) disconnectPlugin(); unregisterReceiver(mBatteryInfoReceiver); mHandler.removeCallbacks(mPluginNotify); mHandler.removeCallbacks(mNotify); mNotificationManager.cancelAll(); log_db.close(); stopForeground(true); } @Override public int onStartCommand(Intent intent, int flags, int startId) { // TODO: Do I need a filter, or is it okay to just update(null) every time? //if (intent != null && intent.getBooleanExtra(EXTRA_UPDATE_PREDICTOR, false)) update(null); return Service.START_STICKY; } @Override public IBinder onBind(Intent intent) { return messenger.getBinder(); } public class MessageHandler extends Handler { @Override public void handleMessage(Message incoming) { switch (incoming.what) { case RemoteConnection.SERVICE_CLIENT_CONNECTED: sendClientMessage(incoming.replyTo, RemoteConnection.CLIENT_SERVICE_CONNECTED); break; case RemoteConnection.SERVICE_REGISTER_CLIENT: clientMessengers.add(incoming.replyTo); sendClientMessage(incoming.replyTo, RemoteConnection.CLIENT_BATTERY_INFO_UPDATED, info.toBundle()); if (nWidgetsPresent > 0) sendClientMessage(incoming.replyTo, RemoteConnection.CLIENT_SERVICE_UNCLOSEABLE); else sendClientMessage(incoming.replyTo, RemoteConnection.CLIENT_SERVICE_CLOSEABLE); break; case RemoteConnection.SERVICE_UNREGISTER_CLIENT: clientMessengers.remove(incoming.replyTo); break; case RemoteConnection.SERVICE_RELOAD_SETTINGS: reloadSettings(false); break; case RemoteConnection.SERVICE_CANCEL_NOTIFICATION_AND_RELOAD_SETTINGS: reloadSettings(true); break; default: super.handleMessage(incoming); } } } private static void sendClientMessage(Messenger clientMessenger, int what) { sendClientMessage(clientMessenger, what, null); } private static void sendClientMessage(Messenger clientMessenger, int what, Bundle data) { Message outgoing = Message.obtain(); outgoing.what = what; outgoing.replyTo = messenger; outgoing.setData(data); try { clientMessenger.send(outgoing); } catch (android.os.RemoteException e) {} } public static class RemoteConnection implements ServiceConnection { // Messages clients send to the service public static final int SERVICE_CLIENT_CONNECTED = 0; public static final int SERVICE_REGISTER_CLIENT = 1; public static final int SERVICE_UNREGISTER_CLIENT = 2; public static final int SERVICE_RELOAD_SETTINGS = 3; public static final int SERVICE_CANCEL_NOTIFICATION_AND_RELOAD_SETTINGS = 4; // Messages the service sends to clients public static final int CLIENT_SERVICE_CONNECTED = 0; public static final int CLIENT_BATTERY_INFO_UPDATED = 1; public static final int CLIENT_SERVICE_CLOSEABLE = 2; public static final int CLIENT_SERVICE_UNCLOSEABLE = 3; public Messenger serviceMessenger; private Messenger clientMessenger; public RemoteConnection(Messenger m) { clientMessenger = m; } public void onServiceConnected(ComponentName name, IBinder iBinder) { serviceMessenger = new Messenger(iBinder); Message outgoing = Message.obtain(); outgoing.what = SERVICE_CLIENT_CONNECTED; outgoing.replyTo = clientMessenger; try { serviceMessenger.send(outgoing); } catch (android.os.RemoteException e) {} } public void onServiceDisconnected(ComponentName name) { serviceMessenger = null; } } private static void loadSettingsFiles(Context context) { settings = context.getSharedPreferences(SettingsActivity.SETTINGS_FILE, Context.MODE_MULTI_PROCESS); sp_store = context.getSharedPreferences(SettingsActivity.SP_STORE_FILE, Context.MODE_MULTI_PROCESS); } private void reloadSettings(boolean cancelFirst) { loadSettingsFiles(context); str = new Str(res); // Language override may have changed if (cancelFirst) stopForeground(true); if (sp_store.getBoolean(KEY_DISABLE_LOCKING, false)) setEnablednessOfKeyguard(false); else setEnablednessOfKeyguard(true); registerReceiver(mBatteryInfoReceiver, batteryChanged); } /* public Boolean pluginHasSettings() { if (pluginServiceConnection.service == null) return false; try { Class<?> c = pluginServiceConnection.service.getClass(); java.lang.reflect.Method m = c.getMethod("hasSettings", EMPTY_CLASS_ARRAY); return (Boolean) m.invoke(pluginServiceConnection.service, EMPTY_OBJECT_ARRAY); } catch (Exception e) { e.printStackTrace(); return false; } } public void configurePlugin() { if (pluginServiceConnection.service == null) return; try { Class<?> c = pluginServiceConnection.service.getClass(); java.lang.reflect.Method m = c.getMethod("configure", EMPTY_CLASS_ARRAY); m.invoke(pluginServiceConnection.service, EMPTY_OBJECT_ARRAY); } catch (Exception e) { e.printStackTrace(); } } */ private final BroadcastReceiver mBatteryInfoReceiver = new BroadcastReceiver() { @Override public void onReceive(Context c, Intent intent) { if (! Intent.ACTION_BATTERY_CHANGED.equals(intent.getAction())) return; update(intent); } }; private void update(Intent intent) { now = System.currentTimeMillis(); sps_editor = sp_store.edit(); updated_lasts = false; setupPlugins(); if (intent != null) info.load(intent, sp_store); predictor.setPredictionType(settings.getString(SettingsActivity.KEY_PREDICTION_TYPE, str.default_prediction_type)); predictor.update(info); info.prediction.updateRelativeTime(); if (statusHasChanged()) handleUpdateWithChangedStatus(); else handleUpdateWithSameStatus(); if (sp_store.getBoolean(KEY_SHOW_NOTIFICATION, true)) { prepareNotification(); doNotify(); } if (alarms.anyActiveAlarms()) handleAlarms(); updateWidgets(); syncSpsEditor(); // Important to sync after other Service code that uses 'lasts' but before sending info to client for (Messenger messenger : clientMessengers) { // TODO: Can I send the same message to multiple clients instead of sending duplicates? sendClientMessage(messenger, RemoteConnection.CLIENT_BATTERY_INFO_UPDATED, info.toBundle()); } alarmManager.set(AlarmManager.ELAPSED_REALTIME, android.os.SystemClock.elapsedRealtime() + (2 * 60 * 1000), updatePredictorPendingIntent); } private void updateWidgets() { Intent mainWindowIntent = new Intent(context, BatteryInfoActivity.class); PendingIntent mainWindowPendingIntent = PendingIntent.getActivity(context, 0, mainWindowIntent, 0); bl.setLevel(info.percent); cwbg.setLevel(info.percent); for (Integer widgetId : widgetIds) { RemoteViews rv; android.appwidget.AppWidgetProviderInfo awpInfo = widgetManager.getAppWidgetInfo(widgetId); if (awpInfo == null) continue; // Based on Developer Console crash reports, this can be null sometimes int initLayout = awpInfo.initialLayout; if (initLayout == R.layout.circle_app_widget) { rv = new RemoteViews(context.getPackageName(), R.layout.circle_app_widget); rv.setImageViewBitmap(R.id.circle_widget_image_view, cwbg.getBitmap()); } else { rv = new RemoteViews(context.getPackageName(), R.layout.full_app_widget); rv.setImageViewBitmap(R.id.battery_level_view, bl.getBitmap()); if (info.prediction.what == BatteryInfo.Prediction.NONE) { rv.setTextViewText(R.id.fully_charged, str.timeRemaining(info)); rv.setTextViewText(R.id.time_remaining, ""); rv.setTextViewText(R.id.until_what, ""); } else { rv.setTextViewText(R.id.fully_charged, ""); rv.setTextViewText(R.id.time_remaining, str.timeRemaining(info)); rv.setTextViewText(R.id.until_what, str.untilWhat(info)); } } rv.setTextViewText(R.id.level, "" + info.percent + str.percent_symbol); rv.setOnClickPendingIntent(R.id.widget_layout, mainWindowPendingIntent); widgetManager.updateAppWidget(widgetId, rv); } } private void syncSpsEditor() { sps_editor.commit(); if (updated_lasts) { info.last_status_cTM = now; info.last_status = info.status; info.last_percent = info.percent; info.last_plugged = info.plugged; } } private void prepareNotification() { mainNotificationTopLine = lineFor(SettingsActivity.KEY_TOP_LINE); mainNotificationBottomLine = lineFor(SettingsActivity.KEY_BOTTOM_LINE); // TODO: Is it necessary to call new() every time here, or can I get away with just setting the icon on existing Notif.? mainNotification = new Notification(iconFor(info.percent), null, 0l); if (android.os.Build.VERSION.SDK_INT >= 16) { mainNotification.priority = Integer.valueOf(settings.getString(SettingsActivity.KEY_MAIN_NOTIFICATION_PRIORITY, str.default_main_notification_priority)); } mainNotification.flags |= Notification.FLAG_ONGOING_EVENT | Notification.FLAG_NO_CLEAR; if (settings.getBoolean(SettingsActivity.KEY_USE_SYSTEM_NOTIFICATION_LAYOUT, res.getBoolean(R.bool.default_use_system_notification_layout))) { mainNotification.setLatestEventInfo(context, mainNotificationTopLine, mainNotificationBottomLine, mainWindowPendingIntent); } else { String icon_area = settings.getString(SettingsActivity.KEY_ICON_AREA, res.getString(R.string.default_icon_area_content)); int layout_id = R.layout.main_notification; if (icon_area.equals("percentage_first")) layout_id = R.layout.main_notification_percentage_first; notificationRV = new RemoteViews(getPackageName(), layout_id); if (icon_area.equals("percentage")) { notificationRV.setViewVisibility(R.id.percent, View.VISIBLE); notificationRV.setViewVisibility(R.id.battery, View.GONE); } else if (icon_area.equals("graphic")) { notificationRV.setViewVisibility(R.id.percent, View.GONE); notificationRV.setViewVisibility(R.id.battery, View.VISIBLE); } notificationRV.setImageViewBitmap(R.id.battery, bl.getBitmap()); bl.setLevel(info.percent); notificationRV.setTextViewText(R.id.percent, "" + info.percent + str.percent_symbol); notificationRV.setTextViewText(R.id.top_line, android.text.Html.fromHtml(mainNotificationTopLine)); notificationRV.setTextViewText(R.id.bottom_line, mainNotificationBottomLine); int color; color = colorFor(SettingsActivity.KEY_NOTIFICATION_PERCENTAGE_TEXT_COLOR, SettingsActivity.KEY_CUSTOM_PERCENTAGE_TEXT_COLOR); if (color != 0) notificationRV.setTextColor(R.id.percent, color); color = colorFor(SettingsActivity.KEY_NOTIFICATION_TOP_LINE_COLOR, SettingsActivity.KEY_CUSTOM_TOP_LINE_COLOR); if (color != 0) notificationRV.setTextColor(R.id.top_line, color); color = colorFor(SettingsActivity.KEY_NOTIFICATION_BOTTOM_LINE_COLOR, SettingsActivity.KEY_CUSTOM_BOTTOM_LINE_COLOR); if (color != 0) notificationRV.setTextColor(R.id.bottom_line, color); boolean default_show_box = res.getBoolean(R.bool.default_show_box_around_icon_area); boolean show_box = settings.getBoolean(SettingsActivity.KEY_SHOW_BOX_AROUND_ICON_AREA, default_show_box); if (show_box) { color = res.getColor(R.color.notification_box_default_color); if (! icon_area.equals("battery_first")) notificationRV.setInt(R.id.percent, "setBackgroundColor", color); if (! icon_area.equals("percentage_first")) notificationRV.setInt(R.id.battery, "setBackgroundColor", color); } mainNotification.contentIntent = mainWindowPendingIntent; mainNotification.contentView = notificationRV; } } // Since alpha values aren't permitted, return 0 for default private int colorFor(String colorKey, String customKey) { String colorString = settings.getString(colorKey, "default"); if (colorString.charAt(0) == '#') return colorFromHex(colorString); else if (colorString.equals("custom")) return settings.getInt(customKey, R.color.main_notification_default_custom_text_color); else return 0; } private static int colorFromHex(String hex) { if (hex.length() != 7) return 0; if (hex.charAt(0) != '#') return 0; int color = 0xff; for (int i = 1; i <= 6; i++) { color <<= 4; char c = hex.charAt(i); if (c >= '0' && c <= '9') color += c - '0'; else if (c >= 'A' && c <= 'F') color += c - 'A' + 10; else if (c >= 'a' && c <= 'f') color += c - 'a' + 10; } return color; } private String lineFor(String key) { String req = settings.getString(key, key.equals(SettingsActivity.KEY_TOP_LINE) ? "remaining" : "vitals"); if (req.equals("remaining")) return predictionLine(); else if (req.equals("vitals")) return vitalStatsLine(); else return statusDurationLine(); } private String predictionLine() { String line; BatteryInfo.RelativeTime predicted = info.prediction.last_rtime; if (info.prediction.what == BatteryInfo.Prediction.NONE) { line = str.statuses[info.status]; } else { if (predicted.days > 0) line = str.n_days_m_hours(predicted.days, predicted.hours); else if (predicted.hours > 0) { String verbosity = settings.getString(SettingsActivity.KEY_TIME_REMAINING_VERBOSITY, res.getString(R.string.default_time_remaining_verbosity)); if (verbosity.equals("condensed")) line = str.n_hours_m_minutes_medium(predicted.hours, predicted.minutes); else if (verbosity.equals("verbose")) line = str.n_hours_m_minutes_long(predicted.hours, predicted.minutes); else line = str.n_hours_long_m_minutes_medium(predicted.hours, predicted.minutes); } else line = str.n_minutes_long(predicted.minutes); if (info.prediction.what == BatteryInfo.Prediction.UNTIL_CHARGED) line += res.getString(R.string.notification_until_charged); else line += res.getString(R.string.notification_until_drained); } return line; } private String vitalStatsLine() { Boolean convertF = settings.getBoolean(SettingsActivity.KEY_CONVERT_F, false); String line = str.healths[info.health] + " / " + str.formatTemp(info.temperature, convertF); if (info.voltage > 500) line += " / " + str.formatVoltage(info.voltage); if (settings.getBoolean(SettingsActivity.KEY_STATUS_DURATION_IN_VITAL_SIGNS, false)) { float statusDurationHours = (now - info.last_status_cTM) / (60 * 60 * 1000f); line += " / " + String.format("%.1f", statusDurationHours) + "h"; // TODO: Translatable 'h' } return line; } private String statusDurationLine() { long statusDuration = now - info.last_status_cTM; int statusDurationHours = (int) ((statusDuration + (1000 * 60 * 30)) / (1000 * 60 * 60)); String line = str.statuses[info.status] + " "; if (statusDuration < 1000 * 60 * 60) line += str.since + " " + formatTime(new Date(info.last_status_cTM)); else line += str.for_n_hours(statusDurationHours); return line; } private void doNotify() { if (! pluginPackage.equals("none")) { // TODO: Set up callback mechanism with plugins V2 mHandler.postDelayed(mPluginNotify, 100); mHandler.postDelayed(mPluginNotify, 300); mHandler.postDelayed(mPluginNotify, 900); mHandler.postDelayed(mNotify, 1000); } else { mHandler.post(mNotify); } } // I take advantage of (count on) R.java having resources alphabetical and incrementing by one. private int iconFor(int percent) { String default_set = "builtin.classic"; if (android.os.Build.VERSION.SDK_INT >= 11) default_set = "builtin.plain_number"; String icon_set = settings.getString(SettingsActivity.KEY_ICON_SET, "null"); if (! icon_set.startsWith("builtin.")) icon_set = "null"; // TODO: Remove this line to re-enable plugins if (icon_set.equals("null")) { icon_set = default_set; SharedPreferences.Editor settings_editor = settings.edit(); settings_editor.putString(SettingsActivity.KEY_ICON_SET, default_set); settings_editor.commit(); } Boolean indicate_charging = settings.getBoolean(SettingsActivity.KEY_INDICATE_CHARGING, true); if (icon_set.equals("builtin.plain_number")) { return ((info.status == BatteryInfo.STATUS_CHARGING && indicate_charging) ? chargingIcon0 : plainIcon0) + info.percent; } else if (icon_set.equals("builtin.smaller_number")) { return ((info.status == BatteryInfo.STATUS_CHARGING && indicate_charging) ? small_chargingIcon0 : small_plainIcon0) + info.percent; } else { if (settings.getBoolean(SettingsActivity.KEY_RED, res.getBoolean(R.bool.default_use_red)) && info.percent < Integer.valueOf(settings.getString(SettingsActivity.KEY_RED_THRESH, str.default_red_thresh)) && info.percent <= SettingsActivity.RED_ICON_MAX) { return R.drawable.r000 + info.percent - 0; } else if (settings.getBoolean(SettingsActivity.KEY_AMBER, res.getBoolean(R.bool.default_use_amber)) && info.percent < Integer.valueOf(settings.getString(SettingsActivity.KEY_AMBER_THRESH, str.default_amber_thresh)) && info.percent <= SettingsActivity.AMBER_ICON_MAX && info.percent >= SettingsActivity.AMBER_ICON_MIN){ return R.drawable.a000 + info.percent - 0; } else if (settings.getBoolean(SettingsActivity.KEY_GREEN, res.getBoolean(R.bool.default_use_green)) && info.percent >= Integer.valueOf(settings.getString(SettingsActivity.KEY_GREEN_THRESH, str.default_green_thresh)) && info.percent >= SettingsActivity.GREEN_ICON_MIN) { return R.drawable.g020 + info.percent - 20; } else { return R.drawable.b000 + info.percent; } } } private boolean statusHasChanged() { int previous_charge = sp_store.getInt(KEY_PREVIOUS_CHARGE, 100); return (info.last_status != info.status || info.last_status_cTM >= now || info.last_plugged != info.plugged || (info.plugged == BatteryInfo.PLUGGED_UNPLUGGED && info.percent > previous_charge + 20)); } private void handleUpdateWithChangedStatus() { if (settings.getBoolean(SettingsActivity.KEY_ENABLE_LOGGING, true)) { log_db.logStatus(info, now, LogDatabase.STATUS_NEW); if (info.status != info.last_status && info.last_status == BatteryInfo.STATUS_UNPLUGGED) log_db.prune(Integer.valueOf(settings.getString(SettingsActivity.KEY_MAX_LOG_AGE, str.default_max_log_age))); } /* TODO: Af first glance, I think I want to do this, but think about it a bit and decide for sure... */ if (info.status != info.last_status && info.status == BatteryInfo.STATUS_UNPLUGGED) mNotificationManager.cancel(NOTIFICATION_ALARM_CHARGE); if (info.last_status != info.status && settings.getBoolean(SettingsActivity.KEY_AUTO_DISABLE_LOCKING, false)) { if (info.last_status == BatteryInfo.STATUS_UNPLUGGED) { sps_editor.putBoolean(KEY_DISABLE_LOCKING, true); setEnablednessOfKeyguard(false); } else if (info.status == BatteryInfo.STATUS_UNPLUGGED) { sps_editor.putBoolean(KEY_DISABLE_LOCKING, false); setEnablednessOfKeyguard(true); /* If the screen was on, "inside" the keyguard, when the keyguard was disabled, then we're still inside it now, even if the screen is off. So we aquire a wakelock that forces the screen to turn on, then release it. If the screen is on now, this has no effect, but if it's off, then either the user will press the power button or the screen will turn itself off after the normal timeout. Either way, when the screen goes off, the keyguard will now be enabled properly. */ PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.ON_AFTER_RELEASE, getPackageName()); wl.acquire(); wl.release(); } } updated_lasts = true; sps_editor.putLong(BatteryInfo.KEY_LAST_STATUS_CTM, now); sps_editor.putInt(BatteryInfo.KEY_LAST_STATUS, info.status); sps_editor.putInt(BatteryInfo.KEY_LAST_PERCENT, info.percent); sps_editor.putInt(BatteryInfo.KEY_LAST_PLUGGED, info.plugged); sps_editor.putInt(KEY_PREVIOUS_CHARGE, info.percent); sps_editor.putInt(KEY_PREVIOUS_TEMP, info.temperature); sps_editor.putInt(KEY_PREVIOUS_HEALTH, info.health); } private void handleUpdateWithSameStatus() { if (settings.getBoolean(SettingsActivity.KEY_ENABLE_LOGGING, true)) log_db.logStatus(info, now, LogDatabase.STATUS_OLD); if (info.percent % 10 == 0) { sps_editor.putInt(KEY_PREVIOUS_CHARGE, info.percent); sps_editor.putInt(KEY_PREVIOUS_TEMP, info.temperature); sps_editor.putInt(KEY_PREVIOUS_HEALTH, info.health); } } private void handleAlarms() { Cursor c; Notification notification; PendingIntent contentIntent = PendingIntent.getActivity(context, 0, alarmsIntent, 0); int previous_charge = sp_store.getInt(KEY_PREVIOUS_CHARGE, 100); if (info.status == BatteryInfo.STATUS_FULLY_CHARGED && info.status != info.last_status) { c = alarms.activeAlarmFull(); if (c != null) { notification = parseAlarmCursor(c); notification.setLatestEventInfo(context, str.alarm_fully_charged, str.alarm_text, contentIntent); mNotificationManager.notify(NOTIFICATION_ALARM_CHARGE, notification); c.close(); } } c = alarms.activeAlarmChargeDrops(info.percent, previous_charge); if (c != null) { sps_editor.putInt(KEY_PREVIOUS_CHARGE, info.percent); notification = parseAlarmCursor(c); notification.setLatestEventInfo(context, str.alarm_charge_drops + c.getInt(alarms.INDEX_THRESHOLD) + str.percent_symbol, str.alarm_text, contentIntent); mNotificationManager.notify(NOTIFICATION_ALARM_CHARGE, notification); c.close(); } c = alarms.activeAlarmChargeRises(info.percent, previous_charge); if (c != null && info.status != BatteryInfo.STATUS_UNPLUGGED) { sps_editor.putInt(KEY_PREVIOUS_CHARGE, info.percent); notification = parseAlarmCursor(c); notification.setLatestEventInfo(context, str.alarm_charge_rises + c.getInt(alarms.INDEX_THRESHOLD) + str.percent_symbol, str.alarm_text, contentIntent); mNotificationManager.notify(NOTIFICATION_ALARM_CHARGE, notification); c.close(); } c = alarms.activeAlarmTempRises(info.temperature, sp_store.getInt(KEY_PREVIOUS_TEMP, 1)); if (c != null) { Boolean convertF = settings.getBoolean(SettingsActivity.KEY_CONVERT_F, false); sps_editor.putInt(KEY_PREVIOUS_TEMP, info.temperature); notification = parseAlarmCursor(c); notification.setLatestEventInfo(context, str.alarm_temp_rises + str.formatTemp(c.getInt(alarms.INDEX_THRESHOLD), convertF, false), str.alarm_text, contentIntent); mNotificationManager.notify(NOTIFICATION_ALARM_TEMP, notification); c.close(); } if (info.health > BatteryInfo.HEALTH_GOOD && info.health != sp_store.getInt(KEY_PREVIOUS_HEALTH, BatteryInfo.HEALTH_GOOD)) { c = alarms.activeAlarmFailure(); if (c != null) { sps_editor.putInt(KEY_PREVIOUS_HEALTH, info.health); notification = parseAlarmCursor(c); notification.setLatestEventInfo(context, str.alarm_health_failure + str.healths[info.health], str.alarm_text, contentIntent); mNotificationManager.notify(NOTIFICATION_ALARM_HEALTH, notification); c.close(); } } } private Notification parseAlarmCursor(Cursor c) { Notification notification = new Notification(R.drawable.stat_notify_alarm, null, now); notification.flags |= Notification.FLAG_AUTO_CANCEL; String ringtone = c.getString(alarms.INDEX_RINGTONE); if (! ringtone.equals("")) notification.sound = android.net.Uri.parse(ringtone); if (c.getInt(alarms.INDEX_VIBRATE) == 1) if (mAudioManager.getRingerMode() != mAudioManager.RINGER_MODE_SILENT) /* I couldn't get the Notification to vibrate, so I do it myself... */ mVibrator.vibrate(new long[] {0, 200, 200, 400}, -1); if (c.getInt(alarms.INDEX_LIGHTS) == 1) { notification.flags |= Notification.FLAG_SHOW_LIGHTS; notification.defaults |= Notification.DEFAULT_LIGHTS; } return notification; } private void setEnablednessOfKeyguard(boolean enabled) { if (enabled) { if (kl != null) { unregisterReceiver(mUserPresentReceiver); mHandler.removeCallbacks(runDisableKeyguard); kl.reenableKeyguard(); kl = null; } } else { if (km.inKeyguardRestrictedInputMode()) { registerReceiver(mUserPresentReceiver, userPresent); } else { if (kl != null) kl.reenableKeyguard(); else registerReceiver(mUserPresentReceiver, userPresent); mHandler.postDelayed(runDisableKeyguard, 300); } } updateKeyguardNotification(); } private void updateKeyguardNotification() { if (kl != null && settings.getBoolean(SettingsActivity.KEY_NOTIFY_WHEN_KG_DISABLED, true)) mNotificationManager.notify(NOTIFICATION_KG_UNLOCKED, kgUnlockedNotification); else mNotificationManager.cancel(NOTIFICATION_KG_UNLOCKED); } private final BroadcastReceiver mUserPresentReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if (Intent.ACTION_USER_PRESENT.equals(intent.getAction())){ if (sp_store.getBoolean(KEY_DISABLE_LOCKING, false)) setEnablednessOfKeyguard(false); } } }; private String formatTime(Date d) { String format = android.provider.Settings.System.getString(getContentResolver(), android.provider.Settings.System.TIME_12_24); if (format == null || format.equals("12")) { return java.text.DateFormat.getTimeInstance(java.text.DateFormat.SHORT, java.util.Locale.getDefault()).format(d); } else { return (new java.text.SimpleDateFormat("HH:mm")).format(d); } } private void setupPlugins() { mHandler.removeCallbacks(mPluginNotify); mHandler.removeCallbacks(mNotify); String desiredPluginPackage = settings.getString(SettingsActivity.KEY_ICON_PLUGIN, "none"); if (! desiredPluginPackage.equals("none")) { SharedPreferences.Editor settings_editor = settings.edit(); settings_editor.putString(SettingsActivity.KEY_ICON_SET, desiredPluginPackage); settings_editor.putString(SettingsActivity.KEY_ICON_PLUGIN, "none"); settings_editor.commit(); } desiredPluginPackage = settings.getString(SettingsActivity.KEY_ICON_SET, "none"); if (desiredPluginPackage.startsWith("builtin.")) desiredPluginPackage = "none"; if (! pluginPackage.equals(desiredPluginPackage) && ! pluginPackage.equals("none")) disconnectPlugin(); if (! pluginPackage.equals(desiredPluginPackage) && ! desiredPluginPackage.equals("none")) { try { Context pluginContext = getApplicationContext().createPackageContext(desiredPluginPackage, Context.CONTEXT_INCLUDE_CODE); ClassLoader pluginClassLoader = pluginContext.getClassLoader(); Class pluginClass = pluginClassLoader.loadClass(desiredPluginPackage + ".PluginService"); pluginIntent = new Intent(pluginContext, pluginClass); startService(pluginIntent); if (! bindService(pluginIntent, pluginServiceConnection, 0)) { stopService(pluginIntent); throw new Exception(); } pluginPackage = desiredPluginPackage; } catch (Exception e) { e.printStackTrace(); pluginPackage = "none"; } } } private void disconnectPlugin() { unbindService(pluginServiceConnection); stopService(pluginIntent); pluginServiceConnection.service = null; pluginPackage = "none"; } public static void onWidgetUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { widgetManager = appWidgetManager; for (int i = 0; i < appWidgetIds.length; i++) { widgetIds.add(appWidgetIds[i]); } context.startService(new Intent(context, BatteryInfoService.class)); } public static void onWidgetDeleted(Context context, int[] appWidgetIds) { for (int i = 0; i < appWidgetIds.length; i++) { widgetIds.remove(appWidgetIds[i]); } } public static void onWidgetEnabled(Context context) { nWidgetsPresent += 1; if (sp_store == null) loadSettingsFiles(context); sps_editor = sp_store.edit(); sps_editor.putInt(KEY_NWIDGETS_PRESENT, nWidgetsPresent); sps_editor.commit(); if (clientMessengers == null) return; for (Messenger messenger : clientMessengers) { sendClientMessage(messenger, RemoteConnection.CLIENT_SERVICE_UNCLOSEABLE); } } public static void onWidgetDisabled(Context context) { nWidgetsPresent -= 1; if (sp_store == null) loadSettingsFiles(context); sps_editor = sp_store.edit(); sps_editor.putInt(KEY_NWIDGETS_PRESENT, nWidgetsPresent); sps_editor.commit(); if (clientMessengers == null) return; for (Messenger messenger : clientMessengers) { sendClientMessage(messenger, RemoteConnection.CLIENT_SERVICE_CLOSEABLE); } } }