Provide interfaces from car-ui-lib to support IME wide screen
Add test cases to paintbooth
Bug: 162268101
Bug: 170343703
Test: Manual
Change-Id: Ie84ef9901756fb06292fee423a0bdb721df4a6c4
Merged-In: Ie84ef9901756fb06292fee423a0bdb721df4a6c4
diff --git a/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/AlertDialogBuilder.java b/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/AlertDialogBuilder.java
index 803bb29..e56fa6b 100644
--- a/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/AlertDialogBuilder.java
+++ b/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/AlertDialogBuilder.java
@@ -15,12 +15,19 @@
*/
package com.android.car.ui;
+import static android.view.WindowInsets.Type.ime;
+
+import static com.android.car.ui.imewidescreen.CarUiImeWideScreenController.ADD_DESC_TITLE_TO_CONTENT_AREA;
+import static com.android.car.ui.imewidescreen.CarUiImeWideScreenController.ADD_DESC_TO_CONTENT_AREA;
+import static com.android.car.ui.imewidescreen.CarUiImeWideScreenController.WIDE_SCREEN_ACTION;
+
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.database.Cursor;
import android.graphics.drawable.Drawable;
+import android.os.Bundle;
import android.text.InputFilter;
import android.text.TextUtils;
import android.text.TextWatcher;
@@ -28,6 +35,7 @@
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView;
import android.widget.EditText;
import android.widget.ImageView;
@@ -62,6 +70,34 @@
private boolean mIconTinted;
private boolean mAllowDismissButton = true;
private boolean mHasSingleChoiceBodyButton = false;
+ private EditText mCarUiEditText;
+ private InputMethodManager mInputMethodManager;
+ private String mWideScreenTitle;
+ private String mWideScreenTitleDesc;
+ private ViewGroup mRoot;
+
+ // Whenever the IME is closed and opened again, the title and desc information needs to be
+ // passed to the IME to be rendered. If the information is not passed to the IME the content
+ // area of the IME will render nothing into the content area.
+ private final View.OnApplyWindowInsetsListener mOnApplyWindowInsetsListener = (v, insets) -> {
+ if (insets.isVisible(ime())) {
+ Bundle bundle = new Bundle();
+ String title = mWideScreenTitle != null ? mWideScreenTitle : mTitle.toString();
+ bundle.putString(ADD_DESC_TITLE_TO_CONTENT_AREA, title);
+ if (mWideScreenTitleDesc != null) {
+ bundle.putString(ADD_DESC_TO_CONTENT_AREA, mWideScreenTitleDesc);
+ }
+ mInputMethodManager.sendAppPrivateCommand(mCarUiEditText, WIDE_SCREEN_ACTION,
+ bundle);
+ }
+ return insets;
+ };
+
+ private final AlertDialog.OnDismissListener mOnDismissListener = dialog -> {
+ if (mRoot != null) {
+ mRoot.setOnApplyWindowInsetsListener(null);
+ }
+ };
public AlertDialogBuilder(Context context) {
// Resource id specified as 0 uses the parent contexts resolved value for alertDialogTheme.
@@ -70,6 +106,8 @@
public AlertDialogBuilder(Context context, int themeResId) {
mBuilder = new AlertDialog.Builder(context, themeResId);
+ mInputMethodManager = (InputMethodManager)
+ context.getSystemService(Context.INPUT_METHOD_SERVICE);
mContext = context;
}
@@ -562,7 +600,6 @@
* dismissed when an item is clicked. It will only be dismissed if clicked on a
* button, if no buttons are supplied it's up to the user to dismiss the dialog.
* @return This Builder object to allow for chaining of calls to set methods
- *
* @deprecated Use {@link #setSingleChoiceItems(CarUiRadioButtonListItemAdapter)} instead.
*/
@Deprecated
@@ -619,19 +656,19 @@
View contentView = LayoutInflater.from(mContext).inflate(
R.layout.car_ui_alert_dialog_edit_text, null);
- EditText editText = CarUiUtils.requireViewByRefId(contentView, R.id.textbox);
- editText.setText(prompt);
+ mCarUiEditText = CarUiUtils.requireViewByRefId(contentView, R.id.textbox);
+ mCarUiEditText.setText(prompt);
if (textChangedListener != null) {
- editText.addTextChangedListener(textChangedListener);
+ mCarUiEditText.addTextChangedListener(textChangedListener);
}
if (inputFilters != null) {
- editText.setFilters(inputFilters);
+ mCarUiEditText.setFilters(inputFilters);
}
if (inputType != 0) {
- editText.setInputType(inputType);
+ mCarUiEditText.setInputType(inputType);
}
mBuilder.setView(contentView);
@@ -668,6 +705,19 @@
return this;
}
+ /**
+ * Sets the title and desc related to the dialog within the IMS templates.
+ *
+ * @param title title to be set.
+ * @param desc description related to the dialog.
+ * @return this Builder object to allow for chaining of calls to set methods
+ */
+ public AlertDialogBuilder setEditTextTitleAndDescForWideScreen(String title, String desc) {
+ mWideScreenTitle = title;
+ mWideScreenTitleDesc = desc;
+
+ return this;
+ }
/** Final steps common to both {@link #create()} and {@link #show()} */
private void prepareDialog() {
@@ -723,9 +773,13 @@
// wrap-around. Android will focus on the first view automatically when the dialog is shown,
// and we want it to focus on the title instead of the FocusParkingView, so we put the
// FocusParkingView at the end of dialog window.
- ViewGroup root = (ViewGroup) alertDialog.getWindow().getDecorView().getRootView();
+ mRoot = (ViewGroup) alertDialog.getWindow().getDecorView().getRootView();
FocusParkingView fpv = new FocusParkingView(mContext);
- root.addView(fpv);
+ mRoot.addView(fpv);
+
+ // apply window insets listener to know when IME is visible so we can set title and desc.
+ mRoot.setOnApplyWindowInsetsListener(mOnApplyWindowInsetsListener);
+ setOnDismissListener(mOnDismissListener);
return alertDialog;
}
diff --git a/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/CarUiEditText.java b/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/CarUiEditText.java
new file mode 100644
index 0000000..f451c1e
--- /dev/null
+++ b/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/CarUiEditText.java
@@ -0,0 +1,121 @@
+/*
+ * 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;
+
+import static com.android.car.ui.imewidescreen.CarUiImeWideScreenController.SEARCH_RESULT_ITEM_ID;
+import static com.android.car.ui.imewidescreen.CarUiImeWideScreenController.SEARCH_RESULT_SECONDARY_IMAGE_ID;
+import static com.android.car.ui.imewidescreen.CarUiImeWideScreenController.WIDE_SCREEN_CLEAR_DATA_ACTION;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.util.AttributeSet;
+import android.widget.EditText;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Edit text supporting the callbacks from the IMS.This will be useful in widescreen IME mode to
+ * notify apps of specific action through Interface.
+ */
+public class CarUiEditText extends EditText {
+ /**
+ * Interface for {@link CarUiEditText} to support different actions and callbacks from IME
+ * when running in wide screen mode.
+ */
+ public interface PrivateImeCommandCallback {
+ /**
+ * Called when user clicks on an item in the search results.
+ *
+ * @param itemId the id of the item clicked. This will be the same id that was passed by the
+ * application to the IMS template to display search results.
+ */
+ void onItemClicked(String itemId);
+
+ /**
+ * Called when user clicks on a secondary image within item in the search results.
+ *
+ * @param secondaryImageId the id of the secondary image clicked. This will be the same id
+ * that was passed by the application to the IMS template to display
+ * search results.
+ */
+ void onSecondaryImageClicked(String secondaryImageId);
+ }
+
+ private final Set<PrivateImeCommandCallback> mPrivateImeCommandCallback = new HashSet<>();
+
+ public CarUiEditText(Context context) {
+ super(context);
+ }
+
+ public CarUiEditText(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public CarUiEditText(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ public CarUiEditText(Context context, AttributeSet attrs, int defStyleAttr,
+ int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ @Override
+ public boolean onPrivateIMECommand(String action, Bundle data) {
+
+ if (WIDE_SCREEN_CLEAR_DATA_ACTION.equals(action)) {
+ // clear the text.
+ setText("");
+ }
+
+ if (data == null || mPrivateImeCommandCallback == null) {
+ return false;
+ }
+
+ if (data.getString(SEARCH_RESULT_ITEM_ID) != null) {
+ for (PrivateImeCommandCallback listener : mPrivateImeCommandCallback) {
+ listener.onItemClicked(data.getString(SEARCH_RESULT_ITEM_ID));
+ }
+ }
+
+ if (data.getString(SEARCH_RESULT_SECONDARY_IMAGE_ID) != null) {
+ for (PrivateImeCommandCallback listener : mPrivateImeCommandCallback) {
+ listener.onSecondaryImageClicked(
+ data.getString(SEARCH_RESULT_SECONDARY_IMAGE_ID));
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Registers a new {@link PrivateImeCommandCallback} to the list of
+ * listeners.
+ */
+ public void registerOnPrivateImeCommandListener(PrivateImeCommandCallback listener) {
+ mPrivateImeCommandCallback.add(listener);
+ }
+
+ /**
+ * Unregisters an existing {@link PrivateImeCommandCallback} from the list
+ * of listeners.
+ */
+ public boolean unregisterOnPrivateImeCommandListener(PrivateImeCommandCallback listener) {
+ return mPrivateImeCommandCallback.remove(listener);
+ }
+}
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
index c6905e2..9856019 100644
--- 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
@@ -94,7 +94,7 @@
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";
+ public 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 =
diff --git a/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/toolbar/SearchView.java b/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/toolbar/SearchView.java
index 9506fe1..8bf0fee 100644
--- a/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/toolbar/SearchView.java
+++ b/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/toolbar/SearchView.java
@@ -15,10 +15,20 @@
*/
package com.android.car.ui.toolbar;
+import static android.view.WindowInsets.Type.ime;
+
+import static com.android.car.ui.imewidescreen.CarUiImeWideScreenController.SEARCH_RESULT_ITEM_ID;
+import static com.android.car.ui.imewidescreen.CarUiImeWideScreenController.SEARCH_RESULT_PRIMARY_IMAGE_RES_ID_LIST;
+import static com.android.car.ui.imewidescreen.CarUiImeWideScreenController.SEARCH_RESULT_SECONDARY_IMAGE_ID;
+import static com.android.car.ui.imewidescreen.CarUiImeWideScreenController.SEARCH_RESULT_SECONDARY_IMAGE_RES_ID_LIST;
+import static com.android.car.ui.imewidescreen.CarUiImeWideScreenController.SEARCH_RESULT_SUB_TITLE_LIST;
+import static com.android.car.ui.imewidescreen.CarUiImeWideScreenController.SEARCH_RESULT_TITLE_LIST;
+import static com.android.car.ui.imewidescreen.CarUiImeWideScreenController.WIDE_SCREEN_ACTION;
import static com.android.car.ui.utils.CarUiUtils.requireViewByRefId;
import android.content.Context;
import android.graphics.drawable.Drawable;
+import android.os.Bundle;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
@@ -34,9 +44,15 @@
import androidx.annotation.NonNull;
import androidx.constraintlayout.widget.ConstraintLayout;
+import com.android.car.ui.CarUiEditText;
import com.android.car.ui.R;
+import com.android.car.ui.imewidescreen.CarUiImeSearchListItem;
+import com.android.car.ui.recyclerview.CarUiContentListItem;
+import com.android.car.ui.recyclerview.CarUiListItem;
+import java.util.ArrayList;
import java.util.Collections;
+import java.util.List;
import java.util.Set;
/**
@@ -50,6 +66,7 @@
private final int mStartPaddingWithoutIcon;
private final int mStartPadding;
private final int mEndPadding;
+ private List<CarUiListItem> mWideScreenSearchItemList = new ArrayList<>();
private Set<Toolbar.OnSearchListener> mSearchListeners = Collections.emptySet();
private Set<Toolbar.OnSearchCompletedListener> mSearchCompletedListeners =
Collections.emptySet();
@@ -82,7 +99,7 @@
super(context, attrs, defStyleAttr);
mInputMethodManager = (InputMethodManager)
- getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
+ getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
LayoutInflater inflater = LayoutInflater.from(context);
inflater.inflate(R.layout.car_ui_toolbar_search_view, this, true);
@@ -130,6 +147,18 @@
});
}
+ /**
+ * Apply window inset listener to the search container.
+ */
+ void installWindowInsetsListener(View searchContainer) {
+ searchContainer.getRootView().setOnApplyWindowInsetsListener((v, insets) -> {
+ if (insets.isVisible(ime())) {
+ displaySearchWideScreen();
+ }
+ return insets;
+ });
+ }
+
private boolean isEnter(KeyEvent event) {
boolean result = false;
if (event != null) {
@@ -180,6 +209,71 @@
}
/**
+ * Sets list of search item {@link CarUiListItem} to be displayed in the IMS
+ * template.
+ */
+ public void setSearchItemsForWideScreen(List<CarUiListItem> searchItems) {
+ mWideScreenSearchItemList = searchItems;
+ displaySearchWideScreen();
+ }
+
+ private void displaySearchWideScreen() {
+ if (mWideScreenSearchItemList.isEmpty()) {
+ return;
+ }
+ ArrayList<String> itemIdList = new ArrayList<>();
+ ArrayList<String> titleList = new ArrayList<>();
+ ArrayList<String> subTitleList = new ArrayList<>();
+ ArrayList<Integer> primaryImageResId = new ArrayList<>();
+ ArrayList<String> secondaryItemId = new ArrayList<>();
+ ArrayList<Integer> secondaryImageResId = new ArrayList<>();
+ for (CarUiListItem listItem : mWideScreenSearchItemList) {
+ if (listItem instanceof CarUiContentListItem) {
+ CarUiImeSearchListItem item = (CarUiImeSearchListItem) listItem;
+ itemIdList.add(item.getItemId() != null ? item.getItemId().toString() : null);
+ titleList.add(item.getTitle() != null ? item.getTitle().toString() : null);
+ subTitleList.add(item.getBody() != null ? item.getBody().toString() : null);
+ primaryImageResId.add(item.getIconResId());
+ secondaryItemId.add(item.getSupplementalIconId() != null
+ ? item.getSupplementalIconId().toString() : null);
+ secondaryImageResId.add(item.getSupplementalIconResId());
+ }
+ }
+
+ Bundle bundle = new Bundle();
+ bundle.putStringArrayList(SEARCH_RESULT_ITEM_ID, itemIdList);
+ bundle.putStringArrayList(SEARCH_RESULT_TITLE_LIST, titleList);
+ bundle.putStringArrayList(SEARCH_RESULT_SUB_TITLE_LIST, subTitleList);
+ bundle.putIntegerArrayList(SEARCH_RESULT_PRIMARY_IMAGE_RES_ID_LIST, primaryImageResId);
+ bundle.putStringArrayList(SEARCH_RESULT_SECONDARY_IMAGE_ID, secondaryItemId);
+ bundle.putIntegerArrayList(SEARCH_RESULT_SECONDARY_IMAGE_RES_ID_LIST, secondaryImageResId);
+ mInputMethodManager.sendAppPrivateCommand(mSearchText, WIDE_SCREEN_ACTION, bundle);
+ }
+
+ /**
+ * Registers a new {@link CarUiEditText.PrivateImeCommandCallback} to the list of
+ * listeners.
+ */
+ public void registerOnPrivateImeCommandListener(
+ CarUiEditText.PrivateImeCommandCallback listener) {
+ if (mSearchText instanceof CarUiEditText) {
+ ((CarUiEditText) mSearchText).registerOnPrivateImeCommandListener(listener);
+ }
+ }
+
+ /**
+ * Unregisters an existing {@link CarUiEditText.PrivateImeCommandCallback} from the list
+ * of listeners.
+ */
+ public boolean unregisterOnPrivateImeCommandListener(
+ CarUiEditText.PrivateImeCommandCallback listener) {
+ if (mSearchText instanceof CarUiEditText) {
+ return ((CarUiEditText) mSearchText).unregisterOnPrivateImeCommandListener(listener);
+ }
+ return false;
+ }
+
+ /**
* Sets the search hint.
*
* @param resId A string resource id of the search hint.
diff --git a/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/toolbar/Toolbar.java b/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/toolbar/Toolbar.java
index 45e7dce..3278edd 100644
--- a/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/toolbar/Toolbar.java
+++ b/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/toolbar/Toolbar.java
@@ -30,7 +30,9 @@
import androidx.annotation.StringRes;
import androidx.annotation.XmlRes;
+import com.android.car.ui.CarUiEditText;
import com.android.car.ui.R;
+import com.android.car.ui.recyclerview.CarUiListItem;
import java.util.List;
@@ -651,6 +653,36 @@
return mController.unregisterOnSearchListener(listener);
}
+ /**
+ * Registers a new {@link CarUiEditText.PrivateImeCommandCallback} to the list of
+ * listeners.
+ */
+ @Override
+ public void registerOnPrivateImeCommandListener(
+ CarUiEditText.PrivateImeCommandCallback listener) {
+ mController.registerOnPrivateImeCommandListener(listener);
+ }
+
+ /**
+ * Unregisters an existing {@link CarUiEditText.PrivateImeCommandCallback} from the list
+ * of listeners.
+ */
+ @Override
+ public boolean unregisterOnPrivateImeCommandListener(
+ CarUiEditText.PrivateImeCommandCallback listener) {
+ return mController.unregisterOnPrivateImeCommandListener(listener);
+ }
+
+ /**
+ * Sets a list of search items to be displayed in the IME window when running as a wide screen
+ * mode. This should be called each time the list is updated. For example, when a user is typing
+ * in the input field and the list gets filtered this method should be invoked each time.
+ */
+ @Override
+ public void setSearchItemsForWideScreen(List<CarUiListItem> searchItems) {
+ mController.setSearchItemsForWideScreen(searchItems);
+ }
+
/** Registers a new {@link OnSearchCompletedListener} to the list of listeners. */
@Override
public void registerOnSearchCompletedListener(OnSearchCompletedListener listener) {
diff --git a/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/toolbar/ToolbarController.java b/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/toolbar/ToolbarController.java
index d3e3910..d88259f 100644
--- a/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/toolbar/ToolbarController.java
+++ b/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/toolbar/ToolbarController.java
@@ -24,6 +24,9 @@
import androidx.annotation.StringRes;
import androidx.annotation.XmlRes;
+import com.android.car.ui.CarUiEditText;
+import com.android.car.ui.recyclerview.CarUiListItem;
+
import java.util.List;
/**
@@ -255,8 +258,10 @@
*/
void registerToolbarHeightChangeListener(Toolbar.OnHeightChangedListener listener);
- /** Unregisters an existing {@link Toolbar.OnHeightChangedListener} from the list of
- * listeners. */
+ /**
+ * Unregisters an existing {@link Toolbar.OnHeightChangedListener} from the list of
+ * listeners.
+ */
boolean unregisterToolbarHeightChangeListener(Toolbar.OnHeightChangedListener listener);
/** Registers a new {@link Toolbar.OnTabSelectedListener} to the list of listeners. */
@@ -271,11 +276,32 @@
/** Unregisters an existing {@link Toolbar.OnSearchListener} from the list of listeners. */
boolean unregisterOnSearchListener(Toolbar.OnSearchListener listener);
+ /**
+ * Registers a new {@link CarUiEditText.PrivateImeCommandCallback} to the list of
+ * listeners.
+ */
+ void registerOnPrivateImeCommandListener(CarUiEditText.PrivateImeCommandCallback listener);
+
+ /**
+ * Unregisters an existing {@link CarUiEditText.PrivateImeCommandCallback} from the list
+ * of listeners.
+ */
+ boolean unregisterOnPrivateImeCommandListener(
+ CarUiEditText.PrivateImeCommandCallback listener);
+
+ /**
+ * Sets list of search item {@link CarUiListItem} to be displayed in the IMS
+ * template.
+ */
+ void setSearchItemsForWideScreen(List<CarUiListItem> searchItems);
+
/** Registers a new {@link Toolbar.OnSearchCompletedListener} to the list of listeners. */
void registerOnSearchCompletedListener(Toolbar.OnSearchCompletedListener listener);
- /** Unregisters an existing {@link Toolbar.OnSearchCompletedListener} from the list of
- * listeners. */
+ /**
+ * Unregisters an existing {@link Toolbar.OnSearchCompletedListener} from the list of
+ * listeners.
+ */
boolean unregisterOnSearchCompletedListener(Toolbar.OnSearchCompletedListener listener);
/** Registers a new {@link Toolbar.OnBackListener} to the list of listeners. */
diff --git a/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/toolbar/ToolbarControllerImpl.java b/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/toolbar/ToolbarControllerImpl.java
index c3ce075..f89d420 100644
--- a/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/toolbar/ToolbarControllerImpl.java
+++ b/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/toolbar/ToolbarControllerImpl.java
@@ -42,6 +42,7 @@
import androidx.annotation.XmlRes;
import com.android.car.ui.AlertDialogBuilder;
+import com.android.car.ui.CarUiEditText;
import com.android.car.ui.R;
import com.android.car.ui.recyclerview.CarUiContentListItem;
import com.android.car.ui.recyclerview.CarUiListItem;
@@ -112,6 +113,7 @@
private boolean mNavIconSpaceReserved;
private boolean mLogoFillsNavIconSpace;
private boolean mShowLogo;
+ private List<CarUiListItem> mSearchItems;
private final ProgressBarController mProgressBar;
private final MenuItem.Listener mOverflowItemListener = item -> {
updateOverflowDialog(item);
@@ -713,6 +715,12 @@
ViewGroup.LayoutParams.MATCH_PARENT);
mSearchViewContainer.addView(searchView, layoutParams);
+ searchView.installWindowInsetsListener(mSearchViewContainer);
+
+ if (mSearchItems != null) {
+ searchView.setSearchItemsForWideScreen(mSearchItems);
+ }
+
mSearchView = searchView;
}
@@ -863,6 +871,39 @@
return mOnSearchListeners.remove(listener);
}
+ /**
+ * Registers a new {@link CarUiEditText.PrivateImeCommandCallback} to the list of
+ * listeners.
+ */
+ @Override
+ public void registerOnPrivateImeCommandListener(
+ CarUiEditText.PrivateImeCommandCallback listener) {
+ if (mSearchView != null) {
+ mSearchView.registerOnPrivateImeCommandListener(listener);
+ }
+ }
+
+ /**
+ * Unregisters an existing {@link CarUiEditText.PrivateImeCommandCallback} from the list
+ * of listeners.
+ */
+ @Override
+ public boolean unregisterOnPrivateImeCommandListener(
+ CarUiEditText.PrivateImeCommandCallback listener) {
+ if (mSearchView != null) {
+ return mSearchView.unregisterOnPrivateImeCommandListener(listener);
+ }
+ return false;
+ }
+
+ @Override
+ public void setSearchItemsForWideScreen(List<CarUiListItem> searchItems) {
+ mSearchItems = searchItems;
+ if (mSearchView != null) {
+ mSearchView.setSearchItemsForWideScreen(searchItems);
+ }
+ }
+
/** Registers a new {@link Toolbar.OnSearchCompletedListener} to the list of listeners. */
@Override
public void registerOnSearchCompletedListener(Toolbar.OnSearchCompletedListener listener) {
diff --git a/car-ui-lib/car-ui-lib/src/main/res/layout/car_ui_alert_dialog_edit_text.xml b/car-ui-lib/car-ui-lib/src/main/res/layout/car_ui_alert_dialog_edit_text.xml
index d654b2b..378b539 100644
--- a/car-ui-lib/car-ui-lib/src/main/res/layout/car_ui_alert_dialog_edit_text.xml
+++ b/car-ui-lib/car-ui-lib/src/main/res/layout/car_ui_alert_dialog_edit_text.xml
@@ -16,7 +16,7 @@
-->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android">
- <EditText
+ <com.android.car.ui.CarUiEditText
android:id="@+id/textbox"
android:layout_width="match_parent"
android:layout_height="@dimen/car_ui_dialog_edittext_height"
diff --git a/car-ui-lib/car-ui-lib/src/main/res/layout/car_ui_preference_dialog_edittext.xml b/car-ui-lib/car-ui-lib/src/main/res/layout/car_ui_preference_dialog_edittext.xml
index 04c1c37..39b4112 100644
--- a/car-ui-lib/car-ui-lib/src/main/res/layout/car_ui_preference_dialog_edittext.xml
+++ b/car-ui-lib/car-ui-lib/src/main/res/layout/car_ui_preference_dialog_edittext.xml
@@ -33,7 +33,7 @@
android:layout_marginEnd="@dimen/car_ui_preference_edit_text_dialog_message_margin_end"
android:visibility="gone"/>
- <EditText
+ <com.android.car.ui.CarUiEditText
android:id="@android:id/edit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
diff --git a/car-ui-lib/car-ui-lib/src/main/res/layout/car_ui_toolbar_search_view.xml b/car-ui-lib/car-ui-lib/src/main/res/layout/car_ui_toolbar_search_view.xml
index c3ad68d..1c82fff 100644
--- a/car-ui-lib/car-ui-lib/src/main/res/layout/car_ui_toolbar_search_view.xml
+++ b/car-ui-lib/car-ui-lib/src/main/res/layout/car_ui_toolbar_search_view.xml
@@ -19,7 +19,7 @@
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
- <EditText
+ <com.android.car.ui.CarUiEditText
android:id="@+id/car_ui_toolbar_search_bar"
android:layout_height="match_parent"
android:layout_width="match_parent"
diff --git a/car-ui-lib/paintbooth/AndroidManifest.xml b/car-ui-lib/paintbooth/AndroidManifest.xml
index c277ff5..9763b47 100644
--- a/car-ui-lib/paintbooth/AndroidManifest.xml
+++ b/car-ui-lib/paintbooth/AndroidManifest.xml
@@ -72,6 +72,12 @@
android:exported="false"
android:parentActivityName=".MainActivity"/>
<activity
+ android:name=".widescreenime.WideScreenImeActivity"
+ android:windowSoftInputMode="stateHidden|adjustNothing"
+ android:exported="false"
+ android:parentActivityName=".MainActivity">
+ </activity>
+ <activity
android:name=".toolbar.ToolbarActivity"
android:exported="false"
android:parentActivityName=".MainActivity">
diff --git a/car-ui-lib/paintbooth/src/main/java/com/android/car/ui/paintbooth/MainActivity.java b/car-ui-lib/paintbooth/src/main/java/com/android/car/ui/paintbooth/MainActivity.java
index 02b8088..bf50162 100644
--- a/car-ui-lib/paintbooth/src/main/java/com/android/car/ui/paintbooth/MainActivity.java
+++ b/car-ui-lib/paintbooth/src/main/java/com/android/car/ui/paintbooth/MainActivity.java
@@ -46,6 +46,7 @@
import com.android.car.ui.paintbooth.toolbar.NoCarUiToolbarActivity;
import com.android.car.ui.paintbooth.toolbar.OldToolbarActivity;
import com.android.car.ui.paintbooth.toolbar.ToolbarActivity;
+import com.android.car.ui.paintbooth.widescreenime.WideScreenImeActivity;
import com.android.car.ui.paintbooth.widgets.WidgetActivity;
import com.android.car.ui.recyclerview.CarUiRecyclerView;
import com.android.car.ui.toolbar.ToolbarController;
@@ -76,6 +77,7 @@
new ActivityElement("Old toolbar sample", OldToolbarActivity.class),
new ActivityElement("No CarUiToolbar sample", NoCarUiToolbarActivity.class),
new ActivityElement("Widget sample", WidgetActivity.class),
+ new ActivityElement("Wide Screen IME", WideScreenImeActivity.class),
new ActivityElement("ListItem sample", CarUiListItemActivity.class));
private abstract static class ViewHolder extends RecyclerView.ViewHolder {
diff --git a/car-ui-lib/paintbooth/src/main/java/com/android/car/ui/paintbooth/VisibleBoundsSimulator.java b/car-ui-lib/paintbooth/src/main/java/com/android/car/ui/paintbooth/VisibleBoundsSimulator.java
index 63a2aed..b3dfeb1 100644
--- a/car-ui-lib/paintbooth/src/main/java/com/android/car/ui/paintbooth/VisibleBoundsSimulator.java
+++ b/car-ui-lib/paintbooth/src/main/java/com/android/car/ui/paintbooth/VisibleBoundsSimulator.java
@@ -106,15 +106,12 @@
int screenHeight = displayMetrics.heightPixels;
int screenWidth = displayMetrics.widthPixels;
LayoutInflater inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
- WindowManager.LayoutParams params = new WindowManager.LayoutParams(
+ final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
- // WindowManager.LayoutParams.TYPE_DISPLAY_OVERLAY is a hidden api, so
- // use its value here so we can still compile on gradle / google3
- WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW + 26,
+ WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
- | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
- | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS,
+ | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
PixelFormat.TRANSLUCENT);
params.packageName = this.getPackageName();
diff --git a/car-ui-lib/paintbooth/src/main/java/com/android/car/ui/paintbooth/dialogs/DialogsActivity.java b/car-ui-lib/paintbooth/src/main/java/com/android/car/ui/paintbooth/dialogs/DialogsActivity.java
index fd70730..3d390fc 100644
--- a/car-ui-lib/paintbooth/src/main/java/com/android/car/ui/paintbooth/dialogs/DialogsActivity.java
+++ b/car-ui-lib/paintbooth/src/main/java/com/android/car/ui/paintbooth/dialogs/DialogsActivity.java
@@ -147,6 +147,7 @@
new AlertDialogBuilder(this)
.setTitle("Standard Alert Dialog")
.setEditBox("Edit me please", null, null)
+ .setEditTextTitleAndDescForWideScreen("title", "desc from app")
.setPositiveButton("OK", (dialogInterface, i) -> {
})
.show();
diff --git a/car-ui-lib/paintbooth/src/main/java/com/android/car/ui/paintbooth/widescreenime/WideScreenImeActivity.java b/car-ui-lib/paintbooth/src/main/java/com/android/car/ui/paintbooth/widescreenime/WideScreenImeActivity.java
new file mode 100644
index 0000000..09fb578
--- /dev/null
+++ b/car-ui-lib/paintbooth/src/main/java/com/android/car/ui/paintbooth/widescreenime/WideScreenImeActivity.java
@@ -0,0 +1,339 @@
+/*
+ * 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.paintbooth.widescreenime;
+
+import static android.view.inputmethod.EditorInfo.IME_FLAG_NO_EXTRACT_UI;
+
+import static com.android.car.ui.imewidescreen.CarUiImeWideScreenController.ADD_DESC_TITLE_TO_CONTENT_AREA;
+import static com.android.car.ui.imewidescreen.CarUiImeWideScreenController.ADD_DESC_TO_CONTENT_AREA;
+import static com.android.car.ui.imewidescreen.CarUiImeWideScreenController.ADD_ERROR_DESC_TO_INPUT_AREA;
+import static com.android.car.ui.imewidescreen.CarUiImeWideScreenController.REQUEST_RENDER_CONTENT_AREA;
+import static com.android.car.ui.imewidescreen.CarUiImeWideScreenController.SEARCH_RESULT_ITEM_ID;
+import static com.android.car.ui.imewidescreen.CarUiImeWideScreenController.SEARCH_RESULT_PRIMARY_IMAGE_RES_ID_LIST;
+import static com.android.car.ui.imewidescreen.CarUiImeWideScreenController.SEARCH_RESULT_SECONDARY_IMAGE_ID;
+import static com.android.car.ui.imewidescreen.CarUiImeWideScreenController.SEARCH_RESULT_SECONDARY_IMAGE_RES_ID_LIST;
+import static com.android.car.ui.imewidescreen.CarUiImeWideScreenController.SEARCH_RESULT_SUB_TITLE_LIST;
+import static com.android.car.ui.imewidescreen.CarUiImeWideScreenController.SEARCH_RESULT_TITLE_LIST;
+import static com.android.car.ui.imewidescreen.CarUiImeWideScreenController.WIDE_SCREEN_ACTION;
+import static com.android.car.ui.imewidescreen.CarUiImeWideScreenController.WIDE_SCREEN_EXTRACTED_TEXT_ICON_RES_ID;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.util.Pair;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.EditText;
+
+import androidx.annotation.NonNull;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.android.car.ui.CarUiEditText;
+import com.android.car.ui.baselayout.Insets;
+import com.android.car.ui.baselayout.InsetsChangedListener;
+import com.android.car.ui.core.CarUi;
+import com.android.car.ui.imewidescreen.CarUiImeSearchListItem;
+import com.android.car.ui.paintbooth.R;
+import com.android.car.ui.recyclerview.CarUiContentListItem;
+import com.android.car.ui.recyclerview.CarUiListItem;
+import com.android.car.ui.recyclerview.CarUiRecyclerView;
+import com.android.car.ui.toolbar.MenuItem;
+import com.android.car.ui.toolbar.Toolbar;
+import com.android.car.ui.toolbar.ToolbarController;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Activity that shows different scenarios for wide screen ime.
+ */
+public class WideScreenImeActivity extends AppCompatActivity implements InsetsChangedListener {
+
+ private final List<MenuItem> mMenuItems = new ArrayList<>();
+ private final List<Pair<CharSequence, View.OnFocusChangeListener>> mEditText =
+ new ArrayList<>();
+
+ private final ArrayList<String> mItemIdList = new ArrayList<>();
+ private final ArrayList<String> mTitleList = new ArrayList<>();
+ private final ArrayList<String> mSubTitleList = new ArrayList<>();
+ private final ArrayList<Integer> mPrimaryImageResId = new ArrayList<>();
+ private final ArrayList<String> mSecondaryItemId = new ArrayList<>();
+ private final ArrayList<Integer> mSecondaryImageResId = new ArrayList<>();
+
+ private InputMethodManager mInputMethodManager;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.car_ui_recycler_view_activity);
+
+ mInputMethodManager = (InputMethodManager)
+ getSystemService(Context.INPUT_METHOD_SERVICE);
+
+ ToolbarController toolbarNonFinal = CarUi.getToolbar(this);
+ if (toolbarNonFinal == null) {
+ toolbarNonFinal = requireViewById(R.id.toolbar);
+ }
+ ToolbarController toolbar = toolbarNonFinal;
+ toolbar.setTitle(getTitle());
+ toolbar.setState(Toolbar.State.SUBPAGE);
+ toolbar.setLogo(R.drawable.ic_launcher);
+ toolbar.registerOnBackListener(
+ () -> {
+ if (toolbar.getState() == Toolbar.State.SEARCH
+ || toolbar.getState() == Toolbar.State.EDIT) {
+ toolbar.setState(Toolbar.State.SUBPAGE);
+ return true;
+ }
+ return false;
+ });
+
+ final int[] count = {1};
+ CarUiImeSearchListItem item = new CarUiImeSearchListItem(CarUiContentListItem.Action.ICON);
+ item.setItemId("Item Id" + count[0]);
+ item.setTitle("Title " + count[0]);
+ item.setBody("Sub title " + count[0]);
+ item.setIconResId(R.drawable.ic_launcher);
+ item.setSupplementalIconId("Image Id " + count[0]);
+ item.setSupplementalIconResId(R.drawable.ic_launcher);
+
+ List<CarUiListItem> searchItems = new ArrayList<>();
+
+ searchItems.add(item);
+
+ // initial list to display in search view.
+ toolbar.setSearchItemsForWideScreen(searchItems);
+
+ toolbar.registerOnSearchListener((query) -> {
+ count[0]++;
+ CarUiImeSearchListItem item1 = new CarUiImeSearchListItem(
+ CarUiContentListItem.Action.ICON);
+ item1.setItemId("Item Id" + count[0]);
+ item1.setTitle("Title " + count[0]);
+ item1.setBody("Sub title " + count[0]);
+ item1.setIconResId(R.drawable.ic_launcher);
+ item1.setSupplementalIconId("Image Id " + count[0]);
+ item1.setSupplementalIconResId(R.drawable.ic_launcher);
+ searchItems.add(item1);
+
+ toolbar.setSearchItemsForWideScreen(searchItems);
+ });
+
+ mMenuItems.add(MenuItem.builder(this)
+ .setToSearch()
+ .setOnClickListener(i -> {
+ toolbar.setState(Toolbar.State.SEARCH);
+ })
+ .build());
+
+ toolbar.setMenuItems(mMenuItems);
+
+ mEditText.add(Pair.create("Default Input Edit Text field", null));
+
+ mEditText.add(Pair.create("Add Desc to content area",
+ this::addDescToContentArea));
+
+ mEditText.add(Pair.create("Hide the content area",
+ this::hideContentArea));
+
+ mEditText.add(Pair.create("Hide extraction view",
+ this::hideExtractionView));
+
+ for (int i = 0; i < 7; i++) {
+ mItemIdList.add("itemId" + i);
+ mTitleList.add("Title " + i);
+ mSubTitleList.add("subtitle " + i);
+ mPrimaryImageResId.add(R.drawable.ic_launcher);
+ mSecondaryItemId.add("imageId" + i);
+ mSecondaryImageResId.add(R.drawable.ic_launcher);
+ }
+
+ mEditText.add(Pair.create("Show IME list view", this::showImeListView));
+
+ mEditText.add(Pair.create("Add icon to extracted view", this::addIconToExtractedView));
+
+ mEditText.add(
+ Pair.create("Add error message to content area", this::addErrorDescToContentArea));
+
+ CarUiRecyclerView recyclerView = requireViewById(R.id.list);
+ recyclerView.setAdapter(mAdapter);
+ }
+
+ private void addIconToExtractedView(View view, boolean hasFocus) {
+ if (!hasFocus) {
+ return;
+ }
+
+ Bundle bundle = new Bundle();
+ bundle.putInt(WIDE_SCREEN_EXTRACTED_TEXT_ICON_RES_ID, R.drawable.car_ui_icon_edit);
+ mInputMethodManager.sendAppPrivateCommand(view, WIDE_SCREEN_ACTION, bundle);
+ }
+
+ private void addErrorDescToContentArea(View view, boolean hasFocus) {
+ if (!hasFocus) {
+ return;
+ }
+
+ Bundle bundle = new Bundle();
+ bundle.putString(ADD_ERROR_DESC_TO_INPUT_AREA, "Some error message");
+ bundle.putString(ADD_DESC_TITLE_TO_CONTENT_AREA, "Title");
+ bundle.putString(ADD_DESC_TO_CONTENT_AREA, "Description provided by the application");
+ mInputMethodManager.sendAppPrivateCommand(view, WIDE_SCREEN_ACTION, bundle);
+ }
+
+ private void showImeListView(View view, boolean hasFocus) {
+ if (!hasFocus) {
+ return;
+ }
+
+ Bundle bundle = new Bundle();
+
+ EditText editText = (EditText) view;
+ editText.addTextChangedListener(new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+
+ }
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+
+ }
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ mItemIdList.add("itemId " + s.toString());
+ mTitleList.add("Title " + s.toString());
+ mSubTitleList.add("subtitle ");
+ mPrimaryImageResId.add(R.drawable.ic_launcher);
+ mSecondaryItemId.add("imageId" + s.toString());
+ mSecondaryImageResId.add(R.drawable.ic_launcher);
+
+ bundle.putStringArrayList(SEARCH_RESULT_TITLE_LIST, mTitleList);
+ bundle.putStringArrayList(SEARCH_RESULT_SUB_TITLE_LIST, mSubTitleList);
+ bundle.putIntegerArrayList(SEARCH_RESULT_PRIMARY_IMAGE_RES_ID_LIST,
+ mPrimaryImageResId);
+ mInputMethodManager.sendAppPrivateCommand(view, WIDE_SCREEN_ACTION, bundle);
+ }
+ });
+
+ bundle.putStringArrayList(SEARCH_RESULT_ITEM_ID, mItemIdList);
+ bundle.putStringArrayList(SEARCH_RESULT_TITLE_LIST, mTitleList);
+ bundle.putStringArrayList(SEARCH_RESULT_SUB_TITLE_LIST, mSubTitleList);
+ bundle.putStringArrayList(SEARCH_RESULT_SECONDARY_IMAGE_ID, mSecondaryItemId);
+ bundle.putIntegerArrayList(SEARCH_RESULT_PRIMARY_IMAGE_RES_ID_LIST, mPrimaryImageResId);
+ bundle.putIntegerArrayList(SEARCH_RESULT_SECONDARY_IMAGE_RES_ID_LIST, mSecondaryImageResId);
+ mInputMethodManager.sendAppPrivateCommand(view, WIDE_SCREEN_ACTION, bundle);
+ }
+
+ private void hideExtractionView(View view, boolean hasFocus) {
+ if (!hasFocus) {
+ return;
+ }
+
+ EditText editText = (EditText) view;
+ editText.setImeOptions(IME_FLAG_NO_EXTRACT_UI);
+
+ Bundle bundle = new Bundle();
+ bundle.putBoolean(REQUEST_RENDER_CONTENT_AREA, false);
+ mInputMethodManager.sendAppPrivateCommand(view, WIDE_SCREEN_ACTION, bundle);
+ }
+
+ private void addDescToContentArea(View view, boolean hasFocus) {
+ if (!hasFocus) {
+ return;
+ }
+
+ Bundle bundle = new Bundle();
+ bundle.putString(ADD_DESC_TITLE_TO_CONTENT_AREA, "Title");
+ bundle.putString(ADD_DESC_TO_CONTENT_AREA, "Description provided by the application");
+ mInputMethodManager.sendAppPrivateCommand(view, WIDE_SCREEN_ACTION, bundle);
+ }
+
+ private void hideContentArea(View view, boolean hasFocus) {
+ if (!hasFocus) {
+ return;
+ }
+
+ Bundle bundle = new Bundle();
+ bundle.putBoolean(REQUEST_RENDER_CONTENT_AREA, false);
+ mInputMethodManager.sendAppPrivateCommand(view, WIDE_SCREEN_ACTION, bundle);
+ }
+
+
+ private static class ViewHolder extends RecyclerView.ViewHolder {
+
+ private final CarUiEditText mEditText;
+
+ ViewHolder(View itemView) {
+ super(itemView);
+ mEditText = itemView.requireViewById(R.id.edit_text);
+ mEditText.registerOnPrivateImeCommandListener(
+ new CarUiEditText.PrivateImeCommandCallback() {
+
+ @Override
+ public void onItemClicked(String itemId) {
+ }
+
+ @Override
+ public void onSecondaryImageClicked(String secondaryImageId) {
+ }
+ });
+ }
+
+ public void bind(CharSequence title, View.OnFocusChangeListener listener) {
+ mEditText.setText(title);
+ mEditText.setOnFocusChangeListener(listener);
+ }
+ }
+
+ private final RecyclerView.Adapter<ViewHolder> mAdapter =
+ new RecyclerView.Adapter<ViewHolder>() {
+ @Override
+ public int getItemCount() {
+ return mEditText.size();
+ }
+
+ @Override
+ public ViewHolder onCreateViewHolder(ViewGroup parent, int position) {
+ View item =
+ LayoutInflater.from(parent.getContext())
+ .inflate(R.layout.edit_text_list_item,
+ parent, false);
+
+ return new ViewHolder(item);
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
+ Pair<CharSequence, View.OnFocusChangeListener> pair = mEditText.get(position);
+ holder.bind(pair.first, pair.second);
+ }
+ };
+
+ @Override
+ public void onCarUiInsetsChanged(@NonNull Insets insets) {
+ requireViewById(R.id.list)
+ .setPadding(0, insets.getTop(), 0, insets.getBottom());
+ requireViewById(android.R.id.content)
+ .setPadding(insets.getLeft(), 0, insets.getRight(), 0);
+ }
+}
diff --git a/car-ui-lib/paintbooth/src/main/res/layout/edit_text_list_item.xml b/car-ui-lib/paintbooth/src/main/res/layout/edit_text_list_item.xml
new file mode 100644
index 0000000..3475b14
--- /dev/null
+++ b/car-ui-lib/paintbooth/src/main/res/layout/edit_text_list_item.xml
@@ -0,0 +1,29 @@
+<?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.
+ -->
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <com.android.car.ui.CarUiEditText
+ android:id="@+id/edit_text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:inputType="text"
+ android:layout_centerHorizontal="true"
+ android:layout_marginTop="20dp"
+ android:text="Edit Text Box"/>
+</RelativeLayout>