[ Android SystemUi ] 动态修改系统状态栏颜色【沉浸式状态栏】
来源:互联网 发布:python 文件重命名 编辑:程序博客网 时间:2024/04/27 23:12
平台: 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
<intent-filter>
<category android:name=
"android.intent.category.LAUNCHER"
>
</category></action></intent-filter>
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];
* 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);
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();
}
}
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);
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<IBinder> notificationKeys = new ArrayList<IBinder>();
ArrayList<StatusBarNotification> notifications = new ArrayList<StatusBarNotification>();
mCommandQueue = new CommandQueue(this, iconList);
int[] switches = new int[7];
ArrayList<IBinder> binders = new ArrayList<IBinder>();
try {
mBarService.registerStatusBar(mCommandQueue, iconList, notificationKeys, notifications,
switches, binders);
} catch (RemoteException ex) {
// If the system process isn't there we're doomed anyway.
}
createAndAddWindows();
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<IBinder> notificationKeys = new ArrayList<IBinder>();
ArrayList<StatusBarNotification> notifications = new ArrayList<StatusBarNotification>();
mCommandQueue = new CommandQueue(this, iconList);
int[] switches = new int[7];
ArrayList<IBinder> binders = new ArrayList<IBinder>();
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();
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);
}
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;
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;
updateAirplaneMode();
首先,获取当前屏幕的现实尺寸,然后再底层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();
// 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的时候,也根据之前拿到的状态,初始化一些应该显示状态图标;
【持续更新。。。。。】
1 0
- [ Android SystemUi ] 动态修改系统状态栏颜色【沉浸式状态栏】
- android沉浸式状态栏、变色状态栏、透明状态栏、修改状态栏颜色及透明
- android沉浸式状态栏、变色状态栏、透明状态栏、修改状态栏颜色及透明
- android沉浸式状态栏、变色状态栏、透明状态栏、修改状态栏颜色及透明
- android沉浸式状态栏、变色状态栏、透明状态栏、修改状态栏颜色及透明
- Android动态修改状态栏沉浸色(取图片颜色)
- Android 沉浸式状态栏,状态栏颜色透明
- Android状态栏颜色设置(沉浸式状态栏)
- Android 设置状态栏颜色&&沉浸式状态栏
- android 沉浸式状态栏颜色
- Android 沉浸式状态栏以及 透明状态栏 和修改状态栏颜色
- android 隐藏状态栏和修改状态栏的背景颜色(沉浸式状态栏)
- 【SystemUI】修改下拉状态栏颜色
- Android状态栏沉浸式模式下全屏、修改颜色
- Android系统状态栏\沉浸状态栏
- 沉浸式状态栏(修改状态栏)颜色的简单实现
- Android5.0沉浸式状态栏,以及动态改变状态栏颜色
- Android底部菜单栏、Android沉浸式状态栏(顶部状态栏修改颜色)、自定义标题栏
- Core Animation
- C语言学习笔记之文件I/O(fgets()函数和fputs()函数)
- 40个Java多线程问题总结
- 《C++ Primer》 第四版 第3章 标准库类型
- 20160328servlet学习笔记网站代码结构分析MVC结构
- [ Android SystemUi ] 动态修改系统状态栏颜色【沉浸式状态栏】
- 代码重定位实战1~2
- 第五周项目四 长方柱类
- 第四周项目3-随机数函数应用于游戏(1)
- tablayout
- 选择排序
- read和write
- 通用树--GTree(双亲孩子法)
- Be a tester