平台: Android MTK 4.4
个人很少在CSDN上写博客,做Android开发几年来,一直都是在印象笔记上写文档,写总结,可能是自己的性格原因吧~!在CSDN上一直保持索取的’姿态’,不管在哪里写,只要能写写博客总结一下自己的进步,总会掌握的更加牢固一些,也会让自己更接近所谓大神吧~!
这是进到进新公司的第一个任务:需求是,系统应用层,入口可以更换主题,修改背景颜色,要求状态栏也跟随系统颜色变化,也就是动态修改状态栏颜色;
虽然,做过1年的系统应用开发,也接触到framework层的一些代码,但是系统开发都是划分清晰,有些人可能做phone、systemui、launcher、settings、sms等等,就会一直做那块,哪怕是换工作也是一直做这块,但是你一旦换到小公司,就会涉及到很多其他模块的工作,我这次跳槽就是,之前做过1年的settings 、launcher的开发,这次一上来就做systemui了,不过,还好自己有自己一套看源码的方法,上手不算太难。
很多人拿到需求,习惯性的百度去了,我个人认为,百度可以,尤其是系统开发,用百度也很正常(因为Android每次的版本升级,都会对源码更新改动,尤其4.4到5.0,再到6.0,这种大版本的发布,更是各种源码颠覆,更新一次,陌生一回),但是,自己总要先看看熟悉一些你需要开发模块的运行流程,实在不理解的地方再去搜索。自己多耐着性子去看陌生的源码,长期以往,对自己阅读源码的能力,会有很大程度的提升。
好了,废话不多说,进入主题~!
1、systenUI,statusbar启动的大致流程
拿到一个陌生模块的代码,首先肯定会去看看大致运行流程,manifest文件,第一个activity,或者service,systemUI中, 首先启动的是
SystemUIService.java,它是从外部启动的,开机完成后,
在SystemService启动时就被调用了。
manifest
"android.intent.category.LAUNCHER"
>
SystemService.java中调用
SystemUIService
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);
}
在
SystemUIService
这个类中,首先初始了几大涉及到的子模块,他们都继承自systemui.java类。
我主要是做了statusbar这块,因此再来看看这个类是怎么调用到statusbar的,
在SystemUIService的OnCreate()函数中会创建实例,并调用mServices[i].start();方法调用各个子类的start()方法,初始化子类。
/**
* Hold a reference on the stuff we start.
*/
private final SystemUI[] mServices =
new SystemUI[SERVICES.length]
;
@Override
public void onCreate() {
HashMap
, Object> components =
new HashMap
, Object>()
;
final int N = SERVICES.length
;
for (
int i=
0
; i; i++) {
Class> cl = SERVICES[i]
;
Log.d(TAG
,
"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])
;
mServices[i].start()
;
}
}
注:由于MTK平台的Android源码带动特别大,看起源码来,相对于aosp、高通,mavell平台相对繁杂,因为他们改变了Google的Android工程师代码习惯,风格混乱,
SystemBars
extends SystemUI
implements ServiceMonitor.Callbacks
systembar类中,start()方法中,初始化ServiceMonitor,并调用它的start()方法,添加了内容提供者并注册了监听后,发handler回调了system bar的
no service()方法,去根据默认config场景状态栏,记者在createStatusBarFromConfig()中,实例化了BaseStatusBar对象,并调用了BaseStatusBar中start()方法;【注:BaseStatusBar.java类网上很多资料这里写的StatusBar.java类,我没有深究到底是MTK改动,还是原生系统版本升级的改动,我这版本是MTK 4.4.2】
BaseStatusBar.java
public void start() {
mWindowManager = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE)
;
mWindowManagerService = WindowManagerGlobal.getWindowManagerService()
;
mDisplay = mWindowManager.getDefaultDisplay()
;
mDreamManager = IDreamManager.Stub.asInterface(
ServiceManager.checkService(DreamService.DREAM_SERVICE))
;
mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE)
;
mProvisioningObserver.onChange(
false)
;
// set up
mContext.getContentResolver().registerContentObserver(
Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED)
, true,
mProvisioningObserver)
;
mBarService = IStatusBarService.Stub.asInterface(
ServiceManager.getService(Context.STATUS_BAR_SERVICE))
;
mRecents = getComponent(RecentsComponent.
class)
;
mLocale = mContext.getResources().getConfiguration().locale
;
mLayoutDirection = TextUtils.getLayoutDirectionFromLocale(mLocale)
;
// Connect in to the status bar manager service
StatusBarIconList iconList =
new StatusBarIconList()
;
ArrayList notificationKeys =
new ArrayList()
;
ArrayList notifications =
new ArrayList()
;
mCommandQueue =
new CommandQueue(
this, iconList)
;
int[] switches =
new int[
7]
;
ArrayList binders =
new ArrayList()
;
try {
mBarService.registerStatusBar(mCommandQueue
, iconList
, notificationKeys
, notifications
,
switches
, binders)
;
}
catch (RemoteException ex) {
// If the system process isn't there we're doomed anyway.
}
createAndAddWindows()
;
在
BaseStatusBar类的start()方法中,才是真的开始准备初始化状态栏界面,window manager类也是各种ask想直接实现沉浸式状态栏的必掉的一个类,进过各种公用的初始化,走到createAndAddWindows()方法,点过去,我们发现他是一个抽象方法,那么这个方法就是有子类来实现的,查看集成体系,锁定BaseStatusBar.java类
public class PhoneStatusBar
extends BaseStatusBar
implements DemoMode {
@Override
public void createAndAddWindows() {
addStatusBarWindow()
;
}
private void addStatusBarWindow() {
// Put up the view
final int height = getStatusBarHeight()
;
final WindowManager.LayoutParams lp =
new WindowManager.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT
,
height
,
WindowManager.LayoutParams.TYPE_STATUS_BAR
,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
| WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
| WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
,
PixelFormat.TRANSLUCENT)
;
lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED
;
lp.gravity = getStatusBarGravity()
;
lp.setTitle(
"StatusBar")
;
lp.packageName = mContext.getPackageName()
;
makeStatusBarView()
;
/// M: [SystemUI] For SystemUI AT.
if (AutoTestHelper.isNotRunningInTest()) {
mWindowManager.addView(mStatusBarWindow
, lp)
;
}
}
添加状态栏window,开始对状态栏的初始化,走到
makeStatusBarView()方法。这就是直接初始化layout和view的具体方法,我们来详细看看这个方法:
protected PhoneStatusBarView makeStatusBarView() {
final Context context = mContext
;
Resources res = context.getResources()
;
updateDisplaySize()
;
// populates mDisplayMetrics
loadDimens()
;
mIconSize = res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_icon_size)
;
/// M: Support "Change font size of phone".
Configuration config = res.getConfiguration()
;
mPreviousConfigFontScale = config.fontScale
;
mPrevioutConfigOrientation = config.orientation
;
首先,获取当前屏幕的现实尺寸,然后再底层dimes中拿到系统对应默认的statusbar 图标和字体的size;
紧接着初始化当前的飞行模式,如果是飞行,后面就直接先飞行模式的icon。
然后,关键点来的:super_statu_bar.xml, 这就是,MTK平台状态栏主要的layout文件,注释中不难看出,并不是它,他只是原生的layout给including到了这个super_stat_bar的layout中,添加了一些MTK自己想要现实的状态布局;
/// M: [SystemUI] Support "Dual SIM". {
// if (FeatureOption.MTK_GEMINI_SUPPORT) {
// mStatusBarWindow = (StatusBarWindowView)View.inflate(context, R.layout.gemini_super_status_bar, null);
// } else {
mStatusBarWindow = (StatusBarWindowView) View.inflate(context
, R.layout.super_status_bar
, null)
;
// }
mStatusBarWindow.mService =
this;
// mStatusBarWindow.setOnTouchListener(new View.OnTouchListener() {
// @Override
// public boolean onTouch(View v, MotionEvent event) {
// checkUserAutohide(v, event);
// if (event.getAction() == MotionEvent.ACTION_DOWN) {
// if (mExpandedVisible) {
// animateCollapsePanels();
// }
// }
// return mStatusBarWindow.onTouchEvent(event);
// }});
//yangxilin.INWATCH_STATUSBAR.inwatch
InwatchMakeView()
;
我们来看看这layout布局文件的结构:
而status_bar.xml才是原生的layout,从结构中可以看到3部分布局:从布局结构不难看出各部分功能状态显示的划分;
ImageView--------@+id/notification_lights_out
通知状态图标icon
LinearLayout-----@+id/status_bar_contents
状态栏内容主体:蓝牙,飞行,WiFi信号,phone信号,
电池(百分比+电池icon),时间
|
—--LinearLayout--
notification_icon_area
|
——-
LinearLayout--
system_icon_area
|
——-statusIcons
|---signal_battery_cluster
|---statusbar.policy.Clock
LinearLayout-----@+id/ticker
回到
makeStatusBarView()方法,紧接着,就是一大串的对其
子view 的初始化
findviewbyid(),初始化view的时候,也根据之前拿到的状态,初始化一些应该显示状态图标;
【持续更新。。。。。】