2 * Copyright (C) 2008,2009 OMRON SOFTWARE Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 * Copyright (C) 2008-2009 Google Inc.
20 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
21 * use this file except in compliance with the License. You may obtain a copy of
24 * http://www.apache.org/licenses/LICENSE-2.0
26 * Unless required by applicable law or agreed to in writing, software
27 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
28 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
29 * License for the specific language governing permissions and limitations under
33 package jp.co.omronsoft.openwnn.JAJP;
35 import jp.co.omronsoft.openwnn.*;
36 import android.content.Context;
37 import android.content.res.Resources;
38 import android.graphics.drawable.Drawable;
39 import android.os.Handler;
40 import android.os.Message;
41 import android.text.Layout;
42 import android.text.SpannableStringBuilder;
43 import android.text.StaticLayout;
44 import android.text.Spanned;
45 import android.text.style.ImageSpan;
46 import android.text.style.DynamicDrawableSpan;
47 import android.view.Gravity;
48 import android.view.LayoutInflater;
49 import android.view.MotionEvent;
50 import android.view.View;
51 import android.view.View.OnTouchListener;
52 import android.widget.PopupWindow;
53 import android.widget.TextView;
55 import java.util.ArrayList;
56 import java.util.List;
58 public class TutorialJAJP implements OnTouchListener {
60 private List<Bubble> mBubbles = new ArrayList<Bubble>();
61 private static final int LONG_PRESS_INDEX = 8;
62 private View mInputView;
63 private OpenWnnJAJP mIme;
64 private int[] mLocation = new int[2];
65 private static final int MSG_SHOW_BUBBLE = 0;
67 private int mBubbleIndex;
68 private DefaultSoftKeyboardJAJP mInputManager;
69 private boolean mEnableKeyTouch = false;
71 Handler mHandler = new Handler() {
73 public void handleMessage(Message msg) {
76 Bubble bubba = (Bubble) msg.obj;
77 bubba.show(mLocation[0], mLocation[1]);
84 Drawable bubbleBackground;
90 boolean dismissOnTouch;
91 boolean dismissOnClose;
96 Bubble(Context context, View inputView,
97 int backgroundResource, int bx, int by, int description, int guide) {
99 CharSequence text = context.getResources().getText(description);
100 init(context, inputView, backgroundResource, bx, by, text, guide, false);
103 Bubble(Context context, View inputView, int backgroundResource, int bx, int by,
104 CharSequence description, int guide, boolean leftAlign) {
105 init(context, inputView, backgroundResource, bx, by, description, guide, leftAlign);
108 void init(Context context, View inputView, int backgroundResource,
109 int bx, int by, CharSequence description, int guide, boolean leftAlign) {
110 bubbleBackground = context.getResources().getDrawable(backgroundResource);
113 width = (int) (inputView.getWidth() * 0.9);
114 this.gravity = Gravity.TOP | Gravity.LEFT;
115 text = new SpannableStringBuilder()
118 .append(context.getResources().getText(guide));
119 this.dismissOnTouch = true;
120 this.dismissOnClose = false;
121 this.inputView = inputView;
122 window = new PopupWindow(context);
123 window.setBackgroundDrawable(null);
124 LayoutInflater inflate =
125 (LayoutInflater) context
126 .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
127 textView = (TextView) inflate.inflate(R.layout.bubble_text, null);
128 textView.setBackgroundDrawable(bubbleBackground);
129 textView.setText(text);
131 textView.setGravity(Gravity.CENTER_VERTICAL | Gravity.LEFT);
133 window.setContentView(textView);
134 window.setFocusable(false);
135 window.setTouchable(true);
136 window.setOutsideTouchable(false);
139 private int chooseSize(PopupWindow pop, View parentView, CharSequence text, TextView tv) {
140 int wid = tv.getPaddingLeft() + tv.getPaddingRight();
141 int ht = tv.getPaddingTop() + tv.getPaddingBottom();
144 * Figure out how big the text would be if we laid it out to the
145 * full width of this view minus the border.
147 int cap = width - wid;
149 Layout l = new StaticLayout(text, tv.getPaint(), cap,
150 Layout.Alignment.ALIGN_NORMAL, 1, 0, true);
152 for (int i = 0; i < l.getLineCount(); i++) {
153 max = Math.max(max, l.getLineWidth(i));
157 * Now set the popup size to be big enough for the text plus the border.
160 pop.setHeight(ht + l.getHeight());
161 return l.getHeight();
164 void show(int offx, int offy) {
165 int textHeight = chooseSize(window, inputView, text, textView);
166 offy -= textView.getPaddingTop() + textHeight;
167 if (inputView.getVisibility() == View.VISIBLE
168 && inputView.getWindowVisibility() == View.VISIBLE) {
170 if ((gravity & Gravity.BOTTOM) == Gravity.BOTTOM) offy -= window.getHeight();
171 if ((gravity & Gravity.RIGHT) == Gravity.RIGHT) offx -= window.getWidth();
172 textView.setOnTouchListener(new View.OnTouchListener() {
173 public boolean onTouch(View view, MotionEvent me) {
175 boolean ret = !mEnableKeyTouch;
176 switch (me.getAction()) {
177 case MotionEvent.ACTION_UP:
178 if (mBubbleIndex >= mBubbles.size()) {
179 mInputView.setOnTouchListener(null);
181 TutorialJAJP.this.next();
190 window.showAtLocation(inputView, Gravity.NO_GRAVITY, x + offx, y + offy);
191 } catch (Exception e) {
197 if (window.isShowing()) {
198 textView.setOnTouchListener(null);
203 boolean isShowing() {
204 return window.isShowing();
209 public TutorialJAJP(OpenWnnJAJP ime, View inputView, DefaultSoftKeyboardJAJP inputManager) {
210 mInputManager = inputManager;
211 mInputView = inputView;
214 Context context = inputView.getContext();
215 int inputWidth = inputView.getWidth();
216 Resources r = inputView.getContext().getResources();
217 final int x = inputWidth / 20;
218 r.getDimensionPixelOffset(R.dimen.bubble_pointer_offset);
220 SpannableStringBuilder spannable = new SpannableStringBuilder();
224 spannable.append(r.getText(R.string.tip_to_step1));
226 setSpan(spannable, "\u25cb", R.drawable.tutorial_12key_key);
227 button = new Bubble(context, inputView,
228 R.drawable.dialog_bubble, x, 0,
229 spannable, R.string.touch_to_continue, false);
230 mBubbles.add(button);
233 spannable.append(r.getText(R.string.tip_to_step2_a));
235 setSpan(spannable, "\u25cb", R.drawable.tutorial_12key_toggle);
236 button = new Bubble(context, inputView,
237 R.drawable.dialog_bubble, x, 0,
238 spannable, R.string.touch_to_continue, true);
239 mBubbles.add(button);
241 spannable.append(r.getText(R.string.tip_to_step2_b));
243 setSpan(spannable, "\u2192", R.drawable.tutorial_12key_right);
245 button = new Bubble(context, inputView,
246 R.drawable.dialog_bubble, x, 0,
247 spannable, R.string.touch_to_continue, true);
248 mBubbles.add(button);
250 spannable.append(r.getText(R.string.tip_to_step2_c));
252 setSpan(spannable, "\u25cb", R.drawable.tutorial_12key_toggle);
254 button = new Bubble(context, inputView,
255 R.drawable.dialog_bubble, x, 0,
256 spannable, R.string.touch_to_continue, true);
257 mBubbles.add(button);
259 spannable.append(r.getText(R.string.tip_to_step2_d));
261 setSpan(spannable, "\u25a0", R.drawable.tutorial_12key_space_jp);
263 setSpan(spannable, "\u2193", R.drawable.tutorial_12key_enter);
265 button = new Bubble(context, inputView,
266 R.drawable.dialog_bubble, x, 0,
267 spannable, R.string.touch_to_continue, true);
268 mBubbles.add(button);
271 spannable.append(r.getText(R.string.tip_to_step3_a));
273 setSpan(spannable, "\u25a0", R.drawable.tutorial_12key_mode);
274 button = new Bubble(context, inputView,
275 R.drawable.dialog_bubble_moji, x, 0,
276 spannable, R.string.touch_to_continue, false);
277 mBubbles.add(button);
279 button = new Bubble(context, inputView,
280 R.drawable.dialog_bubble_moji, x, 0,
281 R.string.tip_to_step3_b, R.string.touch_to_continue);
282 mBubbles.add(button);
284 button = new Bubble(context, inputView,
285 R.drawable.dialog_bubble_moji, x, 0,
286 R.string.tip_to_step3_c, R.string.touch_to_continue);
287 mBubbles.add(button);
290 spannable.append(r.getText(R.string.tip_to_step4));
292 setSpan(spannable, "\u25a0", R.drawable.tutorial_12key_mode);
293 button = new Bubble(context, inputView,
294 R.drawable.dialog_bubble_moji, x, 0,
295 spannable, R.string.touch_to_try, false);
296 mBubbles.add(button);
299 spannable.append(r.getText(R.string.tip_to_step5));
301 setSpan(spannable, "\u2190", R.drawable.tutorial_back);
303 button = new Bubble(context, inputView,
304 R.drawable.dialog_bubble, x, 0,
305 spannable, R.string.touch_to_continue, false);
306 mBubbles.add(button);
308 button = new Bubble(context, inputView,
309 R.drawable.dialog_bubble, x, 0,
310 R.string.tip_to_step6, R.string.touch_to_finish);
311 mBubbles.add(button);
314 private void setSpan(SpannableStringBuilder spannable, String marker, int imageResourceId) {
315 String text = spannable.toString();
316 int target = text.indexOf(marker);
317 while (0 <= target) {
318 ImageSpan span = new ImageSpan(mIme, imageResourceId,
319 DynamicDrawableSpan.ALIGN_BOTTOM);
320 spannable.setSpan(span, target, target + 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
321 target = text.indexOf(marker, target + 1);
325 public void start() {
326 mInputView.getLocationInWindow(mLocation);
328 mInputView.setOnTouchListener(this);
333 if (mBubbleIndex >= 0) {
334 if (!mBubbles.get(mBubbleIndex).isShowing()) {
337 for (int i = 0; i <= mBubbleIndex; i++) {
338 mBubbles.get(i).hide();
342 if (mBubbleIndex >= mBubbles.size()) {
343 mEnableKeyTouch = true;
344 mIme.sendDownUpKeyEvents(-1);
349 if ((6 <= mBubbleIndex) && (mBubbleIndex <= 8)) {
350 mInputManager.nextKeyMode();
353 if (mBubbleIndex == LONG_PRESS_INDEX) {
354 mEnableKeyTouch = true;
355 } else if (LONG_PRESS_INDEX < mBubbleIndex) {
356 mEnableKeyTouch = false;
359 mHandler.sendMessageDelayed(
360 mHandler.obtainMessage(MSG_SHOW_BUBBLE, mBubbles.get(mBubbleIndex)), 500);
365 for (int i = 0; i < mBubbles.size(); i++) {
366 mBubbles.get(i).hide();
368 mInputView.setOnTouchListener(null);
371 public boolean close() {
372 mHandler.removeMessages(MSG_SHOW_BUBBLE);
377 public boolean onTouch(View v, MotionEvent event) {
378 boolean ret = !mEnableKeyTouch;
379 if (event.getAction() == MotionEvent.ACTION_UP) {
380 if (mBubbleIndex >= mBubbles.size()) {
381 mInputView.setOnTouchListener(null);
383 if (mBubbleIndex != LONG_PRESS_INDEX) {