Implement popup suggestions pane
Bug: 5023981 Change-Id: Ie1d69131dbf884a3f6a2beb3ac3427e5437c1486main
parent
e5c705f164
commit
29e7b7ed6e
|
@ -0,0 +1,37 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
/*
|
||||
**
|
||||
** Copyright 2011, 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.
|
||||
*/
|
||||
-->
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
style="?attr/miniKeyboardPanelStyle"
|
||||
>
|
||||
<com.android.inputmethod.latin.MoreSuggestionsView
|
||||
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
|
||||
android:id="@+id/more_suggestions_view"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
latin:keyLabelSize="@dimen/candidate_text_size"
|
||||
latin:keyHintLetterRatio="@fraction/more_suggestions_info_ratio"
|
||||
latin:keyHintLetterColor="@android:color/white"
|
||||
/>
|
||||
</LinearLayout>
|
|
@ -59,6 +59,8 @@
|
|||
<dimen name="key_preview_offset_ics">0.01in</dimen>
|
||||
|
||||
<dimen name="candidate_strip_height">36dip</dimen>
|
||||
<dimen name="more_suggestions_row_height">36dip</dimen>
|
||||
<dimen name="candidate_strip_minimum_height">160sp</dimen>
|
||||
<dimen name="candidate_strip_fading_edge_length">63dip</dimen>
|
||||
<!-- Amount of allowance for selecting keys in a mini popup keyboard by sliding finger. -->
|
||||
<!-- popup_key_height x 1.2 -->
|
||||
|
|
|
@ -67,6 +67,7 @@
|
|||
<dimen name="key_preview_offset_ics">0.05in</dimen>
|
||||
|
||||
<dimen name="candidate_strip_height">44dip</dimen>
|
||||
<dimen name="more_suggestions_row_height">44dip</dimen>
|
||||
<dimen name="candidate_strip_padding">15.0mm</dimen>
|
||||
<dimen name="candidate_min_width">0.3in</dimen>
|
||||
<dimen name="candidate_padding">12dip</dimen>
|
||||
|
|
|
@ -70,9 +70,8 @@
|
|||
<dimen name="key_preview_offset_ics">0.05in</dimen>
|
||||
|
||||
<dimen name="candidate_strip_height">44dip</dimen>
|
||||
<!-- candidate_strip_minimum_height =
|
||||
key_preview_height_holo - key_preview_offset_holo + alpha -->
|
||||
<dimen name="candidate_strip_minimum_height">18mm</dimen>
|
||||
<dimen name="more_suggestions_row_height">44dip</dimen>
|
||||
<dimen name="candidate_strip_minimum_height">200sp</dimen>
|
||||
<dimen name="candidate_strip_padding">15.0mm</dimen>
|
||||
<dimen name="candidate_min_width">46dip</dimen>
|
||||
<dimen name="candidate_padding">8dip</dimen>
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
<attr name="miniKeyboardPanelStyle" format="reference" />
|
||||
<!-- Suggestions strip style -->
|
||||
<attr name="suggestionsStripBackgroundStyle" format="reference" />
|
||||
<attr name="suggestionsPaneViewStyle" format="reference" />
|
||||
<attr name="suggestionBackgroundStyle" format="reference" />
|
||||
<attr name="suggestionPreviewBackgroundStyle" format="reference" />
|
||||
<attr name="candidateViewStyle" format="reference" />
|
||||
|
|
|
@ -77,9 +77,11 @@
|
|||
<dimen name="key_preview_offset_ics">0.05in</dimen>
|
||||
|
||||
<dimen name="candidate_strip_height">40dip</dimen>
|
||||
<!-- candidate_strip_minimum_height =
|
||||
key_preview_height_holo - key_preview_offset_holo + alpha -->
|
||||
<dimen name="candidate_strip_minimum_height">100sp</dimen>
|
||||
<dimen name="more_suggestions_key_horizontal_padding">12dip</dimen>
|
||||
<dimen name="more_suggestions_row_height">40dip</dimen>
|
||||
<dimen name="more_suggestions_slide_allowance">0.2in</dimen>
|
||||
<fraction name="more_suggestions_info_ratio">12%</fraction>
|
||||
<dimen name="candidate_strip_minimum_height">200sp</dimen>
|
||||
<dimen name="candidate_strip_fading_edge_length">63dip</dimen>
|
||||
<dimen name="candidate_strip_padding">0dip</dimen>
|
||||
<dimen name="candidate_min_width">44dip</dimen>
|
||||
|
|
|
@ -79,6 +79,11 @@
|
|||
<item name="android:paddingLeft">@dimen/mini_keyboard_horizontal_edges_padding</item>
|
||||
<item name="android:paddingRight">@dimen/mini_keyboard_horizontal_edges_padding</item>
|
||||
</style>
|
||||
<style
|
||||
name="SuggestionsPaneViewStyle"
|
||||
parent="MiniKeyboardView"
|
||||
>
|
||||
</style>
|
||||
<style name="SuggestionsStripBackgroundStyle">
|
||||
<item name="android:background">@drawable/keyboard_suggest_strip</item>
|
||||
</style>
|
||||
|
@ -235,6 +240,11 @@
|
|||
parent="MiniKeyboardPanelStyle.IceCreamSandwich"
|
||||
>
|
||||
</style>
|
||||
<style
|
||||
name="SuggestionsPaneViewStyle.IceCreamSandwich"
|
||||
parent="MiniKeyboardView.IceCreamSandwich"
|
||||
>
|
||||
</style>
|
||||
<style
|
||||
name="CandidateViewStyle.IceCreamSandwich"
|
||||
parent="SuggestionsStripBackgroundStyle.IceCreamSandwich"
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
<item name="miniKeyboardViewStyle">@style/MiniKeyboardView</item>
|
||||
<item name="miniKeyboardPanelStyle">@style/MiniKeyboardPanelStyle</item>
|
||||
<item name="suggestionsStripBackgroundStyle">@style/SuggestionsStripBackgroundStyle</item>
|
||||
<item name="suggestionsPaneViewStyle">@style/SuggestionsPaneViewStyle</item>
|
||||
<item name="suggestionBackgroundStyle">@style/SuggestionBackgroundStyle</item>
|
||||
<item name="suggestionPreviewBackgroundStyle">@style/SuggestionPreviewBackgroundStyle</item>
|
||||
<item name="candidateViewStyle">@style/CandidateViewStyle</item>
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
<item name="miniKeyboardViewStyle">@style/MiniKeyboardView</item>
|
||||
<item name="miniKeyboardPanelStyle">@style/MiniKeyboardPanelStyle</item>
|
||||
<item name="suggestionsStripBackgroundStyle">@style/SuggestionsStripBackgroundStyle</item>
|
||||
<item name="suggestionsPaneViewStyle">@style/SuggestionsPaneViewStyle</item>
|
||||
<item name="suggestionBackgroundStyle">@style/SuggestionBackgroundStyle</item>
|
||||
<item name="suggestionPreviewBackgroundStyle">@style/SuggestionPreviewBackgroundStyle</item>
|
||||
<item name="candidateViewStyle">@style/CandidateViewStyle</item>
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
<item name="miniKeyboardViewStyle">@style/MiniKeyboardView.Gingerbread</item>
|
||||
<item name="miniKeyboardPanelStyle">@style/MiniKeyboardPanelStyle</item>
|
||||
<item name="suggestionsStripBackgroundStyle">@style/SuggestionsStripBackgroundStyle</item>
|
||||
<item name="suggestionsPaneViewStyle">@style/SuggestionsPaneViewStyle</item>
|
||||
<item name="suggestionBackgroundStyle">@style/SuggestionBackgroundStyle</item>
|
||||
<item name="suggestionPreviewBackgroundStyle">@style/SuggestionPreviewBackgroundStyle</item>
|
||||
<item name="candidateViewStyle">@style/CandidateViewStyle</item>
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
<item name="miniKeyboardViewStyle">@style/MiniKeyboardView.IceCreamSandwich</item>
|
||||
<item name="miniKeyboardPanelStyle">@style/MiniKeyboardPanelStyle.IceCreamSandwich</item>
|
||||
<item name="suggestionsStripBackgroundStyle">@style/SuggestionsStripBackgroundStyle.IceCreamSandwich</item>
|
||||
<item name="suggestionsPaneViewStyle">@style/SuggestionsPaneViewStyle.IceCreamSandwich</item>
|
||||
<item name="suggestionBackgroundStyle">@style/SuggestionBackgroundStyle.IceCreamSandwich</item>
|
||||
<item name="suggestionPreviewBackgroundStyle">@style/SuggestionPreviewBackgroundStyle.IceCreamSandwich</item>
|
||||
<item name="candidateViewStyle">@style/CandidateViewStyle.IceCreamSandwich</item>
|
||||
|
|
|
@ -22,7 +22,8 @@
|
|||
<item name="miniKeyboardViewStyle">@style/MiniKeyboardView.Stone</item>
|
||||
<item name="miniKeyboardPanelStyle">@style/MiniKeyboardPanelStyle</item>
|
||||
<item name="suggestionsStripBackgroundStyle">@style/SuggestionsStripBackgroundStyle</item>
|
||||
<item name="suggestionBackgroundStyle">@style/SuggestionBackgroundStyle</item>
|
||||
<item name="suggestionsPaneViewStyle">@style/SuggestionsPaneViewStyle</item>
|
||||
<item name="suggestionBackgroundStyle">@style/SuggestionBackgroundStyle</item>
|
||||
<item name="suggestionPreviewBackgroundStyle">@style/SuggestionPreviewBackgroundStyle</item>
|
||||
<item name="candidateViewStyle">@style/CandidateViewStyle</item>
|
||||
</style>
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
<item name="miniKeyboardViewStyle">@style/MiniKeyboardView.Stone</item>
|
||||
<item name="miniKeyboardPanelStyle">@style/MiniKeyboardPanelStyle</item>
|
||||
<item name="suggestionsStripBackgroundStyle">@style/SuggestionsStripBackgroundStyle</item>
|
||||
<item name="suggestionsPaneViewStyle">@style/SuggestionsPaneViewStyle</item>
|
||||
<item name="suggestionBackgroundStyle">@style/SuggestionBackgroundStyle</item>
|
||||
<item name="suggestionPreviewBackgroundStyle">@style/SuggestionPreviewBackgroundStyle</item>
|
||||
<item name="candidateViewStyle">@style/CandidateViewStyle</item>
|
||||
|
|
|
@ -20,8 +20,6 @@
|
|||
|
||||
<Keyboard xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
|
||||
latin:keyWidth="8%p"
|
||||
latin:horizontalGap="@fraction/key_horizontal_gap"
|
||||
latin:verticalGap="0px"
|
||||
latin:rowHeight="@dimen/popup_key_height"
|
||||
>
|
||||
</Keyboard>
|
||||
|
|
|
@ -20,8 +20,6 @@
|
|||
|
||||
<Keyboard xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
|
||||
latin:keyWidth="5.0%p"
|
||||
latin:horizontalGap="0px"
|
||||
latin:verticalGap="0px"
|
||||
latin:rowHeight="@dimen/popup_key_height"
|
||||
>
|
||||
</Keyboard>
|
||||
|
|
|
@ -20,8 +20,6 @@
|
|||
|
||||
<Keyboard xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
|
||||
latin:keyWidth="10%p"
|
||||
latin:horizontalGap="@fraction/key_horizontal_gap"
|
||||
latin:verticalGap="0px"
|
||||
latin:rowHeight="@dimen/popup_key_height"
|
||||
>
|
||||
</Keyboard>
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
/*
|
||||
**
|
||||
** Copyright 2011, 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.
|
||||
*/
|
||||
-->
|
||||
|
||||
<Keyboard xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
|
||||
latin:keyWidth="10%p"
|
||||
latin:rowHeight="@dimen/more_suggestions_row_height"
|
||||
>
|
||||
</Keyboard>
|
|
@ -88,16 +88,7 @@ public class MiniKeyboardView extends KeyboardView implements MoreKeysPanel {
|
|||
}
|
||||
}
|
||||
|
||||
private static final TimerProxy EMPTY_TIMER_PROXY = new TimerProxy() {
|
||||
@Override
|
||||
public void startKeyRepeatTimer(long delay, int keyIndex, PointerTracker tracker) {}
|
||||
@Override
|
||||
public void startLongPressTimer(long delay, int keyIndex, PointerTracker tracker) {}
|
||||
@Override
|
||||
public void cancelLongPressTimer() {}
|
||||
@Override
|
||||
public void cancelKeyTimers() {}
|
||||
};
|
||||
private static final TimerProxy EMPTY_TIMER_PROXY = new TimerProxy.Adapter();
|
||||
|
||||
private final KeyboardActionListener mMiniKeyboardListener =
|
||||
new KeyboardActionListener.Adapter() {
|
||||
|
|
|
@ -76,6 +76,17 @@ public class PointerTracker {
|
|||
public void startLongPressTimer(long delay, int keyIndex, PointerTracker tracker);
|
||||
public void cancelLongPressTimer();
|
||||
public void cancelKeyTimers();
|
||||
|
||||
public static class Adapter implements TimerProxy {
|
||||
@Override
|
||||
public void startKeyRepeatTimer(long delay, int keyIndex, PointerTracker tracker) {}
|
||||
@Override
|
||||
public void startLongPressTimer(long delay, int keyIndex, PointerTracker tracker) {}
|
||||
@Override
|
||||
public void cancelLongPressTimer() {}
|
||||
@Override
|
||||
public void cancelKeyTimers() {}
|
||||
}
|
||||
}
|
||||
|
||||
private static KeyboardSwitcher sKeyboardSwitcher;
|
||||
|
|
|
@ -23,6 +23,7 @@ import android.graphics.Color;
|
|||
import android.graphics.Typeface;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Message;
|
||||
import android.os.SystemClock;
|
||||
import android.text.Spannable;
|
||||
import android.text.SpannableString;
|
||||
import android.text.Spanned;
|
||||
|
@ -34,8 +35,10 @@ import android.text.style.ForegroundColorSpan;
|
|||
import android.text.style.StyleSpan;
|
||||
import android.text.style.UnderlineSpan;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.view.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.view.View.OnLongClickListener;
|
||||
|
@ -46,6 +49,9 @@ import android.widget.TextView;
|
|||
|
||||
import com.android.inputmethod.compat.FrameLayoutCompatUtils;
|
||||
import com.android.inputmethod.compat.LinearLayoutCompatUtils;
|
||||
import com.android.inputmethod.keyboard.KeyboardActionListener;
|
||||
import com.android.inputmethod.keyboard.MoreKeysPanel;
|
||||
import com.android.inputmethod.keyboard.PointerTracker;
|
||||
import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
@ -58,16 +64,22 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo
|
|||
}
|
||||
|
||||
// The maximum number of suggestions available. See {@link Suggest#mPrefMaxSuggestions}.
|
||||
private static final int MAX_SUGGESTIONS = 18;
|
||||
public static final int MAX_SUGGESTIONS = 18;
|
||||
|
||||
private static final boolean DBG = LatinImeLogger.sDBG;
|
||||
|
||||
private final ViewGroup mCandidatesPlacer;
|
||||
private final ViewGroup mCandidatesStrip;
|
||||
// TODO: Remove these pane related fields and stuffs.
|
||||
private ViewGroup mCandidatesPane;
|
||||
private ViewGroup mCandidatesPaneContainer;
|
||||
private View mKeyboardView;
|
||||
|
||||
private final View mMoreSuggestionsContainer;
|
||||
private final MoreSuggestionsView mMoreSuggestionsView;
|
||||
private final MoreSuggestions.Builder mMoreSuggestionsBuilder;
|
||||
private final PopupWindow mMoreSuggestionsWindow;
|
||||
|
||||
private final ArrayList<TextView> mWords = new ArrayList<TextView>();
|
||||
private final ArrayList<TextView> mInfos = new ArrayList<TextView>();
|
||||
private final ArrayList<View> mDividers = new ArrayList<View>();
|
||||
|
@ -159,7 +171,7 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo
|
|||
mDividerHeight = divider.getMeasuredHeight();
|
||||
|
||||
final Resources res = word.getResources();
|
||||
mCandidateStripHeight = res.getDimensionPixelOffset(R.dimen.candidate_strip_height);
|
||||
mCandidateStripHeight = res.getDimensionPixelSize(R.dimen.candidate_strip_height);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -257,7 +269,7 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo
|
|||
private final int mColorTypedWord;
|
||||
private final int mColorAutoCorrect;
|
||||
private final int mColorSuggestedCandidate;
|
||||
private final int mCandidateCountInStrip;
|
||||
public final int mCandidateCountInStrip;
|
||||
private final float mCenterCandidateWeight;
|
||||
private final int mCenterCandidateIndex;
|
||||
private final Drawable mMoreCandidateHint;
|
||||
|
@ -449,7 +461,6 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
return countInStrip;
|
||||
}
|
||||
|
||||
|
@ -585,6 +596,15 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo
|
|||
mInfos);
|
||||
mPaneParams = new SuggestionsPaneParams(mWords, mDividers, mInfos);
|
||||
mStripParams.mWordToSaveView.setOnClickListener(this);
|
||||
|
||||
mMoreSuggestionsContainer = inflater.inflate(R.layout.more_suggestions, null);
|
||||
mMoreSuggestionsView = (MoreSuggestionsView)mMoreSuggestionsContainer
|
||||
.findViewById(R.id.more_suggestions_view);
|
||||
mMoreSuggestionsBuilder = new MoreSuggestions.Builder(mMoreSuggestionsView);
|
||||
mMoreSuggestionsWindow = new PopupWindow(context);
|
||||
mMoreSuggestionsWindow.setWindowLayoutMode(
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
mMoreSuggestionsWindow.setBackgroundDrawable(null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -621,8 +641,6 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo
|
|||
final int width = getWidth();
|
||||
final int countInStrip = mStripParams.layout(
|
||||
mSuggestions, mCandidatesStrip, mCandidatesPlacer, width);
|
||||
mPaneParams.layout(
|
||||
mSuggestions, mCandidatesPane, countInStrip, mStripParams.getTextColor(), width);
|
||||
}
|
||||
|
||||
private static CharSequence getDebugInfo(SuggestedWords suggestions, int pos) {
|
||||
|
@ -787,6 +805,7 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo
|
|||
mCandidatesStrip.removeAllViews();
|
||||
mCandidatesPane.removeAllViews();
|
||||
closeCandidatesPane();
|
||||
mMoreSuggestionsWindow.dismiss();
|
||||
}
|
||||
|
||||
private void hidePreview() {
|
||||
|
@ -823,15 +842,102 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo
|
|||
}
|
||||
}
|
||||
|
||||
private final KeyboardActionListener mMoreSuggestionsListener =
|
||||
new KeyboardActionListener.Adapter() {
|
||||
@Override
|
||||
public boolean onCustomRequest(int requestCode) {
|
||||
final int index = requestCode;
|
||||
final CharSequence word = mSuggestions.getWord(index);
|
||||
mListener.pickSuggestionManually(index, word);
|
||||
mMoreSuggestionsView.dismissMoreKeysPanel();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCancelInput() {
|
||||
mMoreSuggestionsView.dismissMoreKeysPanel();
|
||||
}
|
||||
};
|
||||
|
||||
private final MoreKeysPanel.Controller mMoreSuggestionsController =
|
||||
new MoreKeysPanel.Controller() {
|
||||
@Override
|
||||
public boolean dismissMoreKeysPanel() {
|
||||
if (mMoreSuggestionsWindow.isShowing()) {
|
||||
mMoreSuggestionsWindow.dismiss();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public boolean onLongClick(View view) {
|
||||
if (mStripParams.mMoreSuggestionsAvailable) {
|
||||
toggleCandidatesPane();
|
||||
final SuggestionsStripParams params = mStripParams;
|
||||
if (params.mMoreSuggestionsAvailable) {
|
||||
final int stripWidth = getWidth();
|
||||
final View container = mMoreSuggestionsContainer;
|
||||
final int maxWidth = stripWidth - container.getPaddingLeft()
|
||||
- container.getPaddingRight();
|
||||
final DisplayMetrics dm = getContext().getResources().getDisplayMetrics();
|
||||
// TODO: Revise how we determine the height
|
||||
final int maxHeight = dm.heightPixels - mKeyboardView.getHeight() - getHeight() * 3;
|
||||
final MoreSuggestions.Builder builder = mMoreSuggestionsBuilder;
|
||||
builder.layout(mSuggestions, params.mCandidateCountInStrip, maxWidth, maxHeight);
|
||||
mMoreSuggestionsView.setKeyboard(builder.build());
|
||||
container.measure(
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
|
||||
final MoreKeysPanel moreKeysPanel = mMoreSuggestionsView;
|
||||
final int pointX = stripWidth / 2;
|
||||
final int pointY = 0;
|
||||
moreKeysPanel.showMoreKeysPanel(
|
||||
this, mMoreSuggestionsController, pointX, pointY,
|
||||
mMoreSuggestionsWindow, mMoreSuggestionsListener);
|
||||
// TODO: Should figure out how to select the pointer tracker correctly.
|
||||
final PointerTracker tracker = PointerTracker.getPointerTracker(0, moreKeysPanel);
|
||||
final int translatedX = moreKeysPanel.translateX(tracker.getLastX());
|
||||
final int translatedY = moreKeysPanel.translateY(tracker.getLastY());
|
||||
tracker.onShowMoreKeysPanel(
|
||||
translatedX, translatedY, SystemClock.uptimeMillis(), moreKeysPanel);
|
||||
view.setPressed(false);
|
||||
// TODO: Should gray out the keyboard here as well?
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchTouchEvent(MotionEvent me) {
|
||||
if (!mMoreSuggestionsWindow.isShowing()) {
|
||||
return super.dispatchTouchEvent(me);
|
||||
}
|
||||
final int action = me.getAction();
|
||||
final long eventTime = me.getEventTime();
|
||||
final int index = me.getActionIndex();
|
||||
final int id = me.getPointerId(index);
|
||||
final PointerTracker tracker = PointerTracker.getPointerTracker(id, mMoreSuggestionsView);
|
||||
final int x = mMoreSuggestionsView.translateX((int)me.getX(index));
|
||||
final int y = mMoreSuggestionsView.translateY((int)me.getY(index));
|
||||
switch (action) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
case MotionEvent.ACTION_POINTER_DOWN:
|
||||
tracker.onDownEvent(x, y, eventTime, mMoreSuggestionsView);
|
||||
break;
|
||||
case MotionEvent.ACTION_UP:
|
||||
case MotionEvent.ACTION_POINTER_UP:
|
||||
tracker.onUpEvent(x, y, eventTime);
|
||||
break;
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
tracker.onMoveEvent(x, y, eventTime);
|
||||
break;
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
tracker.onCancelEvent(x, y, eventTime);
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
if (view == mStripParams.mWordToSaveView) {
|
||||
|
|
|
@ -0,0 +1,203 @@
|
|||
/*
|
||||
* Copyright (C) 2011 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.inputmethod.latin;
|
||||
|
||||
import android.graphics.Paint;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.android.inputmethod.keyboard.Key;
|
||||
import com.android.inputmethod.keyboard.Keyboard;
|
||||
import com.android.inputmethod.keyboard.KeyboardSwitcher;
|
||||
import com.android.inputmethod.keyboard.KeyboardView;
|
||||
import com.android.inputmethod.keyboard.internal.KeyboardBuilder;
|
||||
import com.android.inputmethod.keyboard.internal.KeyboardParams;
|
||||
import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
|
||||
|
||||
public class MoreSuggestions extends Keyboard {
|
||||
private static final boolean DBG = LatinImeLogger.sDBG;
|
||||
|
||||
public static final int SUGGESTION_CODE_BASE = 1024;
|
||||
|
||||
private MoreSuggestions(Builder.MoreSuggestionsParam params) {
|
||||
super(params);
|
||||
}
|
||||
|
||||
public static class Builder extends KeyboardBuilder<Builder.MoreSuggestionsParam> {
|
||||
private final MoreSuggestionsView mPaneView;
|
||||
private SuggestedWords mSuggestions;
|
||||
private int mFromPos;
|
||||
private int mToPos;
|
||||
|
||||
public static class MoreSuggestionsParam extends KeyboardParams {
|
||||
private final int[] mWidths = new int[CandidateView.MAX_SUGGESTIONS];
|
||||
private final int[] mRowNumbers = new int[CandidateView.MAX_SUGGESTIONS];
|
||||
private final int[] mColumnOrders = new int[CandidateView.MAX_SUGGESTIONS];
|
||||
private final int[] mNumColumnsInRow = new int[CandidateView.MAX_SUGGESTIONS];
|
||||
private static final int MAX_COLUMNS_IN_ROW = 3;
|
||||
private int mNumRows;
|
||||
|
||||
public int layout(SuggestedWords suggestions, int fromPos, int maxWidth, int maxHeight,
|
||||
KeyboardView view) {
|
||||
clearKeys();
|
||||
final Paint paint = new Paint();
|
||||
paint.setAntiAlias(true);
|
||||
final int padding = (int) view.getContext().getResources()
|
||||
.getDimension(R.dimen.more_suggestions_key_horizontal_padding);
|
||||
|
||||
int row = 0;
|
||||
int pos = fromPos, rowStartPos = fromPos;
|
||||
final int size = Math.min(suggestions.size(), CandidateView.MAX_SUGGESTIONS);
|
||||
while (pos < size) {
|
||||
final CharSequence word = suggestions.getWord(pos);
|
||||
// TODO: Should take care of text x-scaling.
|
||||
mWidths[pos] = (int)view.getDefaultLabelWidth(word, paint) + padding;
|
||||
final int numColumn = pos - rowStartPos + 1;
|
||||
if (numColumn > MAX_COLUMNS_IN_ROW
|
||||
|| !fitInWidth(rowStartPos, pos + 1, maxWidth / numColumn)) {
|
||||
if ((row + 1) * mDefaultRowHeight > maxHeight) {
|
||||
break;
|
||||
}
|
||||
mNumColumnsInRow[row] = pos - rowStartPos;
|
||||
rowStartPos = pos;
|
||||
row++;
|
||||
}
|
||||
mColumnOrders[pos] = pos - rowStartPos;
|
||||
mRowNumbers[pos] = row;
|
||||
pos++;
|
||||
}
|
||||
mNumColumnsInRow[row] = pos - rowStartPos;
|
||||
mNumRows = row + 1;
|
||||
mWidth = mOccupiedWidth = calcurateMaxRowWidth(fromPos, pos);
|
||||
mHeight = mOccupiedHeight = mNumRows * mDefaultRowHeight + mVerticalGap;
|
||||
return pos - fromPos;
|
||||
}
|
||||
|
||||
private boolean fitInWidth(int startPos, int endPos, int width) {
|
||||
for (int pos = startPos; pos < endPos; pos++) {
|
||||
if (mWidths[pos] > width)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private int calcurateMaxRowWidth(int startPos, int endPos) {
|
||||
int maxRowWidth = 0;
|
||||
int pos = startPos;
|
||||
for (int row = 0; row < mNumRows; row++) {
|
||||
final int numColumn = mNumColumnsInRow[row];
|
||||
int maxKeyWidth = 0;
|
||||
while (pos < endPos && mRowNumbers[pos] == row) {
|
||||
maxKeyWidth = Math.max(maxKeyWidth, mWidths[pos]);
|
||||
pos++;
|
||||
}
|
||||
maxRowWidth = Math.max(maxRowWidth, maxKeyWidth * numColumn);
|
||||
}
|
||||
return maxRowWidth;
|
||||
}
|
||||
|
||||
private static final int[][] COLUMN_ORDER_TO_NUMBER = {
|
||||
{ 0, },
|
||||
{ 1, 0, },
|
||||
{ 2, 0, 1},
|
||||
};
|
||||
|
||||
private int getColumnNumber(int pos) {
|
||||
final int columnOrder = mColumnOrders[pos];
|
||||
final int numColumn = mNumColumnsInRow[mRowNumbers[pos]];
|
||||
return COLUMN_ORDER_TO_NUMBER[numColumn - 1][columnOrder];
|
||||
}
|
||||
|
||||
public int getX(int pos) {
|
||||
final int columnNumber = getColumnNumber(pos);
|
||||
return columnNumber * getWidth(pos);
|
||||
}
|
||||
|
||||
public int getY(int pos) {
|
||||
final int row = mRowNumbers[pos];
|
||||
return (mNumRows -1 - row) * mDefaultRowHeight + mTopPadding;
|
||||
}
|
||||
|
||||
public int getWidth(int pos) {
|
||||
final int row = mRowNumbers[pos];
|
||||
final int numColumn = mNumColumnsInRow[row];
|
||||
return mWidth / numColumn;
|
||||
}
|
||||
|
||||
public int getFlags(int pos) {
|
||||
int rowFlags = 0;
|
||||
|
||||
final int row = mRowNumbers[pos];
|
||||
if (row == 0)
|
||||
rowFlags |= Keyboard.EDGE_BOTTOM;
|
||||
if (row == mNumRows - 1)
|
||||
rowFlags |= Keyboard.EDGE_TOP;
|
||||
|
||||
final int numColumn = mNumColumnsInRow[row];
|
||||
final int column = getColumnNumber(pos);
|
||||
if (column == 0)
|
||||
rowFlags |= Keyboard.EDGE_LEFT;
|
||||
if (column == numColumn - 1)
|
||||
rowFlags |= Keyboard.EDGE_RIGHT;
|
||||
|
||||
return rowFlags;
|
||||
}
|
||||
}
|
||||
|
||||
public Builder(MoreSuggestionsView paneView) {
|
||||
super(paneView.getContext(), new MoreSuggestionsParam());
|
||||
mPaneView = paneView;
|
||||
}
|
||||
|
||||
public Builder layout(SuggestedWords suggestions, int fromPos, int maxWidth,
|
||||
int maxHeight) {
|
||||
final Keyboard keyboard = KeyboardSwitcher.getInstance().getLatinKeyboard();
|
||||
final int xmlId = R.xml.kbd_suggestions_pane_template;
|
||||
load(keyboard.mId.cloneWithNewXml(mResources.getResourceEntryName(xmlId), xmlId));
|
||||
mParams.mVerticalGap = mParams.mTopPadding = keyboard.mVerticalGap / 2;
|
||||
|
||||
final int count = mParams.layout(suggestions, fromPos, maxWidth, maxHeight, mPaneView);
|
||||
mFromPos = fromPos;
|
||||
mToPos = fromPos + count;
|
||||
mSuggestions = suggestions;
|
||||
return this;
|
||||
}
|
||||
|
||||
private static String getDebugInfo(SuggestedWords suggestions, int pos) {
|
||||
if (!DBG) return null;
|
||||
final SuggestedWordInfo wordInfo = suggestions.getInfo(pos);
|
||||
if (wordInfo == null) return null;
|
||||
final String info = wordInfo.getDebugString();
|
||||
if (TextUtils.isEmpty(info)) return null;
|
||||
return info;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MoreSuggestions build() {
|
||||
final MoreSuggestionsParam params = mParams;
|
||||
for (int pos = mFromPos; pos < mToPos; pos++) {
|
||||
final String word = mSuggestions.getWord(pos).toString();
|
||||
final String info = getDebugInfo(mSuggestions, pos);
|
||||
final int index = pos + SUGGESTION_CODE_BASE;
|
||||
final Key key = new Key(
|
||||
params, word, info, null, index, null, params.getX(pos), params.getY(pos),
|
||||
params.getWidth(pos), params.mDefaultRowHeight, params.getFlags(pos));
|
||||
params.onAddKey(key);
|
||||
}
|
||||
return new MoreSuggestions(params);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,237 @@
|
|||
/*
|
||||
* Copyright (C) 2011 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.inputmethod.latin;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
import android.widget.PopupWindow;
|
||||
|
||||
import com.android.inputmethod.keyboard.Key;
|
||||
import com.android.inputmethod.keyboard.KeyDetector;
|
||||
import com.android.inputmethod.keyboard.Keyboard;
|
||||
import com.android.inputmethod.keyboard.KeyboardActionListener;
|
||||
import com.android.inputmethod.keyboard.KeyboardView;
|
||||
import com.android.inputmethod.keyboard.MoreKeysPanel;
|
||||
import com.android.inputmethod.keyboard.PointerTracker;
|
||||
import com.android.inputmethod.keyboard.PointerTracker.DrawingProxy;
|
||||
import com.android.inputmethod.keyboard.PointerTracker.TimerProxy;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A view that renders a virtual {@link MoreSuggestions}. It handles rendering of keys and detecting
|
||||
* key presses and touch movements.
|
||||
*/
|
||||
public class MoreSuggestionsView extends KeyboardView implements MoreKeysPanel {
|
||||
private final int[] mCoordinates = new int[2];
|
||||
|
||||
private final KeyDetector mKeyDetector;
|
||||
|
||||
private Controller mController;
|
||||
private KeyboardActionListener mListener;
|
||||
private int mOriginX;
|
||||
private int mOriginY;
|
||||
|
||||
private static class SuggestionsPaneKeyDetector extends KeyDetector {
|
||||
private final int mSlideAllowanceSquare;
|
||||
private final int mSlideAllowanceSquareTop;
|
||||
|
||||
public SuggestionsPaneKeyDetector(float slideAllowance) {
|
||||
super(/* keyHysteresisDistance */0);
|
||||
mSlideAllowanceSquare = (int)(slideAllowance * slideAllowance);
|
||||
// Top slide allowance is slightly longer (sqrt(2) times) than other edges.
|
||||
mSlideAllowanceSquareTop = mSlideAllowanceSquare * 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean alwaysAllowsSlidingInput() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getMaxNearbyKeys() {
|
||||
// No nearby key will be returned.
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getKeyIndexAndNearbyCodes(int x, int y, final int[] allCodes) {
|
||||
final List<Key> keys = getKeyboard().mKeys;
|
||||
final int touchX = getTouchX(x);
|
||||
final int touchY = getTouchY(y);
|
||||
|
||||
int nearestIndex = NOT_A_KEY;
|
||||
int nearestDist = (y < 0) ? mSlideAllowanceSquareTop : mSlideAllowanceSquare;
|
||||
final int keyCount = keys.size();
|
||||
for (int index = 0; index < keyCount; index++) {
|
||||
final int dist = keys.get(index).squaredDistanceToEdge(touchX, touchY);
|
||||
if (dist < nearestDist) {
|
||||
nearestIndex = index;
|
||||
nearestDist = dist;
|
||||
}
|
||||
}
|
||||
|
||||
if (allCodes != null && nearestIndex != NOT_A_KEY)
|
||||
allCodes[0] = keys.get(nearestIndex).mCode;
|
||||
return nearestIndex;
|
||||
}
|
||||
}
|
||||
|
||||
private static final TimerProxy EMPTY_TIMER_PROXY = new TimerProxy.Adapter();
|
||||
|
||||
private final KeyboardActionListener mSuggestionsPaneListener =
|
||||
new KeyboardActionListener.Adapter() {
|
||||
@Override
|
||||
public void onPress(int primaryCode, boolean withSliding) {
|
||||
mListener.onPress(primaryCode, withSliding);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRelease(int primaryCode, boolean withSliding) {
|
||||
mListener.onRelease(primaryCode, withSliding);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCodeInput(int primaryCode, int[] keyCodes, int x, int y) {
|
||||
mListener.onCustomRequest(primaryCode - MoreSuggestions.SUGGESTION_CODE_BASE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCancelInput() {
|
||||
mListener.onCancelInput();
|
||||
}
|
||||
};
|
||||
|
||||
public MoreSuggestionsView(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, R.attr.suggestionsPaneViewStyle);
|
||||
}
|
||||
|
||||
public MoreSuggestionsView(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
|
||||
final Resources res = context.getResources();
|
||||
// Override default ProximityKeyDetector.
|
||||
mKeyDetector = new SuggestionsPaneKeyDetector(res.getDimension(
|
||||
R.dimen.more_suggestions_slide_allowance));
|
||||
// Remove gesture detector on suggestions pane
|
||||
setKeyPreviewPopupEnabled(false, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
final Keyboard keyboard = getKeyboard();
|
||||
if (keyboard != null) {
|
||||
final int width = keyboard.mOccupiedWidth + getPaddingLeft() + getPaddingRight();
|
||||
final int height = keyboard.mOccupiedHeight + getPaddingTop() + getPaddingBottom();
|
||||
setMeasuredDimension(width, height);
|
||||
} else {
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setKeyboard(Keyboard keyboard) {
|
||||
super.setKeyboard(keyboard);
|
||||
mKeyDetector.setKeyboard(keyboard, -getPaddingLeft(),
|
||||
-getPaddingTop() + mVerticalCorrection);
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyDetector getKeyDetector() {
|
||||
return mKeyDetector;
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyboardActionListener getKeyboardActionListener() {
|
||||
return mSuggestionsPaneListener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DrawingProxy getDrawingProxy() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TimerProxy getTimerProxy() {
|
||||
return EMPTY_TIMER_PROXY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setKeyPreviewPopupEnabled(boolean previewEnabled, int delay) {
|
||||
// Suggestions pane needs no pop-up key preview displayed, so we pass always false with a
|
||||
// delay of 0. The delay does not matter actually since the popup is not shown anyway.
|
||||
super.setKeyPreviewPopupEnabled(false, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setShifted(boolean shifted) {
|
||||
// Nothing to do with.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showMoreKeysPanel(View parentView, Controller controller, int pointX, int pointY,
|
||||
PopupWindow window, KeyboardActionListener listener) {
|
||||
mController = controller;
|
||||
mListener = listener;
|
||||
final View container = (View)getParent();
|
||||
final MoreSuggestions pane = (MoreSuggestions)getKeyboard();
|
||||
|
||||
parentView.getLocationInWindow(mCoordinates);
|
||||
final int paneLeft = pointX - (pane.mOccupiedWidth / 2) + parentView.getPaddingLeft();
|
||||
final int x = wrapUp(Math.max(0, Math.min(paneLeft,
|
||||
parentView.getWidth() - pane.mOccupiedWidth))
|
||||
- container.getPaddingLeft() + mCoordinates[0],
|
||||
container.getMeasuredWidth(), 0, parentView.getWidth());
|
||||
final int y = pointY
|
||||
- (container.getMeasuredHeight() - container.getPaddingBottom())
|
||||
+ parentView.getPaddingTop() + mCoordinates[1];
|
||||
|
||||
window.setContentView(container);
|
||||
window.setWidth(container.getMeasuredWidth());
|
||||
window.setHeight(container.getMeasuredHeight());
|
||||
window.showAtLocation(parentView, Gravity.NO_GRAVITY, x, y);
|
||||
|
||||
mOriginX = x + container.getPaddingLeft() - mCoordinates[0];
|
||||
mOriginY = y + container.getPaddingTop() - mCoordinates[1];
|
||||
}
|
||||
|
||||
private static int wrapUp(int x, int width, int left, int right) {
|
||||
if (x < left)
|
||||
return left;
|
||||
if (x + width > right)
|
||||
return right - width;
|
||||
return x;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dismissMoreKeysPanel() {
|
||||
return mController.dismissMoreKeysPanel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int translateX(int x) {
|
||||
return x - mOriginX;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int translateY(int y) {
|
||||
return y - mOriginY;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue