SystemUI车载Hvac开发_hvaccontroller(2),java中jvm面试题

先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新HarmonyOS鸿蒙全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
img

img
img
htt

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上鸿蒙开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以添加V获取:vip204888 (备注鸿蒙)
img

正文

android:persistent=“true”>

仅由两个服务以及一个开机广播组成,其中开机广播负责在开机的时候启动服务HvacUiService

HvacUiService

[packages/apps/Car/Hvac/src/com/android/car/hvac/HvacUiService.java]
public class HvacUiService extends Service {}

该服务主要做了以下几件事:

  • 1.在layoutHvacUi()方法中完成HVAC面板的构建,该页面由五个窗口组成,窗口类型皆为WindowManager.LayoutParams.TYPE_DISPLAY_OVERLAY,会盖在sysui上面,分别是
  • 1.1 界面中间部分座椅加热,前后挡风除雾开关等元素构成的窗口,对应布局hvac_panel
  • 1.2 左边的主驾温度控制条窗口,对应布局hvac_temperature_bar_overlay,下同
  • 1.3 左边的主驾温度控制条收起(Collapsed)窗口,代码中通过配置config_showCollapsedBars字段来控制该窗口显示与否,默认为false,该窗口其实就是在控制面板收起时提供一个非完全收起的温度控制条以便调起控制面板
  • 1.4 右边的副驾温度控制条窗口
  • 1.5 右边的副驾温度控制条收起(Collapsed)窗口,同上

hvac_panel.png

  • 2.注册监听广播android.car.intent.action.TOGGLE_HVAC_CONTROLS,后续sysui会通过该广播来通知该服务做展开/收起HVAC面板

@Override
public void onCreate() {

IntentFilter filter = new IntentFilter();
filter.addAction(CAR_INTENT_ACTION_TOGGLE_HVAC_CONTROLS);
// Register receiver such that any user with climate control permission can call it.
registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter,
Car.PERMISSION_CONTROL_CAR_CLIMATE, null);
}

  • 3.创建HvacPanelController对象,将以上构建的五个窗口对应的View传进去

private void layoutHvacUi() {

mHvacPanelController = new HvacPanelController(this /* context */, mContainer,
mWindowManager, mDriverTemperatureBar, mPassengerTemperatureBar,
mDriverTemperatureBarCollapsed, mPassengerTemperatureBarCollapsed
);
Intent bindIntent = new Intent(this /* context */, HvacController.class);
if (!bindService(bindIntent, mServiceConnection, Context.BIND_AUTO_CREATE)) {
Log.e(TAG, “Failed to connect to HvacController.”);
}
}

  • 4.绑定服务HvacController,并在绑定成功时将服务对象HvacController给到HvacPanelController,这里可以看到,相对于sysui,HvacUiService是服务端,而相对于HvacUiService,HvacController才是服务端
HvacPanelController

[packages/apps/Car/Hvac/src/com/android/car/hvac/controllers/HvacPanelController.java]
public class HvacPanelController {}

该控制器是一个HVAC UI 布局元素状态机,负责整个 HVAC 面板UI元素的初始化,响应各布局元素的事件(用户点击 & 系统内部硬件属性变化)以及执行状态切换(如出现消失动画)

上文介绍HvacUiService时我们看到,HvacUiService在创建了各个窗口之后,将各窗口的View对象传了进来,而HvacPanelController则进一步对这些View对象做初始化,下面看看这个类的主要职责:

  • 1.在构造方法中取出各个子元素(findViewById),并设置其Icon资源
  • 2.前面说到,当HvacUiService成功绑定服务HvacController后,会将HvacController服务对象传进HvacPanelController,此时HvacPanelController会构造各类子元素View对应的控制器,去HvacController中获取各子元素的初始状态并设置给各子元素,以及设置各子元素的点击事件

public void updateHvacController(HvacController controller) {
// 构造各类子元素View对应的控制器
mFanSpeedBarController = new FanSpeedBarController(mFanSpeedBar, mHvacController);
mSeatWarmerController = new SeatWarmerController(mPassengerSeatWarmer,
mDriverSeatWarmer, mHvacController);

// 初始化按钮状态,并设置点击事件
mAcButton.setIsOn(mHvacController.getAcState());
mAcButton.setToggleListener(new ToggleButton.ToggleListener() {
@Override
public void onToggled(boolean isOn) {
mHvacController.setAcState(isOn);
}
});
// 注册回调
mHvacController.registerCallback(mToggleButtonCallbacks);
}

  • 3.负责View的 show/hide 以及 动画的执行(transition),前面介绍HvacUiService时第2点我们说过,HvacUiService会去监听一个广播来展开/收起HVAC面板,相关逻辑如下,其中transitionState就是最终展开/收起面板的地方

[packages/apps/Car/Hvac/src/com/android/car/hvac/HvacUiService.java]
private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if(action.equals(CAR_INTENT_ACTION_TOGGLE_HVAC_CONTROLS)){
mHvacPanelController.toggleHvacUi();
}
}
};

[packages/apps/Car/Hvac/src/com/android/car/hvac/controllers/HvacPanelController.java]
public void toggleHvacUi() {
if(mCurrentState != STATE_COLLAPSED) {
mCollapseHvac.onClick(null);
} else {
mExpandHvac.onClick(null);
}
}

public View.OnClickListener mExpandHvac = new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mInAnimation) {
return;
}
if (mCurrentState != STATE_FULL_EXPANDED) {
transitionState(mCurrentState, STATE_FULL_EXPANDED);
}
}
};

car-lib库

前面介绍架构时我们说过,car-lib对应于硬件访问服务,其内部封装了对 HAL层的调用,例如对于HVAC硬件接口,car-lib对外提供了类CarHvacManager,而上层访问者均可通过该类对象直接查询/设置HVAC相关属性

介绍HvacController之前我们先来看看car-lib库下的两个关键类

[packages/services/Car/car-lib/src/android/car/Car.java]
// 源码对该类的说明:针对Android车载开发的顶级car API
public final class Car {
// 1.外界获取硬件访问服务的入口
public static Car createCar(Context context, ServiceConnection serviceConnectionListener,@Nullable Handler handler) {
return new Car(context, serviceConnectionListener, handler);
}
// 2.缓存起来的 mServiceConnectionListenerClient 后面会用到
private Car(Context context, ServiceConnection serviceConnectionListener,@Nullable Handler handler) {
mServiceConnectionListenerClient = serviceConnectionListener;
}
// 3.调用该函数时会触发 startCarService 去创建 CarService服务
public void connect() throws IllegalStateException {
startCarService();
}

private void startCarService() {
// 4.intent 指向了CarService服务,该服务真正的实现在ICarImpl中,这里不展开
boolean bound = mContext.bindServiceAsUser(intent, mServiceConnectionListener,Context.BIND_AUTO_CREATE, UserHandle.CURRENT_OR_SELF);
}

private final ServiceConnection mServiceConnectionListener = new ServiceConnection () {
public void onServiceConnected(ComponentName name, IBinder service) {
synchronized (Car.this) {
mService = ICar.Stub.asInterface(service);
mConnectionState = STATE_CONNECTED;
}
// 5.连接成功时通知 mServiceConnectionListenerClient, 即前面createCar时传进来的服务连接监听器,
// 进而上层访问者可以开始获取诸如 CarHvacManager 等对象
mServiceConnectionListenerClient.onServiceConnected(name, service);
}
};
}

上面第5点中连接CarService成功时会通知调用者,意在告诉调用者你可以获取诸如 CarHvacManager 等对象了,因为诸如CarHvacManager 等对象的获取需要依赖到 CarService.

同时Car类中不仅可以获取CarHvacManager对象,还可以获取Android Car开发相关的各种管理类,如CarAudioManager,CarSensorManager等,详见其createCarManager函数

整个Car主要的功能就是

  • 1.作为外界获取硬件访问服务的入口,上层调用者可通过createCar来获取一个Car对象
  • 2.当调用者调用其connect函数时去连接CarService服务,这个服务是连接车载底层模块的桥梁,并在连接成功时通知调用者(通过ServiceConnection)
  • 3.提供入口供开发者获取所需的Manager,比如HVAC模块中所需的CarHvacManager,这是调用者后续操作相关硬件属性的入口

下面看看CarHvacManager的功能

CarHvacManager使用了一个数据结构,这是一个可跨进程传输的数据结构,封装了车辆相关的属性
[packages/services/Car/car-lib/src/android/car/hardware/CarPropertyValue.java]
public class CarPropertyValue implements Parcelable {
private final int mPropertyId;
private final int mAreaId;
private final int mStatus;
private final long mTimestamp;
private final T mValue;
}

[packages/services/Car/car-lib/src/android/car/hardware/hvac/CarHvacManager.java]
// 源码对该类的说明:用于控制HVAC系统的API
public final class CarHvacManager implements CarManagerBase {
// 步骤1 : 定义了一系列常量,用来对应车辆各个区域(zone)的属性
// 空调温度
public static final int ID_ZONED_TEMP_SETPOINT = 0x15600503;
// 座椅温度,负值制冷,正值制热,
public static final int ID_ZONED_SEAT_TEMP = 0x1540050b;
// 镜子除雾器,布尔值
public static final int ID_MIRROR_DEFROSTER_ON = 0x1440050c;
// 窗口除雾器,布尔值
public static final int ID_WINDOW_DEFROSTER_ON = 0x13200504;

// 步骤2 : 回调 可通过注册该回调来监听各 CarPropertyValue 的变化
public interface CarHvacEventCallback {
void onChangeEvent(CarPropertyValue value);
}
public synchronized void registerCallback(CarHvacEventCallback callback) {}
public synchronized void unregisterCallback(CarHvacEventCallback callback) {}

// 步骤3 : 提供对各 HVAC 属性的 状态查询 与 状态设置接口
public boolean getBooleanProperty(@PropertyId int propertyId, int area)
throws CarNotConnectedException {
return mCarPropertyMgr.getBooleanProperty(propertyId, area);
}

public float getFloatProperty(@PropertyId int propertyId, int area)
throws CarNotConnectedException {
return mCarPropertyMgr.getFloatProperty(propertyId, area);
}
}

首先封装了一个可序列化的类CarPropertyValue, 其对应一个车辆属性,一个车辆属性主要由两部分构成:[propertyId, area]

  • propertyId定义了车辆属性,如空调温度,座椅温度等,具体值定义在CarHvacManager类中,见步骤1
  • area定义了属性对应的区域,因为同一个属性会有多个位置需要控制,如同是座椅温度,有主驾座椅温度,副驾座椅温度,所以就通过该值来对同一属性的不同位置做区分.

CarHvacManager主要做了以下三件事

  • 步骤1 : 定义车辆属性
  • 步骤2 : 提供CarHvacEventCallback回调器及其注册接口,其会去监听底层硬件的状态变化,以便在底层硬件属性变化时告诉上层调用者,可想而知,这个就是我们开发时需要关注的一个接口
  • 步骤3 : 提供查询/设置硬件属性的上层接口,同样这也是我们开发时需要关注的一个接口

这两个类均位于packages/services/Car/car-lib下,我们看下其mk文件

[packages/services/Car/car-lib/Android.mk]


LOCAL_MODULE := android.car

即该模块会被编译成共享库android.car,可被其他应用引用,例如CarHvacApp中就引用了该库

[packages/apps/Car/Hvac/Android.mk]

LOCAL_JAVA_LIBRARIES += android.car

HvacController

回到前面对 CarHvacApp 的分析,前面介绍HvacPanelController第2点中的updateHvacController()方法时我们看到,HvacController对象会被传进各类子元素View对应的控制器中,同时也是获取/设置各类子元素View状态的地方,很明显,这是个总控制器,同时维护了各开关的状态

来看看这个类的主要职责是什么

  • 1.服务启动时利用car-lib库去创建一个Car对象并调用其connect()函数,并在连接成功时通过该对象获取一个CarHvacManager对象

[packages/apps/Car/Hvac/src/com/android/car/hvac/HvacController.java]
public class HvacController extends Service {
@Override
public void onCreate() {
super.onCreate();
if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
mCarApiClient = Car.createCar(this, mCarConnectionCallback);
mCarApiClient.connect();
}
}

private final CarConnectionCallback mCarConnectionCallback = new CarConnectionCallback() {
@Override
public void onConnected(Car car) {
synchronized (mHvacManagerReady) {
try {
initHvacManager((CarHvacManager) mCarApiClient.getCarManager(android.car.Car.HVAC_SERVICE));
mHvacManagerReady.notifyAll();

}

private void initHvacManager(CarHvacManager carHvacManager) {
mHvacManager = carHvacManager;
List properties = null;
try {
properties = mHvacManager.getPropertyList();
mPolicy = new HvacPolicy(HvacController.this, properties);
mHvacManager.registerCallback(mHardwareCallback);
}
}
}

    1. 提供接口供查询 / 设置 各HVAC开关的状态值,这里便是利用了CarHvacManager去获取状态值并保存到mDataStore中的,以及利用CarHvacManager将属性变化告知底层硬件的

public boolean getAirCirculationState() {
return mDataStore.getAirCirculationState();
}

public void setFanDirection(final int direction) {
mDataStore.setAirflow(SEAT_ALL, direction);
setFanDirection(SEAT_ALL, direction);
}

  • 3.向CarHvacManager注册一个监听器监听硬件状态变化,并通知各子元素去做UI刷新

private void initHvacManager(CarHvacManager carHvacManager) {

mHvacManager.registerCallback(mHardwareCallback);

}

private final CarHvacManager.CarHvacEventCallback mHardwareCallback =
new CarHvacManager.CarHvacEventCallback() {
@Override
public void onChangeEvent(final CarPropertyValue val) {
int areaId = val.getAreaId();
switch (val.getPropertyId()) {
case CarHvacManager.ID_ZONED_AC_ON:
handleAcStateUpdate(getValue(val));
break;

}
}
};

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip204888 (备注鸿蒙)
img

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

rtyValue val) {
int areaId = val.getAreaId();
switch (val.getPropertyId()) {
case CarHvacManager.ID_ZONED_AC_ON:
handleAcStateUpdate(getValue(val));
break;

}
}
};

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip204888 (备注鸿蒙)
[外链图片转存中…(img-5juRYbmH-1713155960909)]

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 25
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值