Android Widget 电池插件的开发实现

   最近突发奇想,想自己编一个Android电池插件放在桌面上,一是这个App确实有它的实用价值,二是编起来工程量应该不是很大,不用花太长时间,三来又能学习下Widget的开发方法,一举三得,于是,暂停下游戏开发的学习,来编一个widget先。


    在查找并结合多方资料后终于实现,效果图如下:
长按桌面空白处,出现菜单,点击Widgets,此时的插件已经装入:

 

在电源连接时,机器人周围会星光闪闪,表明正在充电,不在充电时,周围的星光会消失。

机器人身上显示电池电量百分比。


单击机器人图标,会跳出电池信息的详情,再次单击屏幕关闭详情信息。

下面介绍代码的实现:

整个工程主要实现两个部分,一个是AppWidget部分,实现桌面Widget的显示,更新等,另一个部分就是点击widget后出现的显示电池详细信息的Activity的实现了。


首先是AppWidget部分,上代码,NewBatteryWidget.java部分:

package com.ritterliu.newBatteryWidget;

import android.app.AlarmManager;
import android.app.PendingIntent;
import android.app.Service;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.IBinder;
import android.widget.RemoteViews;

public class NewBatteryWidget extends AppWidgetProvider{	
	private static int currentBatteryLevel;
	private static int currentBatteryStatus;

	public void onUpdate(Context context,AppWidgetManager appWidgetManager,int[] appWidgetIds)
	{
		super.onUpdate(context, appWidgetManager, appWidgetIds);
	
		/** 启动自动更新电池信息的service */
		context.startService(new Intent(context,updateService.class));
	
		/** 为AppWidget设置点击事件的响应,启动显示电池信息详情的activity */ 
	    Intent startActivityIntent = new Intent(context,NewBatteryInfoActivity.class);
	    PendingIntent Pintent = PendingIntent.getActivity(context,0,startActivityIntent,0);
	    RemoteViews views = new RemoteViews(context.getPackageName(),R.layout.newrelativelayout);
	    views.setOnClickPendingIntent(R.id.imageView,Pintent);
	    appWidgetManager.updateAppWidget(appWidgetIds,views);
			
	}
	
	/** 自动更新电池信息的service,通过AlarmManager实现定时不间断地发送电池信息 */
	public static class updateService extends Service{
		Bitmap bmp;		//定义机器人图片
		@Override
		public IBinder onBind(Intent intent) {
			// TODO Auto-generated method stub
			return null;
		}
		
		/** 定义一个接收电池信息的broascastReceiver */
		private BroadcastReceiver batteryReceiver=new BroadcastReceiver()
		{
			@Override
			public void onReceive(Context context, Intent intent) {
				// TODO Auto-generated method stub
				currentBatteryLevel=intent.getIntExtra("level", 0);
				currentBatteryStatus=intent.getIntExtra("status", 0);
			}
			
		};
		
		
		public void onStart(Intent intent,int startId)
		{
			super.onStart(intent, startId);
			
			/** 注册接收器 */
			registerReceiver(batteryReceiver,new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
			
			/** 定义一个AppWidgetManager */
			AppWidgetManager manager=AppWidgetManager.getInstance(this);
			
			/** 定义一个RemoteViews,实现对AppWidget界面控制 */
			RemoteViews views=new RemoteViews(getPackageName(),R.layout.newrelativelayout);
		    
			
			if(currentBatteryStatus==2||currentBatteryStatus==5)	//当正在充电或充满电时,显示充电的图片
			{
			    if(currentBatteryLevel>=95)
			    {
			    	bmp=BitmapFactory.decodeResource(getResources(),R.drawable.jcharge);
			    }
			    else if(currentBatteryLevel>=85&& currentBatteryLevel<95)
			    {
			    	bmp=BitmapFactory.decodeResource(getResources(),R.drawable.icharge);
			    }
			    else if(currentBatteryLevel>=75&& currentBatteryLevel<85)
			    {
			    	bmp=BitmapFactory.decodeResource(getResources(),R.drawable.hcharge);
			    }
			    else if(currentBatteryLevel>=65&& currentBatteryLevel<75)
			    {
			    	bmp=BitmapFactory.decodeResource(getResources(),R.drawable.gcharge);
			    }
			    else if(currentBatteryLevel>=55&& currentBatteryLevel<65)
			    {
			    	bmp=BitmapFactory.decodeResource(getResources(),R.drawable.fcharge);
			    }
			    else if(currentBatteryLevel>=45&& currentBatteryLevel<55)
			    {
			    	bmp=BitmapFactory.decodeResource(getResources(),R.drawable.echarge);	
			    }
			    else if(currentBatteryLevel>=35&& currentBatteryLevel<45)
			    {
			    	bmp=BitmapFactory.decodeResource(getResources(),R.drawable.dcharge);	
			    }
			    else if(currentBatteryLevel>=25&& currentBatteryLevel<35)
			    {
			    	bmp=BitmapFactory.decodeResource(getResources(),R.drawable.ccharge);	
			    }
			    else if(currentBatteryLevel>=15&& currentBatteryLevel<25)
			    {
			    	bmp=BitmapFactory.decodeResource(getResources(),R.drawable.bcharge);
			    }
			    else
			    {
			    	bmp=BitmapFactory.decodeResource(getResources(),R.drawable.acharge);	
			    }   
			}
			else	//未在充电时,显示不在充电状态的系列图片
			{
			    if(currentBatteryLevel>=95)
			    {
			    	bmp=BitmapFactory.decodeResource(getResources(),R.drawable.j);
			    }
			    else if(currentBatteryLevel>=85&¤tBatteryLevel<95)
			    {
			    	bmp=BitmapFactory.decodeResource(getResources(),R.drawable.i);
			    }
			    else if(currentBatteryLevel>=75&¤tBatteryLevel<85)
			    {
			    	bmp=BitmapFactory.decodeResource(getResources(),R.drawable.h);
			    }
			    else if(currentBatteryLevel>=65&¤tBatteryLevel<75)
			    {
			    	bmp=BitmapFactory.decodeResource(getResources(),R.drawable.g);
			    }
			    else if(currentBatteryLevel>=55&¤tBatteryLevel<65)
			    {
			    	bmp=BitmapFactory.decodeResource(getResources(),R.drawable.f);
			    }
			    else if(currentBatteryLevel>=45&¤tBatteryLevel<55)
			    {
			    	bmp=BitmapFactory.decodeResource(getResources(),R.drawable.e);	
			    }
			    else if(currentBatteryLevel>=35&¤tBatteryLevel<45)
			    {
			    	bmp=BitmapFactory.decodeResource(getResources(),R.drawable.d);	
			    }
			    else if(currentBatteryLevel>=25&¤tBatteryLevel<35)
			    {
			    	bmp=BitmapFactory.decodeResource(getResources(),R.drawable.c);	
			    }
			    else if(currentBatteryLevel>=15&¤tBatteryLevel<25)
			    {
			    	bmp=BitmapFactory.decodeResource(getResources(),R.drawable.b);
			    }
			    else
			    {
			    	bmp=BitmapFactory.decodeResource(getResources(),R.drawable.a);	
			    }   
			}   

			/** 设置AppWidget上显示的图片和文字的内容 */
		        views.setImageViewBitmap(R.id.imageView,bmp);
			views.setTextViewText(R.id.tv,currentBatteryLevel+"%");
			
			ComponentName thisWidget=new ComponentName(this,NewBatteryWidget.class);
		
			/** 使用AlarmManager实现每隔一秒发送一次更新提示信息,实现信息实时动态变化 */
			long now=System.currentTimeMillis();
			long pause=1000;
			
			Intent alarmIntent=new Intent();
			alarmIntent=intent;
			
			PendingIntent pendingIntent=PendingIntent.getService(this, 0, alarmIntent, 0);
			AlarmManager alarm=(AlarmManager)getSystemService(Context.ALARM_SERVICE);
			alarm.set(AlarmManager.RTC_WAKEUP,now+pause,pendingIntent);
			
			/** 更新AppWidget */
                        manager.updateAppWidget(thisWidget, views);

		}	
	}
}

对于Widget,配置它的显示layout,一个简单的RelativeLayout布局,一个ImageView和一个TextView,居中显示:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >
 
        <ImageView 
        android:id="@+id/imageView"
        android:layout_centerInParent="true"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/j"
        />

        <TextView
        android:id="@+id/tv"
        android:layout_centerInParent="true"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="#000000"
        android:textStyle="bold"
        android:textSize="14sp"
        />

</RelativeLayout>
接着就是编写配置Widget的xml了,设置Widget大小等信息,在res目录下新建一个xml文件夹用来存放Widget的配置xml文件://备注2
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:minHeight="72dip"
    android:minWidth="72dip"
    android:updatePeriodMillis="1000000"	
    android:initialLayout="@layout/newrelativelayout"
    >
    <!--
    关于android:minHeight和android:minWidth
    分别对应appWidget在屏幕上所占位置的高和宽,
    最小高和宽各为一个单元格,值为72dip,
    有资料说计算公式为(74*N)-2
    例如要设置宽为四个单元格时,(74*4)-2=294
    android:minWidth="294dip"
    
    注意,看网上资料说,在SDK1.5之后,
    android:updatePeriodMillis就没用了,
    不会再定时更新appWidget了,所以这里的值
    设置多少都不会有影响,但是最好设置大一点,
    防止万一又有效了,更新的太频繁会不好。
    -->
</appwidget-provider>

备注1,备注2:

请注意,在一些资料上说widget配置文件new_battery_widget.xml中的android:updatePeriodMillis是用来实现widget自动更新的,但本人编程时却发现,这个设置根本就没有效果,后来上网一搜,人家说这个功能在SDK1.5以后就不支持了。所以本次程序自动更新响应系统的battery change事件是通过一个AlarmManager定时发送响应来实现的,同学们千万注意,别像我一样一开始等着靠android:updatePeriodMillis实现更新,看没效果,还以为是别的什么地方出了问题,浪费了不少时间。

Widget的部分差不多了,下面介绍显示电池详情的Activity部分,上代码:

package com.ritterliu.newBatteryWidget;

import android.app.Activity;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.IBinder;
import android.view.MotionEvent;
import android.view.Window;
import android.widget.TextView;

public class NewBatteryInfoActivity extends Activity{
	/** 定义电池信息变量  */
	private static int currentBatteryPlugged=0;
	private static int currentBatteryStatus=0;
	private static int currentBatteryLevel=0;
	private static int currentBatteryHealth=0;
	private static int currentBatteryTemperature=0;
	private static int currentBatteryVoltage=0;
	private static String currentBatteryTechnology="";

	
	/** TextView 声明 */
    private static TextView tvBatteryStatus;
    private static TextView tvBatteryLevel;
    private static TextView tvBatteryHealth;
    private static TextView tvBatteryTemperature;
    private static TextView tvBatteryVoltage;
    private static TextView tvBatteryTechnology;
	
    /** 定义好字符串以备使用 */
	private static String batteryStatus="电池状态: ";
	private static String batteryLevel="电池电量: ";
	private static String batteryHealth="电池健康: ";
	private static String batteryTemperature="电池温度: ";
	private static String batteryVoltage="电池电压: ";
	private static String  batteryTechnology="电池技术: ";
	
    private static String  batteryStatusCharging="正在充电";
    private static String  batteryStatusDischarging="正在放电";
    private static String  batteryStatusFull="已充满";
    private static String  batteryStatusNotCharging="未在充电";
    private static String  batteryStatusUnknown="状态未知";
        
    private static String  batteryPluggedAC="(AC)";
    private static String  batteryPluggedUSB="(USB)";
        
    private static String  batteryHealthCold="过冷";
    private static String  batteryHealthDead="损坏";
    private static String  batteryHealthGood="良好";
    private static String  batteryHealthOverheat="过热";
    private static String  batteryHealthOverVoltage="过压";
    private static String  batteryHealthUnknown="未知";
    private static String  batteryHealthUnspecifiedFailure="未知的故障";
	
    /** 提示Service启动标志位 */
	private static boolean flag;
	
	/** 提示信息接收器 */
	BroadcastReceiver infoReceiver;
	
	public void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		
		this.requestWindowFeature(Window.FEATURE_NO_TITLE);		//设置activity无标题
		setContentView(R.layout.newlayout);		//使用newlayout的布局
		
		tvBatteryStatus=(TextView)findViewById(R.id.tvBatteryStatus);
		tvBatteryLevel=(TextView)findViewById(R.id.tvBatteryLevel);
		tvBatteryHealth=(TextView)findViewById(R.id.tvBatteryHealth);
		tvBatteryTemperature=(TextView)findViewById(R.id.tvBatteryTemperature);
		tvBatteryVoltage=(TextView)findViewById(R.id.tvBatteryVoltage);
		tvBatteryTechnology=(TextView)findViewById(R.id.tvBatteryTechnology);
		
		flag=true;		//提示service的标志位置为true
		
		infoReceiver=new BroadcastReceiver()	//提示信息接收器的定义
		{
			@Override
			public void onReceive(Context context, Intent intent) {
				// TODO Auto-generated method stub
				setText();		//收到intent,就及时修改TextView信息,使得Activity显示时,电池信息也能动态显示
			}
		};
		
		/** 注册提示信息的intentFilter */
		IntentFilter filter=new IntentFilter();
		filter.addAction("com.ritterliu.newBatteryWidget");
		registerReceiver(infoReceiver,filter);

		/** 启动提示service */
		Intent startService=new Intent(this,updateService.class);
		startService(startService);
		
	}
	
	/** 点击屏幕任意位置,关闭电池信息Activity */
	public boolean onTouchEvent(MotionEvent event)
	{
		this.finish();
	//	onDestroy();
	//	System.exit(0);
		return true;
	}

	@Override
	protected void onDestroy() {
		// TODO Auto-generated method stub
		flag=false;
		unregisterReceiver(infoReceiver);
		super.onDestroy();
	}

	/** 及时动态修改Activity上文字信息的函数 */
	public static  void setText()
	{
		String plugState="";
		switch(currentBatteryPlugged)
		{
		case 0:
			plugState="";
			break;
		case 1:
			plugState=batteryPluggedAC;
			break;
		case 2:
			plugState=batteryPluggedUSB;
			break;
		default:
			plugState="";
		}

		switch(currentBatteryStatus)
		{
		case 1:
			tvBatteryStatus.setText(batteryStatus+batteryStatusUnknown);
			break;
		case 2:
			tvBatteryStatus.setText(batteryStatus+batteryStatusCharging+plugState);
			break;
		case 3:
			tvBatteryStatus.setText(batteryStatus+batteryStatusDischarging);
			break;
		case 4:
			tvBatteryStatus.setText(batteryStatus+batteryStatusNotCharging);
			break;
		case 5:
			tvBatteryStatus.setText(batteryStatus+batteryStatusFull+plugState);
			break;
		default:
			tvBatteryStatus.setText(batteryStatus+batteryStatusUnknown);
		}
		
		tvBatteryLevel.setText(batteryLevel+String.valueOf(currentBatteryLevel)+"%");
		
		switch(currentBatteryHealth)
		{
		case 1:
			tvBatteryHealth.setText(batteryHealth+batteryHealthUnknown);
			break;
		case 2:
			tvBatteryHealth.setText(batteryHealth+batteryHealthGood);
			break;
		case 3:
			tvBatteryHealth.setText(batteryHealth+batteryHealthOverheat);
			break;
		case 4:
			tvBatteryHealth.setText(batteryHealth+batteryHealthDead);
			break;
		case 5:
			tvBatteryHealth.setText(batteryHealth+batteryHealthOverVoltage);
			break;
		case 6:
			tvBatteryHealth.setText(batteryHealth+batteryHealthUnspecifiedFailure);
			break;
		case 7:
			tvBatteryHealth.setText(batteryHealth+batteryHealthCold);
			break;
		default:
			tvBatteryHealth.setText(batteryHealth+batteryHealthUnknown);
		}
		
		tvBatteryTemperature.setText(batteryTemperature+currentBatteryTemperature/10f+"℃");
		tvBatteryVoltage.setText(batteryVoltage+currentBatteryVoltage+"mv");
		tvBatteryTechnology.setText(batteryTechnology+currentBatteryTechnology);
	}
	
	/** 提示信息变化的service,约每隔一秒,就发送intent,
	 * 提醒activity更新电池信息,主要为了检测电池状态的变化,
	 * 例如连上充电时,状态会从“未在充电”变为“正在充电”
	 * 通过调用plugged方式,还能判断是AC方式充电还是USB方式充电
	 */
	public static class updateService extends Service{
		@Override
		public IBinder onBind(Intent intent) {
			// TODO Auto-generated method stub
			return null;
		}
		
		/** 定义得到电池信息的BroadcastReceiver,提取出关键信息,存入变量中 */
		private BroadcastReceiver batteryReceiver=new BroadcastReceiver()
		{
			@Override
			public void onReceive(Context context, Intent intent) {
				// TODO Auto-generated method stub
				currentBatteryStatus=intent.getIntExtra("status", 0);
				currentBatteryLevel=intent.getIntExtra("level", 0);
				currentBatteryHealth=intent.getIntExtra("health", 0);
				currentBatteryTemperature=intent.getIntExtra("temperature",0);
				currentBatteryVoltage=intent.getIntExtra("voltage",0);
				currentBatteryTechnology=intent.getStringExtra("technology");
				currentBatteryPlugged=intent.getIntExtra("plugged",0);
			}
		};
		
		
		public void onStart(Intent intent,int startId)
		{
			registerReceiver(batteryReceiver,new IntentFilter(Intent.ACTION_BATTERY_CHANGED));//注册BroadcastReceiver
		
			/** 启动一个线程,约每隔一秒就发送intent提醒Activity更新电池信息 */
			new Thread()
			{
				public void run()
				{
					while(flag)
					{
			            Intent sendInfoToActivity=new Intent();
			            sendInfoToActivity.setAction("com.ritterliu.newBatteryWidget");
			            sendBroadcast(sendInfoToActivity);
		
						try
						{
							Thread.sleep(1000);
						}
						catch(Exception ex)
						{
							ex.printStackTrace();
						}
					}
				}
			}.start();
			super.onStart(intent, startId);
		}
	}
}
布局文件:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

	<TextView
	    android:id="@+id/tvBatteryStatus"
	    android:layout_marginLeft="3sp"
	    android:layout_width="wrap_content"
	    android:layout_height="wrap_content" 
	    android:text="@string/batteryStatus"
	    android:textSize="18dp"
	    android:textColor="#FFFFFF"
	    />
    
	<TextView
	    android:id="@+id/tvBatteryLevel"
	    android:layout_marginLeft="3sp"
	    android:layout_width="wrap_content"
	    android:layout_height="wrap_content" 
	    android:text="@string/batteryLevel"
	    android:textSize="18dp"
	    android:textColor="#FFFFFF"
	    />
	
		<TextView
	    android:id="@+id/tvBatteryHealth"
	    android:layout_marginLeft="3sp"
	    android:layout_width="wrap_content"
	    android:layout_height="wrap_content" 
	    android:text="@string/batteryHealth"
	    android:textSize="18dp"
	    android:textColor="#FFFFFF"
	    />
		
		<TextView
	    android:id="@+id/tvBatteryTemperature"
	    android:layout_marginLeft="3sp"
	    android:layout_width="wrap_content"
	    android:layout_height="wrap_content" 
	    android:text="@string/batteryTemperature"
	    android:textSize="18dp"
	    android:textColor="#FFFFFF"
	    />
			
		<TextView
	    android:id="@+id/tvBatteryVoltage"
	    android:layout_marginLeft="3sp"
	    android:layout_width="wrap_content"
	    android:layout_height="wrap_content" 
	    android:text="@string/batteryVoltage"
	    android:textSize="18dp"
	    android:textColor="#FFFFFF"
	    />

		<TextView
	    android:id="@+id/tvBatteryTechnology"
	    android:layout_marginLeft="3sp"
	    android:layout_width="wrap_content"
	    android:layout_height="wrap_content" 
	    android:text="@string/batteryTechnology"
	    android:textSize="18dp"
	    android:textColor="#FFFFFF"
	    />

		<TextView
	    android:id="@+id/tvInfo"
	    android:layout_marginLeft="3sp"
	    android:layout_width="wrap_content"
	    android:layout_height="wrap_content" 
	    android:text="http://blog.csdn.net/ritterliu"
	    android:textSize="15dp"
	    android:textColor="#FFFFFF"
	    />

</LinearLayout>

在代码中写了注释,还有什么不清楚的部分可以留言。吐舌头

最后是AndroidManifest.xml:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.ritterliu.newBatteryWidget"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk android:minSdkVersion="4" />

    <application
        android:icon="@drawable/j"
        android:label="@string/app_name" >
        <receiver
            android:label="@string/app_name"
            android:name=".NewBatteryWidget" >
            <intent-filter >
                <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
            </intent-filter>
            <meta-data android:name="android.appwidget.provider"
                android:resource="@xml/new_battery_widget"
                />
        </receiver>
       
       	<service android:name=".NewBatteryWidget$updateService"/>
       	    
        <activity android:name=".NewBatteryInfoActivity" android:label="OtherActiviy_app_name"
			android:theme="@android:style/Theme.Dialog">
			<!-- android:theme="@android:style/Theme.Dialog" 这是设置Activity的主题风格为对话框形式 -->
		</activity>
		
       	<service android:name=".NewBatteryInfoActivity$updateService"/>
       	
    </application>

</manifest>

大功告成

总结:

本次开发大概前后折腾了4天时间,这其中绕了一段弯路(就是那个android:updatePeriodMillis发火),不仅学习了如何开发Widget,还对Activity的一些写法,比如设置风格为Dialog等又有了进一步的学习,在关闭Activity时,我是直接调用的finish关闭的,也许在用法上还有不当之处,本人从9月份开始自学Android开发至今两个多月的时间,开发水平还十分有限,代码中有写的不好的地方还请大家多多指点,不甚感激。奋斗

附上完整文件下载地址,由于本人积分很少(只有19 可怜),故略收1分,一周后将改为免费,谢谢大家。

http://download.csdn.net/detail/ritterliu/3791897

------------------------------------------------------------------------------------------

更新于 2011-11-21 13:15 

郁闷,不能修改资源分。。。就重新发了个免费的:http://download.csdn.net/detail/lr19900105/3821420

------------------------------------------------------------------------------------------


——————————————————————————————————————————————————————

更新于2011.11.14 15:17

经过昨晚一夜的测试,发现在AppWidget中设置AlarmManager每隔一秒刷新一次频率太高,过于费电了,一夜耗电量居然占到了8%,故针对这个问题正在修改,修改完成后将及时上传。

使用AlarmManager实现每隔一秒刷新一次主要是为了实现实时的充电状态的检测,电池信息的更新自然不用这么频繁,修改中。。。

 

修改完成,原来的通过AlarmManager每隔一秒刷新一次实现的对充电事件的及时响应改为对ACTION_POWER_CONNECTED和ACTION_POWER_DISCONNECTED监听来实现。

就修改了AppWidget部分:

package com.ritterliu.newBatteryWidget;

import android.app.AlarmManager;
import android.app.PendingIntent;
import android.app.Service;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.IBinder;
import android.util.Log;
import android.widget.RemoteViews;
import android.widget.Toast;

public class NewBatteryWidget extends AppWidgetProvider{
	
	private static int currentBatteryLevel;
	private static int currentBatteryStatus;

	private static boolean firstTimeToCreate=true;
	
	public void onUpdate(Context context,AppWidgetManager appWidgetManager,int[] appWidgetIds)
	{
		super.onUpdate(context, appWidgetManager, appWidgetIds);
	
		/** 启动自动更新电池信息的service */
		context.startService(new Intent(context,updateService.class));
	
		/** 为AppWidget设置点击事件的响应,启动显示电池信息详情的activity */ 
	    Intent startActivityIntent = new Intent(context,NewBatteryInfoActivity.class);
	    PendingIntent Pintent = PendingIntent.getActivity(context,0,startActivityIntent,0);
	    RemoteViews views = new RemoteViews(context.getPackageName(),R.layout.newrelativelayout);
	    views.setOnClickPendingIntent(R.id.imageView,Pintent);
	    appWidgetManager.updateAppWidget(appWidgetIds,views);
			
	}
	
	/** 自动更新电池信息的service,通过AlarmManager实现定时不间断地发送电池信息 */
	public static class updateService extends Service{
		Bitmap bmp;		//定义机器人图片
		@Override
		public IBinder onBind(Intent intent) {
			// TODO Auto-generated method stub
			return null;
		}
		
		/** 定义一个接收电池信息的broascastReceiver */
		
		private BroadcastReceiver batteryReceiver=new BroadcastReceiver()
		{
			@Override
			public void onReceive(Context context, Intent intent) {
				// TODO Auto-generated method stub
				currentBatteryLevel=intent.getIntExtra("level", 0);
				currentBatteryStatus=intent.getIntExtra("status", 0);
			}
			
		};
		
		private BroadcastReceiver powerConnectedReceiver=new BroadcastReceiver()
		{
			@Override
			public void onReceive(Context context, Intent intent) {
				// TODO Auto-generated method stub
				setViews();	
			}
		};
		
		private BroadcastReceiver powerDisconnectedReceiver=new BroadcastReceiver()
		{
			@Override
			public void onReceive(Context context, Intent intent) {
				// TODO Auto-generated method stub
				setViews();

			}
		};
		
		/** 设置Widget的显示 */
		private void setViews()
		{
			/** 定义一个AppWidgetManager */
			AppWidgetManager manager=AppWidgetManager.getInstance(this);
			
			/** 定义一个RemoteViews,实现对AppWidget界面控制 */
			RemoteViews views=new RemoteViews(getPackageName(),R.layout.newrelativelayout);
			
			if(currentBatteryStatus==2||currentBatteryStatus==5)	//当正在充电或充满电时,显示充电的图片
			{
			    if(currentBatteryLevel>=95)
			    {
			    	bmp=BitmapFactory.decodeResource(getResources(),R.drawable.jcharge);
			    }
			    else if(currentBatteryLevel>=85&& currentBatteryLevel<95)
			    {
			    	bmp=BitmapFactory.decodeResource(getResources(),R.drawable.icharge);
			    }
			    else if(currentBatteryLevel>=75&& currentBatteryLevel<85)
			    {
			    	bmp=BitmapFactory.decodeResource(getResources(),R.drawable.hcharge);
			    }
			    else if(currentBatteryLevel>=65&& currentBatteryLevel<75)
			    {
			    	bmp=BitmapFactory.decodeResource(getResources(),R.drawable.gcharge);
			    }
			    else if(currentBatteryLevel>=55&& currentBatteryLevel<65)
			    {
			    	bmp=BitmapFactory.decodeResource(getResources(),R.drawable.fcharge);
			    }
			    else if(currentBatteryLevel>=45&& currentBatteryLevel<55)
			    {
			    	bmp=BitmapFactory.decodeResource(getResources(),R.drawable.echarge);	
			    }
			    else if(currentBatteryLevel>=35&& currentBatteryLevel<45)
			    {
			    	bmp=BitmapFactory.decodeResource(getResources(),R.drawable.dcharge);	
			    }
			    else if(currentBatteryLevel>=25&& currentBatteryLevel<35)
			    {
			    	bmp=BitmapFactory.decodeResource(getResources(),R.drawable.ccharge);	
			    }
			    else if(currentBatteryLevel>=15&& currentBatteryLevel<25)
			    {
			    	bmp=BitmapFactory.decodeResource(getResources(),R.drawable.bcharge);
			    }
			    else
			    {
			    	bmp=BitmapFactory.decodeResource(getResources(),R.drawable.acharge);	
			    }   
			}
			else	//未在充电时,显示不在充电状态的系列图片
			{
			    if(currentBatteryLevel>=95)
			    {
			    	bmp=BitmapFactory.decodeResource(getResources(),R.drawable.j);
			    }
			    else if(currentBatteryLevel>=85&& currentBatteryLevel<95)
			    {
			    	bmp=BitmapFactory.decodeResource(getResources(),R.drawable.i);
			    }
			    else if(currentBatteryLevel>=75&& currentBatteryLevel<85)
			    {
			    	bmp=BitmapFactory.decodeResource(getResources(),R.drawable.h);
			    }
			    else if(currentBatteryLevel>=65&& currentBatteryLevel<75)
			    {
			    	bmp=BitmapFactory.decodeResource(getResources(),R.drawable.g);
			    }
			    else if(currentBatteryLevel>=55&& currentBatteryLevel<65)
			    {
			    	bmp=BitmapFactory.decodeResource(getResources(),R.drawable.f);
			    }
			    else if(currentBatteryLevel>=45&& currentBatteryLevel<55)
			    {
			    	bmp=BitmapFactory.decodeResource(getResources(),R.drawable.e);	
			    }
			    else if(currentBatteryLevel>=35&& currentBatteryLevel<45)
			    {
			    	bmp=BitmapFactory.decodeResource(getResources(),R.drawable.d);	
			    }
			    else if(currentBatteryLevel>=25&& currentBatteryLevel<35)
			    {
			    	bmp=BitmapFactory.decodeResource(getResources(),R.drawable.c);	
			    }
			    else if(currentBatteryLevel>=15&& currentBatteryLevel<25)
			    {
			    	bmp=BitmapFactory.decodeResource(getResources(),R.drawable.b);
			    }
			    else
			    {
			    	bmp=BitmapFactory.decodeResource(getResources(),R.drawable.a);	
			    }   
			}   
		
			/** 设置AppWidget上显示的图片和文字的内容 */
		    views.setImageViewBitmap(R.id.imageView,bmp);
			views.setTextViewText(R.id.tv,currentBatteryLevel+"%");
			
			ComponentName thisWidget=new ComponentName(this,NewBatteryWidget.class);

			/** 更新AppWidget */
            manager.updateAppWidget(thisWidget, views);
			
		}
		
		public void onStart(Intent intent,int startId)
		{
			super.onStart(intent, startId);

			/** 注册接收器 */
			registerReceiver(batteryReceiver,new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
			
			/** 增加了对于POWER_CONNECTED和DISCONNECTED事件的监听,
			 * 以实现充电时信息的动态变化,避免了原来需要依赖AlarmManager
			 * 每隔一秒发送检测信息来实现,节约了电量,用原来隔一秒更新的方法,
			 * 经过一夜测试,插件耗电量居然占到了8%,汗。。。
			 * 
			 * */
			registerReceiver(powerConnectedReceiver,new IntentFilter(Intent.ACTION_POWER_CONNECTED));
			registerReceiver(powerDisconnectedReceiver,new IntentFilter(Intent.ACTION_POWER_DISCONNECTED ));
			
			/** 使用AlarmManager实现,第一次启动Widget时隔一秒立即更新,
			 * 以后均为两分钟发送一次更新提示信息,实现信息实时动态变化,
			 * 实现节电功能
			 *  */
			long now=System.currentTimeMillis();
			long pause;
			
			if(firstTimeToCreate)
			{
				firstTimeToCreate=false;
				pause=1000;
			}
			else
			{
				pause=1000*60*2;
			}
			
			Intent alarmIntent=new Intent();
			alarmIntent=intent;
			
			PendingIntent pendingIntent=PendingIntent.getService(this, 0, alarmIntent, 0);
			AlarmManager alarm=(AlarmManager)getSystemService(Context.ALARM_SERVICE);
			alarm.set(AlarmManager.RTC_WAKEUP,now+pause,pendingIntent);
			
			setViews();

		}	
	}
}

新的源码下载地址:

http://download.csdn.net/detail/ritterliu/3794539

同样将在一周后将改为免费,谢谢大家。吐舌头


------------------------------------------------------------------------------------------

更新于 2011-11-21 13:15 

郁闷,不能修改资源分。。。就重新发了个免费的:http://download.csdn.net/detail/lr19900105/3821420

------------------------------------------------------------------------------------------



-----------------------------------------------------------------------------------------------------------------------------------------------------

更新于2011.11.15  10:52pm

真是不好意思,今天又有同学测出了BUG,桌面横竖屏切换后,点击Widget没反应了,无发启动Activity,显示电池信息详情了。

经过1个小时查找资料,修改完成,依旧是在Service中新增了一个intent检测,用来监听横竖屏切换事件,screenOrientationChangedReceiver接收到 ACTION_CONFIGURATION_CHANGED 后,再次注册widget的click事件,解决横竖屏切换后,widget点击无响应的BUG。

同样只修改了AppWidget部分,上代码:

package com.ritterliu.newBatteryWidgetV2;

import android.app.AlarmManager;
import android.app.PendingIntent;
import android.app.Service;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.IBinder;
import android.widget.RemoteViews;

public class NewBatteryWidget extends AppWidgetProvider{
	
	private static int currentBatteryLevel;
	private static int currentBatteryStatus;

	private static boolean firstTimeToCreate=true;
	
	/** 声明全局变量,方便screenOrientationChangedReceiver里使用 */
	private static AppWidgetManager appWidgetManager;
	private static int[] appWidgetIds;
	
	public void onUpdate(Context context,AppWidgetManager appWidgetManager,int[] appWidgetIds)
	{
		super.onUpdate(context, appWidgetManager, appWidgetIds);
	
		/** 启动自动更新电池信息的service */
		context.startService(new Intent(context,updateService.class));
	
		/** 定义全局变量,方便screenOrientationChangedReceiver里使用 */
		this.appWidgetManager=appWidgetManager;
		this.appWidgetIds=appWidgetIds;
		
		/** 为AppWidget设置点击事件的响应,启动显示电池信息详情的activity */ 
	    Intent startActivityIntent = new Intent(context,NewBatteryInfoActivity.class);
	    PendingIntent Pintent = PendingIntent.getActivity(context,0,startActivityIntent,0);
	    RemoteViews views = new RemoteViews(context.getPackageName(),R.layout.newrelativelayout);
	    views.setOnClickPendingIntent(R.id.imageView,Pintent);
	    appWidgetManager.updateAppWidget(appWidgetIds,views);
	
	}
	
	/** 自动更新电池信息的service,通过AlarmManager实现定时不间断地发送电池信息 */
	public static class updateService extends Service{
		Bitmap bmp;		//定义机器人图片
		@Override
		public IBinder onBind(Intent intent) {
			// TODO Auto-generated method stub
			return null;
		}
		
		/** 定义一个接收电池信息的broadcastReceiver */
		private BroadcastReceiver batteryReceiver=new BroadcastReceiver()
		{
			@Override
			public void onReceive(Context context, Intent intent) {
				// TODO Auto-generated method stub
				currentBatteryLevel=intent.getIntExtra("level", 0);
				currentBatteryStatus=intent.getIntExtra("status", 0);
			}
			
		};
		
		/** 定义一个接受电源连接的broadcastReceiver */
		private BroadcastReceiver powerConnectedReceiver=new BroadcastReceiver()
		{
			@Override
			public void onReceive(Context context, Intent intent) {
				// TODO Auto-generated method stub
				setViews();	
			}
		};
		
		/** 定义一个接受电源断开的broadcastReceiver */
		private BroadcastReceiver powerDisconnectedReceiver=new BroadcastReceiver()
		{
			@Override
			public void onReceive(Context context, Intent intent) {
				// TODO Auto-generated method stub
				setViews();

			}
		};
		
		/** 定义一个监听横竖屏切换的broadcastReceiver */
		private BroadcastReceiver screenOrientationChangedReceiver=new BroadcastReceiver()
		{
			public void onReceive(Context context,Intent intent)
			{		
				/** 为AppWidget设置点击事件的响应,启动显示电池信息详情的activity */ 
			    Intent startActivityIntent = new Intent(context,NewBatteryInfoActivity.class);
			    PendingIntent Pintent = PendingIntent.getActivity(context,0,startActivityIntent,0);
			    RemoteViews views = new RemoteViews(context.getPackageName(),R.layout.newrelativelayout);
			    views.setOnClickPendingIntent(R.id.imageView,Pintent);
			    
			    /** 设置AppWidget上显示的图片和文字的内容 */
			    views.setImageViewBitmap(R.id.imageView,bmp);
				views.setTextViewText(R.id.tv,currentBatteryLevel+"%");
			    
			    appWidgetManager.updateAppWidget(appWidgetIds,views);
			}
		};
		
		/** 设置Widget的显示 */
		private void setViews()
		{
			/** 定义一个AppWidgetManager */
			AppWidgetManager manager=AppWidgetManager.getInstance(this);
			
			/** 定义一个RemoteViews,实现对AppWidget界面控制 */
			RemoteViews views=new RemoteViews(getPackageName(),R.layout.newrelativelayout);
			
			if(currentBatteryStatus==2||currentBatteryStatus==5)	//当正在充电或充满电时,显示充电的图片
			{
			    if(currentBatteryLevel>=95)
			    {
			    	bmp=BitmapFactory.decodeResource(getResources(),R.drawable.jcharge);
			    }
			    else if(currentBatteryLevel>=85&& currentBatteryLevel<95)
			    {
			    	bmp=BitmapFactory.decodeResource(getResources(),R.drawable.icharge);
			    }
			    else if(currentBatteryLevel>=75&& currentBatteryLevel<85)
			    {
			    	bmp=BitmapFactory.decodeResource(getResources(),R.drawable.hcharge);
			    }
			    else if(currentBatteryLevel>=65&& currentBatteryLevel<75)
			    {
			    	bmp=BitmapFactory.decodeResource(getResources(),R.drawable.gcharge);
			    }
			    else if(currentBatteryLevel>=55&& currentBatteryLevel<65)
			    {
			    	bmp=BitmapFactory.decodeResource(getResources(),R.drawable.fcharge);
			    }
			    else if(currentBatteryLevel>=45&& currentBatteryLevel<55)
			    {
			    	bmp=BitmapFactory.decodeResource(getResources(),R.drawable.echarge);	
			    }
			    else if(currentBatteryLevel>=35&& currentBatteryLevel<45)
			    {
			    	bmp=BitmapFactory.decodeResource(getResources(),R.drawable.dcharge);	
			    }
			    else if(currentBatteryLevel>=25&& currentBatteryLevel<35)
			    {
			    	bmp=BitmapFactory.decodeResource(getResources(),R.drawable.ccharge);	
			    }
			    else if(currentBatteryLevel>=15&& currentBatteryLevel<25)
			    {
			    	bmp=BitmapFactory.decodeResource(getResources(),R.drawable.bcharge);
			    }
			    else
			    {
			    	bmp=BitmapFactory.decodeResource(getResources(),R.drawable.acharge);	
			    }   
			}
			else	//未在充电时,显示不在充电状态的系列图片
			{
			    if(currentBatteryLevel>=95)
			    {
			    	bmp=BitmapFactory.decodeResource(getResources(),R.drawable.j);
			    }
			    else if(currentBatteryLevel>=85&& currentBatteryLevel<95)
			    {
			    	bmp=BitmapFactory.decodeResource(getResources(),R.drawable.i);
			    }
			    else if(currentBatteryLevel>=75&& currentBatteryLevel<85)
			    {
			    	bmp=BitmapFactory.decodeResource(getResources(),R.drawable.h);
			    }
			    else if(currentBatteryLevel>=65&& currentBatteryLevel<75)
			    {
			    	bmp=BitmapFactory.decodeResource(getResources(),R.drawable.g);
			    }
			    else if(currentBatteryLevel>=55&& currentBatteryLevel<65)
			    {
			    	bmp=BitmapFactory.decodeResource(getResources(),R.drawable.f);
			    }
			    else if(currentBatteryLevel>=45&& currentBatteryLevel<55)
			    {
			    	bmp=BitmapFactory.decodeResource(getResources(),R.drawable.e);	
			    }
			    else if(currentBatteryLevel>=35&& currentBatteryLevel<45)
			    {
			    	bmp=BitmapFactory.decodeResource(getResources(),R.drawable.d);	
			    }
			    else if(currentBatteryLevel>=25&& currentBatteryLevel<35)
			    {
			    	bmp=BitmapFactory.decodeResource(getResources(),R.drawable.c);	
			    }
			    else if(currentBatteryLevel>=15&& currentBatteryLevel<25)
			    {
			    	bmp=BitmapFactory.decodeResource(getResources(),R.drawable.b);
			    }
			    else
			    {
			    	bmp=BitmapFactory.decodeResource(getResources(),R.drawable.a);	
			    }   
			}   
		
			/** 设置AppWidget上显示的图片和文字的内容 */
		    views.setImageViewBitmap(R.id.imageView,bmp);
			views.setTextViewText(R.id.tv,currentBatteryLevel+"%");
			
			ComponentName thisWidget=new ComponentName(this,NewBatteryWidget.class);

			/** 更新AppWidget */
            manager.updateAppWidget(thisWidget, views);
			
		}
		
		public void onStart(Intent intent,int startId)
		{
			super.onStart(intent, startId);

			/** 注册接收器 */
			registerReceiver(batteryReceiver,new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
			
			/** 增加了对于POWER_CONNECTED和DISCONNECTED事件的监听,
			 * 以实现充电时信息的动态变化,避免了原来需要依赖AlarmManager
			 * 每隔一秒发送检测信息来实现,节约了电量,用原来隔一秒更新的方法,
			 * 经过一夜测试,插件耗电量居然占到了8%,汗。。。
			 * 
			 * */
			registerReceiver(powerConnectedReceiver,new IntentFilter(Intent.ACTION_POWER_CONNECTED));
			registerReceiver(powerDisconnectedReceiver,new IntentFilter(Intent.ACTION_POWER_DISCONNECTED ));
	
			/** 新增用以检测横竖屏切换事件 */
			registerReceiver(screenOrientationChangedReceiver,new IntentFilter(Intent.ACTION_CONFIGURATION_CHANGED));

			/** 使用AlarmManager实现,第一次启动Widget时隔一秒立即更新,
			 * 以后均为两分钟发送一次更新提示信息,实现信息实时动态变化,
			 * 实现节电功能
			 *  */
			long now=System.currentTimeMillis();
			long pause;
			
			if(firstTimeToCreate)
			{
				firstTimeToCreate=false;
				pause=1000;
			}
			else
			{
				pause=1000*60*2;
			}
			
			Intent alarmIntent=new Intent();
			alarmIntent=intent;
			
			PendingIntent pendingIntent=PendingIntent.getService(this, 0, alarmIntent, 0);
			AlarmManager alarm=(AlarmManager)getSystemService(Context.ALARM_SERVICE);
			alarm.set(AlarmManager.RTC_WAKEUP,now+pause,pendingIntent);
			
			setViews();

		}	
	}
}

最新的工程就不上传了,大家将这个部分替换就可以了吐舌头
____________________________________________________________
更新于 2011-11-18 8:44AM:
以下是审核通过的apk下载地址:http://apk.gfan.com/Product/App191871.html



评论 32
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值