/*
* Copyright (C) 2015 asksven
*
* 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.asksven.betterbatterystats.services;
import java.util.ArrayList;
import com.asksven.android.common.privateapiproxies.BatteryStatsProxy;
import com.asksven.android.common.privateapiproxies.Misc;
import com.asksven.android.common.privateapiproxies.StatElement;
import com.asksven.android.common.utils.DateUtils;
import com.asksven.android.common.utils.StringUtils;
import com.asksven.betterbatterystats.data.Reference;
import com.asksven.betterbatterystats.data.ReferenceStore;
import com.asksven.betterbatterystats.data.StatsProvider;
import com.asksven.betterbatterystats.widgetproviders.AppWidget;
import com.asksven.betterbatterystats.widgets.WidgetSummary;
import com.asksven.betterbatterystats.LogSettings;
import com.asksven.betterbatterystats.R;
import com.asksven.betterbatterystats.StatsActivity;
import android.annotation.SuppressLint;
import android.app.PendingIntent;
import android.app.Service;
import android.appwidget.AppWidgetManager;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.preference.PreferenceManager;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.TypedValue;
import android.widget.RemoteViews;
/**
* @author sven
*
*/
public class UpdateWidgetService extends Service
{
private static final String TAG = "UpdateWidgetService";
/** must be unique for each widget */
private static final int PI_CODE = 1;
@SuppressLint("NewApi")
@Override
public void onStart(Intent intent, int startId)
{
if (LogSettings.DEBUG)
{
Log.d(TAG, "Service started");
}
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(this
.getApplicationContext());
int[] allWidgetIds = intent
.getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS);
StatsProvider stats = StatsProvider.getInstance(this);
// make sure to flush cache
BatteryStatsProxy.getInstance(this).invalidate();
for (int widgetId : allWidgetIds)
{
RemoteViews remoteViews = new RemoteViews(this
.getApplicationContext().getPackageName(),
R.layout.widget);
final int cellSize = 40;
int width = 3;
int height = 2;
int widthDim = 0;
int heightDim = 0;
if (Build.VERSION.SDK_INT >= 16)
{
Bundle widgetOptions = appWidgetManager.getAppWidgetOptions(widgetId);
// width = (widgetOptions.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH)) / cellSize;
// height = (widgetOptions.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT)) / cellSize;
width = AppWidget.sizeToCells(widgetOptions.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH ) - 10);
height = AppWidget.sizeToCells(widgetOptions.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT) + 10);
widthDim = widgetOptions.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH);
heightDim = widgetOptions.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT);
Log.i(TAG, "[" + widgetId + "] height=" + height + " (" + widgetOptions.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT) + ")");
Log.i(TAG, "[" + widgetId + "] width=" + width + "(" + widgetOptions.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH) + ")");
remoteViews = new RemoteViews(this.getPackageName(), R.layout.widget_horz);
if ((height <= 2) && (width <= 2))
{
// switch to image only
Log.i(TAG, "[" + widgetId + "] using image-only layout");
remoteViews = new RemoteViews(this.getPackageName(), R.layout.widget);
}
else if (height < width)
{
// switch to horizontal
Log.i(TAG, "[" + widgetId + "] using horizontal layout");
remoteViews = new RemoteViews(this.getPackageName(), R.layout.widget_horz);
}
else
{
// switch to vertical
Log.i(TAG, "[" + widgetId + "] using vertical layout");
remoteViews = new RemoteViews(this.getPackageName(), R.layout.widget_vert);
}
}
// we change the bg color of the layout based on alpha from prefs
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
int opacity = sharedPrefs.getInt("new_widget_bg_opacity", 20);
opacity = (255 * opacity) / 100;
remoteViews.setInt(R.id.background, "setBackgroundColor", (opacity << 24) & android.graphics.Color.BLACK);
//remoteViews.setInt(R.id.layoutBackground, "setImageAlpha", opacity);
long timeAwake = 0;
long timeSince = 0;
long timeScreenOn = 0;
long timeDeepSleep = 0;
long timePWL = 0;
long timeKWL = 0;
String refFrom = sharedPrefs.getString("new_widget_default_stat_type", Reference.UNPLUGGED_REF_FILENAME);
try
{
// retrieve stats
Reference currentRef = StatsProvider.getInstance(this).getUncachedPartialReference(0);
Reference fromRef = ReferenceStore.getReferenceByName(refFrom, this);
ArrayList<StatElement> otherStats = stats.getOtherUsageStatList(true, fromRef, false, true, currentRef);
if ( (otherStats == null) || ( otherStats.size() == 1) )
{
// the desired stat type is unavailable, pick the alternate one and go on with that one
refFrom = sharedPrefs.getString("widget_fallback_stat_type", Reference.UNPLUGGED_REF_FILENAME);
fromRef = ReferenceStore.getReferenceByName(refFrom, this);
otherStats = stats.getOtherUsageStatList(true, fromRef, false, true, currentRef);
}
timeSince = StatsProvider.getInstance(this).getSince(fromRef, currentRef);
if ( (otherStats != null) && ( otherStats.size() > 1) )
{
Misc timeAwakeStat = (Misc) stats.getElementByKey(otherStats, StatsProvider.LABEL_MISC_AWAKE);
if (timeAwakeStat != null)
{
timeAwake = timeAwakeStat.getTimeOn();
}
else
{
timeAwake = 0;
}
Misc timeScreenOnStat = (Misc) stats.getElementByKey(otherStats, "Screen On");
if (timeScreenOnStat != null)
{
timeScreenOn = timeScreenOnStat.getTimeOn();
}
else
{
timeScreenOn = 0;
}
Misc deepSleepStat = ((Misc) stats.getElementByKey(otherStats, "Deep Sleep"));
if (deepSleepStat != null)
{
timeDeepSleep = deepSleepStat.getTimeOn();
}
else
{
timeDeepSleep = 0;
}
ArrayList<StatElement> pWakelockStats = stats.getWakelockStatList(true, fromRef, 0, 0, currentRef);
timePWL = stats.sum(pWakelockStats);
ArrayList<StatElement> kWakelockStats = stats.getKernelWakelockStatList(true, fromRef, 0, 0, currentRef);
timeKWL = stats.sum(kWakelockStats);
}
else
{
// no proper reference found
// remoteViews.setInt(R.id.graph, "setVisibility", View.GONE);
}
}
catch (Exception e)
{
Log.e(TAG, "Exception: "+Log.getStackTraceString(e));
}
finally
{
if (LogSettings.DEBUG)
{
Log.d(TAG, "Reference: " + refFrom);
Log.d(TAG, "Since: " + DateUtils.formatShort(timeSince) + " " + AppWidget.formatDuration(timeSince) + " " + timeSince);
Log.d(TAG, "Awake: " + DateUtils.formatShort(timeAwake) + " " + AppWidget.formatDuration(timeAwake) + " " + timeAwake);
Log.d(TAG, "Screen on: " + DateUtils.formatShort(timeScreenOn) + " " + AppWidget.formatDuration(timeScreenOn) + " " + timeScreenOn);
Log.d(TAG, "Deep sleep: " + DateUtils.formatShort(timeDeepSleep) + " " + AppWidget.formatDuration(timeDeepSleep) + " " + timeDeepSleep);
Log.d(TAG, "KWL: " + DateUtils.formatShort(timeKWL) + " " + AppWidget.formatDuration(timeKWL) + " " + timeKWL);
Log.d(TAG, "PWL: " + DateUtils.formatShort(timePWL) + " " + AppWidget.formatDuration(timePWL) + " " + timePWL);
}
WidgetSummary graph = new WidgetSummary();
graph.setAwake(timeAwake);
graph.setScreenOn(timeScreenOn);
graph.setDeepSleep(timeDeepSleep);
graph.setDuration(timeSince);
graph.setKWL(timeKWL);
graph.setPWL(timePWL);
DisplayMetrics metrics = this.getResources().getDisplayMetrics();
//Float px = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, Math.min(width, height) * cellSize, metrics);
Log.i(TAG, "Widget Dimensions: height=" + heightDim + " width=" + widthDim);
Float px = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, Math.min(Math.max(Math.min(widthDim, heightDim),80),160), metrics);
Log.i(TAG, "BitmapDip=" + Math.min(Math.max(Math.min(widthDim, heightDim),80),160) + ", BitmapPx=" + px.intValue());
graph.setBitmapSizePx(px.intValue());
remoteViews.setImageViewBitmap(R.id.imageView1, graph.getBitmap(this));
// Show % depending on width and if vertical or horz
if ((width > height) && (width <= 4))
{
remoteViews.setTextViewText(R.id.textViewAwakeVal, AppWidget.formatDuration(timeAwake-timeScreenOn));
remoteViews.setTextViewText(R.id.textViewDeepSleepVal, AppWidget.formatDuration(timeDeepSleep));
remoteViews.setTextViewText(R.id.textViewScreenOnVal, AppWidget.formatDuration(timeScreenOn));
remoteViews.setTextViewText(R.id.textViewKWLVal, AppWidget.formatDuration(timeKWL));
remoteViews.setTextViewText(R.id.textViewPWLVal, AppWidget.formatDuration(timePWL));
}
else
{
remoteViews.setTextViewText(R.id.textViewAwakeVal, AppWidget.formatDuration(timeAwake-timeScreenOn)
+ " (" + StringUtils.formatRatio(timeAwake-timeScreenOn, timeSince) + ")");
remoteViews.setTextViewText(R.id.textViewDeepSleepVal, AppWidget.formatDuration(timeDeepSleep)
+ " (" + StringUtils.formatRatio(timeDeepSleep, timeSince) + ")");
remoteViews.setTextViewText(R.id.textViewScreenOnVal, AppWidget.formatDuration(timeScreenOn)
+ " (" + StringUtils.formatRatio(timeScreenOn, timeSince) + ")");
remoteViews.setTextViewText(R.id.textViewKWLVal, AppWidget.formatDuration(timeKWL)
+ " (" + StringUtils.formatRatio(timeKWL, timeSince) + ")");
remoteViews.setTextViewText(R.id.textViewPWLVal, AppWidget.formatDuration(timePWL)
+ " (" + StringUtils.formatRatio(timePWL, timeSince) + ")");
}
// tap zones
// Register an onClickListener for the graph -> refresh
Intent clickIntentRefresh = new Intent(this.getApplicationContext(),
AppWidget.class);
clickIntentRefresh.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
clickIntentRefresh.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS,
allWidgetIds);
PendingIntent pendingIntentRefresh = PendingIntent.getBroadcast(
getApplicationContext(), 0, clickIntentRefresh,
PendingIntent.FLAG_UPDATE_CURRENT);
remoteViews.setOnClickPendingIntent(R.id.imageViewRefresh, pendingIntentRefresh);
// Register an onClickListener for the widget -> call main activity
Intent i = new Intent(Intent.ACTION_MAIN);
PackageManager manager = getPackageManager();
i = manager.getLaunchIntentForPackage(getPackageName());
i.addCategory(Intent.CATEGORY_LAUNCHER);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
int stat = Integer.valueOf(sharedPrefs.getString("widget_default_stat", "0"));
i.putExtra(StatsActivity.STAT, stat);
i.putExtra(StatsActivity.STAT_TYPE_FROM, refFrom);
i.putExtra(StatsActivity.STAT_TYPE_TO, Reference.CURRENT_REF_FILENAME);
PendingIntent clickPI = PendingIntent.getActivity(
this.getApplicationContext(), PI_CODE,
i, PendingIntent.FLAG_UPDATE_CURRENT);
remoteViews.setOnClickPendingIntent(R.id.imageView1, clickPI);
appWidgetManager.updateAppWidget(widgetId, remoteViews);
}
}
stopSelf();
super.onStart(intent, startId);
}
@Override
public IBinder onBind(Intent intent)
{
return null;
}
}