Android4.4 SystemUI分析之PowerUI

来源:互联网 发布:linux 修改语言环境 编辑:程序博客网 时间:2024/04/29 17:59

以下分析是基于MTK Android4.4原生的SystemUI与Google 的SystemUI有微小的区别,但两者的整体框架是差不多的。

这一篇是分析SystemUI的第一篇,先从最简单的PowerUI着手,源码路径:/frameworks/base/packages/SystemUI  程序目录结构如下:

我导入Eclipse编辑,报错的原因是因为找不到Framework上的一些包和资源,这个没有关系;修改完后在使用mmm模块编译,再push到手机(eng版本)上进行调试,push后需要重启才能生效。

在AndroidManifest.xml上没有Activity注册

<intent-filter>                <action android:name="android.intent.action.MAIN" />                <category android:name="android.intent.category.LAUNCHER" />            </intent-filter>
所以整个程序启动是从外部启动SystemUIService的。那么是如何启动SystemUIService的呢?看下这个文件:/frameworks/base/services/java/com/android/server/SystemServer.java在这个文件中可以找到

    static final void startSystemUi(Context context) {        Intent intent = new Intent();        intent.setComponent(new ComponentName("com.android.systemui",                    "com.android.systemui.SystemUIService"));        //Slog.d(TAG, "Starting service: " + intent);        context.startServiceAsUser(intent, UserHandle.OWNER);    }
所以SystemUI在SystemService启动时就被调用了。

SystemUIService的关键代码如下:

package com.android.systemui;import android.app.Service;import android.content.Intent;import android.content.res.Configuration;import android.os.IBinder;import android.util.Log;import java.io.FileDescriptor;import java.io.PrintWriter;import java.util.HashMap;public class SystemUIService extends Service {    private static final String TAG = "SystemUIService";    /**     * The classes of the stuff to start.     */    private final Class<?>[] SERVICES = new Class[] {            com.android.systemui.recent.Recents.class,            com.android.systemui.statusbar.SystemBars.class,            com.android.systemui.usb.StorageNotification.class,            com.android.systemui.power.PowerUI.class,            com.android.systemui.media.RingtonePlayer.class,            com.android.systemui.settings.SettingsUI.class,        };    /**     * Hold a reference on the stuff we start.     */    private final SystemUI[] mServices = new SystemUI[SERVICES.length];    @Override    public void onCreate() {        HashMap<Class<?>, Object> components = new HashMap<Class<?>, Object>();        final int N = SERVICES.length;        for (int i=0; i<N; i++) {            Class<?> cl = SERVICES[i];            Log.d(TAG, "loading: " + cl);            Log.d("dzt", "loading: " + cl);            try {                mServices[i] = (SystemUI)cl.newInstance();            } catch (IllegalAccessException ex) {                throw new RuntimeException(ex);            } catch (InstantiationException ex) {                throw new RuntimeException(ex);            }            mServices[i].mContext = this;            mServices[i].mComponents = components;            Log.d(TAG, "running: " + mServices[i]);            Log.d("dzt", "running: " + mServices[i]);            mServices[i].start();        }    }}
这些类

com.android.systemui.recent.Recents.class,            com.android.systemui.statusbar.SystemBars.class,            com.android.systemui.usb.StorageNotification.class,            com.android.systemui.power.PowerUI.class,            com.android.systemui.media.RingtonePlayer.class,            com.android.systemui.settings.SettingsUI.class,

都是继承于:SystemUI,在SystemUIService的OnCreate()函数中会创建实例,并调用mServices[i].start();方法。

下面就分析最简单的com.android.systemui.power.PowerUI.class

在PowerUI的start()方法中,注册一些监听器

public void start() {        mLowBatteryAlertCloseLevel = mContext.getResources().getInteger(                com.android.internal.R.integer.config_lowBatteryCloseWarningLevel);        mLowBatteryReminderLevels[0] = mContext.getResources().getInteger(                com.android.internal.R.integer.config_lowBatteryWarningLevel);        mLowBatteryReminderLevels[1] = mContext.getResources().getInteger(                com.android.internal.R.integer.config_criticalBatteryWarningLevel);        final PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);        mScreenOffTime = pm.isScreenOn() ? -1 : SystemClock.elapsedRealtime();        // Register for Intent broadcasts for...        IntentFilter filter = new IntentFilter();        filter.addAction(Intent.ACTION_BATTERY_CHANGED);        filter.addAction(Intent.ACTION_SCREEN_OFF);        filter.addAction(Intent.ACTION_SCREEN_ON);        /// M: Support show battery level when configuration changed. @{        filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);        /// M: Support show battery level when configuration changed. @}        /// M: Hide low battery dialog when PowerOffAlarm ring. @{        filter.addAction("android.intent.action.normal.boot");        filter.addAction("android.intent.action.ACTION_SHUTDOWN_IPO");        /// M: Hide low battery dialog when PowerOffAlarm ring. @}        mContext.registerReceiver(mIntentReceiver, filter, null, mHandler);    }
例如监听ACTION_BATTERY_CHANGED判断电量的大小,如果低电给一个提示给用户,其它的ACTION也都是根据广播来处理一些特定的事情,如果跟电源相关功能需要定制或添加新的监听器都可以在这个类中修改。

关于电源监听的详细信息可以查看:http://blog.csdn.net/deng0zhaotai/article/details/39521461

SystemUI上的电池是如何画上去的呢?看下图


在status_bar.xml这个布局文件中可以找到

<com.android.systemui.BatteryMeterView                    android:id="@+id/battery"                    android:layout_height="16dp"                    android:layout_width="10.5dp"                    android:layout_marginBottom="0.33dp"                    android:layout_marginStart="4dip"                    />
这个就是显示电池图标的View,类定义在/frameworks/base/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java


我在这里把BatteryMeterView.java拿出来写了一个Demo就是上图在Activity上显示的电池小图标

在BatteryMeterView类中有两个重要的函数来注册广播和注销广播

@Overridepublic void onAttachedToWindow() {super.onAttachedToWindow();IntentFilter filter = new IntentFilter();filter.addAction(Intent.ACTION_BATTERY_CHANGED);filter.addAction(ACTION_LEVEL_TEST);final Intent sticky = getContext().registerReceiver(mTracker, filter);if (sticky != null) {// preload the battery levelmTracker.onReceive(getContext(), sticky);}}@Overridepublic void onDetachedFromWindow() {super.onDetachedFromWindow();getContext().unregisterReceiver(mTracker);}
在广播上监听电池的改变调用postInvalidate() 去绘制小图标

private class BatteryTracker extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {final String action = intent.getAction();if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {if (testmode && !intent.getBooleanExtra("testmode", false))return;level = (int) (100f * intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0) / intent.getIntExtra(BatteryManager.EXTRA_SCALE, 100));plugType = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0);plugged = plugType != 0;health = intent.getIntExtra(BatteryManager.EXTRA_HEALTH,BatteryManager.BATTERY_HEALTH_UNKNOWN);status = intent.getIntExtra(BatteryManager.EXTRA_STATUS,BatteryManager.BATTERY_STATUS_UNKNOWN);technology = intent.getStringExtra(BatteryManager.EXTRA_TECHNOLOGY);voltage = intent.getIntExtra(BatteryManager.EXTRA_VOLTAGE, 0);temperature = intent.getIntExtra(BatteryManager.EXTRA_TEMPERATURE, 0);Log.i(TAG, "onReceive ----- level = " + level + "  plugType = "+ plugType + "  health = " + health + "  status = "+ status + " technology = " + technology+ "  voltage = " + voltage + "  temperature = "+ temperature);setContentDescription(context.getString(R.string.accessibility_battery_level, level));postInvalidate();} }}BatteryTracker mTracker = new BatteryTracker();
调用postInvalidate()会回调View的public void draw(Canvas c)去重绘图标。

整个小图标的绘制都是在public void draw(Canvas c)中完成的,没有用到图片,详细的细节就需要好好分析源码

log的TAG

private static final String TAG = TestSystemUI.class.getSimpleName();

得到的TAG就是TestSystemUI

0 0
原创粉丝点击