案例一:状态栏多图标情况下三角按钮闪烁问题。
frameworks\base\packages\SystemUI\src\com\android\systemui\statusbar\phone\IconMerger.java
此文件的主要作用是合并通知栏图标,其中:
onLayout 和 checkOverflow
方法是测量状态栏的宽度来决定是否显示隐藏三角指示图标
案例二:下拉栏实现双卡数据开关
①config.xml添加关键字
②QSTileHost.java中创建实例
③创建Sim1 & Sim2的Tile类分别继承之前的Date类
④在两个类中分别做数据初始化及互斥逻辑操作
案例三:状态栏左边是给其他应用显示图标的
案例三、一:
如何将下拉通知栏的宽度修改为适应屏幕宽度?
请在/frameworks/base/packages/SystemUI/res/values/dimens.xml文件中,找到如下内容:
<!-- Width for the notification panel and related windows -->
<dimen name="match_parent">-1px</dimen>
<dimen name="standard_notification_panel_width">416dp</dimen><!-- includes notification_side_padding on each side -->
<dimen name="notification_panel_width">@dimen/match_parent</dimen>
将上述内容中的 <dimen name="standard_notification_panel_width">416dp</dimen>
修改为:<dimen name="standard_notification_panel_width">@dimen/match_parent</dimen>
修改notification之间的间隔
<!-- The height of the divider between the individual notifications. -->
<dimen
name=
"notification_divider_height"
>
2dp
</dimen>
修改日期到时钟的距离 在布局中设置的
设置下拉栏图片及字体的大小
<dimen
name=
"qs_tile_icon_size"
>
24dp
</dimen>
<dimen
name=
"qs_tile_text_size"
>
11sp
</dimen>
快捷图标(item)设置布局模板
图标:SystemUI\src\com\android\systemui\qs\tileimpl\QSIconViewImpl.java
字体:SystemUI\res\layout\qs_tile_label.xml(里面有图标距离字体的高度)
对字体的设置(如颜色等):SystemUI\src\com\android\systemui\qs\tileimpl\QSTileView.java
下拉栏快捷设置点击进入详情界面布局文件
SystemUI\res\layout\qs_detail.xml
下拉栏底部显示及编辑控件
SystemUI\res\layout\qs_paged_tile_layout.xml
二级菜单界面整体布局
SystemUI\res\layout\qs_detail.xml
二级菜单详情界面信息列表布局
SystemUI\res\layout\qs_detail_item.xml
二级菜单详情界面列表信息为空的时候的布局
SystemUI\res\layout\qs_detail_items.xml
用户信息详情界面布局
SystemUI\res\layout\qs_user_detail_item.xml
设置下拉栏高度的尺寸值
<dimen name="qs_tile_height">88dp</dimen> 设置每行之间的距离
锁屏界面充电指示字符串的类
SystemUI\src\com\android\systemui\statusbar\KeyguardIndicationController.java
下拉栏顶部时间布局
SystemUI\res_transsion\layout-v24\status_bar_alarm_group.xml
<!-- The font size of the time when collapsed in QS 。时间字体大小-->
<dimen name="qs_time_collapsed_size">18dp</dimen>
<!-- The font size of the time when expanded in QS。 AM、PM字体大小-->
<dimen name="qs_time_expanded_size">18dp</dimen>
下拉栏编辑快捷设置界面高度的修改方式
SystemUI\res\layout\qs_customize_divider.xml
SystemUI\res\layout\qs_customize_tile_frame.xml
自定义下拉栏图标位置的位置
布局:res/layout/qs_customize_panel_content.xml(
RecyclerView
)
类:SystemUI\src\com\android\systemui\qs\customize\QSCustomizer.java
8.0下拉栏统一对快捷图标着色的地方,修改快捷图标title的地方
SystemUI\src\com\android\systemui\qs\tileimpl\QSIconViewImpl.java
SystemUI\src\com\android\systemui\qs\tileimpl\QSTileView.java
下拉栏控制主题颜色的几个颜色变量
7.0:qs_detail_transition system_primary_color
8.0:qs_detail_transition ?android:attr/colorPrimary
下拉栏快捷设置每行修改为四个,自定义界面修改为每行四个
<integer
name=
"quick_settings_num_columns"
>
4
</integer>
SystemUI\src\com\android\systemui\qs\customize\QSCustomizer.java
SystemUI\src\com\android\systemui\qs\customize\TileAdapter.java
修改Notification样式的几个xml文件
core/res/res/layout/notification_material_action_list.xml
packages/Keyguard/res_transsion/layout-v24/keyguard_status_view.xml
packages/SystemUI/res_transsion/drawable-v24/notification_guts_bg.xml
packages/SystemUI/res_transsion/drawable-v24/notification_material_bg.xml
packages/SystemUI/res_transsion/drawable-v24/notification_material_bg_dim.xml
packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
案例四:状态栏默认图标修改处
SystemUI\res\layout\signal_cluster_view.xml
案例五:状态栏显示图标更换修改处
base/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java
案例六:statusbar图标根据背景显示颜色
SystemUI\src\com\android\systemui\statusbar\phone\StatusBarIconController.java
此类提供所有图标显示颜色数据
private void
setIconTintInternal
(
float
darkIntensity) {
mDarkIntensity
= darkIntensity
;
mIconTint
= (
int
) ArgbEvaluator.getInstance().evaluate(darkIntensity
,
mLightModeIconColorSingleTone
,
mDarkModeIconColorSingleTone
)
;
applyIconTint()
;
}
下面的类根据传递来的数据进行颜色的改变
SystemUI\src\com\android\systemui\statusbar\SignalClusterView.java
public void
setIconTint(
int
tint
, float
darkIntensity) {
private void
applyIconTint() {
系统下拉栏的电量显示在
SystemUI\src\com\android\systemui\statusbar\phone\PhoneStatusBarView.java
SystemUI\res\layout\system_icons.xml
案例六、一:节电助手改变StatusBar背景颜色的方法
(
一开始想在SystemUI中设置颜色来达到状态栏和壁纸颜色冲突问题,但是最后还是决定在Launcher中修改,因为这样影响范围较小
)
在文件:SystemUI\src\com\android\systemui\statusbar\phone\PhoneStatusBar.java
private void checkBarMode(int mode, int windowState, BarTransitions transitions,
boolean noAnimation) {
final boolean powerSave = mBatteryController.isPowerSave();
final boolean anim = !noAnimation && (mScreenOn == null || mScreenOn)
&& windowState != WINDOW_STATE_HIDDEN && !powerSave;
if (powerSave && getBarState() == StatusBarState.SHADE) {
这里同时判断getBarState() == StatusBarState.SHADE,锁屏是StatusBarState.KEYGUARD
mode = MODE_WARNING;
}
transitions.transitionTo(mode, anim);
}
在节电模式下,powerSave = mBatteryController.isPowerSave();会为true,然后当前mode = MODE_WARNING;
在文件:SystemUI\src\com\android\systemui\statusbar\phone\BarTransitions.java
会进行状态栏背景颜色切换,节电模式下的颜色为:
mWarning = context.getColor(com.android.internal.R.color.battery_saver_mode_color);
最后通过绘制函数进行绘图,显示红色状态栏。
@Override
public void draw(Canvas canvas) {
int targetGradientAlpha = 0, targetColor = 0;
if (mMode == MODE_WARNING) {
targetColor = mWarning;
} else if (mMode == MODE_TRANSLUCENT) {
targetColor = mSemiTransparent;
} else if (mMode == MODE_SEMI_TRANSPARENT) {
targetColor = mSemiTransparent;
} else if (mMode == MODE_TRANSPARENT || mMode == MODE_LIGHTS_OUT_TRANSPARENT) {
targetColor = mTransparent;
} else {
targetColor = mOpaque;
}
案例七:其他应用收起下拉栏
[QUESTION] SC7731,来电接通时,如何收起下拉通知栏? [ANSWER] 来电接通时,要收起下拉通知栏,请做以下修改: packages\apps\Dialer\AndroidManifest.xml <uses-permission android:name="android.permission.WRITE_SMS"/> ++ <uses-permission android:name="android.permission.STATUS_BAR" /> packages\apps\InCallUI\src\com\android\incallui\CallCardPresenter.java import com.google.common.base.Preconditions; ++import android.app.StatusBarManager; ... ... private Context mContext; ++ private StatusBarManager mStatusBarManager; ... ... mContext = Preconditions.checkNotNull(context); ++ mStatusBarManager = (StatusBarManager) mContext.getSystemService(Context.STATUS_BAR_SERVICE); ... ... @Override public void onStateChange(InCallState oldState, InCallState newState, CallList callList) { Log.d(this, "onStateChange() " + newState); final CallCardUi ui = getUi(); if (ui == null) { return; } Call primary = null; Call secondary = null; ++ if(newState == InCallState.INCALL && oldState != InCallState.INCALL){ ++ mStatusBarManager.disable(StatusBarManager.DISABLE_EXPAND); ++ mStatusBarManager.disable(StatusBarManager.DISABLE_NONE); ++ } |
案例八:截屏的具体实现
frameworks\base\services\core\java\com\android\server\policy\PhoneWindowManager.java 这个类中判断是按了电源键和音量下键进行截屏截屏的方式是
mHandler.post(mScreenshotRunnable);
takeScreenshot();是绑定截屏服务的主要接口
截屏服务:SystemUI\src\com\android\systemui\screenshot\TakeScreenshotService.java
截屏服务中用的是类SystemUI\src\com\android\systemui\screenshot\GlobalScreenshot.java 的方法 takeScreenshot();
this.mHost.collapsePanels(); 用于收起下拉栏
案例九:recent task 数量的控制
[SC7731C][ITEL][A11]点击Menu键之后出现的recent task数量是在哪控制的?
解决方案:
frameworks/base/core/java/android/app/ActivityManager.java中
static public int getMaxRecentTasksStatic() {
if (gMaxRecentTasks < 0) {
return gMaxRecentTasks = isLowRamDeviceStatic() ? 10 : 100;//这里修改下10改成22
}
return gMaxRecentTasks;
}
这是google原生设计如此,低内存最近任务数做了限制,默认是10,这个主要减少ActivityManager后台维护的开销和最近任务界面的显示负荷
这个限制可以根据情况修改,但不建议改的很大,目前看改成22没有什么问题
案例十:改变下拉栏每行显示的数量
SystemUI\res\values\config.xml
<!-- The number of columns in the QuickSettings -->
<integer name="quick_settings_num_columns">3</integer>
案例十一:各个锁屏界面紧急拨号按钮
frameworks\base\packages\Keyguard\src\com\android\keyguard\EmergencyButton.java 按钮的点击事件是在控件中实现的
案例十二:音量控制按钮
frameworks\base\packages\SystemUI\src\com\android\systemui\volume\VolumeDialog.java
案例十三:锁屏界面不显示相机图标
frameworks\base\packages\SystemUI\res\values\config.xml
<!-- Show camera affordance on Keyguard -->
<bool
name=
"config_keyguardShowCameraAffordance"
>
false
</bool>
案例十四:下拉栏点击勿扰模式后进入的界面
(想去除这个界面和自己用的魅族手机相同)
frameworks\base\packages\SystemUI\src\com\android\systemui\volume\ZenModePanel.java
案例十五:电量百分比代码位置
不下拉statusbar显示电池的百分比有PhoneStatusbarView和KeyguardStatusbarView两个部分。
下拉栏在StatusBarHeaderView.java类中。下面是设置方法
tempBatteryLevel = level;
String percentage = NumberFormat.
getPercentInstance
().format((double) level / 100.0);
mBatteryLevel.setText(percentage);
案例十六:下拉栏的头部中的图标都在这个布局中(自定义的控件)
frameworks\base\packages\SystemUI\res\layout\status_bar_expanded_header.xml 首先此布局中有一个控件frameworks\base\packages\SystemUI\src\com\android\systemui\statusbar\phone\MultiUserSwitch.java 此控件中有实现点击图标打开联系人界面的功能
首先:自测试当滑动下拉栏的时候第一次点击用户设置头像会彻底将下拉栏展开第二次点击的时候才会打开用户信息设置界面。
Intent intent = ContactsContract.QuickContact.composeQuickContactsIntent(
getContext(), v, ContactsContract.Profile.
CONTENT_URI
,
ContactsContract.QuickContact.
MODE_LARGE
, null);
getContext().startActivityAsUser(intent, new UserHandle(UserHandle.USER_CURRENT));
这段代码是打开用户信息设置界面的
if (mQsPanel != null && mQsPanel.getHost() != null) {
mQsPanel.getHost().collapsePanels();
}
这段代码是收起下拉栏功能
如果之前没有设置用户信息的话打开的界面是
com.android.contacts/com.android.contacts.activities.CompactContactEditorActivity
如果之前有设置用户信息的话则打开的是
com.android.contacts/com.android.contacts.quickcontact.QuickContactActivity
从打印出的log的信息来看当没有用户信息的时候先显示此activity然后瞬间打开
CompactContactEditorActivity
来实现打开不同界面的目的此类中的
editContact()
方法即为打开
CompactContactEditorActivity
的具体实现,打开的intent可追溯到是
"android.intent.action.EDIT"
。此activity中加载的是一个
packages\apps\Contacts\src\com\android\contacts\editor\CompactContactEditorFragment.java
此类继承类
packages\apps\Contacts\src\com\android\contacts\editor\ContactEditorBaseFragment.java 此类中含有onOptionsItemSelected()
方法首个菜单即为保存编辑
到此我想了解他是怎么报错和删除用户信息的以及怎样通知SystemUI的?
用户信息查询追踪到
frameworks\base\packages\SystemUI\src\com\android\systemui\statusbar\policy\UserInfoController.java
queryForUserInformation方法 这个方法是在本类中的reloadUserInfo()
方法中使用的,而此方法的使用除此类中的
broadcastrecever
监听使用外还在另外两个类中使用到了分别使用一次这两个类是:
src/com/android/systemui/statusbar/phone/PhoneStatusBar.java 和 src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
是个
Imageview
,控件的id为
multi_user_avatar
。他在
StatusBarHeaderView.java
中做了个监听当用户信息改变的时候会更新用户的头像。
public void setUserInfoController(UserInfoController userInfoController) {
userInfoController.addListener(new UserInfoController.OnUserInfoChangedListener() {
@Override
public void onUserInfoChanged(String name, Drawable picture) {
mMultiUserAvatar.setImageDrawable(picture);
}
});
frameworks\base\packages\SystemUI\src\com\android\systemui\statusbar\policy\UserInfoController.java
此类中有
addListener
方法参数是此类中的
OnUserInfoChangedListener
接口,此接口中有一个抽象方法
onUserInfoChanged
;
此类中还存在一个方法
notifyChanged
,此方法中使用for循环调用接口的
onUserInfoChanged
方法。notifyChanged调用的时机是:此控制类中的
queryForUserInformation
方法中的AysnTask执行完成的时候会将图片返回到此类中。
// Fall back to the UserManager nickname if we can't read the name from the local
// profile below.
String name = userName;
Drawable avatar = null;
Bitmap rawAvatar = um.getUserIcon(userId);
if (rawAvatar != null) {
Log.
d
(
TAG
, "****************rawAvatar != null");
avatar = new BitmapDrawable(mContext.getResources(),
BitmapHelper.
createCircularClip
(rawAvatar, avatarSize, avatarSize));
} else {
此处的代码显示将得到的图片进行了处理,处理为圆形的头像图片。
到此处逻辑上似乎没有什么问题。下面来看Bitmap来源
Bitmap rawAvatar = um.getUserIcon(userId);
调用的是这个类
frameworks\base\core\java\android\os\UserManager.java
中的方法
public Bitmap getUserIcon(int userHandle) {
然后这个方法中调用了
frameworks\base\core\java\android\os\IUserManager.aidl
中的
ParcelFileDescriptor getUserIcon(int userHandle)
;具体实现是在
frameworks\base\services\core\java\com\android\server\pm\UserManagerService.java
这个类中的。
@Override
public ParcelFileDescriptor getUserIcon(int userId) {
此方法中通过
UserInfo info = mUsers.get(userId)
;的到用户信息,其中包括用户图片的存放地址然后返回。
return ParcelFileDescriptor.
open
(
new File(iconPath), ParcelFileDescriptor.
MODE_READ_ONLY
);
过程中有好多的非空判断如果返回的是为null的话则显示默认的图片不会刷新。
此类中的
private UserInfo readUserLocked(int id) {
方法有用户信息的一些数据如:用户图片路径。
案例十七:如何根据省电的模式来动态修改电池的颜色
首先SystemUI\res\values\arrays.xml中保存了三个数组,第一个数组
batterymeter_color_levels
保存的是电量的几个重要的节点状态,有15,、100。
batterymeter_color_values
保存的是电池的颜色。这些数据是在SystemUI\src\com\android\systemui\BatteryMeterView.java这个类中使用的,这个类就是电池的控件。这个类有实现了接口
BatteryController.BatteryStateChangeCallback
中的两个方法
void
onBatteryLevelChanged
(
int
level
, boolean
pluggedIn
, boolean
charging)
;
void
onPowerSaveChanged
()
;
这两个方法是通过回调实现的。
SystemUI\src\com\android\systemui\statusbar\policy\BatteryController.java是继承BrodcastReceive的可以通过传过来的Intent来判断并通过方法
updatePowerSave和
setPowerSave进行电量模式的更新。在updatePowerSave中使用
setPowerSave(
mPowerManager
.isPowerSaveMode())
;
来实现的。然后我们查找mPowerManager的具体类frameworks\base\core\java\android\os\PowerManager.java在
isPowerSaveMode里
调用的是
mService
.isPowerSaveMode()
;
而
mService
的具体实现类是
frameworks\base\core\java\android\os\IPowerManager.aidl
而具体的实现是在
frameworks\base\services\core\java\com\android\server\power\PowerManagerService.java
中的内部类
BinderService
实现的
return isLowPowerModeInternal();
我们在跟进这个方法返回的是
return mLowPowerModeEnabled;
再跟进这个变量的赋值地点是
void updateLowPowerModeLocked() {
中的
mLowPowerModeEnabled = lowPowerModeEnabled;
而
lowPowerModeEnabled
这个变量的赋值方式是
final boolean autoLowPowerModeEnabled = !mIsPowered && mAutoLowPowerModeConfigured
&& !mAutoLowPowerModeSnoozing && mBatteryLevelLow
;这几个变量的意思是不是在充电状态、自动打开低电量模式是开启的、低电量模式自动睡眠是关闭的,电池电量是比较低的。
用到电池的地方一共有三个分别是:锁屏、状态栏和下拉栏,对应的三个类分别是:
src/com/android/systemui/statusbar/phone/PhoneStatusBar.java、src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java、
src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java这三个类
统一使用的代码为:
((BatteryMeterView) findViewById(R.id.battery)).setBatteryController(batteryController);
在我们发送广播的时候打印log显示onReceive走了两次,原因是BatteryController被实例了两次
:
systemui/statusbar/phone/PhoneStatusBar.java: mBatteryController = new BatteryController(mContext);
systemui/statusbar/phone/PhoneStatusBarView.java:
mBatteryController = new BatteryController(context);