/* * Copyright (C) 2015 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 android.support.v17.leanback.widget; import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP; import android.content.Context; import android.support.annotation.RestrictTo; import android.support.v17.leanback.widget.GuidedActionAdapter.EditListener; import android.util.Log; import android.util.Pair; import android.view.View; import android.view.inputmethod.InputMethodManager; import android.widget.TextView; import java.util.ArrayList; /** * Internal implementation manages a group of GuidedActionAdapters, control the next action after * editing finished, maintain the Ime open/close status. * @hide */ @RestrictTo(LIBRARY_GROUP) public class GuidedActionAdapterGroup { private static final String TAG_EDIT = "EditableAction"; private static final boolean DEBUG_EDIT = false; ArrayList<Pair<GuidedActionAdapter, GuidedActionAdapter>> mAdapters = new ArrayList<Pair<GuidedActionAdapter, GuidedActionAdapter>>(); private boolean mImeOpened; private EditListener mEditListener; public void addAdpter(GuidedActionAdapter adapter1, GuidedActionAdapter adapter2) { mAdapters.add(new Pair<GuidedActionAdapter, GuidedActionAdapter>(adapter1, adapter2)); if (adapter1 != null) { adapter1.mGroup = this; } if (adapter2 != null) { adapter2.mGroup = this; } } public GuidedActionAdapter getNextAdapter(GuidedActionAdapter adapter) { for (int i = 0; i < mAdapters.size(); i++) { Pair<GuidedActionAdapter, GuidedActionAdapter> pair = mAdapters.get(i); if (pair.first == adapter) { return pair.second; } } return null; } public void setEditListener(EditListener listener) { mEditListener = listener; } boolean focusToNextAction(GuidedActionAdapter adapter, GuidedAction action, long nextActionId) { // for ACTION_ID_NEXT, we first find out the matching index in Actions list. int index = 0; if (nextActionId == GuidedAction.ACTION_ID_NEXT) { index = adapter.indexOf(action); if (index < 0) { return false; } // start from next, if reach end, will go next Adapter below index++; } do { int size = adapter.getCount(); if (nextActionId == GuidedAction.ACTION_ID_NEXT) { while (index < size && !adapter.getItem(index).isFocusable()) { index++; } } else { while (index < size && adapter.getItem(index).getId() != nextActionId) { index++; } } if (index < size) { GuidedActionsStylist.ViewHolder vh = (GuidedActionsStylist.ViewHolder) adapter.getGuidedActionsStylist() .getActionsGridView().findViewHolderForPosition(index); if (vh != null) { if (vh.getAction().hasTextEditable()) { if (DEBUG_EDIT) Log.v(TAG_EDIT, "openIme of next Action"); // open Ime on next action. openIme(adapter, vh); } else { if (DEBUG_EDIT) Log.v(TAG_EDIT, "closeIme and focus to next Action"); // close IME and focus to next (not editable) action closeIme(vh.itemView); vh.itemView.requestFocus(); } return true; } return false; } // search from index 0 of next Adapter adapter = getNextAdapter(adapter); if (adapter == null) { break; } index = 0; } while (true); return false; } public void openIme(GuidedActionAdapter adapter, GuidedActionsStylist.ViewHolder avh) { adapter.getGuidedActionsStylist().setEditingMode(avh, true); View v = avh.getEditingView(); if (v == null || !avh.isInEditingText()) { return; } InputMethodManager mgr = (InputMethodManager) v.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); // Make the TextView focusable during editing, avoid the TextView gets accessibility focus // before editing started. see also GuidedActionEditText where setFocusable(false). v.setFocusable(true); v.requestFocus(); mgr.showSoftInput(v, 0); if (!mImeOpened) { mImeOpened = true; mEditListener.onImeOpen(); } } public void closeIme(View v) { if (mImeOpened) { mImeOpened = false; InputMethodManager mgr = (InputMethodManager) v.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); mgr.hideSoftInputFromWindow(v.getWindowToken(), 0); mEditListener.onImeClose(); } } public void fillAndStay(GuidedActionAdapter adapter, TextView v) { GuidedActionsStylist.ViewHolder avh = adapter.findSubChildViewHolder(v); updateTextIntoAction(avh, v); mEditListener.onGuidedActionEditCanceled(avh.getAction()); adapter.getGuidedActionsStylist().setEditingMode(avh, false); closeIme(v); avh.itemView.requestFocus(); } public void fillAndGoNext(GuidedActionAdapter adapter, TextView v) { boolean handled = false; GuidedActionsStylist.ViewHolder avh = adapter.findSubChildViewHolder(v); updateTextIntoAction(avh, v); adapter.performOnActionClick(avh); long nextActionId = mEditListener.onGuidedActionEditedAndProceed(avh.getAction()); adapter.getGuidedActionsStylist().setEditingMode(avh, false); if (nextActionId != GuidedAction.ACTION_ID_CURRENT && nextActionId != avh.getAction().getId()) { handled = focusToNextAction(adapter, avh.getAction(), nextActionId); } if (!handled) { if (DEBUG_EDIT) Log.v(TAG_EDIT, "closeIme no next action"); handled = true; closeIme(v); avh.itemView.requestFocus(); } } private void updateTextIntoAction(GuidedActionsStylist.ViewHolder avh, TextView v) { GuidedAction action = avh.getAction(); if (v == avh.getDescriptionView()) { if (action.getEditDescription() != null) { action.setEditDescription(v.getText()); } else { action.setDescription(v.getText()); } } else if (v == avh.getTitleView()) { if (action.getEditTitle() != null) { action.setEditTitle(v.getText()); } else { action.setTitle(v.getText()); } } } }