blob: c6905e27de9cc9b30742703c43f2b88ae4a756c2 [file] [log] [blame]
/*
* 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;
}
}