GuidedActionAdapterGroup.java revision c39d9c75590eca86a5e7e32a8824ba04a0d42e9b
1/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5 * in compliance with the License. You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software distributed under the License
10 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11 * or implied. See the License for the specific language governing permissions and limitations under
12 * the License.
13 */
14package android.support.v17.leanback.widget;
15
16import android.content.Context;
17import android.support.annotation.RestrictTo;
18import android.support.v17.leanback.widget.GuidedActionAdapter.ClickListener;
19import android.support.v17.leanback.widget.GuidedActionAdapter.EditListener;
20import android.util.Log;
21import android.util.Pair;
22import android.view.KeyEvent;
23import android.view.View;
24import android.view.ViewParent;
25import android.view.inputmethod.InputMethodManager;
26import android.widget.EditText;
27import android.widget.TextView;
28import android.widget.TextView.OnEditorActionListener;
29
30import java.util.ArrayList;
31
32import static android.support.annotation.RestrictTo.Scope.GROUP_ID;
33
34/**
35 * Internal implementation manages a group of GuidedActionAdapters, control the next action after
36 * editing finished, maintain the Ime open/close status.
37 * @hide
38 */
39@RestrictTo(GROUP_ID)
40public class GuidedActionAdapterGroup {
41
42    private static final String TAG_EDIT = "EditableAction";
43    private static final boolean DEBUG_EDIT = false;
44
45    ArrayList<Pair<GuidedActionAdapter, GuidedActionAdapter>> mAdapters =
46            new ArrayList<Pair<GuidedActionAdapter, GuidedActionAdapter>>();
47    private boolean mImeOpened;
48    private EditListener mEditListener;
49
50    public void addAdpter(GuidedActionAdapter adapter1, GuidedActionAdapter adapter2) {
51        mAdapters.add(new Pair<GuidedActionAdapter, GuidedActionAdapter>(adapter1, adapter2));
52        if (adapter1 != null) {
53            adapter1.mGroup = this;
54        }
55        if (adapter2 != null) {
56            adapter2.mGroup = this;
57        }
58    }
59
60    public GuidedActionAdapter getNextAdapter(GuidedActionAdapter adapter) {
61        for (int i = 0; i < mAdapters.size(); i++) {
62            Pair<GuidedActionAdapter, GuidedActionAdapter> pair = mAdapters.get(i);
63            if (pair.first == adapter) {
64                return pair.second;
65            }
66        }
67        return null;
68    }
69
70    public void setEditListener(EditListener listener) {
71        mEditListener = listener;
72    }
73
74    boolean focusToNextAction(GuidedActionAdapter adapter, GuidedAction action, long nextActionId) {
75        // for ACTION_ID_NEXT, we first find out the matching index in Actions list.
76        int index = 0;
77        if (nextActionId == GuidedAction.ACTION_ID_NEXT) {
78            index = adapter.indexOf(action);
79            if (index < 0) {
80                return false;
81            }
82            // start from next, if reach end, will go next Adapter below
83            index++;
84        }
85
86        do {
87            int size = adapter.getCount();
88            if (nextActionId == GuidedAction.ACTION_ID_NEXT) {
89                while (index < size && !adapter.getItem(index).isFocusable()) {
90                    index++;
91                }
92            } else {
93                while (index < size && adapter.getItem(index).getId() != nextActionId) {
94                    index++;
95                }
96            }
97            if (index < size) {
98                GuidedActionsStylist.ViewHolder vh =
99                        (GuidedActionsStylist.ViewHolder) adapter.getGuidedActionsStylist()
100                                .getActionsGridView().findViewHolderForPosition(index);
101                if (vh != null) {
102                    if (vh.getAction().hasTextEditable()) {
103                        if (DEBUG_EDIT) Log.v(TAG_EDIT, "openIme of next Action");
104                        // open Ime on next action.
105                        openIme(adapter, vh);
106                    } else {
107                        if (DEBUG_EDIT) Log.v(TAG_EDIT, "closeIme and focus to next Action");
108                        // close IME and focus to next (not editable) action
109                        closeIme(vh.itemView);
110                        vh.itemView.requestFocus();
111                    }
112                    return true;
113                }
114                return false;
115            }
116            // search from index 0 of next Adapter
117            adapter = getNextAdapter(adapter);
118            if (adapter == null) {
119                break;
120            }
121            index = 0;
122        } while (true);
123        return false;
124    }
125
126    public void openIme(GuidedActionAdapter adapter, GuidedActionsStylist.ViewHolder avh) {
127        adapter.getGuidedActionsStylist().setEditingMode(avh, avh.getAction(), true);
128        View v = avh.getEditingView();
129        if (v == null || !avh.isInEditingText()) {
130            return;
131        }
132        InputMethodManager mgr = (InputMethodManager)
133                v.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
134        // Make the TextView focusable during editing, avoid the TextView gets accessibility focus
135        // before editing started. see also GuidedActionEditText where setFocusable(false).
136        v.setFocusable(true);
137        v.requestFocus();
138        mgr.showSoftInput(v, 0);
139        if (!mImeOpened) {
140            mImeOpened = true;
141            mEditListener.onImeOpen();
142        }
143    }
144
145    public void closeIme(View v) {
146        if (mImeOpened) {
147            mImeOpened = false;
148            InputMethodManager mgr = (InputMethodManager)
149                    v.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
150            mgr.hideSoftInputFromWindow(v.getWindowToken(), 0);
151            mEditListener.onImeClose();
152        }
153    }
154
155    public void fillAndStay(GuidedActionAdapter adapter, TextView v) {
156        GuidedActionsStylist.ViewHolder avh = adapter.findSubChildViewHolder(v);
157        updateTextIntoAction(avh, v);
158        mEditListener.onGuidedActionEditCanceled(avh.getAction());
159        adapter.getGuidedActionsStylist().setEditingMode(avh, avh.getAction(), false);
160        closeIme(v);
161        avh.itemView.requestFocus();
162    }
163
164    public void fillAndGoNext(GuidedActionAdapter adapter, TextView v) {
165        boolean handled = false;
166        GuidedActionsStylist.ViewHolder avh = adapter.findSubChildViewHolder(v);
167        updateTextIntoAction(avh, v);
168        adapter.performOnActionClick(avh);
169        long nextActionId = mEditListener.onGuidedActionEditedAndProceed(avh.getAction());
170        adapter.getGuidedActionsStylist().setEditingMode(avh, avh.getAction(), false);
171        if (nextActionId != GuidedAction.ACTION_ID_CURRENT
172                && nextActionId != avh.getAction().getId()) {
173            handled = focusToNextAction(adapter, avh.getAction(), nextActionId);
174        }
175        if (!handled) {
176            if (DEBUG_EDIT) Log.v(TAG_EDIT, "closeIme no next action");
177            handled = true;
178            closeIme(v);
179            avh.itemView.requestFocus();
180        }
181    }
182
183    private void updateTextIntoAction(GuidedActionsStylist.ViewHolder avh, TextView v) {
184        GuidedAction action = avh.getAction();
185        if (v == avh.getDescriptionView()) {
186            if (action.getEditDescription() != null) {
187                action.setEditDescription(v.getText());
188            } else {
189                action.setDescription(v.getText());
190            }
191        } else if (v == avh.getTitleView()) {
192            if (action.getEditTitle() != null) {
193                action.setEditTitle(v.getText());
194            } else {
195                action.setTitle(v.getText());
196            }
197        }
198    }
199
200}
201