Create a lib to support IME wide screen templates
Bug: 162268101
Bug: 170343703
Test: Manual
Change-Id: Ia86fd225eb9dbd38793ef564e676e2ab93de74e5
Merged-In: Ia86fd225eb9dbd38793ef564e676e2ab93de74e5
diff --git a/car-ui-lib/build.gradle b/car-ui-lib/build.gradle
index 9744622..ae26e4c 100644
--- a/car-ui-lib/build.gradle
+++ b/car-ui-lib/build.gradle
@@ -23,7 +23,7 @@
}
dependencies {
- classpath 'com.android.tools.build:gradle:3.6.1'
+ classpath 'com.android.tools.build:gradle:4.1.0-beta05'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
diff --git a/car-ui-lib/car-ui-lib/build.gradle b/car-ui-lib/car-ui-lib/build.gradle
index 5c6ce32..201a8d6 100644
--- a/car-ui-lib/car-ui-lib/build.gradle
+++ b/car-ui-lib/car-ui-lib/build.gradle
@@ -60,20 +60,20 @@
api 'androidx.core:core:1.2.0'
implementation 'com.android.support:support-annotations:28.0.0'
- testImplementation "androidx.test.ext:junit:1.1.1"
- testImplementation 'org.robolectric:robolectric:4.4'
+ testImplementation "androidx.test.ext:junit:1.1.2"
+ testImplementation 'org.robolectric:robolectric:4.3.1'
testImplementation "org.mockito:mockito-core:2.19.0"
testImplementation "com.google.truth:truth:0.29"
testImplementation "org.testng:testng:6.9.9"
androidTestImplementation 'org.hamcrest:hamcrest-library:1.3'
- androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
- androidTestImplementation 'androidx.test.espresso:espresso-contrib:3.2.0'
+ androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
+ androidTestImplementation 'androidx.test.espresso:espresso-contrib:3.3.0'
androidTestImplementation "com.google.truth:truth:0.29"
- androidTestImplementation "androidx.test.ext:junit:1.1.1"
+ androidTestImplementation "androidx.test.ext:junit:1.1.2"
androidTestImplementation "org.mockito:mockito-core:2.19.0"
- androidTestImplementation 'androidx.test:runner:1.1.0'
- androidTestImplementation 'androidx.test:rules:1.1.0'
+ androidTestImplementation 'androidx.test:runner:1.3.0'
+ androidTestImplementation 'androidx.test:rules:1.3.0'
// This is needed to be able to spy certain classes with Mockito
// It's major/minor version must match Mockito's.
androidTestImplementation 'com.linkedin.dexmaker:dexmaker-mockito-inline:2.19.0'
diff --git a/car-ui-lib/car-ui-lib/src/androidTest/AndroidManifest.xml b/car-ui-lib/car-ui-lib/src/androidTest/AndroidManifest.xml
index 73041a4..79b51bb 100644
--- a/car-ui-lib/car-ui-lib/src/androidTest/AndroidManifest.xml
+++ b/car-ui-lib/car-ui-lib/src/androidTest/AndroidManifest.xml
@@ -20,6 +20,7 @@
<uses-library android:name="android.test.runner" />
<activity android:name="com.android.car.ui.TestActivity" />
<activity android:name="com.android.car.ui.recyclerview.CarUiRecyclerViewTestActivity" />
+ <activity android:name="com.android.car.ui.imewidescreen.CarUiImeWideScreenTestActivity" />
<activity android:name="com.android.car.ui.FocusAreaTestActivity" />
<activity android:name="com.android.car.ui.FocusParkingViewTestActivity" />
<activity android:name="com.android.car.ui.preference.PreferenceTestActivity" />
diff --git a/car-ui-lib/car-ui-lib/src/androidTest/java/com/android/car/ui/imewidescreen/CarUiImeWideScreenControllerTest.java b/car-ui-lib/car-ui-lib/src/androidTest/java/com/android/car/ui/imewidescreen/CarUiImeWideScreenControllerTest.java
new file mode 100644
index 0000000..4a8a767
--- /dev/null
+++ b/car-ui-lib/car-ui-lib/src/androidTest/java/com/android/car/ui/imewidescreen/CarUiImeWideScreenControllerTest.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2020 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.car.ui.imewidescreen;
+
+import static androidx.test.espresso.Espresso.onView;
+import static androidx.test.espresso.assertion.ViewAssertions.matches;
+import static androidx.test.espresso.matcher.ViewMatchers.assertThat;
+import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
+import static androidx.test.espresso.matcher.ViewMatchers.withId;
+
+import static com.android.car.ui.imewidescreen.CarUiImeWideScreenController.REQUEST_RENDER_CONTENT_AREA;
+import static com.android.car.ui.imewidescreen.CarUiImeWideScreenController.WIDE_SCREEN_ACTION;
+
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.not;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.when;
+
+import android.app.Dialog;
+import android.content.Context;
+import android.inputmethodservice.ExtractEditText;
+import android.inputmethodservice.InputMethodService;
+import android.inputmethodservice.InputMethodService.Insets;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.Window;
+import android.widget.FrameLayout;
+
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.rule.ActivityTestRule;
+
+import com.android.car.ui.test.R;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * Unit tests for {@link CarUiImeWideScreenController}.
+ */
+public class CarUiImeWideScreenControllerTest {
+
+ private Context mContext = ApplicationProvider.getApplicationContext();
+
+ @Mock
+ Context mMockContext;
+
+ @Mock
+ InputMethodService mInputMethodService;
+
+ @Mock
+ Dialog mDialog;
+
+ @Mock
+ Window mWindow;
+
+ private CarUiImeWideScreenTestActivity mActivity;
+
+ @Rule
+ public ActivityTestRule<CarUiImeWideScreenTestActivity> mActivityRule =
+ new ActivityTestRule<>(CarUiImeWideScreenTestActivity.class);
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mActivity = mActivityRule.getActivity();
+ }
+
+ @After
+ public void destroy() {
+ mActivity.finish();
+ }
+
+ @Test
+ public void createWideScreenImeView_shouldWrapTheViewInTemplate() {
+ // make sure view is wrapped in the template.
+ assertNotNull(mActivity.findViewById(R.id.test_ime_input_view_id));
+
+ // check all views in template default visibility.
+ onView(withId(R.id.wideScreenDescriptionTitle)).check(matches(not(isDisplayed())));
+ onView(withId(R.id.wideScreenDescription)).check(matches(not(isDisplayed())));
+ onView(withId(R.id.inputExtractActionAutomotive)).check(matches(not(isDisplayed())));
+ onView(withId(R.id.wideScreenSearchResultList)).check(matches(not(isDisplayed())));
+ onView(withId(R.id.wideScreenErrorMessage)).check(matches(not(isDisplayed())));
+ onView(withId(R.id.wideScreenError)).check(matches(not(isDisplayed())));
+
+ onView(withId(R.id.contentAreaAutomotive)).check(matches(isDisplayed()));
+ onView(withId(R.id.wideScreenExtractedTextIcon)).check(matches(isDisplayed()));
+ onView(withId(R.id.wideScreenClearData)).check(matches(isDisplayed()));
+ onView(withId(R.id.fullscreenArea)).check(matches(isDisplayed()));
+ onView(withId(R.id.inputExtractEditTextContainer)).check(matches(isDisplayed()));
+
+ // check if the click listener is installed on the image to clear data.
+ View clearDataIcon = mActivity.findViewById(R.id.wideScreenClearData);
+ assertTrue(clearDataIcon.hasOnClickListeners());
+ }
+
+ @Test
+ public void onComputeInsets_showContentArea_shouldUpdateEntireAreaAsTouchable() {
+ when(mInputMethodService.getWindow()).thenReturn(mDialog);
+ when(mDialog.getWindow()).thenReturn(mWindow);
+ View view = new FrameLayout(mContext);
+ view.setTop(0);
+ view.setBottom(200);
+ when(mWindow.getDecorView()).thenReturn(view);
+
+ InputMethodService.Insets outInsets = new Insets();
+ CarUiImeWideScreenController carUiImeWideScreenController = getController();
+ carUiImeWideScreenController.onComputeInsets(outInsets);
+
+ assertThat(outInsets.touchableInsets, is(InputMethodService.Insets.TOUCHABLE_INSETS_FRAME));
+ assertThat(outInsets.contentTopInsets, is(200));
+ assertThat(outInsets.visibleTopInsets, is(200));
+ }
+
+ @Test
+ public void onComputeInsets_hideContentArea_shouldUpdateRegionAsTouchable() {
+ when(mInputMethodService.getWindow()).thenReturn(mDialog);
+ when(mDialog.getWindow()).thenReturn(mWindow);
+ View view = new FrameLayout(mContext);
+ view.setTop(0);
+ view.setBottom(200);
+ when(mWindow.getDecorView()).thenReturn(view);
+
+ View imeInputView = LayoutInflater.from(mContext)
+ .inflate(R.layout.test_ime_input_view, null, false);
+ CarUiImeWideScreenController carUiImeWideScreenController = getController();
+ carUiImeWideScreenController.setExtractEditText(new ExtractEditText(mContext));
+ carUiImeWideScreenController.createWideScreenImeView(imeInputView);
+
+ Bundle bundle = new Bundle();
+ bundle.putBoolean(REQUEST_RENDER_CONTENT_AREA, false);
+ carUiImeWideScreenController.onAppPrivateCommand(WIDE_SCREEN_ACTION, bundle);
+
+ InputMethodService.Insets outInsets = new Insets();
+ carUiImeWideScreenController.onComputeInsets(outInsets);
+
+ assertThat(outInsets.touchableInsets,
+ is(InputMethodService.Insets.TOUCHABLE_INSETS_REGION));
+ assertThat(outInsets.contentTopInsets, is(200));
+ assertThat(outInsets.visibleTopInsets, is(200));
+ }
+
+ private CarUiImeWideScreenController getController() {
+ return new CarUiImeWideScreenController(mContext, mInputMethodService) {
+ @Override
+ public boolean isWideScreenMode() {
+ return true;
+ }
+ };
+ }
+}
diff --git a/car-ui-lib/car-ui-lib/src/androidTest/java/com/android/car/ui/imewidescreen/CarUiImeWideScreenTestActivity.java b/car-ui-lib/car-ui-lib/src/androidTest/java/com/android/car/ui/imewidescreen/CarUiImeWideScreenTestActivity.java
new file mode 100644
index 0000000..8ffd5a2
--- /dev/null
+++ b/car-ui-lib/car-ui-lib/src/androidTest/java/com/android/car/ui/imewidescreen/CarUiImeWideScreenTestActivity.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2020 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.car.ui.imewidescreen;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.FrameLayout;
+
+import com.android.car.ui.test.R;
+
+/**
+ * An {@link Activity} that mimics a wide screen IME and displays the template for testing.
+ */
+public class CarUiImeWideScreenTestActivity extends Activity {
+ public static CarUiImeWideScreenController sCarUiImeWideScreenController;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.car_ui_ime_wide_screen_test_activity);
+
+ FrameLayout root = findViewById(R.id.test_activity);
+
+ sCarUiImeWideScreenController = new CarUiImeWideScreenController(this, null) {
+ @Override
+ public boolean isWideScreenMode() {
+ return true;
+ }
+ };
+
+ View imeInputView = LayoutInflater.from(this)
+ .inflate(R.layout.test_ime_input_view, null, false);
+
+ View templateView = sCarUiImeWideScreenController.createWideScreenImeView(imeInputView);
+
+ root.addView(templateView);
+ }
+}
diff --git a/car-ui-lib/car-ui-lib/src/androidTest/res/layout/car_ui_ime_wide_screen_test_activity.xml b/car-ui-lib/car-ui-lib/src/androidTest/res/layout/car_ui_ime_wide_screen_test_activity.xml
new file mode 100644
index 0000000..e260300
--- /dev/null
+++ b/car-ui-lib/car-ui-lib/src/androidTest/res/layout/car_ui_ime_wide_screen_test_activity.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 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.
+ -->
+<FrameLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/test_activity"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+</FrameLayout>
diff --git a/car-ui-lib/car-ui-lib/src/androidTest/res/layout/test_ime_input_view.xml b/car-ui-lib/car-ui-lib/src/androidTest/res/layout/test_ime_input_view.xml
new file mode 100644
index 0000000..6b1fcb8
--- /dev/null
+++ b/car-ui-lib/car-ui-lib/src/androidTest/res/layout/test_ime_input_view.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 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.
+ -->
+<FrameLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/test_ime_input_view_id"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+</FrameLayout>
diff --git a/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/imewidescreen/CarUiImeSearchListItem.java b/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/imewidescreen/CarUiImeSearchListItem.java
new file mode 100644
index 0000000..fd0ba61
--- /dev/null
+++ b/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/imewidescreen/CarUiImeSearchListItem.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2020 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.car.ui.imewidescreen;
+
+import androidx.annotation.Nullable;
+
+import com.android.car.ui.recyclerview.CarUiContentListItem;
+import com.android.car.ui.recyclerview.CarUiListItemAdapter;
+
+/**
+ * Definition of list items that can be inserted into {@link CarUiListItemAdapter}. This class is
+ * used to display the search items in the template for wide screen mode.
+ *
+ * The class is used to pass application icon resources ids to the IME for rendering in its
+ * process. Applications can also pass a unique id for each item and supplemental icon that will be
+ * used by the IME to notify the application when a click action is taken on them.
+ */
+public class CarUiImeSearchListItem extends CarUiContentListItem {
+
+ private CharSequence mItemId;
+ private int mIconResId;
+ private CharSequence mSupplementalIconId;
+ private int mSupplementalIconResId;
+
+ public CarUiImeSearchListItem(Action action) {
+ super(action);
+ }
+
+ /**
+ * Returns the id of the item.
+ */
+ @Nullable
+ public CharSequence getItemId() {
+ return mItemId;
+ }
+
+ /**
+ * Sets the id of the item.
+ *
+ * @param itemId text to display as title.
+ */
+ public void setItemId(CharSequence itemId) {
+ mItemId = itemId;
+ }
+
+ /**
+ * Returns the icons resource of the item.
+ */
+ public int getIconResId() {
+ return mIconResId;
+ }
+
+ /**
+ * Sets the icons resource of the item.
+ */
+ public void setIconResId(int iconResId) {
+ mIconResId = iconResId;
+ }
+
+ /**
+ * Returns the supplemental icon resource id of the item.
+ */
+ public int getSupplementalIconResId() {
+ return mSupplementalIconResId;
+ }
+
+ /**
+ * Sets supplemental icon resource id.
+ */
+ public void setSupplementalIconResId(int supplementalIconResId) {
+ mSupplementalIconResId = supplementalIconResId;
+ }
+
+ /**
+ * Returns the supplemental icon id of the item.
+ */
+ @Nullable
+ public CharSequence getSupplementalIconId() {
+ return mSupplementalIconId;
+ }
+
+ /**
+ * Sets supplemental icon id.
+ */
+ public void setSupplementalIconId(CharSequence supplementalIconId) {
+ mSupplementalIconId = supplementalIconId;
+ }
+}
diff --git a/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/imewidescreen/CarUiImeWideScreenController.java b/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/imewidescreen/CarUiImeWideScreenController.java
new file mode 100644
index 0000000..c6905e2
--- /dev/null
+++ b/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/imewidescreen/CarUiImeWideScreenController.java
@@ -0,0 +1,661 @@
+/*
+ * Copyright (C) 2020 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.car.ui.imewidescreen;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.inputmethodservice.ExtractEditText;
+import android.inputmethodservice.InputMethodService;
+import android.os.Bundle;
+import android.text.InputType;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputConnection;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import androidx.annotation.DrawableRes;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.android.car.ui.R;
+import com.android.car.ui.recyclerview.CarUiContentListItem;
+import com.android.car.ui.recyclerview.CarUiListItem;
+import com.android.car.ui.recyclerview.CarUiListItemAdapter;
+import com.android.car.ui.utils.CarUiUtils;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Helper class to build an IME that support widescreen mode.
+ *
+ * <p> This class provides helper methods that should be invoked during the lifecycle of an IME.
+ * Usage of these methods are listed below.
+ * <ul>
+ * <li>create an instance of {@link CarUiImeWideScreenController} in
+ * {@link InputMethodService#onCreate()}</li>
+ * <li>return {@link #onEvaluateFullscreenMode(boolean)} from
+ * {@link InputMethodService#onEvaluateFullscreenMode()}</li>
+ * <li>return the view created by
+ * {@link #createWideScreenImeView(View, Context, InputMethodService)}
+ * from {@link InputMethodService#onCreateInputView()}</li>
+ * <li>{@link #onComputeInsets(InputMethodService.Insets, View)} should be called from
+ * {@link InputMethodService#onComputeInsets(InputMethodService.Insets)}</li>
+ * <li>{@link #onAppPrivateCommand(String, Bundle) should be called from {
+ * @link InputMethodService#onAppPrivateCommand(String, Bundle)}}</li>
+ * <li>{@link #setExtractViewShown(boolean)} should be called from
+ * {@link InputMethodService#setExtractViewShown(boolean)}</li>
+ * <li>{@link #onStartInputView(EditorInfo, InputConnection, CharSequence)} should be called
+ * from {@link InputMethodService#onStartInputView(EditorInfo, boolean)}</li>
+ * <li>{@link #onFinishInputView()} should be called from
+ * {@link InputMethodService#onFinishInputView(boolean)}</li>
+ * </ul>
+ *
+ * <p> All the methods in this class are guarded with a check {@link #isWideScreenMode()}. If
+ * wide screen mode is disabled all the method would return without doing anything. Also, IME
+ * should check for {@link #isWideScreenMode()} in
+ * {@link InputMethodService#setExtractViewShown(boolean)} and return the original value instead
+ * of false. for more info see {@link #setExtractViewShown(boolean)}
+ */
+public class CarUiImeWideScreenController {
+
+ private static final String TAG = "ImeWideScreenController";
+
+ // Automotive wide screen mode bundle keys.
+
+ // Action name of the action to support wide screen mode templates data.
+ public static final String WIDE_SCREEN_ACTION = "automotive_wide_screen";
+ // Action name of action that will be used by IMS to notify the application to clear the data
+ // in the EditText.
+ private static final String WIDE_SCREEN_CLEAR_DATA_ACTION = "automotive_wide_screen_clear_data";
+ // Key to provide the resource id for the icon that will be displayed in the input area. If
+ // this is not provided applications icon will be used. Value format is int.
+ public static final String WIDE_SCREEN_EXTRACTED_TEXT_ICON_RES_ID =
+ "extracted_text_icon_res_id";
+ // Key to determine if IME should display the content area or not. Content area is referred to
+ // the area used by IME to display search results, description title and description
+ // provided by the application. By default it will be shown but this value could be ignored
+ // if bool/car_ui_ime_wide_screen_allow_app_hide_content_area is set to false. Value format
+ // is boolean.
+ public static final String REQUEST_RENDER_CONTENT_AREA = "request_render_content_area";
+ // Key used to provide the description title to be rendered in the content area. Value format
+ // is String.
+ public static final String ADD_DESC_TITLE_TO_CONTENT_AREA = "add_desc_title_to_content_area";
+ // Key used to provide the description to be rendered in the content area. Value format is
+ // String.
+ public static final String ADD_DESC_TO_CONTENT_AREA = "add_desc_to_content_area";
+ // Key used to provide the error description to be rendered in the input area. Value format
+ // is String.
+ public static final String ADD_ERROR_DESC_TO_INPUT_AREA = "add_error_desc_to_input_area";
+
+ // wide screen search item keys. Each search item contains a title, sub-title, primary image
+ // and an secondary image. Click actions can be performed on item and secondary image.
+ // Application will be notified with the Ids of item clicked.
+
+ // Each key below represents a list. Search results will be displayed in the same order as
+ // the list provided by the application. For example, to create the search item at index 0
+ // controller will get the information from each lists index 0.
+
+ // Key used to provide list of unique id for each item. This same id will be sent back to
+ // the application when the item is clicked. Value format is ArrayList<String>
+ public static final String SEARCH_RESULT_ITEM_ID = "search_result_item_id";
+ // Key used to provide the list of titles for each search item. Value format is
+ // ArrayList<String>
+ public static final String SEARCH_RESULT_TITLE_LIST = "search_result_title_list";
+ // Key used to provide the list of sub titles for each search item. Value format is
+ // ArrayList<String>
+ public static final String SEARCH_RESULT_SUB_TITLE_LIST = "search_result_sub_title_list";
+ // Key used to provide the list of resource id for each primary image in search item.
+ // ArrayList<Integer>
+ public static final String SEARCH_RESULT_PRIMARY_IMAGE_RES_ID_LIST =
+ "search_result_image_list";
+ // Key used to provide the list of id for each secondary image in search item.
+ // ArrayList<String>
+ public static final String SEARCH_RESULT_SECONDARY_IMAGE_ID =
+ "search_result_secondary_image_id";
+ // Key used to provide the list of resource id for each secondary image in search item.
+ // ArrayList<Integer>
+ public static final String SEARCH_RESULT_SECONDARY_IMAGE_RES_ID_LIST =
+ "search_result_image_list";
+
+ private View mRootView;
+ private Context mContext;
+ @Nullable
+ private View mExtractActionAutomotive;
+ @NonNull
+ private View mContentAreaAutomotive;
+ // whether to render the content area for automotive when in wide screen mode.
+ private boolean mImeRendersAllContent = true;
+ private boolean mAllowAppToHideContentArea;
+ private ArrayList<CarUiListItem> mAutomotiveSearchItems = new ArrayList<>();
+ @NonNull
+ private TextView mWideScreenDescriptionTitle;
+ @NonNull
+ private TextView mWideScreenDescription;
+ @NonNull
+ private TextView mWideScreenErrorMessage;
+ @NonNull
+ private ImageView mWideScreenErrorImage;
+ @NonNull
+ private ImageView mWideScreenClearData;
+ @NonNull
+ private RecyclerView mRecyclerView;
+ @Nullable
+ private ImageView mWideScreenExtractedTextIcon;
+ private boolean mIsExtractIconProvidedByApp;
+ @NonNull
+ private FrameLayout mInputFrame;
+ @NonNull
+ private ExtractEditText mExtractEditText;
+ private EditorInfo mInputEditorInfo;
+ private InputConnection mInputConnection;
+ private boolean mExtractViewHidden;
+ @NonNull
+ private View mFullscreenArea;
+ @NonNull
+ private FrameLayout mInputExtractEditTextContainer;
+ private InputMethodService mInputMethodService;
+
+ public CarUiImeWideScreenController(@NonNull Context context, @NonNull InputMethodService ims) {
+ mContext = context;
+ mInputMethodService = ims;
+ }
+
+ /**
+ * Create and return the view hierarchy used for the input area in wide screen mode. This method
+ * will inflate the templates with the inputView provided.
+ *
+ * @param inputView view of the keyboard created by application.
+ * @return view to be used by {@link InputMethodService}.
+ */
+ public View createWideScreenImeView(@NonNull View inputView) {
+ if (!isWideScreenMode()) {
+ return inputView;
+ }
+ mRootView = View.inflate(mContext, R.layout.car_ui_ims_wide_screen_input_view, null);
+
+ mInputFrame = mRootView.requireViewById(R.id.carUiWideScreenInputArea);
+ mInputFrame.addView(inputView, new FrameLayout.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
+
+ mAllowAppToHideContentArea =
+ mContext.getResources().getBoolean(
+ R.bool.car_ui_ime_wide_screen_allow_app_hide_content_area);
+
+ mWideScreenDescriptionTitle = mRootView.requireViewById(R.id.wideScreenDescriptionTitle);
+ mWideScreenDescription = mRootView.requireViewById(R.id.wideScreenDescription);
+ mExtractActionAutomotive = mRootView.findViewById(R.id.inputExtractActionAutomotive);
+ mContentAreaAutomotive = mRootView.requireViewById(R.id.contentAreaAutomotive);
+ mRecyclerView = mRootView.requireViewById(R.id.wideScreenSearchResultList);
+ mWideScreenErrorMessage = mRootView.requireViewById(R.id.wideScreenErrorMessage);
+ mWideScreenExtractedTextIcon = mRootView.findViewById(R.id.wideScreenExtractedTextIcon);
+ mWideScreenErrorImage = mRootView.requireViewById(R.id.wideScreenError);
+ mWideScreenClearData = mRootView.requireViewById(R.id.wideScreenClearData);
+ mFullscreenArea = mRootView.requireViewById(R.id.fullscreenArea);
+ mInputExtractEditTextContainer = mRootView.requireViewById(
+ R.id.inputExtractEditTextContainer);
+ mWideScreenClearData.setOnClickListener(
+ v -> {
+ // notify the app to clear the data.
+ mInputConnection.performPrivateCommand(WIDE_SCREEN_CLEAR_DATA_ACTION, null);
+ });
+ mExtractViewHidden = false;
+
+ return mRootView;
+ }
+
+ /**
+ * Compute the interesting insets into your UI. When the content view is shown the default
+ * touchable insets are {@link InputMethodService.Insets#TOUCHABLE_INSETS_FRAME}. When content
+ * view is hidden then that area of the application is interactable by user.
+ *
+ * @param outInsets Fill in with the current UI insets.
+ */
+ public void onComputeInsets(@NonNull InputMethodService.Insets outInsets) {
+ if (!isWideScreenMode()) {
+ return;
+ }
+ Rect tempRect = new Rect();
+ int[] tempLocation = new int[2];
+ outInsets.contentTopInsets = outInsets.visibleTopInsets =
+ mInputMethodService.getWindow().getWindow().getDecorView().getHeight();
+ if (mImeRendersAllContent) {
+ outInsets.touchableRegion.setEmpty();
+ outInsets.touchableInsets = InputMethodService.Insets.TOUCHABLE_INSETS_FRAME;
+ } else {
+ mInputFrame.getLocationOnScreen(tempLocation);
+ tempRect.set(/* left= */0, /* top= */ 0,
+ tempLocation[0] + mInputFrame.getWidth(),
+ tempLocation[1] + mInputFrame.getHeight());
+ outInsets.touchableRegion.set(tempRect);
+ outInsets.touchableInsets = InputMethodService.Insets.TOUCHABLE_INSETS_REGION;
+ }
+ }
+
+ /**
+ * Actions passed by the application must be "automotive_wide_screen" with the corresponding
+ * data that application wants to display. See the comments associated with each bundle key to
+ * know what view is rendered.
+ *
+ * <p> Each bundle key renders or updates/controls a particular view in the template. For
+ * example, if application rendered the description title and later also wanted to render an
+ * actual description with it then application should use both "add_desc_title_to_content_area"
+ * and "add_desc_to_content_area" to provide the data. Sending action with only
+ * "add_desc_to_content_area" bundle key will not add an extra view but will display only the
+ * description and not the title.
+ *
+ * When the IME window is closed all the views are reset. For the default view visibility see
+ * {@link #resetAutomotiveWideScreenViews()}.
+ *
+ * @param action Name of the command to be performed.
+ * @param data Any data to include with the command.
+ */
+ public void onAppPrivateCommand(String action, Bundle data) {
+ if (!isWideScreenMode() || data == null || !WIDE_SCREEN_ACTION.equals(action)) {
+ return;
+ }
+ resetAutomotiveWideScreenViews();
+ if (mAllowAppToHideContentArea || (mInputEditorInfo != null && allowPackageList().contains(
+ mInputEditorInfo.packageName))) {
+ mImeRendersAllContent = data.getBoolean(REQUEST_RENDER_CONTENT_AREA, true);
+ }
+
+ String discTitle = data.getString(ADD_DESC_TITLE_TO_CONTENT_AREA);
+ if (!TextUtils.isEmpty(discTitle)) {
+ mWideScreenDescriptionTitle.setText(discTitle);
+ mWideScreenDescriptionTitle.setVisibility(View.VISIBLE);
+ mContentAreaAutomotive.setBackground(
+ mContext.getDrawable(R.drawable.car_ui_ime_wide_screen_background));
+ }
+
+ String disc = data.getString(ADD_DESC_TO_CONTENT_AREA);
+ if (!TextUtils.isEmpty(disc)) {
+ mWideScreenDescription.setText(disc);
+ mWideScreenDescription.setVisibility(View.VISIBLE);
+ mContentAreaAutomotive.setBackground(
+ mContext.getDrawable(R.drawable.car_ui_ime_wide_screen_background));
+ }
+
+ String errorMessage = data.getString(ADD_ERROR_DESC_TO_INPUT_AREA);
+ if (!TextUtils.isEmpty(errorMessage)) {
+ mWideScreenErrorMessage.setVisibility(View.VISIBLE);
+ mWideScreenClearData.setVisibility(View.GONE);
+ mWideScreenErrorImage.setVisibility(View.VISIBLE);
+ setExtractedEditTextBackground(
+ R.drawable.car_ui_ime_wide_screen_input_area_tint_error_color);
+ mWideScreenErrorMessage.setText(errorMessage);
+ mContentAreaAutomotive.setBackground(
+ mContext.getDrawable(R.drawable.car_ui_ime_wide_screen_background));
+ }
+
+ if (TextUtils.isEmpty(errorMessage)) {
+ mWideScreenErrorMessage.setVisibility(View.INVISIBLE);
+ mWideScreenErrorMessage.setText("");
+ mWideScreenClearData.setVisibility(View.VISIBLE);
+ mWideScreenErrorImage.setVisibility(View.GONE);
+ setExtractedEditTextBackground(
+ R.drawable.car_ui_ime_wide_screen_input_area_tint_color);
+ }
+
+ int extractedTextIcon = data.getInt(WIDE_SCREEN_EXTRACTED_TEXT_ICON_RES_ID);
+ if (extractedTextIcon != 0) {
+ setWideScreenExtractedIcon(extractedTextIcon);
+ }
+
+ loadSearchItems(data);
+
+ if (mExtractActionAutomotive != null) {
+ mExtractActionAutomotive.setVisibility(View.VISIBLE);
+ }
+ if (!mAutomotiveSearchItems.isEmpty()) {
+ mRecyclerView.setLayoutManager(new LinearLayoutManager(mContext));
+ mRecyclerView.setVerticalScrollBarEnabled(true);
+ mRecyclerView.setVerticalScrollbarPosition(View.SCROLLBAR_POSITION_LEFT);
+ mRecyclerView.setVisibility(View.VISIBLE);
+ mRecyclerView.setAdapter(new CarUiListItemAdapter(mAutomotiveSearchItems));
+ mContentAreaAutomotive.setBackground(
+ mContext.getDrawable(R.drawable.car_ui_ime_wide_screen_background));
+ if (mExtractActionAutomotive != null) {
+ mExtractActionAutomotive.setVisibility(View.GONE);
+ }
+ }
+ }
+
+ private void loadSearchItems(Bundle data) {
+ mAutomotiveSearchItems = new ArrayList<>();
+ ArrayList<String> itemIdList = data.getStringArrayList(SEARCH_RESULT_ITEM_ID);
+ ArrayList<String> titleList = data.getStringArrayList(SEARCH_RESULT_TITLE_LIST);
+ ArrayList<String> subTitleList = data.getStringArrayList(SEARCH_RESULT_SUB_TITLE_LIST);
+ ArrayList<Integer> primaryImageResIdList =
+ data.getIntegerArrayList(SEARCH_RESULT_PRIMARY_IMAGE_RES_ID_LIST);
+ ArrayList<String> secondaryImageIdList =
+ data.getStringArrayList(SEARCH_RESULT_SECONDARY_IMAGE_ID);
+ ArrayList<Integer> secondaryImageResIdList =
+ data.getIntegerArrayList(SEARCH_RESULT_SECONDARY_IMAGE_RES_ID_LIST);
+ if (itemIdList == null) {
+ return;
+ }
+ for (int i = 0; i < itemIdList.size(); i++) {
+ int index = i;
+ CarUiImeSearchListItem searchItem;
+ if (secondaryImageIdList == null) {
+ searchItem = new CarUiImeSearchListItem(CarUiContentListItem.Action.NONE);
+ } else {
+ searchItem = new CarUiImeSearchListItem(CarUiContentListItem.Action.ICON);
+ searchItem.setSupplementalIconId(secondaryImageIdList.get(i));
+ }
+
+ searchItem.setItemId(itemIdList.get(i));
+ searchItem.setOnItemClickedListener(v -> {
+ Bundle bundle = new Bundle();
+ bundle.putString(SEARCH_RESULT_ITEM_ID, itemIdList.get(index));
+ mInputConnection.performPrivateCommand(WIDE_SCREEN_ACTION, bundle);
+ });
+
+ if (titleList != null) {
+ searchItem.setTitle(titleList.get(i));
+ }
+
+ if (subTitleList != null) {
+ searchItem.setBody(subTitleList.get(i));
+ }
+
+ if (primaryImageResIdList != null) {
+ searchItem.setPrimaryIconType(CarUiContentListItem.IconType.CONTENT);
+ searchItem.setIcon(loadDrawableFromPackage(primaryImageResIdList.get(i)));
+ }
+
+ if (secondaryImageResIdList != null && secondaryImageIdList != null) {
+ searchItem.setSupplementalIcon(
+ loadDrawableFromPackage(secondaryImageResIdList.get(i)), v -> {
+ Bundle bundle = new Bundle();
+ bundle.putString(SEARCH_RESULT_SECONDARY_IMAGE_ID,
+ secondaryImageIdList.get(index));
+ mInputConnection.performPrivateCommand(WIDE_SCREEN_ACTION, bundle);
+ });
+ }
+
+ mAutomotiveSearchItems.add(searchItem);
+ }
+ }
+
+ /**
+ * Evaluate if IME should launch in a fullscreen mode. In wide screen mode IME should always
+ * launch in a fullscreen mode so that {@link ExtractEditText} is inflated. Later the controller
+ * will detach the {@link ExtractEditText} from its original parent and inflate into the
+ * appropriate container in wide screen.
+ *
+ * @param isFullScreen value evaluated to be in fullscreen mode or not by the app.
+ */
+ public boolean onEvaluateFullscreenMode(boolean isFullScreen) {
+ return isWideScreenMode() || isFullScreen;
+ }
+
+ /**
+ * Initialize the view in the wide screen template based on the data provided by the app through
+ * {@link #onAppPrivateCommand(String, Bundle)}
+ */
+ public void onStartInputView(@NonNull EditorInfo editorInfo,
+ @Nullable InputConnection inputConnection, @Nullable CharSequence textForImeAction) {
+ if (!isWideScreenMode()) {
+ return;
+ }
+ mInputEditorInfo = editorInfo;
+ mInputConnection = inputConnection;
+ View header = mRootView.requireViewById(R.id.carUiImeWideScreenInputArea);
+
+ header.setVisibility(View.VISIBLE);
+ if (mExtractViewHidden) {
+ mFullscreenArea.setVisibility(View.INVISIBLE);
+ } else {
+ mFullscreenArea.setVisibility(View.VISIBLE);
+ }
+ if (!mImeRendersAllContent) {
+ mContentAreaAutomotive.setVisibility(View.GONE);
+ } else {
+ mContentAreaAutomotive.setVisibility(View.VISIBLE);
+ }
+
+ // This view is rendered by the framework when IME is in full screen mode. For more info
+ // see {@link #onEvaluateFullscreenMode}
+ mExtractEditText = mRootView.getRootView().requireViewById(
+ android.R.id.inputExtractEditText);
+
+ mExtractEditText.setPadding(
+ mContext.getResources().getDimensionPixelSize(
+ R.dimen.car_ui_ime_wide_screen_input_edit_text_padding_left),
+ /* top= */0,
+ mContext.getResources().getDimensionPixelSize(
+ R.dimen.car_ui_ime_wide_screen_input_edit_text_padding_right),
+ /* bottom= */0);
+ mExtractEditText.setTextSize(mContext.getResources().getDimensionPixelSize(
+ R.dimen.car_ui_ime_wide_screen_input_edit_text_size));
+ mExtractEditText.setGravity(Gravity.START | Gravity.CENTER);
+
+ ViewGroup parent = (ViewGroup) mExtractEditText.getParent();
+ parent.removeViewInLayout(mExtractEditText);
+
+ FrameLayout.LayoutParams params =
+ new FrameLayout.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
+
+ mInputExtractEditTextContainer.addView(mExtractEditText, params);
+
+ ImageView close = mRootView.findViewById(R.id.closeKeyboard);
+ if (close != null) {
+ close.setOnClickListener(
+ (v) -> {
+ mInputMethodService.requestHideSelf(0);
+ });
+ }
+
+ if (!mIsExtractIconProvidedByApp) {
+ setWideScreenExtractedIcon(/* iconResId= */0);
+ }
+
+ boolean hasAction = (mInputEditorInfo.imeOptions & EditorInfo.IME_MASK_ACTION)
+ != EditorInfo.IME_ACTION_NONE;
+ boolean hasInputType = mInputEditorInfo.inputType != InputType.TYPE_NULL;
+ boolean hasNoAccessoryAction =
+ (mInputEditorInfo.imeOptions & EditorInfo.IME_FLAG_NO_ACCESSORY_ACTION) == 0;
+
+ boolean hasLabel =
+ mInputEditorInfo.actionLabel != null || (hasAction && hasNoAccessoryAction
+ && hasInputType);
+
+ if (hasLabel) {
+ intiExtractAction(textForImeAction);
+ }
+ }
+
+ /**
+ * To support wide screen mode, IME should always call
+ * {@link InputMethodService#setExtractViewShown} with false and pass the flag to this method.
+ *
+ * For example, within the IMS service call
+ * <pre>
+ * @Override
+ * public void setExtractViewShown(boolean shown) {
+ * if (!carUiImeWideScreenController.isWideScreenMode()) {
+ * super.setExtractViewShown(shown);
+ * return;
+ * }
+ * super.setExtractViewShown(false);
+ * mImeWideScreenController.setExtractViewShown(shown);
+ * }
+ * </pre>
+ *
+ * This is required as IMS checks for ExtractViewIsShown and if that is true then set the
+ * touchable insets to the entire screen rather than a region. If an app hides the content area
+ * in that case we want the user to be able to interact with the application.
+ */
+ public void setExtractViewShown(boolean shown) {
+ if (!isWideScreenMode()) {
+ return;
+ }
+ if (mExtractViewHidden == !shown) {
+ return;
+ }
+ mExtractViewHidden = !shown;
+ if (mExtractViewHidden) {
+ mFullscreenArea.setVisibility(View.INVISIBLE);
+ } else {
+ mFullscreenArea.setVisibility(View.VISIBLE);
+ }
+ }
+
+ private void intiExtractAction(CharSequence textForImeAction) {
+ if (mExtractActionAutomotive == null) {
+ return;
+ }
+ if (mInputEditorInfo.actionLabel != null) {
+ ((TextView) mExtractActionAutomotive).setText(mInputEditorInfo.actionLabel);
+ } else {
+ ((TextView) mExtractActionAutomotive).setText(textForImeAction);
+ }
+
+ // click listener for the action button shown in the content area.
+ mExtractActionAutomotive.setOnClickListener(v -> {
+ final EditorInfo editorInfo = mInputEditorInfo;
+ final InputConnection inputConnection = mInputConnection;
+ if (editorInfo == null || inputConnection == null) {
+ return;
+ }
+ if (editorInfo.actionId != 0) {
+ inputConnection.performEditorAction(editorInfo.actionId);
+ } else if ((editorInfo.imeOptions & EditorInfo.IME_MASK_ACTION)
+ != EditorInfo.IME_ACTION_NONE) {
+ inputConnection.performEditorAction(
+ editorInfo.imeOptions & EditorInfo.IME_MASK_ACTION);
+ }
+ });
+ }
+
+ private List<String> allowPackageList() {
+ String value = mContext.getString(R.string.car_ui_ime_wide_screen_allowed_package_list);
+ String[] packages = value.split(",");
+ return Arrays.asList(packages);
+ }
+
+ private void setExtractedEditTextBackground(int drawableResId) {
+ mExtractEditText.setBackgroundTintList(mContext.getColorStateList(drawableResId));
+ }
+
+ @VisibleForTesting
+ void setExtractEditText(ExtractEditText editText) {
+ mExtractEditText = editText;
+ }
+
+ /**
+ * Sets the icon in the input area. If the icon resource Id is not provided by the application
+ * then application icon will be used instead.
+ *
+ * @param iconResId icon resource id for the image drawable to load.
+ */
+ private void setWideScreenExtractedIcon(@DrawableRes int iconResId) {
+ if (mInputEditorInfo == null || mWideScreenExtractedTextIcon == null) {
+ return;
+ }
+ try {
+ if (iconResId == 0) {
+ mWideScreenExtractedTextIcon.setImageDrawable(
+ mContext.getPackageManager().getApplicationIcon(
+ mInputEditorInfo.packageName));
+ } else {
+ mIsExtractIconProvidedByApp = true;
+ mWideScreenExtractedTextIcon.setImageDrawable(
+ mContext.createPackageContext(mInputEditorInfo.packageName, 0).getDrawable(
+ iconResId));
+ }
+ mWideScreenExtractedTextIcon.setVisibility(View.VISIBLE);
+ } catch (PackageManager.NameNotFoundException ex) {
+ Log.w(TAG, "setWideScreenExtractedIcon: package name not found ", ex);
+ mWideScreenExtractedTextIcon.setVisibility(View.GONE);
+ } catch (Resources.NotFoundException ex) {
+ Log.w(TAG, "setWideScreenExtractedIcon: resource not found with id " + iconResId, ex);
+ mWideScreenExtractedTextIcon.setVisibility(View.GONE);
+ }
+ }
+
+ /**
+ * Called when IME window closes. Reset all the views once that happens.
+ */
+ public void onFinishInputView() {
+ if (!isWideScreenMode()) {
+ return;
+ }
+ resetAutomotiveWideScreenViews();
+ }
+
+ private void resetAutomotiveWideScreenViews() {
+ mWideScreenDescriptionTitle.setVisibility(View.GONE);
+ mWideScreenErrorMessage.setVisibility(View.GONE);
+ mRecyclerView.setVisibility(View.GONE);
+ mWideScreenDescription.setVisibility(View.GONE);
+ mFullscreenArea.setVisibility(View.VISIBLE);
+ if (mWideScreenExtractedTextIcon != null) {
+ mWideScreenExtractedTextIcon.setVisibility(View.VISIBLE);
+ }
+ mWideScreenClearData.setVisibility(View.VISIBLE);
+ mWideScreenErrorImage.setVisibility(View.GONE);
+ if (mExtractActionAutomotive != null) {
+ mExtractActionAutomotive.setVisibility(View.GONE);
+ }
+ mContentAreaAutomotive.setBackground(
+ mContext.getDrawable(R.drawable.car_ui_ime_wide_screen_no_content_background));
+ setExtractedEditTextBackground(R.drawable.car_ui_ime_wide_screen_input_area_tint_color);
+ mImeRendersAllContent = true;
+ mIsExtractIconProvidedByApp = false;
+ mExtractViewHidden = false;
+ mAutomotiveSearchItems = new ArrayList<>();
+ }
+
+ /**
+ * Returns whether or not system is running in a wide screen mode.
+ */
+ public boolean isWideScreenMode() {
+ return CarUiUtils.getBooleanSystemProperty(mContext.getResources(),
+ R.string.car_ui_ime_wide_screen_system_property_name, false);
+ }
+
+ private Drawable loadDrawableFromPackage(int resId) {
+ try {
+ if (mInputEditorInfo != null) {
+ return mContext.createPackageContext(mInputEditorInfo.packageName, 0)
+ .getDrawable(resId);
+ }
+ } catch (PackageManager.NameNotFoundException ex) {
+ Log.e(TAG, "loadDrawableFromPackage: package name not found: ", ex);
+ } catch (Resources.NotFoundException ex) {
+ Log.w(TAG, "loadDrawableFromPackage: resource not found with id " + resId, ex);
+ }
+ return null;
+ }
+}
diff --git a/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/utils/CarUiUtils.java b/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/utils/CarUiUtils.java
index ce4d8a5..e9ad2ae 100644
--- a/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/utils/CarUiUtils.java
+++ b/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/utils/CarUiUtils.java
@@ -25,6 +25,9 @@
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.os.Build;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.SparseArray;
import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;
@@ -37,10 +40,18 @@
import androidx.annotation.UiThread;
import androidx.core.view.ViewCompat;
+import java.lang.reflect.Method;
+
/**
* Collection of utility methods
*/
public final class CarUiUtils {
+
+ private static final String TAG = "CarUiUtils";
+ private static final String READ_ONLY_SYSTEM_PROPERTY_PREFIX = "ro.";
+ /** A map to cache read-only system properties. */
+ private static final SparseArray<String> READ_ONLY_SYSTEM_PROPERTY_MAP = new SparseArray<>();
+
/** This is a utility class */
private CarUiUtils() {
}
@@ -49,7 +60,7 @@
* Reads a float value from a dimens resource. This is necessary as {@link Resources#getFloat}
* is not currently public.
*
- * @param res {@link Resources} to read values from
+ * @param res {@link Resources} to read values from
* @param resId Id of the dimens resource to read
*/
public static float getFloat(Resources res, @DimenRes int resId) {
@@ -137,11 +148,11 @@
/**
* Updates the ripple state on the given preference.
*
- * @param isEnabled whether the preference is enabled or not
+ * @param isEnabled whether the preference is enabled or not
* @param shouldShowRippleOnDisabledPreference should ripple be displayed when the preference is
- * clicked
- * @param background drawable that represents the ripple
- * @param preference preference on which drawable will be applied
+ * clicked
+ * @param background drawable that represents the ripple
+ * @param preference preference on which drawable will be applied
*/
public static void updateRippleStateOnDisabledPreference(boolean isEnabled,
boolean shouldShowRippleOnDisabledPreference, Drawable background, View preference) {
@@ -215,4 +226,78 @@
}
return view;
}
+
+ /**
+ * Returns the system property of type boolean. This method converts the boolean value in string
+ * returned by {@link #getSystemProperty(Resources, int)}
+ */
+ public static boolean getBooleanSystemProperty(
+ @NonNull Resources resources, int propertyResId, boolean defaultValue) {
+ String value = getSystemProperty(resources, propertyResId);
+
+ if (!TextUtils.isEmpty(value)) {
+ return Boolean.parseBoolean(value);
+ }
+ return defaultValue;
+ }
+
+ /**
+ * Use reflection to interact with the hidden API <code>android.os.SystemProperties</code>.
+ *
+ * <p>This method caches read-only properties. CAVEAT: Please do not set read-only properties
+ * by 'adb setprop' after app started. Read-only properties CAN BE SET ONCE if it is unset.
+ * Thus, read-only properties MAY BE CHANGED from unset to set during application's lifetime if
+ * you use 'adb setprop' command to set read-only properties after app started. For the sake of
+ * performance, this method also caches the unset state. Otherwise, cache may not effective if
+ * the system property is unset (which is most-likely).
+ *
+ * @param resources resources object to fetch string
+ * @param propertyResId the property resource id.
+ * @return The value of the property if defined, else null. Does not return empty strings.
+ */
+ @Nullable
+ public static String getSystemProperty(@NonNull Resources resources, int propertyResId) {
+ String propertyName = resources.getString(propertyResId);
+ boolean isReadOnly = propertyName.startsWith(READ_ONLY_SYSTEM_PROPERTY_PREFIX);
+ if (!isReadOnly) {
+ return readSystemProperty(propertyName);
+ }
+ synchronized (READ_ONLY_SYSTEM_PROPERTY_MAP) {
+ // readOnlySystemPropertyMap may contain null values.
+ if (READ_ONLY_SYSTEM_PROPERTY_MAP.indexOfKey(propertyResId) >= 0) {
+ return READ_ONLY_SYSTEM_PROPERTY_MAP.get(propertyResId);
+ }
+ String value = readSystemProperty(propertyName);
+ READ_ONLY_SYSTEM_PROPERTY_MAP.put(propertyResId, value);
+ return value;
+ }
+ }
+
+ @Nullable
+ private static String readSystemProperty(String propertyName) {
+ Class<?> systemPropertiesClass;
+ try {
+ systemPropertiesClass = Class.forName("android.os.SystemProperties");
+ } catch (ClassNotFoundException e) {
+ Log.w(TAG, "Cannot find android.os.SystemProperties: ", e);
+ return null;
+ }
+
+ Method getMethod;
+ try {
+ getMethod = systemPropertiesClass.getMethod("get", String.class);
+ } catch (NoSuchMethodException e) {
+ Log.w(TAG, "Cannot find SystemProperties.get(): ", e);
+ return null;
+ }
+
+ try {
+ Object[] params = new Object[]{propertyName};
+ String value = (String) getMethod.invoke(systemPropertiesClass, params);
+ return TextUtils.isEmpty(value) ? null : value;
+ } catch (Exception e) {
+ Log.w(TAG, "Failed to invoke SystemProperties.get(): ", e);
+ return null;
+ }
+ }
}
diff --git a/car-ui-lib/car-ui-lib/src/main/res-overlayable/values/overlayable.xml b/car-ui-lib/car-ui-lib/src/main/res-overlayable/values/overlayable.xml
index 453db47..19a5a4c 100644
--- a/car-ui-lib/car-ui-lib/src/main/res-overlayable/values/overlayable.xml
+++ b/car-ui-lib/car-ui-lib/src/main/res-overlayable/values/overlayable.xml
@@ -76,6 +76,8 @@
<item type="bool" name="car_ui_enable_focus_area_foreground_highlight"/>
<item type="bool" name="car_ui_escrow_check_components_automatically"/>
<item type="bool" name="car_ui_focus_area_default_focus_overrides_history"/>
+ <item type="bool" name="car_ui_ime_wide_screen_aligned_left"/>
+ <item type="bool" name="car_ui_ime_wide_screen_allow_app_hide_content_area"/>
<item type="bool" name="car_ui_list_item_single_line_title"/>
<item type="bool" name="car_ui_preference_list_show_full_screen"/>
<item type="bool" name="car_ui_preference_show_chevron"/>
@@ -88,6 +90,12 @@
<item type="color" name="car_ui_activity_background_color"/>
<item type="color" name="car_ui_color_accent"/>
<item type="color" name="car_ui_dialog_icon_color"/>
+ <item type="color" name="car_ui_ime_wide_screen_description_color"/>
+ <item type="color" name="car_ui_ime_wide_screen_description_title_color"/>
+ <item type="color" name="car_ui_ime_wide_screen_divider_color"/>
+ <item type="color" name="car_ui_ime_wide_screen_error_text_color"/>
+ <item type="color" name="car_ui_ime_wide_screen_search_item_sub_title_color"/>
+ <item type="color" name="car_ui_ime_wide_screen_search_item_title_color"/>
<item type="color" name="car_ui_list_item_divider"/>
<item type="color" name="car_ui_preference_icon_color"/>
<item type="color" name="car_ui_preference_two_action_divider_color"/>
@@ -123,6 +131,37 @@
<item type="dimen" name="car_ui_dialog_title_margin"/>
<item type="dimen" name="car_ui_divider_width"/>
<item type="dimen" name="car_ui_header_list_item_text_start_margin"/>
+ <item type="dimen" name="car_ui_ime_wide_screen_action_button_height"/>
+ <item type="dimen" name="car_ui_ime_wide_screen_action_button_margin_bottom"/>
+ <item type="dimen" name="car_ui_ime_wide_screen_action_button_margin_left"/>
+ <item type="dimen" name="car_ui_ime_wide_screen_action_button_text_size"/>
+ <item type="dimen" name="car_ui_ime_wide_screen_description_padding_top"/>
+ <item type="dimen" name="car_ui_ime_wide_screen_description_text_size"/>
+ <item type="dimen" name="car_ui_ime_wide_screen_description_title_margin_top"/>
+ <item type="dimen" name="car_ui_ime_wide_screen_description_title_padding_left"/>
+ <item type="dimen" name="car_ui_ime_wide_screen_description_title_text_size"/>
+ <item type="dimen" name="car_ui_ime_wide_screen_divider_width"/>
+ <item type="dimen" name="car_ui_ime_wide_screen_error_text_padding_start"/>
+ <item type="dimen" name="car_ui_ime_wide_screen_error_text_size"/>
+ <item type="dimen" name="car_ui_ime_wide_screen_input_area_height"/>
+ <item type="dimen" name="car_ui_ime_wide_screen_input_area_margin_top"/>
+ <item type="dimen" name="car_ui_ime_wide_screen_input_edit_text_padding_left"/>
+ <item type="dimen" name="car_ui_ime_wide_screen_input_edit_text_padding_right"/>
+ <item type="dimen" name="car_ui_ime_wide_screen_input_edit_text_size"/>
+ <item type="dimen" name="car_ui_ime_wide_screen_input_padding_start"/>
+ <item type="dimen" name="car_ui_ime_wide_screen_keyboard_area_padding_bottom"/>
+ <item type="dimen" name="car_ui_ime_wide_screen_keyboard_area_padding_end"/>
+ <item type="dimen" name="car_ui_ime_wide_screen_keyboard_area_padding_start"/>
+ <item type="dimen" name="car_ui_ime_wide_screen_keyboard_width"/>
+ <item type="dimen" name="car_ui_ime_wide_screen_recycler_view_padding_top"/>
+ <item type="dimen" name="car_ui_ime_wide_search_item_icon_size"/>
+ <item type="dimen" name="car_ui_ime_wide_search_item_secondary_image_padding_left"/>
+ <item type="dimen" name="car_ui_ime_wide_search_item_sub_title_padding_left"/>
+ <item type="dimen" name="car_ui_ime_wide_search_item_sub_title_padding_top"/>
+ <item type="dimen" name="car_ui_ime_wide_search_item_sub_title_text_size"/>
+ <item type="dimen" name="car_ui_ime_wide_search_item_title_padding_left"/>
+ <item type="dimen" name="car_ui_ime_wide_search_item_title_padding_top"/>
+ <item type="dimen" name="car_ui_ime_wide_search_item_title_text_size"/>
<item type="dimen" name="car_ui_list_item_action_divider_height"/>
<item type="dimen" name="car_ui_list_item_action_divider_width"/>
<item type="dimen" name="car_ui_list_item_avatar_icon_height"/>
@@ -235,12 +274,19 @@
<item type="drawable" name="car_ui_icon_delete"/>
<item type="drawable" name="car_ui_icon_down"/>
<item type="drawable" name="car_ui_icon_edit"/>
+ <item type="drawable" name="car_ui_icon_error"/>
<item type="drawable" name="car_ui_icon_lock"/>
<item type="drawable" name="car_ui_icon_overflow_menu"/>
<item type="drawable" name="car_ui_icon_save"/>
<item type="drawable" name="car_ui_icon_search"/>
<item type="drawable" name="car_ui_icon_search_nav_icon"/>
<item type="drawable" name="car_ui_icon_settings"/>
+ <item type="drawable" name="car_ui_ime_wide_screen_background"/>
+ <item type="drawable" name="car_ui_ime_wide_screen_content_area_background"/>
+ <item type="drawable" name="car_ui_ime_wide_screen_input_area_background"/>
+ <item type="drawable" name="car_ui_ime_wide_screen_input_area_tint_color"/>
+ <item type="drawable" name="car_ui_ime_wide_screen_input_area_tint_error_color"/>
+ <item type="drawable" name="car_ui_ime_wide_screen_no_content_background"/>
<item type="drawable" name="car_ui_list_header_background"/>
<item type="drawable" name="car_ui_list_item_avatar_icon_outline"/>
<item type="drawable" name="car_ui_list_item_background"/>
@@ -249,6 +295,7 @@
<item type="drawable" name="car_ui_preference_icon_chevron"/>
<item type="drawable" name="car_ui_preference_icon_chevron_disabled"/>
<item type="drawable" name="car_ui_preference_icon_chevron_enabled"/>
+ <item type="drawable" name="car_ui_recycler_view_ime_wide_screen_thumb"/>
<item type="drawable" name="car_ui_recyclerview_button_ripple_background"/>
<item type="drawable" name="car_ui_recyclerview_divider"/>
<item type="drawable" name="car_ui_recyclerview_ic_down"/>
@@ -266,6 +313,8 @@
<item type="id" name="action_widget_container"/>
<item type="id" name="avatar_icon"/>
<item type="id" name="body"/>
+ <item type="id" name="carUiImeWideScreenInputArea"/>
+ <item type="id" name="carUiWideScreenInputArea"/>
<item type="id" name="car_ui_alert_icon"/>
<item type="id" name="car_ui_alert_subtitle"/>
<item type="id" name="car_ui_alert_title"/>
@@ -315,10 +364,16 @@
<item type="id" name="car_ui_toolbar_title_logo_container"/>
<item type="id" name="car_ui_toolbar_top_guideline"/>
<item type="id" name="checkbox_widget"/>
+ <item type="id" name="closeKeyboard"/>
<item type="id" name="container"/>
+ <item type="id" name="contentAreaAutomotive"/>
<item type="id" name="content_icon"/>
+ <item type="id" name="fullscreenArea"/>
<item type="id" name="icon"/>
<item type="id" name="icon_container"/>
+ <item type="id" name="inputExtractActionAutomotive"/>
+ <item type="id" name="inputExtractEditText"/>
+ <item type="id" name="inputExtractEditTextContainer"/>
<item type="id" name="list"/>
<item type="id" name="nested_recycler_view_layout"/>
<item type="id" name="radio_button"/>
@@ -341,6 +396,17 @@
<item type="id" name="title_template"/>
<item type="id" name="toolbar"/>
<item type="id" name="touch_interceptor"/>
+ <item type="id" name="wideScreenClearData"/>
+ <item type="id" name="wideScreenDescription"/>
+ <item type="id" name="wideScreenDescriptionTitle"/>
+ <item type="id" name="wideScreenError"/>
+ <item type="id" name="wideScreenErrorMessage"/>
+ <item type="id" name="wideScreenExtractedTextIcon"/>
+ <item type="id" name="wideScreenSearchItemPrimaryImageView"/>
+ <item type="id" name="wideScreenSearchItemSecondaryImageView"/>
+ <item type="id" name="wideScreenSearchItemSubTitle"/>
+ <item type="id" name="wideScreenSearchItemTitle"/>
+ <item type="id" name="wideScreenSearchResultList"/>
<item type="integer" name="car_ui_default_max_string_length"/>
<item type="integer" name="car_ui_focus_area_history_cache_type"/>
<item type="integer" name="car_ui_focus_area_history_expiration_period_ms"/>
@@ -355,6 +421,7 @@
<item type="layout" name="car_ui_base_layout_toolbar"/>
<item type="layout" name="car_ui_base_layout_toolbar_legacy"/>
<item type="layout" name="car_ui_header_list_item"/>
+ <item type="layout" name="car_ui_ims_wide_screen_input_view"/>
<item type="layout" name="car_ui_list_item"/>
<item type="layout" name="car_ui_list_limiting_message"/>
<item type="layout" name="car_ui_list_preference"/>
@@ -387,6 +454,8 @@
<item type="string" name="car_ui_dialog_preference_negative"/>
<item type="string" name="car_ui_dialog_preference_positive"/>
<item type="string" name="car_ui_ellipsis"/>
+ <item type="string" name="car_ui_ime_wide_screen_allowed_package_list"/>
+ <item type="string" name="car_ui_ime_wide_screen_system_property_name"/>
<item type="string" name="car_ui_installer_process_name"/>
<item type="string" name="car_ui_preference_switch_off"/>
<item type="string" name="car_ui_preference_switch_on"/>
diff --git a/car-ui-lib/car-ui-lib/src/main/res/drawable/car_ui_icon_error.xml b/car-ui-lib/car-ui-lib/src/main/res/drawable/car_ui_icon_error.xml
new file mode 100644
index 0000000..b0f4a34
--- /dev/null
+++ b/car-ui-lib/car-ui-lib/src/main/res/drawable/car_ui_icon_error.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 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="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:pathData="M15.73,3L8.27,3L3,8.27v7.46L8.27,21h7.46L21,15.73L21,8.27L15.73,3zM12,17.3c-0.72,0 -1.3,-0.58 -1.3,-1.3 0,-0.72 0.58,-1.3 1.3,-1.3 0.72,0 1.3,0.58 1.3,1.3 0,0.72 -0.58,1.3 -1.3,1.3zM13,13h-2L11,7h2v6z"
+ android:fillColor="#F00"/>
+</vector>
diff --git a/car-ui-lib/car-ui-lib/src/main/res/drawable/car_ui_recycler_view_ime_wide_screen_thumb.xml b/car-ui-lib/car-ui-lib/src/main/res/drawable/car_ui_recycler_view_ime_wide_screen_thumb.xml
new file mode 100644
index 0000000..5cb78e4
--- /dev/null
+++ b/car-ui-lib/car-ui-lib/src/main/res/drawable/car_ui_recycler_view_ime_wide_screen_thumb.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 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">
+ <gradient android:startColor="#60A8F0" android:endColor="#60A8F0"
+ android:angle="45"/>
+ <corners android:radius="6dp" />
+</shape>
diff --git a/car-ui-lib/car-ui-lib/src/main/res/layout/car_ui_ims_wide_screen_input_view.xml b/car-ui-lib/car-ui-lib/src/main/res/layout/car_ui_ims_wide_screen_input_view.xml
new file mode 100644
index 0000000..81384ba
--- /dev/null
+++ b/car-ui-lib/car-ui-lib/src/main/res/layout/car_ui_ims_wide_screen_input_view.xml
@@ -0,0 +1,179 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 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.
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="horizontal">
+
+ <RelativeLayout
+ android:layout_width="@dimen/car_ui_ime_wide_screen_keyboard_width"
+ android:layout_height="match_parent"
+ android:gravity="bottom"
+ android:paddingStart="@dimen/car_ui_ime_wide_screen_keyboard_area_padding_start"
+ android:paddingEnd="@dimen/car_ui_ime_wide_screen_keyboard_area_padding_end"
+ android:paddingBottom="@dimen/car_ui_ime_wide_screen_keyboard_area_padding_bottom"
+ android:layout_gravity="bottom"
+ android:background="@drawable/car_ui_ime_wide_screen_background">
+
+ <RelativeLayout
+ android:id="@id/carUiImeWideScreenInputArea"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/car_ui_ime_wide_screen_input_area_height"
+ android:layout_marginTop="@dimen/car_ui_ime_wide_screen_input_area_margin_top"
+ android:layout_alignParentTop="true">
+ <ImageView
+ android:id="@id/closeKeyboard"
+ android:layout_width="@dimen/car_ui_primary_icon_size"
+ android:layout_height="@dimen/car_ui_primary_icon_size"
+ android:layout_centerVertical="true"
+ style="@style/Widget.CarUi.Toolbar.NavIcon"
+ android:layout_alignParentLeft="true"/>
+
+ <FrameLayout
+ android:id="@id/fullscreenArea"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_centerVertical="true"
+ android:layout_toRightOf="@id/closeKeyboard"
+ android:paddingLeft="@dimen/car_ui_ime_wide_screen_input_padding_start"
+ android:background="@drawable/car_ui_ime_wide_screen_input_area_background"
+ android:orientation="vertical">
+
+ <FrameLayout
+ android:id="@id/inputExtractEditTextContainer"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:scrollbars="vertical"
+ android:gravity="left|center"
+ android:backgroundTint="@drawable/car_ui_ime_wide_screen_input_area_tint_color"
+ android:minLines="1"
+ android:inputType="text"/>
+
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@android:color/transparent">
+ <ImageView
+ android:id="@id/wideScreenExtractedTextIcon"
+ android:layout_width="@dimen/car_ui_primary_icon_size"
+ android:layout_height="@dimen/car_ui_primary_icon_size"
+ android:gravity="center"
+ android:layout_gravity="center"
+ android:layout_alignParentLeft="true"
+ android:layout_centerVertical="true"/>
+
+ <ImageView
+ android:id="@id/wideScreenClearData"
+ android:layout_width="@dimen/car_ui_primary_icon_size"
+ android:layout_height="@dimen/car_ui_primary_icon_size"
+ android:gravity="center"
+ android:layout_gravity="center"
+ android:background="@drawable/car_ui_icon_close"
+ android:layout_alignParentRight="true"
+ android:layout_centerVertical="true"/>
+
+ <ImageView
+ android:id="@id/wideScreenError"
+ android:layout_width="@dimen/car_ui_primary_icon_size"
+ android:layout_height="@dimen/car_ui_primary_icon_size"
+ android:gravity="center"
+ android:layout_gravity="center"
+ android:background="@drawable/car_ui_icon_error"
+ android:layout_alignParentRight="true"
+ android:layout_centerVertical="true"
+ android:visibility="gone"/>
+ </RelativeLayout>
+
+ </FrameLayout>
+ </RelativeLayout>
+
+ <TextView
+ android:id="@id/wideScreenErrorMessage"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_below="@id/carUiImeWideScreenInputArea"
+ android:paddingLeft="@dimen/car_ui_ime_wide_screen_error_text_padding_start"
+ android:textColor="@color/car_ui_ime_wide_screen_error_text_color"
+ android:visibility="gone"
+ android:textSize="@dimen/car_ui_ime_wide_screen_error_text_size"/>
+
+ <FrameLayout
+ android:id="@id/carUiWideScreenInputArea"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_alignParentBottom="true">
+ </FrameLayout>
+ </RelativeLayout>
+
+ <View
+ android:layout_width="@dimen/car_ui_ime_wide_screen_divider_width"
+ android:layout_height="match_parent"
+ android:background="@color/car_ui_ime_wide_screen_divider_color"/>
+
+ <RelativeLayout
+ android:id="@id/contentAreaAutomotive"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@drawable/car_ui_ime_wide_screen_no_content_background">
+ <androidx.recyclerview.widget.RecyclerView
+ android:id="@id/wideScreenSearchResultList"
+ android:scrollbarThumbVertical="@drawable/car_ui_recycler_view_ime_wide_screen_thumb"
+ android:scrollbars="vertical"
+ android:requiresFadingEdge="vertical"
+ android:paddingTop="@dimen/car_ui_ime_wide_screen_recycler_view_padding_top"
+ android:layout_width="match_parent"
+ android:visibility="gone"
+ android:layout_height="match_parent"/>
+ <TextView
+ android:id="@id/wideScreenDescriptionTitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_marginTop="@dimen/car_ui_ime_wide_screen_description_title_margin_top"
+ android:paddingLeft="@dimen/car_ui_ime_wide_screen_description_title_padding_left"
+ android:textColor="@color/car_ui_ime_wide_screen_description_title_color"
+ android:textSize="@dimen/car_ui_ime_wide_screen_description_title_text_size"
+ android:visibility="gone"/>
+ <TextView
+ android:id="@id/wideScreenDescription"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/wideScreenDescriptionTitle"
+ android:layout_alignParentLeft="true"
+ android:paddingLeft="@dimen/car_ui_ime_wide_screen_description_title_padding_left"
+ android:paddingTop="@dimen/car_ui_ime_wide_screen_description_padding_top"
+ android:textColor="@color/car_ui_ime_wide_screen_description_color"
+ android:textSize="@dimen/car_ui_ime_wide_screen_description_text_size"
+ android:visibility="gone"/>
+
+ <Button
+ android:id="@id/inputExtractActionAutomotive"
+ android:layout_width="wrap_content"
+ android:layout_height="@dimen/car_ui_ime_wide_screen_action_button_height"
+ android:theme="@android:style/Theme.DeviceDefault"
+ android:textSize="@dimen/car_ui_ime_wide_screen_action_button_text_size"
+ android:layout_alignParentBottom="true"
+ android:visibility="gone"
+ android:layout_marginBottom="@dimen/car_ui_ime_wide_screen_action_button_margin_bottom"
+ android:layout_marginLeft="@dimen/car_ui_ime_wide_screen_action_button_margin_left"
+ android:layout_gravity="center"/>
+ </RelativeLayout>
+
+</LinearLayout>
diff --git a/car-ui-lib/car-ui-lib/src/main/res/values/bools.xml b/car-ui-lib/car-ui-lib/src/main/res/values/bools.xml
index f53ee3f..b34d620 100644
--- a/car-ui-lib/car-ui-lib/src/main/res/values/bools.xml
+++ b/car-ui-lib/car-ui-lib/src/main/res/values/bools.xml
@@ -66,4 +66,10 @@
<!-- If there is no positive/negative/neutral button, should we add one that says "dismiss"? -->
<bool name="car_ui_alert_dialog_force_dismiss_button">true</bool>
+ <!-- Whether or not to allow application to hide the content area in IME wide screen. -->
+ <bool name="car_ui_ime_wide_screen_allow_app_hide_content_area">true</bool>
+
+ <!-- Whether IME is aligned left or not(which means its on right). This value will be used by
+ the applications not using car-ui-lib components and are hiding the content area. -->
+ <bool name="car_ui_ime_wide_screen_aligned_left">true</bool>
</resources>
diff --git a/car-ui-lib/car-ui-lib/src/main/res/values/colors.xml b/car-ui-lib/car-ui-lib/src/main/res/values/colors.xml
index 326dcfb..b407cb6 100644
--- a/car-ui-lib/car-ui-lib/src/main/res/values/colors.xml
+++ b/car-ui-lib/car-ui-lib/src/main/res/values/colors.xml
@@ -52,4 +52,13 @@
<color name="car_ui_rotary_focus_pressed_fill_color">#8A94CBFF</color>
<color name="car_ui_rotary_focus_stroke_secondary_color">#0059B3</color>
<color name="car_ui_rotary_focus_fill_secondary_color">#3D0059B3</color>
+
+ <!-- IME wide screen -->
+
+ <color name="car_ui_ime_wide_screen_error_text_color">#F00</color>
+ <color name="car_ui_ime_wide_screen_divider_color">#2E3134</color>
+ <color name="car_ui_ime_wide_screen_description_title_color">#FFF</color>
+ <color name="car_ui_ime_wide_screen_description_color">#FFF</color>
+ <color name="car_ui_ime_wide_screen_search_item_title_color">#FFF</color>
+ <color name="car_ui_ime_wide_screen_search_item_sub_title_color">#FFF</color>
</resources>
diff --git a/car-ui-lib/car-ui-lib/src/main/res/values/dimens.xml b/car-ui-lib/car-ui-lib/src/main/res/values/dimens.xml
index b2eaadc..d355f99 100644
--- a/car-ui-lib/car-ui-lib/src/main/res/values/dimens.xml
+++ b/car-ui-lib/car-ui-lib/src/main/res/values/dimens.xml
@@ -212,4 +212,39 @@
<dimen name="car_ui_rotary_focus_stroke_width">8dp</dimen>
<dimen name="car_ui_rotary_focus_pressed_stroke_width">4dp</dimen>
+ <!-- IME wide screen -->
+ <dimen name="car_ui_ime_wide_screen_keyboard_width">1250dp</dimen>
+ <dimen name="car_ui_ime_wide_screen_keyboard_area_padding_start">36dp</dimen>
+ <dimen name="car_ui_ime_wide_screen_keyboard_area_padding_end">36dp</dimen>
+ <dimen name="car_ui_ime_wide_screen_keyboard_area_padding_bottom">40dp</dimen>
+ <dimen name="car_ui_ime_wide_screen_input_area_height">96dp</dimen>
+ <dimen name="car_ui_ime_wide_screen_input_area_margin_top">56dp</dimen>
+ <dimen name="car_ui_ime_wide_screen_input_padding_start">36dp</dimen>
+ <dimen name="car_ui_ime_wide_screen_input_edit_text_padding_left">68dp</dimen>
+ <dimen name="car_ui_ime_wide_screen_input_edit_text_padding_right">0dp</dimen>
+ <dimen name="car_ui_ime_wide_screen_input_edit_text_size">68dp</dimen>
+ <dimen name="car_ui_ime_wide_screen_error_text_padding_start">68dp</dimen>
+ <dimen name="car_ui_ime_wide_screen_error_text_size">24dp</dimen>
+
+ <dimen name="car_ui_ime_wide_screen_divider_width">5dp</dimen>
+
+ <dimen name="car_ui_ime_wide_screen_recycler_view_padding_top">100dp</dimen>
+ <dimen name="car_ui_ime_wide_screen_description_title_margin_top">190dp</dimen>
+ <dimen name="car_ui_ime_wide_screen_description_title_padding_left">36dp</dimen>
+ <dimen name="car_ui_ime_wide_screen_description_title_text_size">44dp</dimen>
+ <dimen name="car_ui_ime_wide_screen_description_text_size">32dp</dimen>
+ <dimen name="car_ui_ime_wide_screen_description_padding_top">16dp</dimen>
+ <dimen name="car_ui_ime_wide_screen_action_button_text_size">32dp</dimen>
+ <dimen name="car_ui_ime_wide_screen_action_button_margin_bottom">40dp</dimen>
+ <dimen name="car_ui_ime_wide_screen_action_button_margin_left">36dp</dimen>
+ <dimen name="car_ui_ime_wide_screen_action_button_height">88dp</dimen>
+
+ <dimen name="car_ui_ime_wide_search_item_icon_size">116dp</dimen>
+ <dimen name="car_ui_ime_wide_search_item_title_text_size">32dp</dimen>
+ <dimen name="car_ui_ime_wide_search_item_title_padding_left">24dp</dimen>
+ <dimen name="car_ui_ime_wide_search_item_title_padding_top">22dp</dimen>
+ <dimen name="car_ui_ime_wide_search_item_sub_title_padding_left">24dp</dimen>
+ <dimen name="car_ui_ime_wide_search_item_sub_title_padding_top">22dp</dimen>
+ <dimen name="car_ui_ime_wide_search_item_sub_title_text_size">24dp</dimen>
+ <dimen name="car_ui_ime_wide_search_item_secondary_image_padding_left">36dp</dimen>
</resources>
diff --git a/car-ui-lib/car-ui-lib/src/main/res/values/drawables.xml b/car-ui-lib/car-ui-lib/src/main/res/values/drawables.xml
index 181846c..34ee538 100644
--- a/car-ui-lib/car-ui-lib/src/main/res/values/drawables.xml
+++ b/car-ui-lib/car-ui-lib/src/main/res/values/drawables.xml
@@ -36,4 +36,25 @@
<item name="car_ui_preference_icon_chevron_enabled" type="drawable">@null</item>
<!-- Overlayable drawable to use for the preference chevron when preference is disabled -->
<item name="car_ui_preference_icon_chevron_disabled" type="drawable">@null</item>
+
+ <!-- IME wide screen -->
+
+ <!-- Background of the entire area other than content area which is
+ input text box and keyboard. -->
+ <drawable name="car_ui_ime_wide_screen_background">#000</drawable>
+
+ <!-- Background of the content area. -->
+ <drawable name="car_ui_ime_wide_screen_content_area_background">#000</drawable>
+
+ <!-- Background of the content area when there is no content. -->
+ <drawable name="car_ui_ime_wide_screen_no_content_background">#cc000000</drawable>
+
+ <!-- Background of the input area. -->
+ <drawable name="car_ui_ime_wide_screen_input_area_background">#000</drawable>
+
+ <!-- Tint color of input area in wide screen with error string. -->
+ <drawable name="car_ui_ime_wide_screen_input_area_tint_error_color">#f00</drawable>
+
+ <!-- Tint color of input area in wide screen. -->
+ <drawable name="car_ui_ime_wide_screen_input_area_tint_color">#f5f5f5</drawable>
</resources>
diff --git a/car-ui-lib/car-ui-lib/src/main/res/values/ids.xml b/car-ui-lib/car-ui-lib/src/main/res/values/ids.xml
index 3f0c9b1..21eb30a 100644
--- a/car-ui-lib/car-ui-lib/src/main/res/values/ids.xml
+++ b/car-ui-lib/car-ui-lib/src/main/res/values/ids.xml
@@ -19,4 +19,24 @@
<!-- Id used for in car_ui_toolbar_menu_item.xml -->
<item name="car_ui_toolbar_menu_item_text_container" type="id"/>
+
+ <item type="id" name="carUiImeWideScreenInputArea"/>
+ <item type="id" name="closeKeyboard"/>
+ <item type="id" name="fullscreenArea"/>
+ <item type="id" name="wideScreenErrorMessage"/>
+ <item type="id" name="carUiWideScreenInputArea"/>
+ <item type="id" name="contentAreaAutomotive"/>
+ <item type="id" name="wideScreenSearchResultList"/>
+ <item type="id" name="wideScreenDescriptionTitle"/>
+ <item type="id" name="wideScreenDescription"/>
+ <item type="id" name="inputExtractActionAutomotive"/>
+ <item type="id" name="inputExtractEditText"/>
+ <item type="id" name="wideScreenExtractedTextIcon"/>
+ <item type="id" name="wideScreenClearData"/>
+ <item type="id" name="wideScreenError"/>
+ <item type="id" name="wideScreenSearchItemPrimaryImageView"/>
+ <item type="id" name="wideScreenSearchItemTitle"/>
+ <item type="id" name="wideScreenSearchItemSubTitle"/>
+ <item type="id" name="wideScreenSearchItemSecondaryImageView"/>
+ <item type="id" name="inputExtractEditTextContainer"/>
</resources>
diff --git a/car-ui-lib/car-ui-lib/src/main/res/values/strings.xml b/car-ui-lib/car-ui-lib/src/main/res/values/strings.xml
index 46a29fe..8956411 100644
--- a/car-ui-lib/car-ui-lib/src/main/res/values/strings.xml
+++ b/car-ui-lib/car-ui-lib/src/main/res/values/strings.xml
@@ -39,9 +39,11 @@
<string name="car_ui_toolbar_menu_item_overflow_title">Overflow</string>
<!-- Positive option for a preference dialog. [CHAR_LIMIT=30] -->
- <string name="car_ui_dialog_preference_positive" translatable="false">@android:string/ok</string>
+ <string name="car_ui_dialog_preference_positive" translatable="false">@android:string/ok
+ </string>
<!-- Negative option for a preference dialog. [CHAR_LIMIT=30] -->
- <string name="car_ui_dialog_preference_negative" translatable="false">@android:string/cancel</string>
+ <string name="car_ui_dialog_preference_negative" translatable="false">@android:string/cancel
+ </string>
<!-- Text to show when a preference switch is on. [CHAR_LIMIT=30] -->
<string name="car_ui_preference_switch_on">On</string>
<!-- Text to show when a preference switch is off. [CHAR_LIMIT=30] -->
@@ -61,4 +63,17 @@
<!-- Clients should override this value instead of changing the process name -->
<!-- from manifest file. -->
<string name="car_ui_installer_process_name" translatable="false"></string>
+
+ <!--
+ List of packages allowed to hide the content area in wide screen mode when
+ bool/car_ui_ime_wide_screen_allow_app_hide_content_area is set to false. Each package name
+ should be separated by a ",". For example, "com.package1,com.package2,com.package3" will allow
+ packages "com.package1", "com.package2" and "com.package3" to hide the content area.
+ -->
+ <string name="car_ui_ime_wide_screen_allowed_package_list" translatable="false"></string>
+
+ <!-- Name of system property used to determine when wide screen mode is used. -->
+ <string name="car_ui_ime_wide_screen_system_property_name" translatable="false">
+ ro.build.automotive.ime.wide_screen.enabled
+ </string>
</resources>
diff --git a/car-ui-lib/paintbooth/src/main/java/com/android/car/ui/paintbooth/caruirecyclerview/CarUiListItemActivity.java b/car-ui-lib/paintbooth/src/main/java/com/android/car/ui/paintbooth/caruirecyclerview/CarUiListItemActivity.java
index 1819427..68ec45b 100644
--- a/car-ui-lib/paintbooth/src/main/java/com/android/car/ui/paintbooth/caruirecyclerview/CarUiListItemActivity.java
+++ b/car-ui-lib/paintbooth/src/main/java/com/android/car/ui/paintbooth/caruirecyclerview/CarUiListItemActivity.java
@@ -191,6 +191,11 @@
item = new CarUiContentListItem(CarUiContentListItem.Action.ICON);
item.setTitle("Supplemental icon with listener");
+ item.setPrimaryIconType(CarUiContentListItem.IconType.CONTENT);
+ item.setIcon(getDrawable(R.drawable.ic_launcher));
+ item.setBody("body");
+ item.setOnItemClickedListener(v -> Toast.makeText(context, "Clicked item",
+ Toast.LENGTH_SHORT).show());
item.setSupplementalIcon(getDrawable(R.drawable.ic_launcher),
v -> Toast.makeText(context, "Clicked supplemental icon",
Toast.LENGTH_SHORT).show());
diff --git a/car-ui-lib/tests/apitest/current.xml b/car-ui-lib/tests/apitest/current.xml
index 6abc24d..a018f18 100644
--- a/car-ui-lib/tests/apitest/current.xml
+++ b/car-ui-lib/tests/apitest/current.xml
@@ -11,6 +11,8 @@
<public type="bool" name="car_ui_enable_focus_area_foreground_highlight"/>
<public type="bool" name="car_ui_escrow_check_components_automatically"/>
<public type="bool" name="car_ui_focus_area_default_focus_overrides_history"/>
+ <public type="bool" name="car_ui_ime_wide_screen_aligned_left"/>
+ <public type="bool" name="car_ui_ime_wide_screen_allow_app_hide_content_area"/>
<public type="bool" name="car_ui_list_item_single_line_title"/>
<public type="bool" name="car_ui_preference_list_show_full_screen"/>
<public type="bool" name="car_ui_preference_show_chevron"/>
@@ -23,6 +25,12 @@
<public type="color" name="car_ui_activity_background_color"/>
<public type="color" name="car_ui_color_accent"/>
<public type="color" name="car_ui_dialog_icon_color"/>
+ <public type="color" name="car_ui_ime_wide_screen_description_color"/>
+ <public type="color" name="car_ui_ime_wide_screen_description_title_color"/>
+ <public type="color" name="car_ui_ime_wide_screen_divider_color"/>
+ <public type="color" name="car_ui_ime_wide_screen_error_text_color"/>
+ <public type="color" name="car_ui_ime_wide_screen_search_item_sub_title_color"/>
+ <public type="color" name="car_ui_ime_wide_screen_search_item_title_color"/>
<public type="color" name="car_ui_list_item_divider"/>
<public type="color" name="car_ui_preference_icon_color"/>
<public type="color" name="car_ui_preference_two_action_divider_color"/>
@@ -58,6 +66,37 @@
<public type="dimen" name="car_ui_dialog_title_margin"/>
<public type="dimen" name="car_ui_divider_width"/>
<public type="dimen" name="car_ui_header_list_item_text_start_margin"/>
+ <public type="dimen" name="car_ui_ime_wide_screen_action_button_height"/>
+ <public type="dimen" name="car_ui_ime_wide_screen_action_button_margin_bottom"/>
+ <public type="dimen" name="car_ui_ime_wide_screen_action_button_margin_left"/>
+ <public type="dimen" name="car_ui_ime_wide_screen_action_button_text_size"/>
+ <public type="dimen" name="car_ui_ime_wide_screen_description_padding_top"/>
+ <public type="dimen" name="car_ui_ime_wide_screen_description_text_size"/>
+ <public type="dimen" name="car_ui_ime_wide_screen_description_title_margin_top"/>
+ <public type="dimen" name="car_ui_ime_wide_screen_description_title_padding_left"/>
+ <public type="dimen" name="car_ui_ime_wide_screen_description_title_text_size"/>
+ <public type="dimen" name="car_ui_ime_wide_screen_divider_width"/>
+ <public type="dimen" name="car_ui_ime_wide_screen_error_text_padding_start"/>
+ <public type="dimen" name="car_ui_ime_wide_screen_error_text_size"/>
+ <public type="dimen" name="car_ui_ime_wide_screen_input_area_height"/>
+ <public type="dimen" name="car_ui_ime_wide_screen_input_area_margin_top"/>
+ <public type="dimen" name="car_ui_ime_wide_screen_input_edit_text_padding_left"/>
+ <public type="dimen" name="car_ui_ime_wide_screen_input_edit_text_padding_right"/>
+ <public type="dimen" name="car_ui_ime_wide_screen_input_edit_text_size"/>
+ <public type="dimen" name="car_ui_ime_wide_screen_input_padding_start"/>
+ <public type="dimen" name="car_ui_ime_wide_screen_keyboard_area_padding_bottom"/>
+ <public type="dimen" name="car_ui_ime_wide_screen_keyboard_area_padding_end"/>
+ <public type="dimen" name="car_ui_ime_wide_screen_keyboard_area_padding_start"/>
+ <public type="dimen" name="car_ui_ime_wide_screen_keyboard_width"/>
+ <public type="dimen" name="car_ui_ime_wide_screen_recycler_view_padding_top"/>
+ <public type="dimen" name="car_ui_ime_wide_search_item_icon_size"/>
+ <public type="dimen" name="car_ui_ime_wide_search_item_secondary_image_padding_left"/>
+ <public type="dimen" name="car_ui_ime_wide_search_item_sub_title_padding_left"/>
+ <public type="dimen" name="car_ui_ime_wide_search_item_sub_title_padding_top"/>
+ <public type="dimen" name="car_ui_ime_wide_search_item_sub_title_text_size"/>
+ <public type="dimen" name="car_ui_ime_wide_search_item_title_padding_left"/>
+ <public type="dimen" name="car_ui_ime_wide_search_item_title_padding_top"/>
+ <public type="dimen" name="car_ui_ime_wide_search_item_title_text_size"/>
<public type="dimen" name="car_ui_list_item_action_divider_height"/>
<public type="dimen" name="car_ui_list_item_action_divider_width"/>
<public type="dimen" name="car_ui_list_item_avatar_icon_height"/>
@@ -170,12 +209,19 @@
<public type="drawable" name="car_ui_icon_delete"/>
<public type="drawable" name="car_ui_icon_down"/>
<public type="drawable" name="car_ui_icon_edit"/>
+ <public type="drawable" name="car_ui_icon_error"/>
<public type="drawable" name="car_ui_icon_lock"/>
<public type="drawable" name="car_ui_icon_overflow_menu"/>
<public type="drawable" name="car_ui_icon_save"/>
<public type="drawable" name="car_ui_icon_search"/>
<public type="drawable" name="car_ui_icon_search_nav_icon"/>
<public type="drawable" name="car_ui_icon_settings"/>
+ <public type="drawable" name="car_ui_ime_wide_screen_background"/>
+ <public type="drawable" name="car_ui_ime_wide_screen_content_area_background"/>
+ <public type="drawable" name="car_ui_ime_wide_screen_input_area_background"/>
+ <public type="drawable" name="car_ui_ime_wide_screen_input_area_tint_color"/>
+ <public type="drawable" name="car_ui_ime_wide_screen_input_area_tint_error_color"/>
+ <public type="drawable" name="car_ui_ime_wide_screen_no_content_background"/>
<public type="drawable" name="car_ui_list_header_background"/>
<public type="drawable" name="car_ui_list_item_avatar_icon_outline"/>
<public type="drawable" name="car_ui_list_item_background"/>
@@ -184,6 +230,7 @@
<public type="drawable" name="car_ui_preference_icon_chevron"/>
<public type="drawable" name="car_ui_preference_icon_chevron_disabled"/>
<public type="drawable" name="car_ui_preference_icon_chevron_enabled"/>
+ <public type="drawable" name="car_ui_recycler_view_ime_wide_screen_thumb"/>
<public type="drawable" name="car_ui_recyclerview_button_ripple_background"/>
<public type="drawable" name="car_ui_recyclerview_divider"/>
<public type="drawable" name="car_ui_recyclerview_ic_down"/>
@@ -201,6 +248,8 @@
<public type="id" name="action_widget_container"/>
<public type="id" name="avatar_icon"/>
<public type="id" name="body"/>
+ <public type="id" name="carUiImeWideScreenInputArea"/>
+ <public type="id" name="carUiWideScreenInputArea"/>
<public type="id" name="car_ui_alert_icon"/>
<public type="id" name="car_ui_alert_subtitle"/>
<public type="id" name="car_ui_alert_title"/>
@@ -250,10 +299,16 @@
<public type="id" name="car_ui_toolbar_title_logo_container"/>
<public type="id" name="car_ui_toolbar_top_guideline"/>
<public type="id" name="checkbox_widget"/>
+ <public type="id" name="closeKeyboard"/>
<public type="id" name="container"/>
+ <public type="id" name="contentAreaAutomotive"/>
<public type="id" name="content_icon"/>
+ <public type="id" name="fullscreenArea"/>
<public type="id" name="icon"/>
<public type="id" name="icon_container"/>
+ <public type="id" name="inputExtractActionAutomotive"/>
+ <public type="id" name="inputExtractEditText"/>
+ <public type="id" name="inputExtractEditTextContainer"/>
<public type="id" name="list"/>
<public type="id" name="nested_recycler_view_layout"/>
<public type="id" name="radio_button"/>
@@ -276,6 +331,17 @@
<public type="id" name="title_template"/>
<public type="id" name="toolbar"/>
<public type="id" name="touch_interceptor"/>
+ <public type="id" name="wideScreenClearData"/>
+ <public type="id" name="wideScreenDescription"/>
+ <public type="id" name="wideScreenDescriptionTitle"/>
+ <public type="id" name="wideScreenError"/>
+ <public type="id" name="wideScreenErrorMessage"/>
+ <public type="id" name="wideScreenExtractedTextIcon"/>
+ <public type="id" name="wideScreenSearchItemPrimaryImageView"/>
+ <public type="id" name="wideScreenSearchItemSecondaryImageView"/>
+ <public type="id" name="wideScreenSearchItemSubTitle"/>
+ <public type="id" name="wideScreenSearchItemTitle"/>
+ <public type="id" name="wideScreenSearchResultList"/>
<public type="integer" name="car_ui_default_max_string_length"/>
<public type="integer" name="car_ui_focus_area_history_cache_type"/>
<public type="integer" name="car_ui_focus_area_history_expiration_period_ms"/>
@@ -290,6 +356,7 @@
<public type="layout" name="car_ui_base_layout_toolbar"/>
<public type="layout" name="car_ui_base_layout_toolbar_legacy"/>
<public type="layout" name="car_ui_header_list_item"/>
+ <public type="layout" name="car_ui_ims_wide_screen_input_view"/>
<public type="layout" name="car_ui_list_item"/>
<public type="layout" name="car_ui_list_limiting_message"/>
<public type="layout" name="car_ui_list_preference"/>
@@ -322,6 +389,8 @@
<public type="string" name="car_ui_dialog_preference_negative"/>
<public type="string" name="car_ui_dialog_preference_positive"/>
<public type="string" name="car_ui_ellipsis"/>
+ <public type="string" name="car_ui_ime_wide_screen_allowed_package_list"/>
+ <public type="string" name="car_ui_ime_wide_screen_system_property_name"/>
<public type="string" name="car_ui_installer_process_name"/>
<public type="string" name="car_ui_preference_switch_off"/>
<public type="string" name="car_ui_preference_switch_on"/>