Add an option to display HVAC temp values in sysui
Bug: 77148007 Test: on device that has a real HVAC unit Change-Id: I97b303dd947858157ede72c5d537ae6a1e40cc67
This commit is contained in:
@@ -56,7 +56,8 @@ LOCAL_STATIC_JAVA_LIBRARIES := \
|
||||
SystemUI-tags \
|
||||
SystemUI-proto
|
||||
|
||||
LOCAL_JAVA_LIBRARIES := telephony-common
|
||||
LOCAL_JAVA_LIBRARIES := telephony-common \
|
||||
android.car
|
||||
|
||||
LOCAL_PACKAGE_NAME := SystemUI
|
||||
LOCAL_PRIVATE_PLATFORM_APIS := true
|
||||
|
||||
@@ -205,6 +205,9 @@
|
||||
<!-- Listen app op changes -->
|
||||
<uses-permission android:name="android.permission.WATCH_APPOPS" />
|
||||
|
||||
<!-- to read and change hvac values in a car -->
|
||||
<uses-permission android:name="android.car.permission.ADJUST_CAR_CLIMATE" />
|
||||
|
||||
<application
|
||||
android:name=".SystemUIApplication"
|
||||
android:persistent="true"
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="match_parent"
|
||||
android:animateLayoutChanges="true"
|
||||
android:src="@drawable/car_ic_arrow"
|
||||
android:background="@android:color/transparent"
|
||||
android:scaleType="fitCenter">
|
||||
</com.android.keyguard.AlphaOptimizedImageButton>
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
**
|
||||
** Copyright 2018, The Android Open Source Project
|
||||
**
|
||||
** Licensed under the Apache License, Version 2.0 (the "License");
|
||||
** you may not use this file except in compliance with the License.
|
||||
** You may obtain a copy of the License at
|
||||
**
|
||||
** http://www.apache.org/licenses/LICENSE-2.0
|
||||
**
|
||||
** Unless required by applicable law or agreed to in writing, software
|
||||
** distributed under the License is distributed on an "AS IS" BASIS,
|
||||
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
** See the License for the specific language governing permissions and
|
||||
** limitations under the License.
|
||||
*/
|
||||
-->
|
||||
|
||||
<com.android.systemui.statusbar.car.CarNavigationBarView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:systemui="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_width="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:background="@drawable/system_bar_background">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_height="match_parent"
|
||||
android:layout_width="match_parent"
|
||||
android:id="@+id/nav_buttons"
|
||||
android:orientation="vertical"
|
||||
android:gravity="top"
|
||||
android:paddingTop="30dp"
|
||||
android:layout_weight="1"
|
||||
android:background="@drawable/system_bar_background"
|
||||
android:animateLayoutChanges="true">
|
||||
|
||||
<com.android.systemui.statusbar.car.CarNavigationButton
|
||||
android:id="@+id/home"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="match_parent"
|
||||
systemui:intent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.HOME;end"
|
||||
android:src="@drawable/car_ic_overview"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:paddingTop="30dp"
|
||||
android:paddingBottom="30dp"
|
||||
/>
|
||||
|
||||
<com.android.systemui.statusbar.car.CarNavigationButton
|
||||
android:id="@+id/hvac"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="match_parent"
|
||||
systemui:intent="intent:#Intent;action=android.car.intent.action.TOGGLE_HVAC_CONTROLS;end"
|
||||
systemui:broadcast="true"
|
||||
android:src="@drawable/car_ic_hvac"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:paddingTop="30dp"
|
||||
android:paddingBottom="30dp"
|
||||
/>
|
||||
</LinearLayout>
|
||||
</com.android.systemui.statusbar.car.CarNavigationBarView>
|
||||
@@ -0,0 +1,61 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
**
|
||||
** Copyright 2018, The Android Open Source Project
|
||||
**
|
||||
** Licensed under the Apache License, Version 2.0 (the "License");
|
||||
** you may not use this file except in compliance with the License.
|
||||
** You may obtain a copy of the License at
|
||||
**
|
||||
** http://www.apache.org/licenses/LICENSE-2.0
|
||||
**
|
||||
** Unless required by applicable law or agreed to in writing, software
|
||||
** distributed under the License is distributed on an "AS IS" BASIS,
|
||||
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
** See the License for the specific language governing permissions and
|
||||
** limitations under the License.
|
||||
*/
|
||||
-->
|
||||
|
||||
<com.android.systemui.statusbar.car.CarNavigationBarView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:systemui="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_width="match_parent"
|
||||
android:background="@drawable/system_bar_background">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_height="match_parent"
|
||||
android:layout_width="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:id="@+id/nav_buttons"
|
||||
android:gravity="left"
|
||||
android:paddingLeft="30dp"
|
||||
android:layout_weight="1"
|
||||
android:animateLayoutChanges="true">
|
||||
|
||||
<com.android.systemui.statusbar.car.CarNavigationButton
|
||||
android:id="@+id/home"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_width="wrap_content"
|
||||
systemui:intent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.HOME;end"
|
||||
android:src="@drawable/car_ic_overview"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:paddingLeft="30dp"
|
||||
android:paddingRight="30dp"
|
||||
/>
|
||||
|
||||
<com.android.systemui.statusbar.car.CarNavigationButton
|
||||
android:id="@+id/hvac"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_width="wrap_content"
|
||||
systemui:intent="intent:#Intent;action=android.car.intent.action.TOGGLE_HVAC_CONTROLS;end"
|
||||
systemui:broadcast="true"
|
||||
android:src="@drawable/car_ic_hvac"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:paddingLeft="30dp"
|
||||
android:paddingRight="30dp"
|
||||
/>
|
||||
</LinearLayout>
|
||||
</com.android.systemui.statusbar.car.CarNavigationBarView>
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
**
|
||||
** Copyright 2018, The Android Open Source Project
|
||||
**
|
||||
** Licensed under the Apache License, Version 2.0 (the "License");
|
||||
** you may not use this file except in compliance with the License.
|
||||
** You may obtain a copy of the License at
|
||||
**
|
||||
** http://www.apache.org/licenses/LICENSE-2.0
|
||||
**
|
||||
** Unless required by applicable law or agreed to in writing, software
|
||||
** distributed under the License is distributed on an "AS IS" BASIS,
|
||||
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
** See the License for the specific language governing permissions and
|
||||
** limitations under the License.
|
||||
*/
|
||||
-->
|
||||
|
||||
<com.android.systemui.statusbar.car.CarNavigationBarView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:systemui="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_width="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:background="@drawable/system_bar_background">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_height="match_parent"
|
||||
android:layout_width="match_parent"
|
||||
android:id="@+id/nav_buttons"
|
||||
android:orientation="vertical"
|
||||
android:gravity="top"
|
||||
android:paddingTop="30dp"
|
||||
android:layout_weight="1"
|
||||
android:background="@drawable/system_bar_background"
|
||||
android:animateLayoutChanges="true">
|
||||
|
||||
<com.android.systemui.statusbar.car.CarNavigationButton
|
||||
android:id="@+id/home"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="match_parent"
|
||||
systemui:intent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.HOME;end"
|
||||
android:src="@drawable/car_ic_overview"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:paddingTop="30dp"
|
||||
android:paddingBottom="30dp"
|
||||
/>
|
||||
|
||||
<com.android.systemui.statusbar.car.CarNavigationButton
|
||||
android:id="@+id/hvac"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="match_parent"
|
||||
systemui:intent="intent:#Intent;action=android.car.intent.action.TOGGLE_HVAC_CONTROLS;end"
|
||||
systemui:broadcast="true"
|
||||
android:src="@drawable/car_ic_hvac"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:paddingTop="30dp"
|
||||
android:paddingBottom="30dp"
|
||||
/>
|
||||
</LinearLayout>
|
||||
</com.android.systemui.statusbar.car.CarNavigationBarView>
|
||||
@@ -13,7 +13,7 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<!-- Extends RelativeLayout -->
|
||||
<!-- Extends LinearLayout -->
|
||||
<com.android.systemui.qs.car.CarStatusBarHeader
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:systemui="http://schemas.android.com/apk/res-auto"
|
||||
@@ -23,22 +23,21 @@
|
||||
android:paddingStart="8dp"
|
||||
android:paddingEnd="8dp" >
|
||||
|
||||
<include
|
||||
layout="@layout/system_icons"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_centerVertical="true" />
|
||||
<include layout="@layout/system_icons"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center_vertical|end"
|
||||
android:layout_weight="1"
|
||||
/>
|
||||
|
||||
<com.android.systemui.statusbar.policy.Clock
|
||||
android:id="@+id/clock"
|
||||
android:textAppearance="@style/TextAppearance.StatusBar.Clock"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:singleLine="true"
|
||||
android:paddingStart="@dimen/status_bar_clock_starting_padding"
|
||||
android:paddingEnd="@dimen/status_bar_clock_end_padding"
|
||||
systemui:showDark="false" />
|
||||
android:gravity="center_vertical|end"
|
||||
/>
|
||||
</com.android.systemui.qs.car.CarStatusBarHeader>
|
||||
|
||||
38
packages/SystemUI/res/layout/car_top_navigation_bar.xml
Normal file
38
packages/SystemUI/res/layout/car_top_navigation_bar.xml
Normal file
@@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
/**
|
||||
** Copyright 2018, The Android Open Source Project
|
||||
**
|
||||
** Licensed under the Apache License, Version 2.0 (the "License");
|
||||
** you may not use this file except in compliance with the License.
|
||||
** You may obtain a copy of the License at
|
||||
**
|
||||
** http://www.apache.org/licenses/LICENSE-2.0
|
||||
**
|
||||
** Unless required by applicable law or agreed to in writing, software
|
||||
** distributed under the License is distributed on an "AS IS" BASIS,
|
||||
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
** See the License for the specific language governing permissions and
|
||||
** limitations under the License.
|
||||
*/
|
||||
-->
|
||||
|
||||
<com.android.systemui.statusbar.car.CarNavigationBarView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_width="match_parent"
|
||||
android:background="@drawable/system_bar_background">
|
||||
|
||||
<com.android.systemui.statusbar.policy.Clock
|
||||
android:id="@+id/clock"
|
||||
android:textAppearance="@style/TextAppearance.StatusBar.Clock"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:singleLine="true"
|
||||
android:paddingStart="@dimen/status_bar_clock_starting_padding"
|
||||
android:paddingEnd="@dimen/status_bar_clock_end_padding"
|
||||
android:gravity="center_vertical"
|
||||
/>
|
||||
|
||||
</com.android.systemui.statusbar.car.CarNavigationBarView>
|
||||
|
||||
@@ -27,6 +27,13 @@
|
||||
<attr name="categories" format="string"/>
|
||||
<!-- package names that will be added as extras to the fired intents -->
|
||||
<attr name="packages" format="string" />
|
||||
<!-- Alpha value to used when in selected state. Defaults 1f -->
|
||||
<attr name="selectedAlpha" format="float" />
|
||||
<!-- Alpha value to used when in un-selected state. Defaults 0.7f -->
|
||||
<attr name="unselectedAlpha" format="float" />
|
||||
<!-- Render a "more" icon. Defaults true -->
|
||||
<attr name="useMoreIcon" format="boolean" />
|
||||
|
||||
</declare-styleable>
|
||||
|
||||
|
||||
@@ -39,4 +46,11 @@
|
||||
<!-- start the intent as a broad cast instead of an activity if true-->
|
||||
<attr name="broadcast" format="boolean"/>
|
||||
</declare-styleable>
|
||||
|
||||
<!-- Custom attributes to configure hvac values -->
|
||||
<declare-styleable name="TemperatureView">
|
||||
<attr name="hvacAreaId" format="integer"/>
|
||||
<attr name="hvacPropertyId" format="integer"/>
|
||||
<attr name="hvacTempFormat" format="string"/>
|
||||
</declare-styleable>
|
||||
</resources>
|
||||
|
||||
@@ -21,6 +21,8 @@ import android.util.ArrayMap;
|
||||
import com.android.systemui.Dependency.DependencyProvider;
|
||||
import com.android.systemui.SystemUIFactory;
|
||||
import com.android.systemui.statusbar.NotificationEntryManager;
|
||||
import com.android.systemui.statusbar.car.CarFacetButtonController;
|
||||
import com.android.systemui.statusbar.car.hvac.HvacController;
|
||||
|
||||
/**
|
||||
* Class factory to provide car specific SystemUI components.
|
||||
@@ -32,5 +34,7 @@ public class CarSystemUIFactory extends SystemUIFactory {
|
||||
super.injectDependencies(providers, context);
|
||||
providers.put(NotificationEntryManager.class,
|
||||
() -> new CarNotificationEntryManager(context));
|
||||
providers.put(CarFacetButtonController.class, () -> new CarFacetButtonController(context));
|
||||
providers.put(HvacController.class, () -> new HvacController(context));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ import android.graphics.Rect;
|
||||
import android.support.annotation.IdRes;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import com.android.settingslib.Utils;
|
||||
import com.android.systemui.BatteryMeterView;
|
||||
@@ -30,7 +30,7 @@ import com.android.systemui.statusbar.policy.DarkIconDispatcher;
|
||||
* A view that forms the header of the notification panel. This view will ensure that any
|
||||
* status icons that are displayed are tinted accordingly to the current theme.
|
||||
*/
|
||||
public class CarStatusBarHeader extends RelativeLayout {
|
||||
public class CarStatusBarHeader extends LinearLayout {
|
||||
public CarStatusBarHeader(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.android.systemui.statusbar.car;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
@@ -10,6 +11,7 @@ import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import com.android.keyguard.AlphaOptimizedImageButton;
|
||||
import com.android.systemui.Dependency;
|
||||
import com.android.systemui.R;
|
||||
|
||||
/**
|
||||
@@ -21,9 +23,6 @@ import com.android.systemui.R;
|
||||
* other music apps installed.
|
||||
*/
|
||||
public class CarFacetButton extends LinearLayout {
|
||||
private static final float SELECTED_ALPHA = 1f;
|
||||
private static final float UNSELECTED_ALPHA = 0.7f;
|
||||
|
||||
private static final String FACET_FILTER_DELIMITER = ";";
|
||||
/**
|
||||
* Extra information to be sent to a helper to make the decision of what app to launch when
|
||||
@@ -42,6 +41,10 @@ public class CarFacetButton extends LinearLayout {
|
||||
private String[] mFacetCategories;
|
||||
/** App packages that are allowed to be used with this widget */
|
||||
private String[] mFacetPackages;
|
||||
private int mIconResourceId;
|
||||
private boolean mUseMoreIcon = true;
|
||||
private float mSelectedAlpha = 1f;
|
||||
private float mUnselectedAlpha = 1f;
|
||||
|
||||
|
||||
public CarFacetButton(Context context, AttributeSet attrs) {
|
||||
@@ -53,6 +56,10 @@ public class CarFacetButton extends LinearLayout {
|
||||
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CarFacetButton);
|
||||
setupIntents(typedArray);
|
||||
setupIcons(typedArray);
|
||||
CarFacetButtonController carFacetButtonController = Dependency.get(
|
||||
CarFacetButtonController.class);
|
||||
carFacetButtonController.addFacetButton(this);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -96,21 +103,25 @@ public class CarFacetButton extends LinearLayout {
|
||||
|
||||
|
||||
private void setupIcons(TypedArray styledAttributes) {
|
||||
mSelectedAlpha = styledAttributes.getFloat(
|
||||
R.styleable.CarFacetButton_selectedAlpha, mSelectedAlpha);
|
||||
mUnselectedAlpha = styledAttributes.getFloat(
|
||||
R.styleable.CarFacetButton_unselectedAlpha, mUnselectedAlpha);
|
||||
mIcon = findViewById(R.id.car_nav_button_icon);
|
||||
mIcon.setScaleType(ImageView.ScaleType.CENTER);
|
||||
mIcon.setClickable(false);
|
||||
mIcon.setAlpha(UNSELECTED_ALPHA);
|
||||
int iconResourceId = styledAttributes.getResourceId(R.styleable.CarFacetButton_icon, 0);
|
||||
if (iconResourceId == 0) {
|
||||
mIcon.setAlpha(mUnselectedAlpha);
|
||||
mIconResourceId = styledAttributes.getResourceId(R.styleable.CarFacetButton_icon, 0);
|
||||
if (mIconResourceId == 0) {
|
||||
throw new RuntimeException("specified icon resource was not found and is required");
|
||||
}
|
||||
mIcon.setImageResource(iconResourceId);
|
||||
mIcon.setImageResource(mIconResourceId);
|
||||
|
||||
mMoreIcon = findViewById(R.id.car_nav_button_more_icon);
|
||||
mMoreIcon.setClickable(false);
|
||||
mMoreIcon.setImageDrawable(getContext().getDrawable(R.drawable.car_ic_arrow));
|
||||
mMoreIcon.setAlpha(UNSELECTED_ALPHA);
|
||||
mMoreIcon.setAlpha(mSelectedAlpha);
|
||||
mMoreIcon.setVisibility(GONE);
|
||||
mUseMoreIcon = styledAttributes.getBoolean(R.styleable.CarFacetButton_useMoreIcon, true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -145,17 +156,27 @@ public class CarFacetButton extends LinearLayout {
|
||||
/**
|
||||
* Updates the visual state to let the user know if it's been selected.
|
||||
* @param selected true if should update the alpha of the icon to selected, false otherwise
|
||||
* @param showMoreIcon true if the "more icon" should be shown, false otherwise
|
||||
* @param showMoreIcon true if the "more icon" should be shown, false otherwise. Note this
|
||||
* is ignored if the attribute useMoreIcon is set to false
|
||||
*/
|
||||
public void setSelected(boolean selected, boolean showMoreIcon) {
|
||||
mSelected = selected;
|
||||
if (selected) {
|
||||
mMoreIcon.setVisibility(showMoreIcon ? VISIBLE : GONE);
|
||||
mMoreIcon.setAlpha(SELECTED_ALPHA);
|
||||
mIcon.setAlpha(SELECTED_ALPHA);
|
||||
if (mUseMoreIcon) {
|
||||
mMoreIcon.setVisibility(showMoreIcon ? VISIBLE : GONE);
|
||||
}
|
||||
mIcon.setAlpha(mSelectedAlpha);
|
||||
} else {
|
||||
mMoreIcon.setVisibility(GONE);
|
||||
mIcon.setAlpha(UNSELECTED_ALPHA);
|
||||
mIcon.setAlpha(mUnselectedAlpha);
|
||||
}
|
||||
}
|
||||
|
||||
public void setIcon(Drawable d) {
|
||||
if (d != null) {
|
||||
mIcon.setImageDrawable(d);
|
||||
} else {
|
||||
mIcon.setImageResource(mIconResourceId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,8 +5,6 @@ import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@@ -29,39 +27,25 @@ public class CarFacetButtonController {
|
||||
}
|
||||
|
||||
/**
|
||||
* Goes through the supplied CarNavigationBarView and keeps track of all the CarFacetButtons
|
||||
* such that it can select and unselect them based on running task chages
|
||||
* @param bar that may contain CarFacetButtons
|
||||
* Add facet button to this controller. The expected use is for the facet button
|
||||
* to get a reference to this controller via {@link com.android.systemui.Dependency}
|
||||
* and self add.
|
||||
* @param facetButton
|
||||
*/
|
||||
public void addCarNavigationBar(CarNavigationBarView bar) {
|
||||
findFacets(bar);
|
||||
}
|
||||
public void addFacetButton(CarFacetButton facetButton) {
|
||||
String[] categories = facetButton.getCategories();
|
||||
for (int j = 0; j < categories.length; j++) {
|
||||
String category = categories[j];
|
||||
mButtonsByCategory.put(category, facetButton);
|
||||
}
|
||||
|
||||
private void findFacets(ViewGroup root) {
|
||||
final int childCount = root.getChildCount();
|
||||
|
||||
for (int i = 0; i < childCount; ++i) {
|
||||
final View v = root.getChildAt(i);
|
||||
if (v instanceof CarFacetButton) {
|
||||
CarFacetButton facetButton = (CarFacetButton) v;
|
||||
String[] categories = facetButton.getCategories();
|
||||
for (int j = 0; j < categories.length; j++) {
|
||||
String category = categories[j];
|
||||
mButtonsByCategory.put(category, facetButton);
|
||||
}
|
||||
|
||||
String[] facetPackages = facetButton.getFacetPackages();
|
||||
for (int j = 0; j < facetPackages.length; j++) {
|
||||
String facetPackage = facetPackages[j];
|
||||
mButtonsByPackage.put(facetPackage, facetButton);
|
||||
}
|
||||
} else if (v instanceof ViewGroup) {
|
||||
findFacets((ViewGroup) v);
|
||||
}
|
||||
String[] facetPackages = facetButton.getFacetPackages();
|
||||
for (int j = 0; j < facetPackages.length; j++) {
|
||||
String facetPackage = facetPackages[j];
|
||||
mButtonsByPackage.put(facetPackage, facetButton);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This will unselect the currently selected CarFacetButton and determine which one should be
|
||||
* selected next. It does this by reading the properties on the CarFacetButton and seeing if
|
||||
|
||||
@@ -22,6 +22,7 @@ import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.android.keyguard.AlphaOptimizedImageButton;
|
||||
import com.android.systemui.R;
|
||||
@@ -36,9 +37,11 @@ class CarNavigationBarView extends LinearLayout {
|
||||
private LinearLayout mNavButtons;
|
||||
private AlphaOptimizedImageButton mNotificationsButton;
|
||||
private CarStatusBar mCarStatusBar;
|
||||
private Context mContext;
|
||||
|
||||
public CarNavigationBarView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -46,7 +49,9 @@ class CarNavigationBarView extends LinearLayout {
|
||||
mNavButtons = findViewById(R.id.nav_buttons);
|
||||
|
||||
mNotificationsButton = findViewById(R.id.notifications);
|
||||
mNotificationsButton.setOnClickListener(this::onNotificationsClick);
|
||||
if (mNotificationsButton != null) {
|
||||
mNotificationsButton.setOnClickListener(this::onNotificationsClick);
|
||||
}
|
||||
}
|
||||
|
||||
void setStatusBar(CarStatusBar carStatusBar) {
|
||||
|
||||
@@ -17,13 +17,9 @@
|
||||
package com.android.systemui.statusbar.car;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.app.ActivityOptions;
|
||||
import android.content.Intent;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Bundle;
|
||||
import android.os.RemoteException;
|
||||
import android.os.UserHandle;
|
||||
import android.os.SystemProperties;
|
||||
import android.util.Log;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
@@ -45,8 +41,8 @@ import com.android.systemui.recents.Recents;
|
||||
import com.android.systemui.recents.misc.SysUiTaskStackChangeListener;
|
||||
import com.android.systemui.shared.system.ActivityManagerWrapper;
|
||||
import com.android.systemui.statusbar.StatusBarState;
|
||||
import com.android.systemui.statusbar.car.hvac.HvacController;
|
||||
import com.android.systemui.statusbar.phone.CollapsedStatusBarFragment;
|
||||
import com.android.systemui.statusbar.phone.NavigationBarView;
|
||||
import com.android.systemui.statusbar.phone.StatusBar;
|
||||
import com.android.systemui.statusbar.policy.BatteryController;
|
||||
import com.android.systemui.statusbar.policy.UserSwitcherController;
|
||||
@@ -60,6 +56,8 @@ import java.util.Map;
|
||||
public class CarStatusBar extends StatusBar implements
|
||||
CarBatteryController.BatteryViewHandler {
|
||||
private static final String TAG = "CarStatusBar";
|
||||
public static final boolean ENABLE_HVAC_CONNECTION
|
||||
= !SystemProperties.getBoolean("android.car.hvac.demo", true);
|
||||
|
||||
private TaskStackListenerImpl mTaskStackListener;
|
||||
|
||||
@@ -93,6 +91,11 @@ public class CarStatusBar extends StatusBar implements
|
||||
|
||||
createBatteryController();
|
||||
mCarBatteryController.startListening();
|
||||
|
||||
if (ENABLE_HVAC_CONNECTION) {
|
||||
Log.d(TAG, "Connecting to HVAC service");
|
||||
Dependency.get(HvacController.class).connectToCarService();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -164,7 +167,7 @@ public class CarStatusBar extends StatusBar implements
|
||||
|
||||
@Override
|
||||
protected void createNavigationBar() {
|
||||
mCarFacetButtonController = new CarFacetButtonController(mContext);
|
||||
mCarFacetButtonController = Dependency.get(CarFacetButtonController.class);
|
||||
if (mNavigationBarView != null) {
|
||||
return;
|
||||
}
|
||||
@@ -225,7 +228,6 @@ public class CarStatusBar extends StatusBar implements
|
||||
lp.windowAnimations = 0;
|
||||
|
||||
|
||||
mCarFacetButtonController.addCarNavigationBar(mNavigationBarView);
|
||||
mWindowManager.addView(mNavigationBarWindow, lp);
|
||||
}
|
||||
|
||||
@@ -243,7 +245,6 @@ public class CarStatusBar extends StatusBar implements
|
||||
throw new RuntimeException("Unable to build left nav bar due to missing layout");
|
||||
}
|
||||
mLeftNavigationBarView.setStatusBar(this);
|
||||
mCarFacetButtonController.addCarNavigationBar(mLeftNavigationBarView);
|
||||
|
||||
WindowManager.LayoutParams leftlp = new WindowManager.LayoutParams(
|
||||
widthForSides, LayoutParams.MATCH_PARENT,
|
||||
@@ -275,7 +276,6 @@ public class CarStatusBar extends StatusBar implements
|
||||
throw new RuntimeException("Unable to build right nav bar due to missing layout");
|
||||
}
|
||||
mRightNavigationBarView.setStatusBar(this);
|
||||
mCarFacetButtonController.addCarNavigationBar(mRightNavigationBarView);
|
||||
|
||||
WindowManager.LayoutParams rightlp = new WindowManager.LayoutParams(
|
||||
widthForSides, LayoutParams.MATCH_PARENT,
|
||||
|
||||
@@ -0,0 +1,205 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui.statusbar.car.hvac;
|
||||
|
||||
import android.car.Car;
|
||||
import android.car.CarNotConnectedException;
|
||||
import android.car.hardware.CarPropertyValue;
|
||||
import android.car.hardware.hvac.CarHvacManager;
|
||||
import android.car.hardware.hvac.CarHvacManager.CarHvacEventCallback;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.ServiceConnection;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Manages the connection to the Car service and delegates value changes to the registered
|
||||
* {@link TemperatureView}s
|
||||
*/
|
||||
public class HvacController {
|
||||
|
||||
public static final String TAG = "HvacController";
|
||||
public final static int BIND_TO_HVAC_RETRY_DELAY = 5000;
|
||||
|
||||
private Context mContext;
|
||||
private Handler mHandler;
|
||||
private Car mCar;
|
||||
private CarHvacManager mHvacManager;
|
||||
private HashMap<HvacKey, TemperatureView> mTempComponents = new HashMap<>();
|
||||
|
||||
public HvacController(Context context) {
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create connection to the Car service. Note: call backs from the Car service
|
||||
* ({@link CarHvacManager}) will happen on the same thread this method was called from.
|
||||
*/
|
||||
public void connectToCarService() {
|
||||
mHandler = new Handler();
|
||||
mCar = Car.createCar(mContext, mServiceConnection, mHandler);
|
||||
if (mCar != null) {
|
||||
// note: this connect call handles the retries
|
||||
mCar.connect();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers callbacks and initializes components upon connection.
|
||||
*/
|
||||
private ServiceConnection mServiceConnection = new ServiceConnection() {
|
||||
@Override
|
||||
public void onServiceConnected(ComponentName name, IBinder service) {
|
||||
try {
|
||||
service.linkToDeath(mRestart, 0);
|
||||
mHvacManager = (CarHvacManager) mCar.getCarManager(Car.HVAC_SERVICE);
|
||||
mHvacManager.registerCallback(mHardwareCallback);
|
||||
initComponents();
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Failed to correctly connect to HVAC", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceDisconnected(ComponentName name) {
|
||||
destroyHvacManager();
|
||||
}
|
||||
};
|
||||
|
||||
private void destroyHvacManager() {
|
||||
if (mHvacManager != null) {
|
||||
mHvacManager.unregisterCallback(mHardwareCallback);
|
||||
mHvacManager = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If the connection to car service goes away then restart it.
|
||||
*/
|
||||
private final IBinder.DeathRecipient mRestart = new IBinder.DeathRecipient() {
|
||||
@Override
|
||||
public void binderDied() {
|
||||
Log.d(TAG, "Death of HVAC triggering a restart");
|
||||
if (mCar != null) {
|
||||
mCar.disconnect();
|
||||
}
|
||||
destroyHvacManager();
|
||||
mHandler.postDelayed(() -> mCar.connect(), BIND_TO_HVAC_RETRY_DELAY);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Add component to list and initialize it if the connection is up.
|
||||
* @param temperatureView
|
||||
*/
|
||||
public void addHvacTextView(TemperatureView temperatureView) {
|
||||
mTempComponents.put(
|
||||
new HvacKey(temperatureView.getPropertyId(), temperatureView.getAreaId()),
|
||||
temperatureView);
|
||||
initComponent(temperatureView);
|
||||
}
|
||||
|
||||
private void initComponents() {
|
||||
Iterator<Map.Entry<HvacKey, TemperatureView>> iterator =
|
||||
mTempComponents.entrySet().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Map.Entry<HvacKey, TemperatureView> next = iterator.next();
|
||||
initComponent(next.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void initComponent(TemperatureView view) {
|
||||
int id = view.getPropertyId();
|
||||
int zone = view.getAreaId();
|
||||
try {
|
||||
if (mHvacManager == null || !mHvacManager.isPropertyAvailable(id, zone)) {
|
||||
view.setTemp(Float.NaN);
|
||||
return;
|
||||
}
|
||||
view.setTemp(mHvacManager.getFloatProperty(id, zone));
|
||||
} catch (CarNotConnectedException e) {
|
||||
view.setTemp(Float.NaN);
|
||||
Log.e(TAG, "Failed to get value from hvac service", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for getting changes from {@link CarHvacManager} and setting the UI elements to
|
||||
* match.
|
||||
*/
|
||||
private final CarHvacEventCallback mHardwareCallback = new CarHvacEventCallback() {
|
||||
@Override
|
||||
public void onChangeEvent(final CarPropertyValue val) {
|
||||
try {
|
||||
int areaId = val.getAreaId();
|
||||
int propertyId = val.getPropertyId();
|
||||
TemperatureView temperatureView = mTempComponents.get(
|
||||
new HvacKey(propertyId, areaId));
|
||||
if (temperatureView != null) {
|
||||
float value = (float) val.getValue();
|
||||
temperatureView.setTemp(value);
|
||||
} // else the data is not of interest
|
||||
} catch (Exception e) {
|
||||
// catch all so we don't take down the sysui if a new data type is
|
||||
// introduced.
|
||||
Log.e(TAG, "Failed handling hvac change event", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onErrorEvent(final int propertyId, final int zone) {
|
||||
Log.d(TAG, "HVAC error event, propertyId: " + propertyId +
|
||||
" zone: " + zone);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Key for storing {@link TemperatureView}s in a hash map
|
||||
*/
|
||||
private static class HvacKey {
|
||||
|
||||
int mPropertyId;
|
||||
int mAreaId;
|
||||
|
||||
public HvacKey(int propertyId, int areaId) {
|
||||
mPropertyId = propertyId;
|
||||
mAreaId = areaId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
HvacKey hvacKey = (HvacKey) o;
|
||||
return mPropertyId == hvacKey.mPropertyId &&
|
||||
mAreaId == hvacKey.mAreaId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(mPropertyId, mAreaId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui.statusbar.car.hvac;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.android.systemui.Dependency;
|
||||
import com.android.systemui.R;
|
||||
|
||||
/**
|
||||
* Simple text display of HVAC properties, It is designed to show temperature and is configured in
|
||||
* the XML.
|
||||
* XML properties:
|
||||
* hvacPropertyId - Example: CarHvacManager.ID_ZONED_TEMP_SETPOINT (16385)
|
||||
* hvacAreaId - Example: VehicleSeat.SEAT_ROW_1_LEFT (1)
|
||||
* hvacTempFormat - Example: "%.1f\u00B0" (1 decimal and the degree symbol)
|
||||
*
|
||||
* Note: It registers itself with {@link HvacController}
|
||||
*/
|
||||
public class TemperatureView extends TextView {
|
||||
|
||||
private final int mAreaId;
|
||||
private final int mPropertyId;
|
||||
private final String mTempFormat;
|
||||
|
||||
public TemperatureView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.TemperatureView);
|
||||
mAreaId = typedArray.getInt(R.styleable.TemperatureView_hvacAreaId,-1);
|
||||
mPropertyId = typedArray.getInt(R.styleable.TemperatureView_hvacPropertyId, -1);
|
||||
String format = typedArray.getString(R.styleable.TemperatureView_hvacTempFormat);
|
||||
mTempFormat = (format == null) ? "%.1f\u00B0" : format;
|
||||
|
||||
// register with controller
|
||||
HvacController hvacController = Dependency.get(HvacController.class);
|
||||
hvacController.addHvacTextView(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the float for display
|
||||
* @param temp - The current temp or NaN
|
||||
*/
|
||||
public void setTemp(float temp) {
|
||||
if (Float.isNaN(temp)) {
|
||||
setText("--");
|
||||
return;
|
||||
}
|
||||
setText(String.format(mTempFormat, temp));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return propertiyId Example: CarHvacManager.ID_ZONED_TEMP_SETPOINT (16385)
|
||||
*/
|
||||
public int getPropertyId() {
|
||||
return mPropertyId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return hvac AreaId - Example: VehicleSeat.SEAT_ROW_1_LEFT (1)
|
||||
*/
|
||||
public int getAreaId() {
|
||||
return mAreaId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ LOCAL_JAVA_LIBRARIES := \
|
||||
android.test.runner \
|
||||
telephony-common \
|
||||
android.test.base \
|
||||
|
||||
android.car
|
||||
|
||||
LOCAL_AAPT_FLAGS := --extra-packages com.android.systemui:com.android.keyguard
|
||||
|
||||
|
||||
Reference in New Issue
Block a user