Reputation: 37733
I developed a widget some years ago. The widget works perfectly until now. It is not working fine in Android 5.1.1 devices, but it works perfect in Android 4.4 and lower versions. The widget displays three numeric values given by the operating system. These values are correctly obtained, because i can display them outside of this widget in a test app, and they are getting updated in that test non widget app.
In android 5.1.1 no icon is being displayed in widgets menu, it is showing default android icon. Also, widget is not being updated!!! i don't know what is wrong. I need a widget that must work on 4.1, 4.4 and 5.1 devices.
Something has changed in Android 5.1.1 widgets that must be implemented? I can't find anything different in the documentation
This is my widget:
manifest:
<receiver android:name="com.myapp.CPUWidgetProvider" android:label="@string/app_name" android:icon="@drawable/icon128">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<intent-filter>
<action android:name="AUTO_UPDATE" />
</intent-filter>
<meta-data android:name="android.appwidget.provider" android:resource="@xml/widget_provider" />
</receiver>
<service android:name="com.myapp.UpdateService"/>
my widget_provider.xml file:
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:minWidth="40dp"
android:minHeight="40dp"
android:initialLayout="@layout/widget_layout"
android:updatePeriodMillis="0"
/>
my widget_layout.xml file:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/fondo"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@drawable/widget_background"
android:paddingLeft="1dp"
android:paddingRight="1dp"
android:paddingTop="10dp"
android:paddingBottom="10dp">
<TextView
android:id="@+id/freq"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="@string/loading"
android:textSize="12sp"
android:textColor="#EE08B608"
android:layout_weight="1"/>
<TextView
android:id="@+id/usage"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="..."
android:textSize="12sp"
android:textColor="#EE08B608"
android:layout_weight="1"/>
<TextView
android:id="@+id/temp"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="27ºC 80ºF"
android:textSize="11sp"
android:textColor="#EE08B608"
android:layout_weight="1"/>
</LinearLayout>
my widget alarm:
public class WidgetAlarm{
private final int ALARM_ID = 0;
private final int INTERVAL_MILLIS = 5000;
private Context mContext;
public WidgetAlarm(Context context){
mContext = context;
}
public void startAlarm(){
Intent alarmIntent = new Intent(CPUWidgetProvider.ACTION_AUTO_UPDATE);
PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, ALARM_ID, alarmIntent, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager alarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
alarmManager.setRepeating(AlarmManager.RTC, System.currentTimeMillis(), INTERVAL_MILLIS, pendingIntent); // RTC does not wake the device up
}
public void stopAlarm(){
Intent alarmIntent = new Intent(CPUWidgetProvider.ACTION_AUTO_UPDATE);
PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, ALARM_ID, alarmIntent, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager alarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
alarmManager.cancel(pendingIntent);
}
}
my updateservice:
public class UpdateService extends Service implements SensorEventListener {
private SensorManager mSensorManager;
private Sensor mTempSensor;
double auxBatteryTemp;
String systemTemp=null;
String systemTempFarenheit=null;
String batteryTemp="25";
String batteryTempFarenheit="80";
int processorMaxFreq=-1;
DecimalFormatSymbols symbols;
DecimalFormat tempDecimalFormat;
boolean serviceDestroyed=false;
Context ctx;
PowerManager pm;
RemoteViews remoteViews;
ComponentName thisWidget;
private BroadcastReceiver mBatInfoReceiver; //Broadcast receiver for the battery temperature
private BroadcastReceiver screenoffReceiver; //Broadcast receiver for stop the alarm when the screen is off
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
//System.out.println("XXXXX SERVICE START COMMAND");
/* receivers */
mBatInfoReceiver = new BroadcastReceiver(){
@Override
public void onReceive(Context arg0, Intent intent) {
try {
auxBatteryTemp = intent.getIntExtra(BatteryManager.EXTRA_TEMPERATURE, 0);
batteryTemp = ""+(int) (auxBatteryTemp / 10);
auxBatteryTemp=auxBatteryTemp/10;
batteryTempFarenheit = ""+(int)(((auxBatteryTemp*((float)9/5))+32));
updateTemperatures();
} catch (Exception e) {e.printStackTrace();}
}
};
screenoffReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if(intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
WidgetAlarm widgetAlarm = new WidgetAlarm(context.getApplicationContext());
widgetAlarm.stopAlarm();
}
else if(intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
WidgetAlarm widgetAlarm = new WidgetAlarm(context.getApplicationContext());
widgetAlarm.startAlarm();
}
return;
}
};
symbols = new DecimalFormatSymbols(Locale.GERMAN);
symbols.setDecimalSeparator('.');
tempDecimalFormat = new DecimalFormat("#.#", symbols);
this.ctx = this;
pm = (PowerManager) ctx.getSystemService(Context.POWER_SERVICE);
remoteViews = new RemoteViews(ctx.getPackageName(), R.layout.widget_layout);
thisWidget = new ComponentName( ctx, CPUWidgetProvider.class );
//Temperature sensors
mSensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);
if (Build.VERSION.SDK_INT >= 14)
mTempSensor = mSensorManager.getDefaultSensor(13); //13 = Sensor.TYPE_AMBIENT_TEMPERATURE //this constant required Android 4.0
else
mTempSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_TEMPERATURE);
mSensorManager.registerListener(this, mTempSensor, SensorManager.SENSOR_DELAY_FASTEST);
//adding receivers
registerReceiver(this.mBatInfoReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
registerReceiver(screenoffReceiver, filter);
//return super.onStartCommand(intent, flags, startId);
return Service.START_STICKY;
}
@Override
public void onDestroy() {
super.onDestroy();
try {
mSensorManager.unregisterListener(this);
unregisterReceiver(this.mBatInfoReceiver);
unregisterReceiver(this.screenoffReceiver);
serviceDestroyed=true;
} catch (Exception e) {e.printStackTrace();}
//System.out.println("XXXXX SERVICE DESTROY");
}
@Override
public IBinder onBind(Intent arg0) {
return null;
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {}
@Override
public void onSensorChanged(SensorEvent event) {
if (Build.VERSION.SDK_INT >= 14){
if (event.sensor.getType() == 13) { //13 = Sensor.TYPE_AMBIENT_TEMPERATURE //this constant required Android 4.0
getTemperature(event);
}
}else{
if (event.sensor.getType() == Sensor.TYPE_TEMPERATURE) {
getTemperature(event);
}
}
}
public void getTemperature(SensorEvent event){
float values[] = event.values;
if (values.length>0){
systemTemp = ""+(int)values[0];
systemTempFarenheit = ""+(int)((values[0]*((float)9/5))+32);
updateTemperatures();
}
}
public void updateTemperatures(){
if (pm.isScreenOn() && serviceDestroyed==false){
//si hemos podido obtener la temperatura del sistema, la mostramos, si no, mostramos la temperatura de la bateria.
if (systemTemp!=null){
remoteViews.setTextViewText(R.id.temp,systemTemp+"ºC"+" "+systemTempFarenheit+"ºF");
}
else{
remoteViews.setTextViewText(R.id.temp,batteryTemp+"ºC"+" "+batteryTempFarenheit+"ºF");
}
AppWidgetManager.getInstance( ctx).updateAppWidget( thisWidget, remoteViews );
//System.out.println("XXXXX SERVICE UPDATE TEMPERATURES");
}
}
}
my app widget provider:
public class CPUWidgetProvider extends AppWidgetProvider{
public static final String ACTION_WIDGET_CLICK = "ActionWidgetClick";
public static final String ACTION_AUTO_UPDATE = "AUTO_UPDATE";
DecimalFormatSymbols symbols;
DecimalFormat tempDecimalFormat;
int processorMaxFreq=-1;
String cpuCurrentFreq=null;
int freq = 0;
float usage =-1;
BufferedReader freqBufferedReader;
PowerManager pm;
RemoteViews remoteViews;
ComponentName thisWidget;
WidgetAlarm widgetAlarm;
ActivityManager manager;
Intent active;
PendingIntent actionPendingIntent;
@Override
public void onDisabled(Context context) {
super.onDisabled(context);
context.stopService(new Intent(context, UpdateService.class));
//stop alarm
widgetAlarm = new WidgetAlarm(context.getApplicationContext());
widgetAlarm.stopAlarm();
//System.out.println("XXXXX onDISABLED");
}
@Override
public void onDeleted(Context context, int[] appWidgetIds) {
super.onDeleted(context, appWidgetIds);
//System.out.println("XXXXX onDELETED");
}
@Override
public void onEnabled(Context context) {
super.onEnabled(context);
//System.out.println("XXXXX onENABLED");
}
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
super.onUpdate(context, appWidgetManager, appWidgetIds);
if (isMyServiceRunning(context)==false){
context.startService(new Intent(context, UpdateService.class));
}
remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget_layout);
thisWidget = new ComponentName(context, CPUWidgetProvider.class );
//preparamos el evento para cuando el usuario presiona en el widget, ese evento será recibido en onReceive()
active = new Intent(context, CPUWidgetProvider.class);
active.setAction(ACTION_WIDGET_CLICK);
actionPendingIntent = PendingIntent.getBroadcast(context, 0, active, 0);
remoteViews.setOnClickPendingIntent(R.id.fondo, actionPendingIntent);
AppWidgetManager.getInstance(context).updateAppWidget( thisWidget, remoteViews );
// start alarm
widgetAlarm = new WidgetAlarm(context.getApplicationContext());
widgetAlarm.startAlarm();
//System.out.println("XXXXX onUPDATE");
}
@Override
public void onReceive(Context context, Intent intent){
if (intent.getAction().equals(ACTION_WIDGET_CLICK)){
switchWidget(context);
}else if(intent.getAction().equals(ACTION_AUTO_UPDATE)){
symbols = new DecimalFormatSymbols(Locale.GERMAN);
symbols.setDecimalSeparator('.');
tempDecimalFormat = new DecimalFormat("#.#", symbols);
pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget_layout);
thisWidget = new ComponentName(context, CPUWidgetProvider.class );
if (pm.isScreenOn()){
try{
freqBufferedReader = new BufferedReader(new InputStreamReader(new FileInputStream(new File("/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq"))));
freq = Integer.valueOf(freqBufferedReader.readLine()).intValue();
freqBufferedReader.close();
freqBufferedReader = null;
cpuCurrentFreq=freq / 1000 + " Mhz";
}
catch (Exception Exception){
cpuCurrentFreq=null;
}
remoteViews.setTextViewText(R.id.freq,cpuCurrentFreq);
if (processorMaxFreq==-1)
getProcessorMaxFreq();
usage=(float) (freq/processorMaxFreq);
remoteViews.setTextViewText(R.id.usage,tempDecimalFormat.format(usage / 10.0D)+" %");
//preparamos el evento para cuando el usuario presiona en el widget, ese evento será recibido en onReceive()
active = new Intent(context, CPUWidgetProvider.class);
active.setAction(ACTION_WIDGET_CLICK);
actionPendingIntent = PendingIntent.getBroadcast(context, 0, active, 0);
remoteViews.setOnClickPendingIntent(R.id.fondo, actionPendingIntent);
AppWidgetManager.getInstance(context).updateAppWidget( thisWidget, remoteViews );
//System.out.println("XXXXX UPDATING WIDGET");
}
}else{
super.onReceive(context, intent);
}
//System.out.println("XXXXX onRECEIVE: "+intent.getAction());
}
public void switchWidget(Context context){
symbols = new DecimalFormatSymbols(Locale.GERMAN);
symbols.setDecimalSeparator('.');
tempDecimalFormat = new DecimalFormat("#.#", symbols);
remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget_layout);
thisWidget = new ComponentName(context.getPackageName(), CPUWidgetProvider.class.getName());
widgetAlarm = new WidgetAlarm(context.getApplicationContext());
if (isMyServiceRunning(context)==true){ //si el widget está encendido la apagamos
context.stopService(new Intent(context, UpdateService.class));
widgetAlarm.stopAlarm();
remoteViews.setTextViewText(R.id.freq,"");
remoteViews.setTextViewText(R.id.usage,"OFF");
remoteViews.setTextViewText(R.id.temp,"");
}
else{ //si el widget está apagado lo encendemos
context.startService(new Intent(context, UpdateService.class));
widgetAlarm.startAlarm();
remoteViews.setTextViewText(R.id.freq,"-----");
remoteViews.setTextViewText(R.id.usage,"--");
remoteViews.setTextViewText(R.id.temp,"");
}
AppWidgetManager.getInstance(context).updateAppWidget(thisWidget,remoteViews);
}
private boolean isMyServiceRunning(Context context) {
manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if (UpdateService.class.getName().equals(service.service.getClassName())) {
return true;
}
}
return false;
}
public void getProcessorMaxFreq(){
int freq = 0;
try{
freqBufferedReader = new BufferedReader(new InputStreamReader(new FileInputStream(new File("/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq"))));
freq = Integer.valueOf(freqBufferedReader.readLine()).intValue();
freqBufferedReader.close();
freqBufferedReader=null;
processorMaxFreq=(freq / 1000);
}
catch (Exception e){e.printStackTrace();}
}
}
Upvotes: 0
Views: 661
Reputation: 200120
Per this blog post and the associated bug closed as Working as Intended:
low polling periods are rounded up to 60000ms (one minute)
and you'll see a logcat message to that effect:
Suspiciously short interval 5000 millis; expanding to 60 seconds
When asked about alternatives, post #9 on the bug states:
If you are trying to run more often than every 5 seconds, alarms are the wrong way to go about it. Waking up the device that often is extremely bad for battery life. If you have live UI that needs to be updated continually, use a wakelock and then schedule your activity on a handler. This is actually more battery efficient than setting an alarm every second.
Remember that widgets are intended to run only occasionally; the smallest updatePeriodMillis that the OS will provide is 30 minutes.
Upvotes: 3