Merge "[RESTRICT AUTOMERGE] Replace SharedPrefs with flat file persistable bundle" into sc-v2-dev
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_minimize.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_minimize.xml
new file mode 100644
index 0000000..721cec4
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_minimize.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+ ~ Copyright (C) 2021 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.
+ -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item>
+ <vector
+ android:width="@dimen/system_bar_icon_drawing_size"
+ android:height="@dimen/system_bar_icon_drawing_size"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:pathData="M12,15.375l-6,-6 1.4,-1.4 4.6,4.6 4.6,-4.6 1.4,1.4z"
+ android:fillColor="@color/car_nav_minimize_icon_fill_color"/>
+ </vector>
+ </item>
+</selector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/nav_bar_button_background.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/nav_bar_button_background.xml
index de76f55..7c8b669 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/nav_bar_button_background.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/nav_bar_button_background.xml
@@ -15,19 +15,9 @@
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt">
- <item android:state_activated="true">
+ <item android:state_selected="true">
<layer-list>
<item>
- <shape android:shape="rectangle">
- <size android:width="@dimen/system_bar_button_size"
- android:height="@dimen/system_bar_button_size"/>
- <corners
- android:radius="@dimen/system_bar_button_corner_radius"/>
- <solid
- android:color="@color/car_nav_icon_fill_color"/>
- </shape>
- </item>
- <item>
<ripple android:color="@color/car_ui_ripple_color">
<item>
<shape android:shape="rectangle">
@@ -36,26 +26,18 @@
<corners
android:radius="@dimen/system_bar_button_corner_radius"/>
<solid
- android:color="@color/car_nav_icon_fill_color"/>
+ android:color="?android:attr/colorAccent"/>
</shape>
</item>
</ripple>
</item>
+ <item android:drawable="@drawable/ic_minimize"
+ android:gravity="center"/>
</layer-list>
</item>
<item>
<layer-list>
<item>
- <shape android:shape="rectangle">
- <size android:width="@dimen/system_bar_button_size"
- android:height="@dimen/system_bar_button_size"/>
- <corners
- android:radius="@dimen/system_bar_button_corner_radius"/>
- <solid
- android:color="@color/car_nav_icon_background_color"/>
- </shape>
- </item>
- <item>
<ripple android:color="@color/car_ui_ripple_color">
<item>
<shape android:shape="rectangle">
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/car_bottom_system_bar.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/car_bottom_system_bar.xml
index 557547a..69c3d30 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/car_bottom_system_bar.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/car_bottom_system_bar.xml
@@ -52,8 +52,9 @@
android:id="@+id/grid_nav"
style="@style/SystemBarButton"
systemui:componentNames="com.android.car.carlauncher/.AppGridActivity"
- systemui:highlightWhenSelected="true"
systemui:icon="@drawable/car_ic_apps"
+ systemui:highlightWhenSelected="true"
+ systemui:toggleSelected="true"
systemui:intent="intent:#Intent;component=com.android.car.carlauncher/.AppGridActivity;launchFlags=0x24000000;end"
systemui:clearBackStack="true"/>
@@ -61,23 +62,25 @@
android:id="@+id/standalone_notifications"
style="@style/SystemBarButton"
systemui:componentNames="com.android.car.notification/.CarNotificationCenterActivity"
- systemui:highlightWhenSelected="true"
+ systemui:packages="com.android.car.notification"
systemui:icon="@drawable/car_ic_notification"
+ systemui:highlightWhenSelected="true"
+ systemui:toggleSelected="true"
systemui:intent="intent:#Intent;component=com.android.car.notification/.CarNotificationCenterActivity;launchFlags=0x24000000;end"
systemui:longIntent="intent:#Intent;component=com.android.car.bugreport/.BugReportActivity;end"/>
<com.android.systemui.car.systembar.CarSystemBarButton
android:id="@+id/hvac"
style="@style/SystemBarButton"
- systemui:highlightWhenSelected="true"
systemui:icon="@drawable/car_ic_hvac"
+ systemui:highlightWhenSelected="true"
systemui:broadcast="true"/>
<com.android.systemui.car.systembar.AssitantButton
android:id="@+id/assist"
style="@style/SystemBarButton"
- systemui:highlightWhenSelected="true"
systemui:icon="@drawable/car_ic_mic"
+ systemui:highlightWhenSelected="true"
systemui:useDefaultAppIconForRole="true"/>
</LinearLayout>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/colors.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/colors.xml
index 8792680..3f62d35 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/colors.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/colors.xml
@@ -20,6 +20,7 @@
<color name="car_nav_icon_fill_color">#FFFFFF</color>
<color name="car_nav_icon_background_color">#282A2D</color>
+ <color name="car_nav_minimize_icon_fill_color">@android:color/black</color>
<drawable name="system_bar_background">#000000</drawable>
<color name="system_bar_text_color">#E8EAED</color>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/dimens.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/dimens.xml
index 8ed622b..f900e57 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/dimens.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/dimens.xml
@@ -42,6 +42,9 @@
<dimen name="system_bar_user_icon_drawing_size">44dp</dimen>
<dimen name="status_bar_system_icon_spacing">32dp</dimen>
+ <dimen name="system_bar_minimize_icon_height">17dp</dimen>
+ <dimen name="system_bar_minimize_icon_width">28dp</dimen>
+
<dimen name="hvac_panel_handle_bar_container_height">64dp</dimen>
<dimen name="hvac_panel_handle_bar_container_width">728dp</dimen>
<dimen name="hvac_panel_handle_bar_height">6dp</dimen>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/styles.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/styles.xml
index 6e400e5..b5f46f8 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/styles.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/styles.xml
@@ -17,12 +17,19 @@
<resources
xmlns:android="http://schemas.android.com/apk/res/android">
+ <!--
+ Note on selected/unselected icons:
+ The icon is always tinted with @color/car_nav_icon_fill_color_selected in @layout/car_system_bar_button
+ Unselected: keep this behavior so all icons have consistent color (eg. tint a multi-colored default app icon)
+ Selected: set selected alpha 0, making icon transparent. Use state list nav_bar_button_background to show selected icon (in addition to background).
+ -->
<style name="SystemBarButton">
<item name="android:layout_width">@dimen/system_bar_button_size</item>
<item name="android:layout_height">@dimen/system_bar_button_size</item>
<item name="android:background">@drawable/nav_bar_button_background</item>
<item name="android:gravity">center</item>
<item name="unselectedAlpha">1.0</item>
+ <item name="selectedAlpha">0</item>
</style>
<style name="TextAppearance.SystemBar.Username"
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/Android.bp b/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/Android.bp
index fecf167..92bd722 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/Android.bp
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/Android.bp
@@ -25,5 +25,7 @@
static_libs: [
"androidx-constraintlayout_constraintlayout",
"androidx-constraintlayout_constraintlayout-solver",
+ "car-apps-common",
+ "car-ui-lib",
],
}
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/drawable/dialer_ripple_background.xml b/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/drawable/dialer_ripple_background.xml
new file mode 100644
index 0000000..131afd5
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/drawable/dialer_ripple_background.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 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.
+ -->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+ <item>
+ <shape
+ android:shape="oval">
+ <solid
+ android:color="@color/keypad_background_color" />
+ <size
+ android:width="@dimen/dialer_keypad_button_size"
+ android:height="@dimen/dialer_keypad_button_size"/>
+ </shape>
+ </item>
+</layer-list>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/drawable/ic_arrow_right.xml b/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/drawable/ic_arrow_right.xml
new file mode 100644
index 0000000..f1210dc
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/drawable/ic_arrow_right.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 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.
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:viewportWidth="48"
+ android:viewportHeight="48"
+ android:width="44dp"
+ android:height="44dp"
+ android:tint="?attr/colorControlNormal"
+ android:autoMirrored="true">
+
+ <path android:pathData="M0-.25h48v48H0z"/>
+ <path
+ android:fillColor="?android:attr/textColorPrimary"
+ android:pathData="M17.17 32.92l9.17-9.17-9.17-9.17L20 11.75l12 12-12 12z"/>
+</vector>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/drawable/ic_backspace.xml b/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/drawable/ic_backspace.xml
new file mode 100644
index 0000000..6b4f369
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/drawable/ic_backspace.xml
@@ -0,0 +1,26 @@
+<!--
+ ~ Copyright (C) 2021 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.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="44dp"
+ android:height="32dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M22,3L7,3c-0.69,0 -1.23,0.35 -1.59,0.88L0,12l5.41,8.11c0.36,0.53 0.9,0.89 1.59,0.89h15c1.1,0 2,-0.9 2,-2L24,5c0,-1.1 -0.9,-2 -2,-2zM22,19L7.07,19L2.4,12l4.66,-7L22,5v14zM10.41,17L14,13.41 17.59,17 19,15.59 15.41,12 19,8.41 17.59,7 14,10.59 10.41,7 9,8.41 12.59,12 9,15.59z"/>
+</vector>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/drawable/ic_phone.xml b/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/drawable/ic_phone.xml
index b659da1..3e2e824 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/drawable/ic_phone.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/drawable/ic_phone.xml
@@ -22,7 +22,7 @@
<path
android:pathData="M0 0h24v24H0z" />
<path
- android:fillColor="#fffafafa"
+ android:fillColor="?android:attr/textColorPrimary"
android:pathData="M6.62 10.79c1.44 2.83 3.76 5.14 6.59 6.59l2.2-2.2c.27-.27 .67 -.36 1.02-.24 1.12
.37 2.33 .57 3.57 .57 .55 0 1 .45 1 1V20c0 .55-.45 1-1 1-9.39 0-17-7.61-17-17
0-.55 .45 -1 1-1h3.5c.55 0 1 .45 1 1 0 1.25 .2 2.45 .57 3.57 .11 .35 .03 .74-.25
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/drawable/icon_call_button.xml b/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/drawable/icon_call_button.xml
index 748a1d0..d048af9 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/drawable/icon_call_button.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/drawable/icon_call_button.xml
@@ -19,11 +19,11 @@
<shape
android:shape="rectangle">
<solid
- android:color="#52CCB0" />
+ android:color="#29cb86" />
<corners android:radius="100dp"/>
<size
- android:width="424dp"
- android:height="120dp"/>
+ android:width="416dp"
+ android:height="@dimen/dialer_keypad_button_size"/>
</shape>
</item>
<item android:drawable="@drawable/ic_phone" android:gravity="center"/>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/drawable/keypad_default_background.xml b/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/drawable/keypad_default_background.xml
index bf49159..131afd5 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/drawable/keypad_default_background.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/drawable/keypad_default_background.xml
@@ -19,10 +19,10 @@
<shape
android:shape="oval">
<solid
- android:color="#282A2D" />
+ android:color="@color/keypad_background_color" />
<size
- android:width="120dp"
- android:height="120dp"/>
+ android:width="@dimen/dialer_keypad_button_size"
+ android:height="@dimen/dialer_keypad_button_size"/>
</shape>
</item>
</layer-list>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/drawable/restricted_dialing_mode_label_background.xml b/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/drawable/restricted_dialing_mode_label_background.xml
new file mode 100644
index 0000000..ea5a715
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/drawable/restricted_dialing_mode_label_background.xml
@@ -0,0 +1,20 @@
+<!--
+ ~ Copyright (C) 2021 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.
+ -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
+ <corners android:radius="4dp"/>
+ <solid android:color="@color/car_red_500a"/>
+</shape>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/layout/dialpad_fragment_with_type_down.xml b/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/layout/dialpad_fragment_with_type_down.xml
new file mode 100644
index 0000000..0185f23
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/layout/dialpad_fragment_with_type_down.xml
@@ -0,0 +1,94 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 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.
+ -->
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_marginLeft="100dp">
+ <TextView
+ android:id="@+id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="45dp"
+ android:maxLines="1"
+ android:layout_marginBottom="48dp"
+ android:textAppearance="@style/TextAppearance.DialNumber"
+ android:autoSizeMinTextSize="24sp"
+ android:autoSizeMaxTextSize="28sp"
+ android:layout_marginLeft="150dp"
+ android:layout_alignParentTop="true"/>
+
+ <com.android.car.ui.recyclerview.CarUiRecyclerView
+ android:id="@+id/list_view"
+ android:layout_width="536dp"
+ android:layout_height="266dp"
+ android:layout_marginBottom="10dp"
+ android:layout_marginLeft="70dp"
+ android:layout_below="@id/title"/>
+ <fragment
+ android:id="@+id/dialpad_fragment"
+ android:name="com.android.car.dialer.ui.dialpad.KeypadFragment"
+ android:layout_height="456dp"
+ android:layout_width="416dp"
+ android:layout_marginLeft="120dp"
+ android:layout_below="@id/list_view"/>
+
+ <RelativeLayout
+ android:layout_height="@dimen/dialer_keypad_button_size"
+ android:layout_width="0dp"
+ android:layout_below="@id/dialpad_fragment"
+ android:layout_marginTop="38dp"
+ android:layout_alignLeft="@id/dialpad_fragment"
+ android:layout_alignRight="@id/dialpad_fragment">
+
+ <ImageView
+ android:id="@+id/call_button"
+ android:layout_height="match_parent"
+ android:layout_width="match_parent"
+ android:adjustViewBounds="true"
+ android:scaleType="fitXY"
+ android:src="@drawable/icon_call_button"
+ android:layout_toLeftOf="@id/delete_button"/>
+
+ <ImageButton
+ android:id="@+id/delete_button"
+ android:layout_width="@dimen/dialer_keypad_button_size"
+ android:layout_height="match_parent"
+ style="@style/DialpadSecondaryButton"
+ android:src="@drawable/ic_backspace"
+ android:layout_marginLeft="64dp"
+ android:visibility="gone"
+ android:layout_alignParentRight="true"/>
+ </RelativeLayout>
+
+ <include
+ layout="@layout/dialpad_user_profile"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_marginTop="10dp"
+ android:layout_below="@id/title"
+ android:layout_centerHorizontal="true"/>
+
+ <include
+ layout="@layout/restricted_dialing_mode_label"
+ android:id="@+id/restricted_dialing_mode_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerHorizontal="true"
+ android:layout_marginTop="8dp"
+ android:layout_below="@id/title"
+ android:visibility="invisible"/>
+</RelativeLayout>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/layout/dialpad_user_profile.xml b/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/layout/dialpad_user_profile.xml
new file mode 100644
index 0000000..bb4e11f
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/layout/dialpad_user_profile.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 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.
+ -->
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <TextView
+ android:id="@+id/display_name"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="@style/TextAppearance.DialpadDisplayName"
+ android:singleLine="true"
+ android:layout_centerHorizontal="true"
+ android:layout_alignParentTop="true"/>
+
+ <TextView
+ android:id="@+id/label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:singleLine="true"
+ android:layout_marginTop="12dp"
+ android:layout_below="@id/display_name"
+ android:layout_centerHorizontal="true"/>
+
+ <ImageView
+ android:id="@+id/dialpad_contact_avatar"
+ android:layout_height="@dimen/dialpad_contact_avatar_size"
+ android:layout_width="@dimen/dialpad_contact_avatar_size"
+ android:layout_below="@id/label"
+ android:layout_alignParentBottom="true"
+ android:layout_centerHorizontal="true"/>
+
+ <TextView
+ android:id="@+id/dialpad_contact_initials"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:layout_width="10dp"
+ android:layout_height="10dp"/>
+</RelativeLayout>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/layout/restricted_dialing_mode_label.xml b/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/layout/restricted_dialing_mode_label.xml
new file mode 100644
index 0000000..6a23fd5
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/layout/restricted_dialing_mode_label.xml
@@ -0,0 +1,27 @@
+<!--
+ ~ Copyright (C) 2021 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.
+ -->
+
+<TextView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/restricted_dialing_mode_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="8dp"
+ android:padding="8dp"
+ android:textAppearance="@style/TextAppearance.Body2"
+ android:text="@string/restricted_dialing_mode_label"
+ android:alpha="0.8"
+ android:background="@drawable/restricted_dialing_mode_label_background"/>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/layout/type_down_list_item.xml b/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/layout/type_down_list_item.xml
new file mode 100644
index 0000000..68cf567
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/layout/type_down_list_item.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 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.
+ -->
+
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/contact_result"
+ android:foreground="?android:attr/selectableItemBackground"
+ android:layout_width="match_parent"
+ android:layout_height="112dp">
+
+ <ImageView
+ android:id="@+id/contact_picture"
+ android:layout_width="72dp"
+ android:layout_height="72dp"
+ android:scaleType="centerCrop"
+ android:layout_centerVertical="true"
+ android:layout_alignParentLeft="true"/>
+
+ <TextView
+ android:id="@+id/contact_name"
+ android:layout_marginStart="24dp"
+ android:layout_marginTop="14dp"
+ android:layout_marginBottom="8dp"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:textAppearance="@style/TextAppearance.ContactResultTitle"
+ android:duplicateParentState="true"
+ android:layout_alignParentTop="true"
+ android:layout_toRightOf="@id/contact_picture"/>
+
+ <TextView
+ android:id="@+id/phone_number"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="14dp"
+ android:theme="@style/Theme.CarUi.WithToolbar"
+ android:singleLine="true"
+ android:layout_alignParentBottom="true"
+ android:layout_alignLeft="@id/contact_name"/>
+</RelativeLayout>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/values-night/colors.xml b/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/values-night/colors.xml
new file mode 100644
index 0000000..929bfe2
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/values-night/colors.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 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.
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
+ <color name="keypad_background_color">#282A2D</color>
+</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/values/colors.xml b/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/values/colors.xml
new file mode 100644
index 0000000..5452e77
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/values/colors.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 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.
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
+ <color name="keypad_background_color">#E8EAED</color>
+</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/values/dimens.xml b/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/values/dimens.xml
new file mode 100644
index 0000000..108cfb1
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/values/dimens.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 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.
+ -->
+<resources>
+ <dimen name="dialer_keypad_button_size">96dp</dimen>
+ <dimen name="dialpad_contact_avatar_size">64dp</dimen>
+</resources>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/values/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/values/strings.xml
new file mode 100644
index 0000000..88b64b6
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/values/strings.xml
@@ -0,0 +1,19 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!--
+ ~ Copyright (C) 2021 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.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="restricted_dialing_mode_label">Dialpad usage is restricted while driving</string>
+</resources>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/values/styles.xml b/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/values/styles.xml
index 678cf0c..d67d485 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/values/styles.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/values/styles.xml
@@ -20,18 +20,53 @@
<item name="android:clickable">true</item>
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">wrap_content</item>
- <item name="android:layout_marginTop">16dp</item>
- <item name="android:layout_marginRight">16dp</item>
- <item name="android:layout_marginBottom">16dp</item>
- <item name="android:layout_marginLeft">16dp</item>
+ <item name="android:layout_marginTop">12dp</item>
+ <item name="android:layout_marginRight">32dp</item>
+ <item name="android:layout_marginBottom">12dp</item>
+ <item name="android:layout_marginLeft">32dp</item>
<item name="android:background">@drawable/keypad_default_background</item>
<item name="android:focusable">true</item>
</style>
- <style name="DialpadPrimaryButton">
- <item name="android:layout_width">match_parent</item>
- <item name="android:layout_height">150dp</item>
- <item name="android:layout_marginBottom">180dp</item>
- <item name="android:scaleType">center</item>
+ <style name="TextAppearance.DialNumber" parent="android:style/TextAppearance">
+ <item name="android:textColor">?android:attr/textColorPrimary</item>
+ <item name="android:textSize">32sp</item>
+ </style>
+
+ <style name="SubheaderText" parent="android:style/TextAppearance">
+ <item name="android:textColor">?android:attr/textColorPrimary</item>
+ <item name="android:textSize">24sp</item>
+ <item name="android:textFontWeight">500</item>
+ <item name="android:textStyle">normal</item>
+ </style>
+
+ <style name="AddFavoriteText">
+ <item name="android:textColor">?android:attr/textColorPrimary</item>
+ </style>
+
+ <!-- Call history -->
+ <style name="TextAppearance.CallLogTitleDefault" parent="TextAppearance.Body1">
+ <item name="android:textColor">?android:attr/textColorPrimary</item>
+ </style>
+ <!-- Customized text color for missed calls can be added here -->
+ <style name="TextAppearance.CallLogTitleMissedCall" parent="TextAppearance.Body1">
+ <item name="android:textColor">?android:attr/textColorPrimary</item>
+ </style>
+
+ <style name="DialpadSecondaryButton">
+ <item name="android:background">@drawable/dialer_ripple_background</item>
+ <item name="android:scaleType">centerInside</item>
+ <item name="android:tint">?android:attr/textColorPrimary</item>
+ </style>
+
+ <style name="TextAppearance.DialpadDisplayName" parent="TextAppearance.Body1"/>
+
+ <style name="TextAppearance.ContactResultTitle" parent="TextAppearance.Body1">
+ <item name="android:textColor">?android:attr/textColorPrimary</item>
+ </style>
+
+ <style name="TextAppearance.TypeDownListSpan" parent="TextAppearance.Body3">
+ <item name="android:textSize">32sp</item>
+ <item name="android:textColor">#29cb86</item>
</style>
</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/xml/overlays.xml b/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/xml/overlays.xml
index a404157..b75bc81 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/xml/overlays.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/xml/overlays.xml
@@ -15,9 +15,40 @@
~ limitations under the License.
-->
<overlay>
- <item target="style/KeypadButtonStyle" value="@style/KeypadButtonStyle"/>
- <item target="style/DialpadPrimaryButton" value="@style/DialpadPrimaryButton"/>
-
<item target="drawable/ic_phone" value="@drawable/ic_phone"/>
<item target="drawable/icon_call_button" value="@drawable/icon_call_button"/>
+ <item target="drawable/ic_backspace" value="@drawable/ic_backspace"/>
+ <item target="drawable/dialer_ripple_background" value="@drawable/dialer_ripple_background"/>
+ <item target="drawable/restricted_dialing_mode_label_background" value="@drawable/restricted_dialing_mode_label_background"/>
+ <item target="drawable/ic_arrow_right" value="@drawable/ic_arrow_right"/>
+
+ <item target="id/dialpad_fragment" value="@id/dialpad_fragment" />
+ <item target="id/call_button" value="@id/call_button" />
+ <item target="id/title" value="@id/title" />
+ <item target="id/delete_button" value="@id/delete_button" />
+ <item target="id/display_name" value="@id/display_name" />
+ <item target="id/label" value="@id/label" />
+ <item target="id/dialpad_contact_avatar" value="@id/dialpad_contact_avatar" />
+ <item target="id/dialpad_contact_initials" value="@id/dialpad_contact_initials" />
+ <item target="id/list_view" value="@id/list_view" />
+ <item target="id/restricted_dialing_mode_label" value="@id/restricted_dialing_mode_label" />
+ <item target="id/contact_picture" value="@id/contact_picture" />
+ <item target="id/contact_result" value="@id/contact_result" />
+ <item target="id/contact_name" value="@id/contact_name" />
+ <item target="id/phone_number" value="@id/phone_number" />
+
+ <item target="layout/dialpad_fragment_with_type_down" value="@layout/dialpad_fragment_with_type_down"/>
+ <item target="layout/dialpad_user_profile" value="@layout/dialpad_user_profile"/>
+ <item target="layout/type_down_list_item" value="@layout/type_down_list_item"/>
+ <item target="layout/restricted_dialing_mode_label" value="@layout/restricted_dialing_mode_label"/>
+
+ <item target="style/KeypadButtonStyle" value="@style/KeypadButtonStyle"/>
+ <item target="style/TextAppearance.DialNumber" value="@style/TextAppearance.DialNumber"/>
+ <item target="style/SubheaderText" value="@style/SubheaderText"/>
+ <item target="style/AddFavoriteText" value="@style/AddFavoriteText"/>
+ <item target="style/TextAppearance.CallLogTitleDefault" value="@style/TextAppearance.CallLogTitleDefault"/>
+ <item target="style/TextAppearance.DialpadDisplayName" value="@style/TextAppearance.DialpadDisplayName"/>
+ <item target="style/TextAppearance.ContactResultTitle" value="@style/TextAppearance.ContactResultTitle"/>
+ <item target="style/TextAppearance.TypeDownListSpan" value="@style/TextAppearance.TypeDownListSpan"/>
+
</overlay>
diff --git a/car_product/car_ui_portrait/rro/android/res/values/colors_device_default.xml b/car_product/car_ui_portrait/rro/android/res/values/colors_device_default.xml
index e9c768b..6258766 100644
--- a/car_product/car_ui_portrait/rro/android/res/values/colors_device_default.xml
+++ b/car_product/car_ui_portrait/rro/android/res/values/colors_device_default.xml
@@ -63,8 +63,8 @@
<color name="surface_highlight_light">@*android:color/system_neutral1_1000</color>
<!-- Please refer to text_color_[primary]_device_default_[light].xml for text colors-->
- <color name="foreground_device_default_light">@*android:color/text_color_primary_device_default_dark</color>
- <color name="foreground_device_default_dark">@*android:color/text_color_primary_device_default_light</color>
+ <color name="foreground_device_default_light">@*android:color/text_color_primary_device_default_light</color>
+ <color name="foreground_device_default_dark">@*android:color/text_color_primary_device_default_dark</color>
<color name="list_divider_color_light">@*android:color/system_neutral1_700</color>
<color name="list_divider_color_dark">@*android:color/system_neutral1_200</color>
diff --git a/car_product/car_ui_portrait/rro/car-ui-toolbar-customizations/res/drawable/tab_background.xml b/car_product/car_ui_portrait/rro/car-ui-toolbar-customizations/res/drawable/tab_background.xml
index 0162e5b..ffbeb18 100644
--- a/car_product/car_ui_portrait/rro/car-ui-toolbar-customizations/res/drawable/tab_background.xml
+++ b/car_product/car_ui_portrait/rro/car-ui-toolbar-customizations/res/drawable/tab_background.xml
@@ -17,7 +17,7 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_activated="true">
<shape android:shape="rectangle">
- <solid android:color="#2E3134"/>
+ <solid android:color="@color/tab_background_color"/>
</shape>
</item>
<item android:state_activated="false">
diff --git a/car_product/car_ui_portrait/rro/car-ui-toolbar-customizations/res/layout/car_ui_base_layout_toolbar.xml b/car_product/car_ui_portrait/rro/car-ui-toolbar-customizations/res/layout/car_ui_base_layout_toolbar.xml
index 39d910c..02a7320 100644
--- a/car_product/car_ui_portrait/rro/car-ui-toolbar-customizations/res/layout/car_ui_base_layout_toolbar.xml
+++ b/car_product/car_ui_portrait/rro/car-ui-toolbar-customizations/res/layout/car_ui_base_layout_toolbar.xml
@@ -75,7 +75,7 @@
android:layout_gravity="center"
android:scaleType="fitXY"
android:background="@drawable/car_ui_toolbar_menu_item_icon_ripple"
- android:tint="@color/car_ui_text_color_primary"/>
+ android:tint="?android:attr/textColorPrimary"/>
<ImageView
android:id="@+id/car_ui_toolbar_logo"
diff --git a/car_product/car_ui_portrait/rro/car-ui-toolbar-customizations/res/values-night/colors.xml b/car_product/car_ui_portrait/rro/car-ui-toolbar-customizations/res/values-night/colors.xml
new file mode 100644
index 0000000..9134d34
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/car-ui-toolbar-customizations/res/values-night/colors.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 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.
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
+ <color name="tab_background_color">#282A2D</color>
+</resources>
diff --git a/car_product/car_ui_portrait/rro/car-ui-toolbar-customizations/res/values/colors.xml b/car_product/car_ui_portrait/rro/car-ui-toolbar-customizations/res/values/colors.xml
new file mode 100644
index 0000000..fca1ab1
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/car-ui-toolbar-customizations/res/values/colors.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 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.
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
+ <color name="tab_background_color">#E8EAED</color>
+</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values/config.xml b/car_product/overlay/frameworks/base/core/res/res/values/config.xml
index a1b0cd2..73326f1 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values/config.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values/config.xml
@@ -156,4 +156,10 @@
This flag should be enabled only when the product does not have any UI to toggle airplane
mode like automotive devices.-->
<bool name="config_autoResetAirplaneMode">true</bool>
+
+ <!-- The component name of the activity for the companion-device-manager notification access
+ confirmation. -->
+ <string name="config_notificationAccessConfirmationActivity" translatable="false">
+ com.android.car.settings/com.android.car.settings.notifications.NotificationAccessConfirmationActivity
+ </string>
</resources>
diff --git a/cpp/libsysfsmonitor/Android.bp b/cpp/libsysfsmonitor/Android.bp
new file mode 100644
index 0000000..545255b
--- /dev/null
+++ b/cpp/libsysfsmonitor/Android.bp
@@ -0,0 +1,60 @@
+// Copyright (C) 2021 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 {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_defaults {
+ name: "libsysfsmonitor_defaults",
+ cflags: [
+ "-Wall",
+ "-Wno-missing-field-initializers",
+ "-Werror",
+ "-Wno-unused-variable",
+ "-Wunused-parameter",
+ ],
+ shared_libs: [
+ "libbase",
+ "liblog",
+ "libutils",
+ ],
+}
+
+cc_library {
+ name: "libsysfsmonitor",
+ srcs: [
+ "src/SysfsMonitor.cpp",
+ ],
+ defaults: [
+ "libsysfsmonitor_defaults",
+ ],
+ export_include_dirs: [
+ "src",
+ ],
+}
+
+cc_test {
+ name: "libsysfsmonitor_test",
+ srcs: [
+ "tests/SysfsMonitorTest.cpp",
+ ],
+ defaults: [
+ "libsysfsmonitor_defaults",
+ ],
+ static_libs: [
+ "libgtest",
+ "libsysfsmonitor",
+ ],
+}
diff --git a/cpp/libsysfsmonitor/src/SysfsMonitor.cpp b/cpp/libsysfsmonitor/src/SysfsMonitor.cpp
new file mode 100644
index 0000000..ee89ec0
--- /dev/null
+++ b/cpp/libsysfsmonitor/src/SysfsMonitor.cpp
@@ -0,0 +1,135 @@
+/**
+ * Copyright (c) 2021, 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.
+ */
+
+#define LOG_TAG "libsysfsmonitor"
+#define DEBUG false
+
+#include "SysfsMonitor.h"
+
+#include <android-base/stringprintf.h>
+#include <log/log.h>
+
+#include <sys/epoll.h>
+
+namespace {
+
+using ::android::base::Error;
+using ::android::base::Result;
+using ::android::base::StringPrintf;
+
+// The maximum number of sysfs files to monitor.
+constexpr int32_t EPOLL_MAX_EVENTS = 10;
+
+} // namespace
+
+namespace android {
+namespace automotive {
+
+Result<void> SysfsMonitor::init(CallbackFunc callback) {
+ if (mEpollFd >= 0) {
+ return Error() << "Epoll instance was already created";
+ }
+ if (mEpollFd.reset(epoll_create1(EPOLL_CLOEXEC)); mEpollFd < 0) {
+ return Error() << "Cannot create epoll instance: errno = " << errno;
+ }
+ mCallback = callback;
+ return {};
+}
+
+Result<void> SysfsMonitor::release() {
+ if (mEpollFd < 0) {
+ return Error() << "Epoll instance wasn't created";
+ }
+ for (const int32_t fd : mMonitoringFds) {
+ if (epoll_ctl(mEpollFd, EPOLL_CTL_DEL, fd, /*event=*/nullptr)) {
+ ALOGW("Failed to deregister fd(%d) from epoll instance: errno = %d", fd, errno);
+ }
+ }
+ mMonitoringFds.clear();
+ mEpollFd.reset();
+ mCallback = nullptr;
+ return {};
+}
+
+Result<void> SysfsMonitor::registerFd(int32_t fd) {
+ if (fd < 0) {
+ return Error() << StringPrintf("fd(%d) is invalid", fd);
+ }
+ if (mMonitoringFds.count(fd) > 0) {
+ return Error() << StringPrintf("fd(%d) is already being monitored", fd);
+ }
+ if (mMonitoringFds.size() == EPOLL_MAX_EVENTS) {
+ return Error() << "Cannot monitor more than " << EPOLL_MAX_EVENTS << " sysfs files";
+ }
+ struct epoll_event eventItem = {};
+ eventItem.events = EPOLLIN | EPOLLPRI | EPOLLET;
+ eventItem.data.fd = fd;
+ if (int result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, &eventItem); result != 0) {
+ return Error() << StringPrintf("Failed to add fd(%d) to epoll instance: errno = %d", fd,
+ errno);
+ }
+ mMonitoringFds.insert(fd);
+ return {};
+}
+
+Result<void> SysfsMonitor::unregisterFd(int32_t fd) {
+ if (fd < 0) {
+ return Error() << StringPrintf("fd(%d) is invalid", fd);
+ }
+ if (mMonitoringFds.count(fd) == 0) {
+ return Error() << StringPrintf("fd(%d) is not being monitored", fd);
+ }
+ // Even when epoll_ctl() fails, we proceed to handle the request.
+ if (epoll_ctl(mEpollFd, EPOLL_CTL_DEL, fd, /*event=*/nullptr)) {
+ ALOGW("Failed to deregister fd(%d) from epoll instance: errno = %d", fd, errno);
+ }
+ mMonitoringFds.erase(fd);
+ return {};
+}
+
+Result<void> SysfsMonitor::observe() {
+ if (mEpollFd < 0) {
+ return Error() << "Epoll instance is not initialized";
+ }
+
+ struct epoll_event events[EPOLL_MAX_EVENTS];
+ while (true) {
+ int pollResult = epoll_wait(mEpollFd, events, EPOLL_MAX_EVENTS, /*timeout=*/-1);
+ if (pollResult < 0) {
+ ALOGW("Polling sysfs failed, but continue polling: errno = %d", errno);
+ continue;
+ }
+ std::vector<int32_t> fds;
+ for (int i = 0; i < pollResult; i++) {
+ int fd = events[i].data.fd;
+ if (mMonitoringFds.count(fd) == 0) {
+ continue;
+ }
+ if (events[i].events & EPOLLIN) {
+ fds.push_back(fd);
+ } else if (events[i].events & EPOLLERR) {
+ ALOGW("An error occurred when polling fd(%d)", fd);
+ }
+ }
+ if (mCallback && fds.size() > 0) {
+ mCallback(fds);
+ }
+ }
+ return {};
+}
+
+} // namespace automotive
+} // namespace android
diff --git a/cpp/libsysfsmonitor/src/SysfsMonitor.h b/cpp/libsysfsmonitor/src/SysfsMonitor.h
new file mode 100644
index 0000000..f941041
--- /dev/null
+++ b/cpp/libsysfsmonitor/src/SysfsMonitor.h
@@ -0,0 +1,59 @@
+/**
+ * Copyright (c) 2021, 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.
+ */
+
+#ifndef CPP_LIBSYSFSMONITOR_SRC_SYSFSMONITOR_H_
+#define CPP_LIBSYSFSMONITOR_SRC_SYSFSMONITOR_H_
+
+#include <android-base/result.h>
+#include <android-base/unique_fd.h>
+#include <utils/RefBase.h>
+
+#include <functional>
+#include <string>
+#include <unordered_set>
+
+namespace android {
+namespace automotive {
+
+using CallbackFunc = ::std::function<void(const std::vector<int32_t>&)>;
+
+/**
+ * SysfsMonitor monitors sysfs file changes and invokes the registered callback when there is a
+ * change at the sysfs files to monitor.
+ */
+class SysfsMonitor final : public RefBase {
+public:
+ // Initializes SysfsMonitor instance.
+ android::base::Result<void> init(CallbackFunc callback);
+ // Releases resources used for monitoring.
+ android::base::Result<void> release();
+ // Registers a sysfs file to monitor.
+ android::base::Result<void> registerFd(int32_t fd);
+ // Unregisters a sysfs file to monitor.
+ android::base::Result<void> unregisterFd(int32_t fd);
+ // Starts observing sysfs file changes.
+ android::base::Result<void> observe();
+
+private:
+ android::base::unique_fd mEpollFd;
+ std::unordered_set<int32_t> mMonitoringFds;
+ CallbackFunc mCallback;
+};
+
+} // namespace automotive
+} // namespace android
+
+#endif // CPP_LIBSYSFSMONITOR_SRC_SYSFSMONITOR_H_
diff --git a/cpp/libsysfsmonitor/tests/SysfsMonitorTest.cpp b/cpp/libsysfsmonitor/tests/SysfsMonitorTest.cpp
new file mode 100644
index 0000000..f6dda6c
--- /dev/null
+++ b/cpp/libsysfsmonitor/tests/SysfsMonitorTest.cpp
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2021, 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.
+ */
+
+#include "SysfsMonitor.h"
+
+#include <gtest/gtest.h>
+#include <utils/StrongPointer.h>
+
+#include <sys/socket.h>
+
+#include <vector>
+
+namespace android {
+namespace automotive {
+
+class SysfsMonitorTest : public ::testing::Test {
+public:
+ void SetUp() override { mSysfsMonitor = sp<SysfsMonitor>::make(); }
+ void TearDown() override { mSysfsMonitor = nullptr; }
+
+protected:
+ sp<SysfsMonitor> mSysfsMonitor;
+};
+
+TEST_F(SysfsMonitorTest, TestDuplicateInitialize) {
+ auto ret = mSysfsMonitor->init([](const std::vector<int32_t>&) {});
+ ASSERT_TRUE(ret.ok()) << "First initialization should be successful: " << ret.error().message();
+ ASSERT_FALSE(mSysfsMonitor->init([](const std::vector<int32_t>&) {}).ok())
+ << "Initialization cannot be done twice";
+}
+
+TEST_F(SysfsMonitorTest, TestDuplicateRelease) {
+ auto ret = mSysfsMonitor->init([](const std::vector<int32_t>&) {});
+ ASSERT_TRUE(ret.ok()) << "First initialization should be successful: " << ret.error().message();
+ ret = mSysfsMonitor->release();
+ ASSERT_TRUE(ret.ok()) << "Releasing the initialized instance should be successful: "
+ << ret.error().message();
+ ASSERT_FALSE(mSysfsMonitor->release().ok()) << "Released instance cannot be released";
+}
+
+TEST_F(SysfsMonitorTest, TestNoInitRelease) {
+ ASSERT_FALSE(mSysfsMonitor->release().ok()) << "Uninitailized instance cannot be released";
+}
+
+TEST_F(SysfsMonitorTest, TestUnregisterNotRegisteredFd) {
+ // A regular file cannot be registered to epoll instance. So, the test is using a socket file.
+ int32_t fd = socket(AF_UNIX, SOCK_DGRAM, /*protocol=*/0);
+ mSysfsMonitor->init([](const std::vector<int32_t>&) {});
+
+ ASSERT_FALSE(mSysfsMonitor->unregisterFd(fd).ok())
+ << "Unregistered file description cannot be unregistered";
+ close(fd);
+}
+
+TEST_F(SysfsMonitorTest, TestDuplicateRegister) {
+ int32_t fd = socket(AF_UNIX, SOCK_DGRAM, /*protocol=*/0);
+ mSysfsMonitor->init([](const std::vector<int32_t>&) {});
+
+ auto ret = mSysfsMonitor->registerFd(fd);
+ ASSERT_TRUE(ret.ok()) << "Registering a file descriptor first time should be successful: "
+ << ret.error().message();
+ ASSERT_FALSE(mSysfsMonitor->registerFd(fd).ok())
+ << "Registering a file descriptor twice cannot be done";
+ close(fd);
+}
+
+TEST_F(SysfsMonitorTest, TestDuplicateUnregister) {
+ int32_t fd = socket(AF_UNIX, SOCK_DGRAM, /*protocol=*/0);
+ mSysfsMonitor->init([](const std::vector<int32_t>&) {});
+
+ auto ret = mSysfsMonitor->registerFd(fd);
+ ASSERT_TRUE(ret.ok()) << "Registering a file descriptor first time should be successful: "
+ << ret.error().message();
+ ret = mSysfsMonitor->unregisterFd(fd);
+ ASSERT_TRUE(ret.ok()) << "The registered file descriptor should be unregistered: "
+ << ret.error().message();
+ ASSERT_FALSE(mSysfsMonitor->unregisterFd(fd).ok())
+ << "Unregistering the unregistered file descriptor cannot be done";
+ close(fd);
+}
+
+TEST_F(SysfsMonitorTest, TestRegisterInvalidFd) {
+ const int32_t invalidFd = -1;
+ ASSERT_FALSE(mSysfsMonitor->registerFd(invalidFd).ok())
+ << "fd(-1) cannot be registered to SysfsMonitor";
+}
+
+TEST_F(SysfsMonitorTest, TestUnregisterInvalidFd) {
+ const int32_t invalidFd = -1;
+ ASSERT_FALSE(mSysfsMonitor->unregisterFd(invalidFd).ok())
+ << "fd(-1) cannot be given to unregisterFd";
+}
+
+TEST_F(SysfsMonitorTest, TestRegisterMultipleFds) {
+ const int32_t maxFdCount = 10;
+ int32_t fdsToMonitor[maxFdCount + 1];
+
+ mSysfsMonitor->init([](const std::vector<int32_t>&) {});
+ for (int i = 0; i < maxFdCount; i++) {
+ fdsToMonitor[i] = socket(AF_UNIX, SOCK_DGRAM, /*protocol=*/0);
+ auto ret = mSysfsMonitor->registerFd(fdsToMonitor[i]);
+ ASSERT_TRUE(ret.ok()) << "Registering a file descriptor first time should be successful: "
+ << ret.error().message();
+ }
+ fdsToMonitor[maxFdCount] = socket(AF_UNIX, SOCK_DGRAM, /*protocol=*/0);
+ ASSERT_FALSE(mSysfsMonitor->registerFd(fdsToMonitor[maxFdCount]).ok())
+ << "Registering more than " << maxFdCount << " files cannot be done";
+
+ mSysfsMonitor->release();
+ for (int i = 0; i <= maxFdCount; i++) {
+ close(fdsToMonitor[i]);
+ }
+}
+
+TEST_F(SysfsMonitorTest, TestObserveWithoutInitialization) {
+ ASSERT_FALSE(mSysfsMonitor->observe().ok()) << "Uninitialized instance cannot observe";
+}
+
+} // namespace automotive
+} // namespace android
diff --git a/cpp/powerpolicy/server/Android.bp b/cpp/powerpolicy/server/Android.bp
index 094a3f5..2dd40bd 100644
--- a/cpp/powerpolicy/server/Android.bp
+++ b/cpp/powerpolicy/server/Android.bp
@@ -36,6 +36,9 @@
"libtinyxml2",
"libutils",
],
+ static_libs: [
+ "libsysfsmonitor",
+ ],
}
cc_library {
diff --git a/cpp/powerpolicy/server/src/SilentModeHandler.cpp b/cpp/powerpolicy/server/src/SilentModeHandler.cpp
index c57b6fa..79d78be 100644
--- a/cpp/powerpolicy/server/src/SilentModeHandler.cpp
+++ b/cpp/powerpolicy/server/src/SilentModeHandler.cpp
@@ -25,7 +25,7 @@
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
-#include <sys/inotify.h>
+#include <sys/epoll.h>
#include <sys/stat.h>
#include <unistd.h>
@@ -35,6 +35,7 @@
namespace powerpolicy {
using ::android::Mutex;
+using ::android::automotive::SysfsMonitor;
using ::android::base::Error;
using ::android::base::GetProperty;
using ::android::base::ReadFileToString;
@@ -49,12 +50,11 @@
constexpr const char kPropertySystemBootReason[] = "sys.boot.reason";
constexpr const char kSilentModeHwStateFilename[] = "/sys/power/pm_silentmode_hw_state";
-constexpr const char kKernelSilentModeFilename[] = "/sys/power/pm_silentmode_kernel";
+constexpr const char kKernelSilentModeFilename[] = "/sys/power/pm_silentmode_kernel_state";
// To prevent boot animation from being started.
constexpr const char kPropertyNoBootAnimation[] = "debug.sf.nobootanimation";
// To stop boot animation while it is being played.
constexpr const char kPropertyBootAnimationExit[] = "service.bootanim.exit";
-constexpr int kEventBufferSize = 512;
bool fileExists(const char* filename) {
struct stat buffer;
@@ -68,7 +68,7 @@
mSilentModeHwStateFilename(kSilentModeHwStateFilename),
mKernelSilentModeFilename(kKernelSilentModeFilename),
mSilentModeChangeHandler(handler),
- mFdInotify(-1) {
+ mSysfsMonitor(sp<SysfsMonitor>::make()) {
mBootReason = GetProperty(kPropertySystemBootReason, "");
}
@@ -83,7 +83,7 @@
if (mForcedMode) {
handleSilentModeChange(mSilentModeByHwState);
mSilentModeChangeHandler->notifySilentModeChange(mSilentModeByHwState);
- ALOGI("Now in forced mode: monitoring %s is disabled", kSilentModeHwStateFilename);
+ ALOGI("Now in forced mode: monitoring %s is disabled", mSilentModeHwStateFilename.c_str());
} else {
startMonitoringSilentModeHwState();
}
@@ -101,13 +101,15 @@
void SilentModeHandler::stopMonitoringSilentModeHwState(bool shouldWaitThread) {
if (mIsMonitoring) {
mIsMonitoring = false;
- inotify_rm_watch(mFdInotify, mWdSilentModeHwState);
- mWdSilentModeHwState = -1;
+ if (auto ret = mSysfsMonitor->unregisterFd(mFdSilentModeHwState.get()); !ret.ok()) {
+ ALOGW("Unregistering %s from SysfsMonitor failed", mSilentModeHwStateFilename.c_str());
+ }
if (shouldWaitThread && mSilentModeMonitoringThread.joinable()) {
mSilentModeMonitoringThread.join();
}
}
- mFdInotify.reset(-1);
+ mFdSilentModeHwState.reset();
+ mSysfsMonitor->release();
}
Result<void> SilentModeHandler::dump(int fd, const Vector<String16>& /*args*/) {
@@ -132,56 +134,38 @@
ALOGW("Silent Mode monitoring is already started");
return;
}
- if (mFdInotify < 0) {
- mFdInotify.reset(inotify_init1(IN_CLOEXEC));
- if (mFdInotify < 0) {
- ALOGE("Failed to start monitoring Silent Mode HW state: creating inotify instance "
- "failed (errno = %d)",
- errno);
- return;
- }
- }
const char* filename = mSilentModeHwStateFilename.c_str();
if (!fileExists(filename)) {
ALOGW("Failed to start monitoring Silent Mode HW state: %s doesn't exist", filename);
- mFdInotify.reset(-1);
return;
}
- // TODO(b/178843534): Additional masks might be needed to detect sysfs change.
- const uint32_t masks = IN_MODIFY;
- mWdSilentModeHwState = inotify_add_watch(mFdInotify, filename, masks);
+ if (mFdSilentModeHwState == -1) {
+ if (mFdSilentModeHwState.reset(open(filename, O_RDONLY | O_NONBLOCK | O_CLOEXEC));
+ mFdSilentModeHwState == -1) {
+ ALOGW("Failed to open %s for monitoring: errno = %d", filename, errno);
+ return;
+ }
+ }
+ auto ret = mSysfsMonitor->init([this](const std::vector<int32_t>& fileDescriptors) {
+ // Only one sysfs file is registered.
+ if (mFdSilentModeHwState != fileDescriptors[0]) {
+ return;
+ }
+ handleSilentModeHwStateChange();
+ });
+ if (!ret.ok()) {
+ ALOGW("Failed to initialize SysfsMonitor: %s", ret.error().message().c_str());
+ return;
+ }
+ if (auto ret = mSysfsMonitor->registerFd(mFdSilentModeHwState.get()); !ret.ok()) {
+ ALOGW("Failed to register %s to SysfsMonitor: %s", filename, ret.error().message().c_str());
+ return;
+ }
mIsMonitoring = true;
- mSilentModeMonitoringThread = std::thread([this]() {
- char eventBuf[kEventBufferSize];
- struct inotify_event* event;
- constexpr size_t inotifyEventSize = sizeof(*event);
- ALOGI("Monitoring %s started", mSilentModeHwStateFilename.c_str());
- while (mIsMonitoring) {
- int eventPos = 0;
- int numBytes = read(mFdInotify, eventBuf, sizeof(eventBuf));
- if (numBytes < static_cast<int>(inotifyEventSize)) {
- if (errno == EINTR) {
- ALOGW("System call interrupted. Wait for inotify event again.");
- continue;
- }
- mIsMonitoring = false;
- inotify_rm_watch(mFdInotify, mWdSilentModeHwState);
- mWdSilentModeHwState = -1;
- mFdInotify.reset(-1);
- ALOGW("Failed to wait for change at %s (errno = %d)",
- mSilentModeHwStateFilename.c_str(), errno);
- return;
- }
- while (numBytes >= static_cast<int>(inotifyEventSize)) {
- int eventSize;
- event = (struct inotify_event*)(eventBuf + eventPos);
- if (event->wd == mWdSilentModeHwState && (event->mask & masks)) {
- handleSilentModeHwStateChange();
- }
- eventSize = inotifyEventSize + event->len;
- numBytes -= eventSize;
- eventPos += eventSize;
- }
+ mSilentModeMonitoringThread = std::thread([this, filename]() {
+ if (auto ret = mSysfsMonitor->observe(); !ret.ok()) {
+ ALOGI("Failed to observe %s", filename);
+ return;
}
ALOGI("Monitoring %s ended", mSilentModeHwStateFilename.c_str());
});
diff --git a/cpp/powerpolicy/server/src/SilentModeHandler.h b/cpp/powerpolicy/server/src/SilentModeHandler.h
index 9fae109..96074f8 100644
--- a/cpp/powerpolicy/server/src/SilentModeHandler.h
+++ b/cpp/powerpolicy/server/src/SilentModeHandler.h
@@ -21,8 +21,11 @@
#include <android-base/unique_fd.h>
#include <utils/Mutex.h>
#include <utils/String16.h>
+#include <utils/StrongPointer.h>
#include <utils/Vector.h>
+#include <SysfsMonitor.h>
+
#include <atomic>
#include <thread> // NOLINT(build/c++11)
@@ -47,8 +50,8 @@
/**
* SilentModeHandler monitors {@code /sys/power/pm_silentmode_hw_state} in sysfs to detect Silent
- * Mode change by a vehicle processor. Also, it updates {@code /sys/power/pm_silentmode_kernel} in
- * sysfs to tell kernel the current Silent Mode.
+ * Mode change by a vehicle processor. Also, it updates
+ * {@code /sys/power/pm_silentmode_kernel_state} in sysfs to tell kernel the current Silent Mode.
*/
class SilentModeHandler final {
public:
@@ -80,9 +83,9 @@
std::string mKernelSilentModeFilename;
ISilentModeChangeHandler* mSilentModeChangeHandler;
std::thread mSilentModeMonitoringThread;
- android::base::unique_fd mFdInotify;
- int mWdSilentModeHwState = -1;
std::atomic_bool mIsMonitoring = false;
+ android::sp<android::automotive::SysfsMonitor> mSysfsMonitor;
+ android::base::unique_fd mFdSilentModeHwState;
// For unit tests.
friend class internal::SilentModeHandlerPeer;
diff --git a/cpp/powerpolicy/server/tests/SilentModeHandlerTest.cpp b/cpp/powerpolicy/server/tests/SilentModeHandlerTest.cpp
index 1eaec81..6548cf1 100644
--- a/cpp/powerpolicy/server/tests/SilentModeHandlerTest.cpp
+++ b/cpp/powerpolicy/server/tests/SilentModeHandlerTest.cpp
@@ -46,20 +46,6 @@
constexpr int kMaxPollingAttempts = 5;
constexpr std::chrono::microseconds kPollingDelayUs = 50ms;
-bool waitForSilentMode(SilentModeHandler* handler, bool expectedSilentMode) {
- int count = 0;
- while (true) {
- if (handler->isSilentMode() == expectedSilentMode) {
- return true;
- }
- if (count++; count == kMaxPollingAttempts) {
- break;
- }
- usleep(kPollingDelayUs.count());
- }
- return false;
-}
-
} // namespace
namespace internal {
@@ -124,23 +110,6 @@
sp<MockCarPowerPolicyServer> carPowerPolicyServer;
};
-TEST_F(SilentModeHandlerTest, TestSilentModeHwStateMonitoring) {
- SilentModeHandler handler(carPowerPolicyServer.get());
- internal::SilentModeHandlerPeer handlerPeer(&handler);
- handlerPeer.injectBootReason(kBootReasonNormal);
- handlerPeer.init();
-
- handlerPeer.updateSilentModeHwState(/*isSilent=*/true);
-
- ASSERT_TRUE(waitForSilentMode(&handler, /*expectedSilentMode=*/true))
- << "It should be silent mode when HW state is on";
-
- handlerPeer.updateSilentModeHwState(/*isSilent=*/false);
-
- ASSERT_TRUE(waitForSilentMode(&handler, /*expectedSilentMode=*/false))
- << "It should be non-silent mode when HW state is off";
-}
-
TEST_F(SilentModeHandlerTest, TestRebootForForcedSilentMode) {
SilentModeHandler handler(carPowerPolicyServer.get());
internal::SilentModeHandlerPeer handlerPeer(&handler);
diff --git a/service/src/com/android/car/power/SilentModeHandler.java b/service/src/com/android/car/power/SilentModeHandler.java
index 2631c01..bb78810 100644
--- a/service/src/com/android/car/power/SilentModeHandler.java
+++ b/service/src/com/android/car/power/SilentModeHandler.java
@@ -39,9 +39,9 @@
* Class to handle Silent Mode and Non-Silent Mode.
*
* <p>This monitors {@code /sys/power/pm_silentmode_hw_state} to figure out when to switch to Silent
- * Mode and updates {@code /sys/power/pm_silentmode_kernel} to tell early-init services about Silent
- * Mode change. Also, it handles forced Silent Mode for testing purpose, which is given through
- * reboot reason.
+ * Mode and updates {@code /sys/power/pm_silentmode_kernel_state} to tell early-init services about
+ * Silent Mode change. Also, it handles forced Silent Mode for testing purpose, which is given
+ * through reboot reason.
*/
final class SilentModeHandler {
static final String SILENT_MODE_FORCED_SILENT = "forced-silent";
@@ -53,7 +53,7 @@
private static final String SYSFS_FILENAME_HW_STATE_MONITORING =
"/sys/power/pm_silentmode_hw_state";
private static final String SYSFS_FILENAME_KERNEL_SILENTMODE =
- "/sys/power/pm_silentmode_kernel";
+ "/sys/power/pm_silentmode_kernel_state";
private static final String VALUE_SILENT_MODE = "1";
private static final String VALUE_NON_SILENT_MODE = "0";
private static final String SYSTEM_BOOT_REASON = "sys.boot.reason";
diff --git a/service/src/com/android/car/watchdog/PackageInfoHandler.java b/service/src/com/android/car/watchdog/PackageInfoHandler.java
index 5ee811d..e3f4bb8 100644
--- a/service/src/com/android/car/watchdog/PackageInfoHandler.java
+++ b/service/src/com/android/car/watchdog/PackageInfoHandler.java
@@ -292,4 +292,10 @@
}
return ComponentType.THIRD_PARTY;
}
+
+ void setVendorPackagePrefixes(List<String> vendorPackagePrefixes) {
+ synchronized (mLock) {
+ mVendorPackagePrefixes = vendorPackagePrefixes;
+ }
+ }
}
diff --git a/service/src/com/android/car/watchdog/WatchdogPerfHandler.java b/service/src/com/android/car/watchdog/WatchdogPerfHandler.java
index fee73b9..e83288b 100644
--- a/service/src/com/android/car/watchdog/WatchdogPerfHandler.java
+++ b/service/src/com/android/car/watchdog/WatchdogPerfHandler.java
@@ -797,6 +797,8 @@
break;
case ComponentType.VENDOR:
mSafeToKillVendorPackages.addAll(internalConfigs.get(i).safeToKillPackages);
+ mPackageInfoHandler.setVendorPackagePrefixes(
+ internalConfigs.get(i).vendorPackagePrefixes);
break;
default:
// All third-party apps are killable.
@@ -804,7 +806,7 @@
}
}
if (DEBUG) {
- Slogf.d(TAG, "Fetched and synced safe to kill packages.");
+ Slogf.d(TAG, "Fetched and synced resource overuse configs.");
}
}
}
@@ -1705,12 +1707,14 @@
}
/** Defines I/O usage fields for a package. */
public static final class PackageIoUsage {
+ private static final android.automotive.watchdog.PerStateBytes DEFAULT_PER_STATE_BYTES =
+ new android.automotive.watchdog.PerStateBytes();
private android.automotive.watchdog.IoOveruseStats mIoOveruseStats;
private android.automotive.watchdog.PerStateBytes mForgivenWriteBytes;
private int mTotalTimesKilled;
private PackageIoUsage() {
- mForgivenWriteBytes = new android.automotive.watchdog.PerStateBytes();
+ mForgivenWriteBytes = DEFAULT_PER_STATE_BYTES;
mTotalTimesKilled = 0;
}
@@ -1777,7 +1781,7 @@
void resetStats() {
mIoOveruseStats = null;
- mForgivenWriteBytes = null;
+ mForgivenWriteBytes = DEFAULT_PER_STATE_BYTES;
mTotalTimesKilled = 0;
}
}
diff --git a/tests/carservice_unit_test/src/com/android/car/watchdog/CarWatchdogServiceUnitTest.java b/tests/carservice_unit_test/src/com/android/car/watchdog/CarWatchdogServiceUnitTest.java
index f97965e..a3914d7 100644
--- a/tests/carservice_unit_test/src/com/android/car/watchdog/CarWatchdogServiceUnitTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/watchdog/CarWatchdogServiceUnitTest.java
@@ -1211,10 +1211,6 @@
@Test
public void testGetPackageKillableStatesAsUserWithSafeToKillPackages() throws Exception {
mockUmGetAliveUsers(mMockUserManager, 11, 12);
- List<android.automotive.watchdog.internal.ResourceOveruseConfiguration> configs =
- sampleInternalResourceOveruseConfigurations();
- injectResourceOveruseConfigsAndWait(configs);
-
injectPackageInfos(Arrays.asList(
constructPackageManagerPackageInfo("system_package.non_critical.A", 1102459, null),
constructPackageManagerPackageInfo("third_party_package", 1103456, null),
@@ -1223,6 +1219,10 @@
constructPackageManagerPackageInfo("third_party_package", 1203456, null),
constructPackageManagerPackageInfo("vendor_package.critical.B", 1201278, null)));
+ List<android.automotive.watchdog.internal.ResourceOveruseConfiguration> configs =
+ sampleInternalResourceOveruseConfigurations();
+ injectResourceOveruseConfigsAndWait(configs);
+
PackageKillableStateSubject.assertThat(
mCarWatchdogService.getPackageKillableStatesAsUser(UserHandle.ALL))
.containsExactly(
@@ -1241,6 +1241,37 @@
}
@Test
+ public void testGetPackageKillableStatesAsUserWithVendorPackagePrefixes() throws Exception {
+ mockUmGetAliveUsers(mMockUserManager, 11);
+ /* Package names which start with "system" are constructed as system packages. */
+ injectPackageInfos(Arrays.asList(
+ constructPackageManagerPackageInfo("system_package_as_vendor", 1102459, null)));
+
+ android.automotive.watchdog.internal.ResourceOveruseConfiguration vendorConfig =
+ new android.automotive.watchdog.internal.ResourceOveruseConfiguration();
+ vendorConfig.componentType = ComponentType.VENDOR;
+ vendorConfig.safeToKillPackages = Collections.singletonList("system_package_as_vendor");
+ vendorConfig.vendorPackagePrefixes = Collections.singletonList(
+ "system_package_as_vendor");
+ injectResourceOveruseConfigsAndWait(Collections.singletonList(vendorConfig));
+
+ List<PackageKillableState> killableStates =
+ mCarWatchdogService.getPackageKillableStatesAsUser(new UserHandle(11));
+
+ /* When CarWatchdogService connects with the watchdog daemon, CarWatchdogService fetches
+ * resource overuse configs from watchdog daemon. The vendor package prefixes in the
+ * configs help identify vendor packages. The safe-to-kill list in the configs helps
+ * identify safe-to-kill vendor packages. |system_package_as_vendor| is a critical system
+ * package by default but with the latest resource overuse configs, this package should be
+ * classified as a safe-to-kill vendor package.
+ */
+ PackageKillableStateSubject.assertThat(killableStates)
+ .containsExactly(
+ new PackageKillableState("system_package_as_vendor", 11,
+ PackageKillableState.KILLABLE_STATE_YES));
+ }
+
+ @Test
public void testGetPackageKillableStatesAsUserWithSharedUids() throws Exception {
mockUmGetAliveUsers(mMockUserManager, 11, 12);
injectPackageInfos(Arrays.asList(
@@ -1274,13 +1305,6 @@
public void testGetPackageKillableStatesAsUserWithSharedUidsAndSafeToKillPackages()
throws Exception {
mockUmGetAliveUsers(mMockUserManager, 11);
- android.automotive.watchdog.internal.ResourceOveruseConfiguration vendorConfig =
- new android.automotive.watchdog.internal.ResourceOveruseConfiguration();
- vendorConfig.componentType = ComponentType.VENDOR;
- vendorConfig.safeToKillPackages = Collections.singletonList(
- "vendor_package.non_critical.A");
- injectResourceOveruseConfigsAndWait(Collections.singletonList(vendorConfig));
-
injectPackageInfos(Arrays.asList(
constructPackageManagerPackageInfo(
"vendor_package.non_critical.A", 1103456, "vendor_shared_package.A"),
@@ -1293,6 +1317,14 @@
constructPackageManagerPackageInfo(
"third_party_package.D", 1105678, "third_party_shared_package")));
+ android.automotive.watchdog.internal.ResourceOveruseConfiguration vendorConfig =
+ new android.automotive.watchdog.internal.ResourceOveruseConfiguration();
+ vendorConfig.componentType = ComponentType.VENDOR;
+ vendorConfig.safeToKillPackages = Collections.singletonList(
+ "vendor_package.non_critical.A");
+ vendorConfig.vendorPackagePrefixes = new ArrayList<>();
+ injectResourceOveruseConfigsAndWait(Collections.singletonList(vendorConfig));
+
PackageKillableStateSubject.assertThat(
mCarWatchdogService.getPackageKillableStatesAsUser(new UserHandle(11)))
.containsExactly(
@@ -1312,13 +1344,6 @@
public void testGetPackageKillableStatesAsUserWithSharedUidsAndSafeToKillSharedPackage()
throws Exception {
mockUmGetAliveUsers(mMockUserManager, 11);
- android.automotive.watchdog.internal.ResourceOveruseConfiguration vendorConfig =
- new android.automotive.watchdog.internal.ResourceOveruseConfiguration();
- vendorConfig.componentType = ComponentType.VENDOR;
- vendorConfig.safeToKillPackages = Collections.singletonList(
- "shared:vendor_shared_package.B");
- injectResourceOveruseConfigsAndWait(Collections.singletonList(vendorConfig));
-
injectPackageInfos(Arrays.asList(
constructPackageManagerPackageInfo(
"vendor_package.non_critical.A", 1103456, "vendor_shared_package.B"),
@@ -1327,6 +1352,15 @@
constructPackageManagerPackageInfo(
"vendor_package.non_critical.B", 1103456, "vendor_shared_package.B")));
+ android.automotive.watchdog.internal.ResourceOveruseConfiguration vendorConfig =
+ new android.automotive.watchdog.internal.ResourceOveruseConfiguration();
+ vendorConfig.componentType = ComponentType.VENDOR;
+ vendorConfig.safeToKillPackages = Collections.singletonList(
+ "shared:vendor_shared_package.B");
+ vendorConfig.vendorPackagePrefixes = new ArrayList<>();
+ injectResourceOveruseConfigsAndWait(Collections.singletonList(vendorConfig));
+
+
PackageKillableStateSubject.assertThat(
mCarWatchdogService.getPackageKillableStatesAsUser(new UserHandle(11)))
.containsExactly(
@@ -2013,6 +2047,37 @@
}
@Test
+ public void testSaveToStorageAfterResetResourceOveruseStats() throws Exception {
+ setDate(1);
+ mGenericPackageNameByUid.put(1011200, "system_package");
+ SparseArray<PackageIoOveruseStats> stats = injectIoOveruseStatsForPackages(
+ mGenericPackageNameByUid, /* killablePackages= */ new ArraySet<>(),
+ /* shouldNotifyPackages= */ new ArraySet<>());
+
+ mWatchdogServiceForSystemImpl.resetResourceOveruseStats(
+ Collections.singletonList("system_package"));
+
+ /* |resetResourceOveruseStats| sets the package's IoOveruseStats to null, packages with
+ * null I/O stats are not written to disk. Push new IoOveruseStats to the |system_package|
+ * so that the package can be written to the database when date changes.
+ */
+ pushLatestIoOveruseStatsAndWait(Collections.singletonList(stats.get(1011200)));
+
+ /* Force write to disk by changing the date and pushing new I/O overuse stats. */
+ setDate(0);
+ pushLatestIoOveruseStatsAndWait(Collections.singletonList(new PackageIoOveruseStats()));
+
+ WatchdogStorage.IoUsageStatsEntry expectedSavedEntries =
+ new WatchdogStorage.IoUsageStatsEntry(/* userId= */ 10, "system_package",
+ new WatchdogPerfHandler.PackageIoUsage(stats.get(1011200).ioOveruseStats,
+ /* forgivenWriteBytes= */ constructPerStateBytes(0, 0, 0),
+ /* totalTimesKilled= */ 0));
+
+ IoUsageStatsEntrySubject.assertThat(mIoUsageStatsEntries)
+ .containsExactlyElementsIn(Collections.singletonList(expectedSavedEntries));
+ }
+
+ @Test
public void testGetPackageInfosForUids() throws Exception {
injectPackageInfos(Arrays.asList(
constructPackageManagerPackageInfo(
@@ -2432,6 +2497,11 @@
*/
crashWatchdogDaemon();
restartWatchdogDaemonAndAwait();
+
+ /* Method should be invoked 2 times. Once at test setup and once more after the daemon
+ * crashes and reconnects.
+ */
+ verify(mMockCarWatchdogDaemon, times(2)).getResourceOveruseConfigurations();
}
private SparseArray<PackageIoOveruseStats> injectIoOveruseStatsForPackages(