CombinerChain.java revision cbed462d192d0c5af9614f5f997b2768f3d0eb56
1/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.inputmethod.event;
18
19import android.text.SpannableStringBuilder;
20
21import com.android.inputmethod.latin.utils.CollectionUtils;
22
23import java.util.ArrayList;
24
25/**
26 * This class implements the logic chain between receiving events and generating code points.
27 *
28 * Event sources are multiple. It may be a hardware keyboard, a D-PAD, a software keyboard,
29 * or any exotic input source.
30 * This class will orchestrate the composing chain that starts with an event as its input. Each
31 * composer will be given turns one after the other.
32 * The output is composed of two sequences of code points: the first, representing the already
33 * finished combining part, will be shown normally as the composing string, while the second is
34 * feedback on the composing state and will typically be shown with different styling such as
35 * a colored background.
36 */
37public class CombinerChain {
38    // The already combined text, as described above
39    private StringBuilder mCombinedText;
40    // The feedback on the composing state, as described above
41    private SpannableStringBuilder mStateFeedback;
42    private final ArrayList<Combiner> mCombiners;
43
44    /**
45     * Create an combiner chain.
46     *
47     * The combiner chain takes events as inputs and outputs code points and combining state.
48     * For example, if the input language is Japanese, the combining chain will typically perform
49     * kana conversion.
50     *
51     * @param combinerList A list of combiners to be applied in order.
52     */
53    public CombinerChain(final Combiner... combinerList) {
54        mCombiners = CollectionUtils.newArrayList();
55        // The dead key combiner is always active, and always first
56        mCombiners.add(new DeadKeyCombiner());
57        mCombinedText = new StringBuilder();
58        mStateFeedback = new SpannableStringBuilder();
59    }
60
61    public void reset() {
62        mCombinedText.setLength(0);
63        mStateFeedback.clear();
64        for (final Combiner c : mCombiners) {
65            c.reset();
66        }
67    }
68
69    /**
70     * Pass a new event through the whole chain.
71     * @param previousEvents the list of previous events in this composition
72     * @param newEvent the new event to process
73     */
74    public void processEvent(final ArrayList<Event> previousEvents, final Event newEvent) {
75        final ArrayList<Event> modifiablePreviousEvents = new ArrayList<Event>(previousEvents);
76        Event event = newEvent;
77        for (final Combiner combiner : mCombiners) {
78            // A combiner can never return more than one event; it can return several
79            // code points, but they should be encapsulated within one event.
80            event = combiner.processEvent(modifiablePreviousEvents, event);
81            if (null == event) {
82                // Combiners return null if they eat the event.
83                break;
84            }
85        }
86        if (null != event) {
87            mCombinedText.append(event.getTextToCommit());
88        }
89        mStateFeedback.clear();
90        for (int i = mCombiners.size() - 1; i >= 0; --i) {
91            mStateFeedback.append(mCombiners.get(i).getCombiningStateFeedback());
92        }
93    }
94
95    /**
96     * Get the char sequence that should be displayed as the composing word. It may include
97     * styling spans.
98     */
99    public CharSequence getComposingWordWithCombiningFeedback() {
100        final SpannableStringBuilder s = new SpannableStringBuilder(mCombinedText);
101        return s.append(mStateFeedback);
102    }
103}
104